diff --git a/CHANGES b/CHANGES index cf700e975..5de140640 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,88 @@ +9.4.0 +- Fixed bug OpenAsync throws unhandled exception from thread pool (MySQL Bug #110789, Oracle Bug #35474099). +- Fixed Entity Framework 6 from NET9 is deprecated due to Nunit4 Upgrade (MySQL Bug #117976, Oracle Bug #37837374). +- Added support for GSSAPI/Kerberos authentication on Windows using authentication_ldap_sasl_client plug-in (WL15984). +- Added support for .NET 10 and EF Core 10 preview versions (WL16900). +- Fixed MySql.EntityFrameworkCore 8.0.8 rename bug (MySQL Bug #116704, Oracle Bug #37462099). +- Fixed Invalid cast exception (MySQL Bug #118282, Oracle Bug #38001821). Thanks to Dev Nullinside for the contribution. +- Fixed MySqlHelper.ExecuteReaderAsync causes stack overflow (MySQL Bug #114006, Oracle Bug #36303124). +- Fixed bug Connector/Net Not honouring MinPoolSize Configuration (MySQL Bug #117020, Oracle Bug #37462116). +- Fixed bug bugfix schema name (specially usefull when use multiple schema) (MySQL Bug #111030, Oracle Bug #35392218). Thanks to Stéphane Graziano for the contribution. +- Fixed bug reorganize test suite (Oracle Bug #38029691). + + +9.3.0 +- Fixed bug MySql.EntityFrameworkCore.dll in NuGet packages is not signed (Oracle Bug #37503859). +- Fixed some tests due to incorrect implementation (WL16033). +- Updated third party dependencies (WL16852). +- Fixed bug Cannot Perform Database Migration using MySql.EntityFrameworkCore 9.0.0 (MySQL Bug #117258, Oracle Bug #37513445). +- Fixed failing tests due to server changes (Oracle Bug #37705281). + + +9.2.0 +- Added support for .NET 9 and EF Core 9 GA versions (WL16638). +- Removed support for .NET 6 and EFCore 6 (WL16654). +- Fixed bug Run inserts in batch command as one block (MySQL Bug #110553, Oracle Bug #35240186). Thanks to Sebastian Schwarzhuber for the contribution. +- Fixed failing tests due to server changes (Oracle Bug #37365939). +- Fixed bug Fix: MySQLUpdateSqlGenerator to inherit UpdateAndSelectSqlGenerator (MySQL Bug #115020, Oracle Bug #36624158). Thanks to Hikari Fujioka for the contribution. +- Fixed bug Fixed NullReferenceException (MySQL Bug #114457, Oracle Bug #36568102). Thanks to Maximilian Bienhüls for the contribution. +- Fixed bug MySql.Data.OpenTelemetry dll has a version 0.0.0.0 (Oracle Bug #37198051). +- Fixed bug Missing VersionInfo file in multiple projects (Oracle Bug #37240118). +- Fixed bug ConcurrencyFix - Added back in RowCount checking (MySQL Bug #115853, Oracle Bug #36960454). Thanks to Ryan Kelly for the contribution. + + +9.1.0 +- Updated test suite to use constraint-based assertions (WL16397). +- Changed testsuite to use assummptions instead of Assert.Ignore (WL16402). +- Added support for .NET 9 and EFCore 9 preview versions (WL16308). +- Added OpenTelemetry.Api NuGet package reference (WL16453). +- Fixed Code coverage (WL16309). +- Added support for OpenID Connect client authentication (WL16491). +- Fixed bug 8.0.33 Removes Important Locks (MySQL Bug #111759, Oracle Bug #35937318). Thanks to Stuart Lang for the contribution. +- Fixed bug EntityFramework SQL generation of TPT pseudo discriminator column incorrect (MySQL Bug #116028, Oracle Bug #37032982). Thanks to Kristoffer Sjöberg for the contribution. +- Fixed bug Connector does crashes when retrieving data from the database (MySQL Bug #111630, Oracle Bug #35937293). Thanks to Sidraya Jayagond for the contribution. + + +9.0.0 +- Updated NUnit to 4.x (WL16279). +- Removed deprecated OldGetStringBehavior option (WL16280). +- Remove MySqlX.Data.Performance.Console.Tests project (WL16387). +- Updated third party dependencies (WL16291). +- Remove .NET 7 and EF Core 7 (WL16386). +- Fixed bug SQL Keyword "RETURNING" not handled properly when updating data (Oracle Bug #36116171). Thanks to Wang Shiyao for the contribution. +- Fixed bug IIS Website is crashing after upgrading MySQL.Data package to 8.3.0 (Oracle Bug #36483069). +- Updated Wix Toolset to 4.0.5 (Oracle Bug #36627858). +- Fixed bug disabling of mysql_native_password in server causes errors in testsuite (Oracle Bug #36529814). +- Fixed bug EFCore test failing due to misconfiguration (Oracle Bug #36701652). + + +8.4.0 +- Updated FOSS license text in all source files (WL16197). +- Fixed bug Shared memory connection doesn't work in multithread environment (Oracle Bug #36208932). +- Fixed bug Named pipe connection doesn't work in multithread environment (Oracle Bug #36208929). +- Fixed bug Byte array type mapping has a fixed limit of 8000 in EFCore (Oracle Bug #36208913). +- Removed support for FIDO authentication (WL16150). +- Add support for TLS 1.3 (WL16176). +- Updated installer and binary metadata (WL16204). +- Fixed bug Minpoolsize different than 0 causes connector to hang after first connection (Oracle Bug #36319784). +- Fixed bug Tests failing due to removal of 'HAVE_SSL' variable from server (Oracle Bug #36374702). +- Added support for Vector data type (WL16175). +- Fixed bug Fix deadlock in mysql poolmanager attempt (Oracle Bug #36380976). Thanks to Marek Matys for the contribution. +- Fixed bug Test failing due to removal of 'default_authentication_plugin' server variable (Oracle Bug #36405198). + + +8.3.0 +- Added support for build traversal (WL15798). +- Added AssemblyInfo file to MySQL.Data.OpenTelemetry (Oracle Bug #35957212). +- Fix broken .GetString() behavior on MySqlDataReader (WL15972). +- Fixed a bug that prevented a connection from being removed from the in use connection pool. (MySQL Bug #112123, Oracle Bug #35731216). +- Added missing target frameworks to EFCore nuget packages (Oracle Bug #35968775). +- Added missing README files to Nuget packages (WL16041). +- Upgraded the Google.Protobuf dependency to version 3.25.1 (WL16075). +- Added support for .NET 8 and EFCore 8 GA versions (WL16035). +- Fixed a bug that permitted to open a disposed connection (MySQL bug #112399, Oracle bug #35827809). + + 8.2.0 - Migrated installer to Wix 4.0 (WL15847). - Fixed bug Opening two MySqlConnections simultaneously can crash (Oracle Bug #35307501). @@ -469,4 +554,4 @@ - Support for MySqlX.Session and NodeSession objects in new Dev API. - Support for Collection and Documents objects new Dev API. - Support for Relational tables in new Dev API. -- Support for Transactions in new Dev API. \ No newline at end of file +- Support for Transactions in new Dev API. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 280a049de..e5612e3bd 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,48 +1,65 @@ # Contributing Guidelines -We love getting feedback from our users. Bugs and code contributions are great forms of feedback and we thank you for any bugs you report or code you contribute. +We greatly appreciate feedback from our users, including bug reports and code contributions. Your input helps us improve, and we thank you for any issues you report or code you contribute. ## Reporting Issues -Before reporting a new bug, please [check first](https://bugs.mysql.com/search.php) to see if a similar bug exists. +Before submitting a new bug report, please [check here](https://bugs.mysql.com/search.php) to see if the issue has already been reported. -Bug reports should be as complete as possible. Please try and include the following: -* Complete steps to reproduce the issue. -* Any information about platform and environment that could be specific to the bug. -* Specific version of the product you are using. -* Specific version of the server being used. -* Sample code to help reproduce the issue if possible. +When reporting a bug, ensure your report is as detailed as possible. Please include the following: + +* Clear, reproducible steps to demonstrate the issue. +* Relevant platform and environment information. +* The specific version of the product in use. +* The version of the MySQL Server in use. +* Sample code that can help reproduce the issue, if applicable. ## Contributing Code -Contributing to this project is easy. You just need to follow these steps: +We welcome your code contributions. Before submitting code via a GitHub pull request or by filing a bug on [bugs.mysql.com](https://bugs.mysql.com), you will need to sign the Oracle Contributor Agreement (OCA). Instructions for signing the OCA are available on the [OCA Page](https://oca.opensource.oracle.com). + +**Only pull requests from contributors who have signed the OCA can be accepted.** + +### Submitting a Contribution -* Make sure you have a user account at [bugs.mysql.com](bugs.mysql.com). You'll need to reference this user account when you submit your OCA (Oracle Contributor Agreement). -* Sign the Oracle OCA. You can find instructions for doing that at the [OCA Page](https://oca.opensource.oracle.com/). -* Develop your pull request. - * Make sure you are aware of the requirements for the project (e.g. don't require .NET Core 3.0 if we are curently supporting .NET Core 2.2 and lower). -* Validate your pull request by including tests that sufficiently cover the functionality. -* Verify that the entire test suite passes with your code applied. -* Submit your pull request. While you can submit the pull request with [Github](https://github.com/mysql/mysql-connector-net/pulls), you can also submit it directly with [bugs.mysql.com](https://bugs.mysql.com). +1. Ensure you have a user account at [bugs.mysql.com](https://bugs.mysql.com). You'll need to reference this account when submitting your OCA. +2. Sign the Oracle Contributor Agreement. Instructions are provided on the [OCA Page](https://oca.opensource.oracle.com). +3. Validate your contribution by including tests that adequately cover the functionality you're adding. +4. Ensure the entire test suite passes with your changes applied. +5. Submit your pull request through [GitHub](https://github.com/mysql/mysql-connector-net/pulls/) or upload it to a bug record on [bugs.mysql.com](https://bugs.mysql.com) using the _Contributions_ tab. -Thanks again for being willing to contribute to MySQL. We truly believe in the principles of open source and appreciate any and all contributions to our projects. +### Developing Your Pull Request + +1. Create your pull request, following the [project's requirements](https://dev.mysql.com/doc/connector-net/en/connector-net-installation.html). +2. Include sufficient tests to validate the new functionality. +3. Confirm that the entire test suite passes with your changes applied. +4. Submit the pull request via [GitHub](https://github.com/mysql/mysql-connector-net/pulls/) or directly via [bugs.mysql.com](https://bugs.mysql.com). + +We deeply value contributions to MySQL and thank you for supporting open-source development. ## Setting Up a Development Environment -You can use your preferred .NET IDE to view, edit, and compile the MySQL Connector/NET source code. The configuration setup can be adapted from [Installing from Source](https://dev.mysql.com/doc/connector-net/en/connector-net-installation-source.html). +You can use your preferred .NET IDE to view, edit, and compile the MySQL Connector/NET source code. For project configuration, please refer to the instructions in [Installing from Source](https://dev.mysql.com/doc/connector-net/en/connector-net-installation-source.html). ## Running Tests -Any code you contribute needs to pass our test suite, each of our projects have his own (e.g. MySql.Data.Tests). You must run the entire suite just to make sure that no other functionality have been affected by the change. You can run the test suite by using the IDE of your preference or by CLI with the help of the "dotnet" tool. - +Any code you contribute must pass our test suite. Each project has its own suite (e.g., *MySql.Data.Tests*). Be sure to run the entire test suite to ensure that no other functionality is affected by your changes. You can run the tests using your preferred IDE or via the CLI with the "dotnet" tool. + ## Getting Help -If you need help or just want to get in touch with us, please use the following resources: +If you need assistance or would like to reach out to the community, please use the following resources: -* [MySQL Connector/NET and C# forum](https://forums.mysql.com/list.php?38) -* [MySQL NuGet](https://www.nuget.org/profiles/MySQL) -* [MySQL Bugs database](https://bugs.mysql.com/) +* [MySQL Connector/NET Developer Guide](https://dev.mysql.com/doc/connector-net/en/) +* [MySQL Connector/NET API](https://dev.mysql.com/doc/dev/connector-net/latest/) +* [MySQL NuGet](https://www.nuget.org/profiles/MySQL/) +* [MySQL Connector/NET and C#, Mono, .Net Forum](https://forums.mysql.com/list.php?38) +* [`#connectors` channel on MySQL Community Slack](https://mysqlcommunity.slack.com/messages/connectors/) ([Sign-up](https://lefred.be/mysql-community-on-slack/) required if you do not have an Oracle account.) +* [@MySQL on X](https://x.com/MySQL/). +* [MySQL Blog](https://blogs.oracle.com/mysql/). +* [MySQL Connectors Blog archive](https://dev.mysql.com/blog-archive/?cat=Connectors%20%2F%20Languages). +* [MySQL Newsletter](https://www.mysql.com/news-and-events/newsletter/). +* [MySQL Bugs Tracking System](https://bugs.mysql.com). -We hope to hear from you soon. Enjoy your coding! +We look forward to hearing from you and encourage you to get involved. Happy coding! -[![Twitter Follow](https://img.shields.io/twitter/follow/MySQL.svg?label=Follow%20%40MySQL&style=social)](https://twitter.com/intent/follow?screen_name=MySQL) \ No newline at end of file +[![X (formerly Twitter) Follow](https://img.shields.io/twitter/follow/MySQL?style=social)](https://x.com/intent/follow?screen_name=MySQL) diff --git a/Dependencies/MITLibs/comerr64.dll b/Dependencies/MITLibs/comerr64.dll index 0a48cb5b6..70753cc79 100644 Binary files a/Dependencies/MITLibs/comerr64.dll and b/Dependencies/MITLibs/comerr64.dll differ diff --git a/Dependencies/MITLibs/gssapi64.dll b/Dependencies/MITLibs/gssapi64.dll index 1628e3842..21d6feb38 100644 Binary files a/Dependencies/MITLibs/gssapi64.dll and b/Dependencies/MITLibs/gssapi64.dll differ diff --git a/Dependencies/MITLibs/k5sprt64.dll b/Dependencies/MITLibs/k5sprt64.dll index 9237ce9d7..ff77f1a3b 100644 Binary files a/Dependencies/MITLibs/k5sprt64.dll and b/Dependencies/MITLibs/k5sprt64.dll differ diff --git a/Dependencies/MITLibs/krb5_64.dll b/Dependencies/MITLibs/krb5_64.dll index 582f680f8..42db6f7b1 100644 Binary files a/Dependencies/MITLibs/krb5_64.dll and b/Dependencies/MITLibs/krb5_64.dll differ diff --git a/Dependencies/MITLibs/krbcc64.dll b/Dependencies/MITLibs/krbcc64.dll index ba5a5190d..c3891e817 100644 Binary files a/Dependencies/MITLibs/krbcc64.dll and b/Dependencies/MITLibs/krbcc64.dll differ diff --git a/Dependencies/OpenTelemetry.Api/OpenTelemetry.Api.dll b/Dependencies/OpenTelemetry.Api/OpenTelemetry.Api.dll deleted file mode 100644 index 9f8aee47f..000000000 Binary files a/Dependencies/OpenTelemetry.Api/OpenTelemetry.Api.dll and /dev/null differ diff --git a/Documentation/docfx.json b/Documentation/docfx.json index 0989b6025..f194fe7e3 100644 --- a/Documentation/docfx.json +++ b/Documentation/docfx.json @@ -28,7 +28,7 @@ } ], "dest": "api/efcore_api", - "properties": { "TargetFramework": "net7.0" } + "properties": { "TargetFramework": "net9.0" } }, { "src": [ @@ -77,7 +77,7 @@ } ], "globalMetadata": { - "_appFooter": "Copyright © 2021, 2023, Oracle and/or its affiliates.", + "_appFooter": "Copyright © 2021, 2025, Oracle and/or its affiliates.", "_appLogoPath": "/images/logo.svg", "_appFaviconPath": "/images/favicon.ico", "_enableSearch": true @@ -86,4 +86,4 @@ "markdownEngineName": "markdig", "xrefService": [ "https://xref.docs.microsoft.com/query?uid={uid}" ] } -} \ No newline at end of file +} diff --git a/Documentation/index.md b/Documentation/index.md index ad6cc25d6..8fed932d0 100644 --- a/Documentation/index.md +++ b/Documentation/index.md @@ -1,6 +1,6 @@ ## MySQL Connector/NET and X DevAPI -MySQL Connector/NET 8.2 supports X Protocol, which enables you to use X DevAPI with the .NET language of choice to develop applications that communicate with a MySQL server functioning as a document store, relational database, or both. +MySQL Connector/NET 9.4 supports X Protocol, which enables you to use X DevAPI with the .NET language of choice to develop applications that communicate with a MySQL server functioning as a document store, relational database, or both. To get started, review the following main classes: @@ -16,7 +16,7 @@ For an introduction to X DevAPI concepts, see the [X DevAPI User Guide](https:// ## MySQL Connector/NET -MySQL Connector/NET 8.2 also supports the development of .NET, .NET Core and .NET Framework applications that require secure, high-performance data connectivity with MySQL through the classic protocol. It supports ADO.NET, Entity Framework and various web providers. +MySQL Connector/NET 9.4 also supports the development of .NET, .NET Core and .NET Framework applications that require secure, high-performance data connectivity with MySQL through the classic protocol. It supports ADO.NET, Entity Framework and various web providers. To get started, review the following main classes: diff --git a/Documentation/templates/custom/partials/class.header.tmpl.partial b/Documentation/templates/custom/partials/class.header.tmpl.partial index 9a663a1e5..f545c2864 100644 --- a/Documentation/templates/custom/partials/class.header.tmpl.partial +++ b/Documentation/templates/custom/partials/class.header.tmpl.partial @@ -25,7 +25,7 @@ {{/implements.0}}
{{__global.namespace}}: {{{namespace.specName.0.value}}}
{{__global.assembly}}: {{assemblies.0}}.dll
-
Version: 8.2.0
+
Version: 9.4.0
{{__global.syntax}}
{{syntax.content.0.value}}
diff --git a/EFCore/Directory.Build.targets b/EFCore/Directory.Build.targets deleted file mode 100644 index 08bf7e756..000000000 --- a/EFCore/Directory.Build.targets +++ /dev/null @@ -1,16 +0,0 @@ - - - Copyright (c) 2021, 2023, Oracle and/or its affiliates. - 6.0.21+MySQL8.2.0 - - - - Copyright (c) 2022, 2023, Oracle and/or its affiliates. - 7.0.10+MySQL8.2.0 - - - - Copyright (c) 2023, Oracle and/or its affiliates. - 8.0.0-preview+MySQL8.2.0 - - \ No newline at end of file diff --git a/EFCore/src/DataAnnotations/MySQLCharsetAttribute.cs b/EFCore/src/DataAnnotations/MySQLCharsetAttribute.cs index 93341796a..6541f6d5e 100644 --- a/EFCore/src/DataAnnotations/MySQLCharsetAttribute.cs +++ b/EFCore/src/DataAnnotations/MySQLCharsetAttribute.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/DataAnnotations/MySQLCollationAttribute.cs b/EFCore/src/DataAnnotations/MySQLCollationAttribute.cs index a5096091c..53cdb1bb8 100644 --- a/EFCore/src/DataAnnotations/MySQLCollationAttribute.cs +++ b/EFCore/src/DataAnnotations/MySQLCollationAttribute.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/Design/Internal/MySQLAnnotationCodeGenerator.cs b/EFCore/src/Design/Internal/MySQLAnnotationCodeGenerator.cs index c784b531f..4fce96898 100644 --- a/EFCore/src/Design/Internal/MySQLAnnotationCodeGenerator.cs +++ b/EFCore/src/Design/Internal/MySQLAnnotationCodeGenerator.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/Design/Internal/MySQLDesignTimeServices.cs b/EFCore/src/Design/Internal/MySQLDesignTimeServices.cs index 145c197a1..30389cea5 100644 --- a/EFCore/src/Design/Internal/MySQLDesignTimeServices.cs +++ b/EFCore/src/Design/Internal/MySQLDesignTimeServices.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/Diagnostics/Internal/MySQLLoggingDefinitions.cs b/EFCore/src/Diagnostics/Internal/MySQLLoggingDefinitions.cs index 0eb84c2b6..6ac04605a 100644 --- a/EFCore/src/Diagnostics/Internal/MySQLLoggingDefinitions.cs +++ b/EFCore/src/Diagnostics/Internal/MySQLLoggingDefinitions.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -64,4 +64,4 @@ internal class MySQLLoggingDefinitions : RelationalLoggingDefinitions public EventDefinitionBase? LogReflexiveConstraintIgnored; } -} \ No newline at end of file +} diff --git a/EFCore/src/Diagnostics/MySQLEventId.cs b/EFCore/src/Diagnostics/MySQLEventId.cs index 571f75f12..e2a639ea6 100644 --- a/EFCore/src/Diagnostics/MySQLEventId.cs +++ b/EFCore/src/Diagnostics/MySQLEventId.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -187,4 +187,4 @@ private enum Id /// public static readonly EventId ReflexiveConstraintIgnored = MakeScaffoldingId(Id.ReflexiveConstraintIgnored); } -} \ No newline at end of file +} diff --git a/EFCore/src/Extensions/MySQLDatabaseFacadeExtensions.cs b/EFCore/src/Extensions/MySQLDatabaseFacadeExtensions.cs index 585b4a51d..43f02dfe9 100644 --- a/EFCore/src/Extensions/MySQLDatabaseFacadeExtensions.cs +++ b/EFCore/src/Extensions/MySQLDatabaseFacadeExtensions.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/Extensions/MySQLDbContextOptionsExtensions.cs b/EFCore/src/Extensions/MySQLDbContextOptionsExtensions.cs index 50072cf32..9cc0b5150 100644 --- a/EFCore/src/Extensions/MySQLDbContextOptionsExtensions.cs +++ b/EFCore/src/Extensions/MySQLDbContextOptionsExtensions.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -201,4 +201,4 @@ var coreOptionsExtension ((IDbContextOptionsBuilderInfrastructure)optionsBuilder).AddOrUpdateExtension(coreOptionsExtension); } } -} \ No newline at end of file +} diff --git a/EFCore/src/Extensions/MySQLDbFunctionsEnums.cs b/EFCore/src/Extensions/MySQLDbFunctionsEnums.cs index cc8e6a5b6..48e224773 100644 --- a/EFCore/src/Extensions/MySQLDbFunctionsEnums.cs +++ b/EFCore/src/Extensions/MySQLDbFunctionsEnums.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/Extensions/MySQLDbFunctionsExtensions.cs b/EFCore/src/Extensions/MySQLDbFunctionsExtensions.cs index 4e10401c6..6cc956262 100644 --- a/EFCore/src/Extensions/MySQLDbFunctionsExtensions.cs +++ b/EFCore/src/Extensions/MySQLDbFunctionsExtensions.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/Extensions/MySQLEntityTypeBuilderExtensions.cs b/EFCore/src/Extensions/MySQLEntityTypeBuilderExtensions.cs index cf19851e7..33bc3b1e4 100644 --- a/EFCore/src/Extensions/MySQLEntityTypeBuilderExtensions.cs +++ b/EFCore/src/Extensions/MySQLEntityTypeBuilderExtensions.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/Extensions/MySQLEntityTypeExtensions.cs b/EFCore/src/Extensions/MySQLEntityTypeExtensions.cs index ed70a8753..9eec6cc26 100644 --- a/EFCore/src/Extensions/MySQLEntityTypeExtensions.cs +++ b/EFCore/src/Extensions/MySQLEntityTypeExtensions.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/Extensions/MySQLIndexExtensions.cs b/EFCore/src/Extensions/MySQLIndexExtensions.cs index b6e6984c6..bc4be7b3c 100644 --- a/EFCore/src/Extensions/MySQLIndexExtensions.cs +++ b/EFCore/src/Extensions/MySQLIndexExtensions.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -194,4 +194,4 @@ public static int[] SetPrefixLength([NotNull] this IConventionIndex index, int[] public static ConfigurationSource? GetPrefixLengthConfigurationSource([NotNull] this IConventionIndex property) => property.FindAnnotation(MySQLAnnotationNames.IndexPrefixLength)?.GetConfigurationSource(); } -} \ No newline at end of file +} diff --git a/EFCore/src/Extensions/MySQLKeyBuilderExtensions.cs b/EFCore/src/Extensions/MySQLKeyBuilderExtensions.cs index e60b9a12d..72727aefb 100644 --- a/EFCore/src/Extensions/MySQLKeyBuilderExtensions.cs +++ b/EFCore/src/Extensions/MySQLKeyBuilderExtensions.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/Extensions/MySQLKeyExtensions.cs b/EFCore/src/Extensions/MySQLKeyExtensions.cs index 5481669a3..2be6817e1 100644 --- a/EFCore/src/Extensions/MySQLKeyExtensions.cs +++ b/EFCore/src/Extensions/MySQLKeyExtensions.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/Extensions/MySQLMigrationBuilderExtensions.cs b/EFCore/src/Extensions/MySQLMigrationBuilderExtensions.cs index ddb6a689d..6aef77044 100644 --- a/EFCore/src/Extensions/MySQLMigrationBuilderExtensions.cs +++ b/EFCore/src/Extensions/MySQLMigrationBuilderExtensions.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/Extensions/MySQLModelBuilderExtensions.cs b/EFCore/src/Extensions/MySQLModelBuilderExtensions.cs index e6a07340f..89a4a2801 100644 --- a/EFCore/src/Extensions/MySQLModelBuilderExtensions.cs +++ b/EFCore/src/Extensions/MySQLModelBuilderExtensions.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/Extensions/MySQLModelExtensions.cs b/EFCore/src/Extensions/MySQLModelExtensions.cs index 932546941..f2284ec4f 100644 --- a/EFCore/src/Extensions/MySQLModelExtensions.cs +++ b/EFCore/src/Extensions/MySQLModelExtensions.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/Extensions/MySQLPropertyBuilderExtensions.cs b/EFCore/src/Extensions/MySQLPropertyBuilderExtensions.cs index edd95f691..88729618a 100644 --- a/EFCore/src/Extensions/MySQLPropertyBuilderExtensions.cs +++ b/EFCore/src/Extensions/MySQLPropertyBuilderExtensions.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/Extensions/MySQLPropertyExtensions.cs b/EFCore/src/Extensions/MySQLPropertyExtensions.cs index 27b3b44cb..ebc0ebed1 100644 --- a/EFCore/src/Extensions/MySQLPropertyExtensions.cs +++ b/EFCore/src/Extensions/MySQLPropertyExtensions.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -253,4 +253,4 @@ private static void CheckValueGenerationStrategy(IReadOnlyProperty property, MyS } } } -} \ No newline at end of file +} diff --git a/EFCore/src/Extensions/MySQLServiceCollectionExtensions.cs b/EFCore/src/Extensions/MySQLServiceCollectionExtensions.cs index db08f46e5..42317fa9b 100644 --- a/EFCore/src/Extensions/MySQLServiceCollectionExtensions.cs +++ b/EFCore/src/Extensions/MySQLServiceCollectionExtensions.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -168,4 +168,4 @@ public static IServiceCollection AddEntityFrameworkMySQL(this IServiceCollection return services; } } -} \ No newline at end of file +} diff --git a/EFCore/src/Extensions/MySQLTypeBaseExtensions.cs b/EFCore/src/Extensions/MySQLTypeBaseExtensions.cs new file mode 100644 index 000000000..ba1e608bc --- /dev/null +++ b/EFCore/src/Extensions/MySQLTypeBaseExtensions.cs @@ -0,0 +1,60 @@ +// Copyright © 2023, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using Microsoft.EntityFrameworkCore.Metadata; +using MySql.EntityFrameworkCore.Metadata.Internal; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MySql.EntityFrameworkCore.Extensions +{ + /// + /// MySQL extension methods for type base. + /// + public static class MySQLTypeBaseExtensions + { + /// + /// Gets the MySQL character set for the table associated with this TypeBase. + /// + /// The TypeBase. + /// The name of the character set. + public static string? GetCharSet([NotNull] this IReadOnlyTypeBase typeBase) + => typeBase[MySQLAnnotationNames.Charset] as string; + + /// + /// Gets the MySQL collation for the table associated with this TypeBase. + /// + /// The TypeBase. + /// The name of the collation. + public static string? GetCollation([NotNull] this IReadOnlyTypeBase typeBase) + => typeBase[RelationalAnnotationNames.Collation] as string; + } +} diff --git a/EFCore/src/Extensions/MySqlIndexBuilderExtensions.cs b/EFCore/src/Extensions/MySqlIndexBuilderExtensions.cs index 6409ac85a..43257933f 100644 --- a/EFCore/src/Extensions/MySqlIndexBuilderExtensions.cs +++ b/EFCore/src/Extensions/MySqlIndexBuilderExtensions.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/Infrastructure/Internal/IMySQLOptions.cs b/EFCore/src/Infrastructure/Internal/IMySQLOptions.cs index 4252d8677..116f21644 100644 --- a/EFCore/src/Infrastructure/Internal/IMySQLOptions.cs +++ b/EFCore/src/Infrastructure/Internal/IMySQLOptions.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -52,4 +52,4 @@ public interface IMySQLOptions : ISingletonOptions /// The SchemaNameTranslator. MySQLSchemaNameTranslator? SchemaNameTranslator { get; } } -} \ No newline at end of file +} diff --git a/EFCore/src/Infrastructure/Internal/MySQLOptionsExtension.cs b/EFCore/src/Infrastructure/Internal/MySQLOptionsExtension.cs index 0231be384..e2fc4616d 100644 --- a/EFCore/src/Infrastructure/Internal/MySQLOptionsExtension.cs +++ b/EFCore/src/Infrastructure/Internal/MySQLOptionsExtension.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -153,4 +153,4 @@ public override void PopulateDebugInfo(IDictionary debugInfo) = (Extension.CharSet?.GetHashCode() ?? 0L).ToString(CultureInfo.InvariantCulture); } } -} \ No newline at end of file +} diff --git a/EFCore/src/Infrastructure/MySQLDbContextOptionsBuilder.cs b/EFCore/src/Infrastructure/MySQLDbContextOptionsBuilder.cs index cae15cd48..b01a40fcf 100644 --- a/EFCore/src/Infrastructure/MySQLDbContextOptionsBuilder.cs +++ b/EFCore/src/Infrastructure/MySQLDbContextOptionsBuilder.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/Infrastructure/MySQLSchemaBehavior.cs b/EFCore/src/Infrastructure/MySQLSchemaBehavior.cs index acb63a8df..75f1002e7 100644 --- a/EFCore/src/Infrastructure/MySQLSchemaBehavior.cs +++ b/EFCore/src/Infrastructure/MySQLSchemaBehavior.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/Internal/MySQLModelValidator.cs b/EFCore/src/Internal/MySQLModelValidator.cs index adebfc755..3ffd0388f 100644 --- a/EFCore/src/Internal/MySQLModelValidator.cs +++ b/EFCore/src/Internal/MySQLModelValidator.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -48,4 +48,4 @@ public override void Validate(IModel model, IDiagnosticsLogger /// Represents a character-set attribute for an entity. /// @@ -58,4 +59,30 @@ protected override void ProcessEntityTypeAdded( true); } } +#else + /// + /// Represents a character-set attribute for a Type. + /// + internal class MySqlEntityCharsetAttributeConvention : TypeAttributeConventionBase + { + /// + /// Creates a new instance of . + /// + /// Parameter object containing dependencies for this convention. + public MySqlEntityCharsetAttributeConvention([NotNull] ProviderConventionSetBuilderDependencies dependencies) + : base(dependencies) + { } + + protected override void ProcessEntityTypeAdded( + [NotNull] IConventionEntityTypeBuilder entityTypeBuilder, + [NotNull] MySQLCharsetAttribute attribute, + [NotNull] IConventionContext context) + { + entityTypeBuilder.Metadata.SetAnnotation( + MySQLAnnotationNames.Charset, + attribute.Charset, + true); + } + } +#endif } diff --git a/EFCore/src/Metadata/Conventions/MySqlEntityCollationAttributeConvention.cs b/EFCore/src/Metadata/Conventions/MySqlEntityCollationAttributeConvention.cs index 966e485bc..5c2ea15c3 100644 --- a/EFCore/src/Metadata/Conventions/MySqlEntityCollationAttributeConvention.cs +++ b/EFCore/src/Metadata/Conventions/MySqlEntityCollationAttributeConvention.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -34,6 +34,7 @@ namespace MySql.EntityFrameworkCore.Metadata.Conventions { +#if !NET8_0_OR_GREATER /// /// Represents a collation attribute for an entity. /// @@ -58,4 +59,30 @@ protected override void ProcessEntityTypeAdded( true); } } +#else + /// + /// Represents a collation attribute for an Type. + /// + internal class MySqlEntityCollationAttributeConvention : TypeAttributeConventionBase + { + /// + /// Creates a new instance of . + /// + /// Parameter object containing dependencies for this convention. + internal MySqlEntityCollationAttributeConvention([NotNull] ProviderConventionSetBuilderDependencies dependencies) + : base(dependencies) + { } + + protected override void ProcessEntityTypeAdded( + [NotNull] IConventionEntityTypeBuilder entityTypeBuilder, + [NotNull] MySQLCollationAttribute attribute, + [NotNull] IConventionContext context) + { + entityTypeBuilder.Metadata.SetAnnotation( + MySQLAnnotationNames.Collation, + attribute.Collation, + true); + } + } +#endif } diff --git a/EFCore/src/Metadata/Internal/MySQLAnnotationNames.cs b/EFCore/src/Metadata/Internal/MySQLAnnotationNames.cs index 1678ca30a..b60e8c7ca 100644 --- a/EFCore/src/Metadata/Internal/MySQLAnnotationNames.cs +++ b/EFCore/src/Metadata/Internal/MySQLAnnotationNames.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/Metadata/Internal/MySQLAnnotationProvider.cs b/EFCore/src/Metadata/Internal/MySQLAnnotationProvider.cs index f6174f88e..15783391d 100644 --- a/EFCore/src/Metadata/Internal/MySQLAnnotationProvider.cs +++ b/EFCore/src/Metadata/Internal/MySQLAnnotationProvider.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -29,6 +29,7 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Metadata.Internal; using MySql.EntityFrameworkCore.Extensions; using MySql.EntityFrameworkCore.Infrastructure.Internal; using MySql.EntityFrameworkCore.Storage.Internal; @@ -69,15 +70,21 @@ public override IEnumerable For(ITable table, bool designTime) { yield break; } +#if NET8_0_OR_GREATER + var entityType = table.EntityTypeMappings.First().TypeBase; + if (GetActualTypeBaseCharSet(entityType) is string charSet) + yield return new Annotation(MySQLAnnotationNames.Charset, charSet); + if (GetActualTypeBaseCollation(entityType) is string collation) + yield return new Annotation(RelationalAnnotationNames.Collation, collation); +#else var entityType = table.EntityTypeMappings.First().EntityType; - if (GetActualEntityTypeCharSet(entityType) is string charSet) yield return new Annotation(MySQLAnnotationNames.Charset, charSet); if (GetActualEntityTypeCollation(entityType) is string collation) yield return new Annotation(RelationalAnnotationNames.Collation, collation); - +#endif foreach (var annotation in entityType.GetAnnotations().Where(a => a.Name is MySQLAnnotationNames.StoreOptions)) yield return annotation; } @@ -118,7 +125,6 @@ public override IEnumerable For(ITableIndex index, bool designTime) yield return new Annotation(MySQLAnnotationNames.SpatialIndex, isSpatial.Value); } -#if NET6_0 public override IEnumerable For(IColumn column, bool designTime) { if (!designTime) @@ -126,48 +132,25 @@ public override IEnumerable For(IColumn column, bool designTime) var table = StoreObjectIdentifier.Table(column.Table.Name, column.Table.Schema); var properties = column.PropertyMappings.Select(m => m.Property).ToArray(); - - if (column.PropertyMappings.Where( - m => m.TableMapping.IsSharedTablePrincipal && m.TableMapping.EntityType == m.Property.DeclaringEntityType) - .Select(m => m.Property) - .FirstOrDefault(p => p.GetValueGenerationStrategy(table) == MySQLValueGenerationStrategy.IdentityColumn) is IProperty identityProperty) - { - var valueGenerationStrategy = identityProperty.GetValueGenerationStrategy(table); - yield return new Annotation(MySQLAnnotationNames.ValueGenerationStrategy, valueGenerationStrategy); - } - else if (properties.FirstOrDefault - (p => p.GetValueGenerationStrategy(table) == MySQLValueGenerationStrategy.ComputedColumn) is IProperty computedProperty) - { - var valueGenerationStrategy = computedProperty.GetValueGenerationStrategy(table); - yield return new Annotation(MySQLAnnotationNames.ValueGenerationStrategy, valueGenerationStrategy); - } - } -#elif NET7_0 || NET8_0 - public override IEnumerable For(IColumn column, bool designTime) - { - if (!designTime) - yield break; - - var table = StoreObjectIdentifier.Table(column.Table.Name, column.Table.Schema); - var properties = column.PropertyMappings.Select(m => m.Property).ToArray(); - - if (column.PropertyMappings.Where(m => m.TableMapping.IsSharedTablePrincipal ?? true - && m.TableMapping.EntityType == m.Property.DeclaringEntityType) - .Select(m => m.Property) - .FirstOrDefault(p => p.GetValueGenerationStrategy(table) == MySQLValueGenerationStrategy.IdentityColumn) is IProperty identityProperty) +#if NET8_0_OR_GREATER + if (column.PropertyMappings.Where(m => m.TableMapping.IsSharedTablePrincipal ?? true && m.TableMapping.TypeBase == m.Property.DeclaringType) + .Select(m => m.Property) + .FirstOrDefault(p => p.GetValueGenerationStrategy(table) == MySQLValueGenerationStrategy.IdentityColumn) is IProperty identityProperty) +#else + if (column.PropertyMappings.Where(m => m.TableMapping.IsSharedTablePrincipal && m.TableMapping.EntityType == m.Property.DeclaringEntityType) + .Select(m => m.Property) + .FirstOrDefault(p => p.GetValueGenerationStrategy(table) == MySQLValueGenerationStrategy.IdentityColumn) is IProperty identityProperty) +#endif { var valueGenerationStrategy = identityProperty.GetValueGenerationStrategy(table); yield return new Annotation(MySQLAnnotationNames.ValueGenerationStrategy, valueGenerationStrategy); } - else if (properties.FirstOrDefault - (p => p.GetValueGenerationStrategy(table) == MySQLValueGenerationStrategy.ComputedColumn) is IProperty computedProperty) + else if (properties.FirstOrDefault(p => p.GetValueGenerationStrategy(table) == MySQLValueGenerationStrategy.ComputedColumn) is IProperty computedProperty) { var valueGenerationStrategy = computedProperty.GetValueGenerationStrategy(table); yield return new Annotation(MySQLAnnotationNames.ValueGenerationStrategy, valueGenerationStrategy); } } -#endif - protected virtual string GetActualModelCharSet(IModel model) { @@ -179,6 +162,59 @@ protected virtual string GetActualModelCollation(IModel model) return model.GetCollation()!; } +#if NET8_0_OR_GREATER + protected virtual string? GetActualTypeBaseCharSet(ITypeBase typeBase) + { + var typeBaseCharSet = typeBase.GetCharSet(); + + if (typeBaseCharSet is not null) + return typeBaseCharSet; + + if (typeBaseCharSet is null) + { + var typeBaseCollation = typeBase.GetCollation(); + var actualModelCharSet = GetActualModelCharSet(typeBase.Model); + + if (typeBaseCollation is not null) + { + return actualModelCharSet is not null && typeBaseCollation.StartsWith(actualModelCharSet, StringComparison.OrdinalIgnoreCase) + ? actualModelCharSet : null; + } + + var actualModelCollation = GetActualModelCollation(typeBase.Model); + + if (actualModelCollation is not null) + { + return actualModelCharSet is not null && actualModelCollation.StartsWith(actualModelCharSet, StringComparison.OrdinalIgnoreCase) + ? actualModelCharSet : null; + } + return actualModelCharSet; + } + return null; + } + + protected virtual string? GetActualTypeBaseCollation(ITypeBase typeBase) + { + var typeBaseCollation = typeBase.GetCollation(); + + if (typeBaseCollation is not null) + return typeBaseCollation; + + if (typeBaseCollation is null) + { + var typeBaseCharSet = typeBase.GetCharSet(); + var actualModelCollation = GetActualModelCollation(typeBase.Model); + + if (typeBaseCharSet is not null) + { + return actualModelCollation is not null && actualModelCollation.StartsWith(typeBaseCharSet, StringComparison.OrdinalIgnoreCase) + ? actualModelCollation : null; + } + return actualModelCollation; + } + return null; + } +#else protected virtual string? GetActualEntityTypeCharSet(IEntityType entityType) { var entityTypeCharSet = entityType.GetCharSet(); @@ -204,10 +240,8 @@ protected virtual string GetActualModelCollation(IModel model) return actualModelCharSet is not null && actualModelCollation.StartsWith(actualModelCharSet, StringComparison.OrdinalIgnoreCase) ? actualModelCharSet : null; } - return actualModelCharSet; } - return null; } @@ -228,25 +262,38 @@ protected virtual string GetActualModelCollation(IModel model) return actualModelCollation is not null && actualModelCollation.StartsWith(entityTypeCharSet, StringComparison.OrdinalIgnoreCase) ? actualModelCollation : null; } - return actualModelCollation; } - return null; } +#endif protected virtual string? GetActualPropertyCharSet(IProperty[] properties) { +#if NET8_0_OR_GREATER + return properties.Select(p => p.GetCharSet()).FirstOrDefault(s => s is not null) ?? + properties.Select( + p => p.FindTypeMapping() is MySQLStringTypeMapping + ? GetActualTypeBaseCharSet(p.DeclaringType) is string charSet && + (p.GetCollation() is not string collation || + collation.StartsWith(charSet, StringComparison.OrdinalIgnoreCase)) + ? charSet + : null + : null) + .FirstOrDefault(s => s is not null); + } +#else return properties.Select(p => p.GetCharSet()).FirstOrDefault(s => s is not null) ?? properties.Select( - p => p.FindTypeMapping() is MySQLStringTypeMapping - ? GetActualEntityTypeCharSet(p.DeclaringEntityType) is string charSet && - (p.GetCollation() is not string collation || - collation.StartsWith(charSet, StringComparison.OrdinalIgnoreCase)) - ? charSet - : null - : null) + p => p.FindTypeMapping() is MySQLStringTypeMapping + ? GetActualEntityTypeCharSet(p.DeclaringEntityType) is string charSet && + (p.GetCollation() is not string collation || + collation.StartsWith(charSet, StringComparison.OrdinalIgnoreCase)) + ? charSet + : null + : null) .FirstOrDefault(s => s is not null); } +#endif } } diff --git a/EFCore/src/Metadata/MySQLValueGenerationStrategy.cs b/EFCore/src/Metadata/MySQLValueGenerationStrategy.cs index f45079ded..730a80900 100644 --- a/EFCore/src/Metadata/MySQLValueGenerationStrategy.cs +++ b/EFCore/src/Metadata/MySQLValueGenerationStrategy.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/Migrations/Internal/MySQLHistoryRepository.cs b/EFCore/src/Migrations/Internal/MySQLHistoryRepository.cs index fbf859f28..ce1c8d1f0 100644 --- a/EFCore/src/Migrations/Internal/MySQLHistoryRepository.cs +++ b/EFCore/src/Migrations/Internal/MySQLHistoryRepository.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -27,12 +27,15 @@ // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Diagnostics; using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Storage; using Microsoft.Extensions.DependencyInjection; using MySql.EntityFrameworkCore.Utils; using System; using System.Text; +using System.Threading.Tasks; +using System.Threading; namespace MySql.EntityFrameworkCore.Migrations.Internal { @@ -50,7 +53,89 @@ public MySQLHistoryRepository([NotNull] HistoryRepositoryDependencies dependenci : base(dependencies) { } +#if NET9_0_OR_GREATER + public override LockReleaseBehavior LockReleaseBehavior => LockReleaseBehavior.Connection; + public override IMigrationsDatabaseLock AcquireDatabaseLock() + { + Dependencies.MigrationsLogger.AcquiringMigrationLock(); + + var dbLock = CreateMigrationDatabaseLock(); + Int64 result; + try + { + result = (Int64)CreateGetLockCommand().ExecuteScalar(CreateRelationalCommandParameters())!; + } + catch + { + try + { + dbLock.Dispose(); + } + catch + { + } + + throw; + } + + return result < 0 + ? throw new TimeoutException() + : dbLock; + } + + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + public override async Task AcquireDatabaseLockAsync(CancellationToken cancellationToken = default) + { + Dependencies.MigrationsLogger.AcquiringMigrationLock(); + + var dbLock = CreateMigrationDatabaseLock(); + Int64 result; + try + { + result = (Int64)(await CreateGetLockCommand().ExecuteScalarAsync(CreateRelationalCommandParameters(), cancellationToken) + .ConfigureAwait(false))!; + } + catch + { + try + { + await dbLock.DisposeAsync().ConfigureAwait(false); + } + catch + { + } + + throw; + } + + return result < 0 + ? throw new TimeoutException() + : dbLock; + } + + private IRelationalCommand CreateGetLockCommand() + => Dependencies.RawSqlCommandBuilder.Build("SELECT GET_LOCK('__EFMigrationsLock',-1);", []).RelationalCommand; + + private MySQLMigrationDatabaseLock CreateMigrationDatabaseLock() + => new( + Dependencies.RawSqlCommandBuilder.Build("SELECT RELEASE_LOCK('__EFMigrationsLock');"), + CreateRelationalCommandParameters(), + this); + + private RelationalCommandParameterObject CreateRelationalCommandParameters() + => new( + Dependencies.Connection, + null, + null, + Dependencies.CurrentContext.Context, + Dependencies.CommandLogger, CommandSource.Migrations); +#endif protected override string ExistsSql { get diff --git a/EFCore/src/Migrations/Internal/MySQLMigrationDatabaseLockcs.cs b/EFCore/src/Migrations/Internal/MySQLMigrationDatabaseLockcs.cs new file mode 100644 index 000000000..668e43971 --- /dev/null +++ b/EFCore/src/Migrations/Internal/MySQLMigrationDatabaseLockcs.cs @@ -0,0 +1,53 @@ +// Copyright © 2024, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage; +using System.Threading; +using System.Threading.Tasks; + +namespace MySql.EntityFrameworkCore.Migrations.Internal +{ +#if NET9_0_OR_GREATER + internal class MySQLMigrationDatabaseLock( + IRelationalCommand releaseLockCommand, + RelationalCommandParameterObject relationalCommandParameters, + IHistoryRepository historyRepository, + CancellationToken cancellationToken = default) + : IMigrationsDatabaseLock + { + public virtual IHistoryRepository HistoryRepository => historyRepository; + + public void Dispose() + => releaseLockCommand.ExecuteScalar(relationalCommandParameters); + + public async ValueTask DisposeAsync() + => await releaseLockCommand.ExecuteScalarAsync(relationalCommandParameters, cancellationToken).ConfigureAwait(false); + } +#endif +} diff --git a/EFCore/src/Migrations/Internal/MySQLMigrationsModelDiffer.cs b/EFCore/src/Migrations/Internal/MySQLMigrationsModelDiffer.cs index 640abaadb..63ad27fb2 100644 --- a/EFCore/src/Migrations/Internal/MySQLMigrationsModelDiffer.cs +++ b/EFCore/src/Migrations/Internal/MySQLMigrationsModelDiffer.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -44,19 +44,17 @@ namespace MySql.EntityFrameworkCore.Migrations.Internal internal class MySQLMigrationsModelDiffer : MigrationsModelDiffer { -#if NET6_0 +#if NET8_0 public MySQLMigrationsModelDiffer( - [NotNull] IRelationalTypeMappingSource typeMappingSource, - [NotNull] IMigrationsAnnotationProvider migrationsAnnotations, - [NotNull] IChangeDetector changeDetector, - [NotNull] IUpdateAdapterFactory updateAdapterFactory, - [NotNull] CommandBatchPreparerDependencies commandBatchPreparerDependencies) - : base( - typeMappingSource, - migrationsAnnotations, - changeDetector, - updateAdapterFactory, - commandBatchPreparerDependencies) + [NotNull] IRelationalTypeMappingSource typeMappingSource, + [NotNull] IMigrationsAnnotationProvider migrationsAnnotations, + [NotNull] IRowIdentityMapFactory rowIdentityMapFactory, + [NotNull] CommandBatchPreparerDependencies commandBatchPreparerDependencies) + : base( + typeMappingSource, + migrationsAnnotations, + rowIdentityMapFactory, + commandBatchPreparerDependencies) { } @@ -65,33 +63,35 @@ protected override IEnumerable Add(IColumn target, DiffConte var _property = target.PropertyMappings.ToArray().FirstOrDefault()!.Property; if (_property.FindTypeMapping() is RelationalTypeMapping storeType) { - var valueGenerationStrategy = MySQLValueGenerationStrategyCompatibility.GetValueGenerationStrategy(MigrationsAnnotations.ForRemove(target).ToArray()); + var valueGenerationStrategy = MySQLValueGenerationStrategyCompatibility.GetValueGenerationStrategy(MigrationsAnnotationProvider.ForRemove(target).ToArray()); // Ensure that null will be set for the columns default value, if CURRENT_TIMESTAMP has been required, // or when the store type of the column does not support default values at all. inline = inline || - (storeType.StoreTypeNameBase == "datetime" || - storeType.StoreTypeNameBase == "timestamp") && - (valueGenerationStrategy == MySQLValueGenerationStrategy.IdentityColumn || - valueGenerationStrategy == MySQLValueGenerationStrategy.ComputedColumn) || - storeType.StoreTypeNameBase.Contains("text") || - storeType.StoreTypeNameBase.Contains("blob") || - storeType.StoreTypeNameBase == "geometry" || - storeType.StoreTypeNameBase == "json"; + (storeType.StoreTypeNameBase == "datetime" || + storeType.StoreTypeNameBase == "timestamp") && + (valueGenerationStrategy == MySQLValueGenerationStrategy.IdentityColumn || + valueGenerationStrategy == MySQLValueGenerationStrategy.ComputedColumn) || + storeType.StoreTypeNameBase.Contains("text") || + storeType.StoreTypeNameBase.Contains("blob") || + storeType.StoreTypeNameBase == "geometry" || + storeType.StoreTypeNameBase == "json"; } return base.Add(target, diffContext, inline); } -#elif NET7_0 || NET8_0 +#elif NET9_0_OR_GREATER public MySQLMigrationsModelDiffer( - [NotNull] IRelationalTypeMappingSource typeMappingSource, - [NotNull] IMigrationsAnnotationProvider migrationsAnnotations, - [NotNull] IRowIdentityMapFactory rowIdentityMapFactory, - [NotNull] CommandBatchPreparerDependencies commandBatchPreparerDependencies) - : base( - typeMappingSource, - migrationsAnnotations, - rowIdentityMapFactory, - commandBatchPreparerDependencies) + [NotNull] IRelationalTypeMappingSource typeMappingSource, + [NotNull] IMigrationsAnnotationProvider migrationsAnnotations, + [NotNull] IRelationalAnnotationProvider relationalAnnotationProvider, + [NotNull] IRowIdentityMapFactory rowIdentityMapFactory, + [NotNull] CommandBatchPreparerDependencies commandBatchPreparerDependencies) + : base( + typeMappingSource, + migrationsAnnotations, + relationalAnnotationProvider, + rowIdentityMapFactory, + commandBatchPreparerDependencies) { } @@ -115,8 +115,9 @@ protected override IEnumerable Add(IColumn target, DiffConte } return base.Add(target, diffContext, inline); } + #endif } -} \ No newline at end of file +} diff --git a/EFCore/src/Migrations/Internal/MySQLMigrator.cs b/EFCore/src/Migrations/Internal/MySQLMigrator.cs index b4d944664..416ba9ef5 100644 --- a/EFCore/src/Migrations/Internal/MySQLMigrator.cs +++ b/EFCore/src/Migrations/Internal/MySQLMigrator.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -28,7 +28,9 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Diagnostics; +using Microsoft.EntityFrameworkCore.Diagnostics.Internal; using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Migrations.Internal; using Microsoft.EntityFrameworkCore.Migrations.Operations; @@ -36,11 +38,683 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reflection; using System.Text; using System.Text.RegularExpressions; +using System.Threading.Tasks; +using System.Threading; +using System.Transactions; namespace MySql.EntityFrameworkCore.Migrations.Internal { +#if NET9_0_OR_GREATER + public class MySQLMigrator : IMigrator + { + private readonly IMigrationsAssembly _migrationsAssembly; + private readonly IHistoryRepository _historyRepository; + private readonly IRelationalDatabaseCreator _databaseCreator; + private readonly IMigrationsSqlGenerator _migrationsSqlGenerator; + private readonly IRawSqlCommandBuilder _rawSqlCommandBuilder; + private readonly IMigrationCommandExecutor _migrationCommandExecutor; + private readonly IRelationalConnection _connection; + private readonly ISqlGenerationHelper _sqlGenerationHelper; + private readonly ICurrentDbContext _currentContext; + private readonly IModelRuntimeInitializer _modelRuntimeInitializer; + private readonly IDiagnosticsLogger _logger; + private readonly IRelationalCommandDiagnosticsLogger _commandLogger; + private readonly IMigrationsModelDiffer _migrationsModelDiffer; + private readonly IDesignTimeModel _designTimeModel; + private readonly string _activeProvider; + private readonly IDbContextOptions _dbContextOptions; + private readonly IExecutionStrategy _executionStrategy; + + public MySQLMigrator( + IMigrationsAssembly migrationsAssembly, + IHistoryRepository historyRepository, + IDatabaseCreator databaseCreator, + IMigrationsSqlGenerator migrationsSqlGenerator, + IRawSqlCommandBuilder rawSqlCommandBuilder, + IMigrationCommandExecutor migrationCommandExecutor, + IRelationalConnection connection, + ISqlGenerationHelper sqlGenerationHelper, + ICurrentDbContext currentContext, + IModelRuntimeInitializer modelRuntimeInitializer, + IDiagnosticsLogger logger, + IRelationalCommandDiagnosticsLogger commandLogger, + IDatabaseProvider databaseProvider, + IMigrationsModelDiffer migrationsModelDiffer, + IDesignTimeModel designTimeModel, + IDbContextOptions dbContextOptions, + IExecutionStrategy executionStrategy) + { + _migrationsAssembly = migrationsAssembly; + _historyRepository = historyRepository; + _databaseCreator = (IRelationalDatabaseCreator)databaseCreator; + _migrationsSqlGenerator = migrationsSqlGenerator; + _rawSqlCommandBuilder = rawSqlCommandBuilder; + _migrationCommandExecutor = migrationCommandExecutor; + _connection = connection; + _sqlGenerationHelper = sqlGenerationHelper; + _currentContext = currentContext; + _modelRuntimeInitializer = modelRuntimeInitializer; + _logger = logger; + _commandLogger = commandLogger; + _migrationsModelDiffer = migrationsModelDiffer; + _designTimeModel = designTimeModel; + _activeProvider = databaseProvider.Name; + _dbContextOptions = dbContextOptions; + _executionStrategy = executionStrategy; + } + + protected virtual System.Data.IsolationLevel? MigrationTransactionIsolationLevel => null; + + public virtual void Migrate(string? targetMigration) + { + var useTransaction = _connection.CurrentTransaction is null; + if (!useTransaction + && _executionStrategy.RetriesOnFailure) + { + throw new NotSupportedException(RelationalStrings.TransactionSuppressedMigrationInUserTransaction); + } + + if (RelationalResources.LogPendingModelChanges(_logger).WarningBehavior != WarningBehavior.Ignore + && HasPendingModelChanges()) + { + _logger.PendingModelChangesWarning(_currentContext.Context.GetType()); + } + + if (!useTransaction) + { + _logger.MigrationsUserTransactionWarning(); + } + + _logger.MigrateUsingConnection(this, _connection); + + using var transactionScope = new TransactionScope(TransactionScopeOption.Suppress, TransactionScopeAsyncFlowOption.Enabled); + + if (!_databaseCreator.Exists()) + { + _databaseCreator.Create(); + } + + _connection.Open(); + try + { + var state = new MigrationExecutionState(); + if (_historyRepository.LockReleaseBehavior != LockReleaseBehavior.Transaction + && useTransaction) + { + state.DatabaseLock = _historyRepository.AcquireDatabaseLock(); + } + + _executionStrategy.Execute( + this, + static (_, migrator) => + { + migrator._connection.Open(); + try + { + return migrator._historyRepository.CreateIfNotExists(); + } + finally + { + migrator._connection.Close(); + } + }, + verifySucceeded: null); + + _executionStrategy.Execute( + (Migrator: this, + TargetMigration: targetMigration, + State: state, + UseTransaction: useTransaction), + static (c, s) => s.Migrator.MigrateImplementation(c, s.TargetMigration, s.State, s.UseTransaction), + static (_, s) => new ExecutionResult( + successful: s.Migrator.VerifyMigrationSucceeded(s.TargetMigration, s.State), + result: true)); + } + finally + { + _connection.Close(); + } + } + + private bool MigrateImplementation(DbContext context, string? targetMigration, MigrationExecutionState state, bool useTransaction) + { + var connectionOpened = _connection.Open(); + try + { + if (useTransaction) + { + state.Transaction = MigrationTransactionIsolationLevel == null + ? _connection.BeginTransaction() + : _connection.BeginTransaction(MigrationTransactionIsolationLevel.Value); + + state.DatabaseLock = state.DatabaseLock == null + ? _historyRepository.AcquireDatabaseLock() + : state.DatabaseLock.ReacquireIfNeeded(connectionOpened, useTransaction); + } + + PopulateMigrations( + _historyRepository.GetAppliedMigrations().Select(t => t.MigrationId), + targetMigration, + out var migratorData); + + var commandLists = GetMigrationCommandLists(migratorData); + foreach (var commandList in commandLists) + { + var (id, getCommands) = commandList; + if (id != state.CurrentMigrationId) + { + state.CurrentMigrationId = id; + state.LastCommittedCommandIndex = 0; + } + + _migrationCommandExecutor.ExecuteNonQuery(getCommands(), _connection, state, commitTransaction: false, MigrationTransactionIsolationLevel); + } + + var coreOptionsExtension = + _dbContextOptions.FindExtension() + ?? new CoreOptionsExtension(); + + var seed = coreOptionsExtension.Seeder; + if (seed != null) + { + seed(context, state.AnyOperationPerformed); + } + else if (coreOptionsExtension.AsyncSeeder != null) + { + throw new InvalidOperationException(CoreStrings.MissingSeeder); + } + + state.Transaction?.Commit(); + return state.AnyOperationPerformed; + } + finally + { + state.DatabaseLock?.Dispose(); + state.DatabaseLock = null; + state.Transaction?.Dispose(); + state.Transaction = null; + _connection.Close(); + } + } + + public virtual async Task MigrateAsync( + string? targetMigration, + CancellationToken cancellationToken = default) + { + var useTransaction = _connection.CurrentTransaction is null; + if (!useTransaction + && _executionStrategy.RetriesOnFailure) + { + throw new NotSupportedException(RelationalStrings.TransactionSuppressedMigrationInUserTransaction); + } + + if (RelationalResources.LogPendingModelChanges(_logger).WarningBehavior != WarningBehavior.Ignore + && HasPendingModelChanges()) + { + _logger.PendingModelChangesWarning(_currentContext.Context.GetType()); + } + + if (!useTransaction) + { + _logger.MigrationsUserTransactionWarning(); + } + + _logger.MigrateUsingConnection(this, _connection); + + using var transactionScope = new TransactionScope(TransactionScopeOption.Suppress, TransactionScopeAsyncFlowOption.Enabled); + + if (!await _databaseCreator.ExistsAsync(cancellationToken).ConfigureAwait(false)) + { + await _databaseCreator.CreateAsync(cancellationToken).ConfigureAwait(false); + } + + await _connection.OpenAsync(cancellationToken).ConfigureAwait(false); + try + { + var state = new MigrationExecutionState(); + if (_historyRepository.LockReleaseBehavior != LockReleaseBehavior.Transaction + && useTransaction) + { + state.DatabaseLock = await _historyRepository.AcquireDatabaseLockAsync(cancellationToken).ConfigureAwait(false); + } + + await _executionStrategy.ExecuteAsync( + this, + static async (_, migrator, ct) => + { + await migrator._connection.OpenAsync(ct).ConfigureAwait(false); + try + { + return await migrator._historyRepository.CreateIfNotExistsAsync(ct).ConfigureAwait(false); + } + finally + { + await migrator._connection.CloseAsync().ConfigureAwait(false); + } + }, + verifySucceeded: null, + cancellationToken).ConfigureAwait(false); + + await _executionStrategy.ExecuteAsync( + (Migrator: this, + TargetMigration: targetMigration, + State: state, + UseTransaction: useTransaction), + async static (c, s, ct) => await s.Migrator.MigrateImplementationAsync( + c, s.TargetMigration, s.State, s.UseTransaction, ct).ConfigureAwait(false), + async static (_, s, ct) => new ExecutionResult( + successful: await s.Migrator.VerifyMigrationSucceededAsync(s.TargetMigration, s.State, ct).ConfigureAwait(false), + result: true), + cancellationToken) + .ConfigureAwait(false); + } + finally + { + await _connection.CloseAsync().ConfigureAwait(false); + } + } + + private async Task MigrateImplementationAsync( + DbContext context, string? targetMigration, MigrationExecutionState state, bool useTransaction, CancellationToken cancellationToken = default) + { + var connectionOpened = await _connection.OpenAsync(cancellationToken).ConfigureAwait(false); + try + { + if (useTransaction) + { + state.Transaction = await (MigrationTransactionIsolationLevel == null + ? context.Database.BeginTransactionAsync(cancellationToken) + : context.Database.BeginTransactionAsync(MigrationTransactionIsolationLevel.Value, cancellationToken)) + .ConfigureAwait(false); + + state.DatabaseLock = state.DatabaseLock == null + ? await _historyRepository.AcquireDatabaseLockAsync(cancellationToken).ConfigureAwait(false) + : await state.DatabaseLock.ReacquireIfNeededAsync(connectionOpened, useTransaction, cancellationToken) + .ConfigureAwait(false); + } + + PopulateMigrations( + (await _historyRepository.GetAppliedMigrationsAsync(cancellationToken).ConfigureAwait(false)).Select(t => t.MigrationId), + targetMigration, + out var migratorData); + + var commandLists = GetMigrationCommandLists(migratorData); + foreach (var commandList in commandLists) + { + var (id, getCommands) = commandList; + if (id != state.CurrentMigrationId) + { + state.CurrentMigrationId = id; + state.LastCommittedCommandIndex = 0; + } + + await _migrationCommandExecutor.ExecuteNonQueryAsync( + getCommands(), _connection, state, commitTransaction: false, MigrationTransactionIsolationLevel, cancellationToken) + .ConfigureAwait(false); + } + + var coreOptionsExtension = + _dbContextOptions.FindExtension() + ?? new CoreOptionsExtension(); + + var seedAsync = coreOptionsExtension.AsyncSeeder; + if (seedAsync != null) + { + await seedAsync(context, state.AnyOperationPerformed, cancellationToken).ConfigureAwait(false); + } + else if (coreOptionsExtension.Seeder != null) + { + throw new InvalidOperationException(CoreStrings.MissingSeeder); + } + + if (state.Transaction != null) + { + await state.Transaction.CommitAsync(cancellationToken).ConfigureAwait(false); + } + return state.AnyOperationPerformed; + } + finally + { + if (state.DatabaseLock != null) + { + state.DatabaseLock.Dispose(); + state.DatabaseLock = null; + } + if (state.Transaction != null) + { + await state.Transaction.DisposeAsync().ConfigureAwait(false); + state.Transaction = null; + } + await _connection.CloseAsync().ConfigureAwait(false); + } + } + + private IEnumerable<(string, Func>)> GetMigrationCommandLists(MigratorData parameters) + { + var migrationsToApply = parameters.AppliedMigrations; + var migrationsToRevert = parameters.RevertedMigrations; + var actualTargetMigration = parameters.TargetMigration; + + for (var i = 0; i < migrationsToRevert.Count; i++) + { + var migration = migrationsToRevert[i]; + + var index = i; + yield return (migration.GetId(), () => + { + _logger.MigrationReverting(this, migration); + + var commands = GenerateDownSql( + migration, + index != migrationsToRevert.Count - 1 + ? migrationsToRevert[index + 1] + : actualTargetMigration); + if (migration.DownOperations.Count > 1 + && commands.FirstOrDefault(c => c.TransactionSuppressed) is MigrationCommand nonTransactionalCommand) + { + _logger.NonTransactionalMigrationOperationWarning(this, migration, nonTransactionalCommand); + } + + return commands; + } + ); + } + + foreach (var migration in migrationsToApply) + { + yield return (migration.GetId(), () => + { + _logger.MigrationApplying(this, migration); + + var commands = GenerateUpSql(migration); + if (migration.UpOperations.Count > 1 + && commands.FirstOrDefault(c => c.TransactionSuppressed) is MigrationCommand nonTransactionalCommand) + { + _logger.NonTransactionalMigrationOperationWarning(this, migration, nonTransactionalCommand); + } + + return commands; + } + ); + } + + if (migrationsToRevert.Count + migrationsToApply.Count == 0) + { + _logger.MigrationsNotApplied(this); + } + } + + protected virtual void PopulateMigrations( + IEnumerable appliedMigrationEntries, + string? targetMigration, + out MigratorData parameters) + { + var appliedMigrations = new Dictionary(); + var unappliedMigrations = new Dictionary(); + var appliedMigrationEntrySet = new HashSet(appliedMigrationEntries, StringComparer.OrdinalIgnoreCase); + if (_migrationsAssembly.Migrations.Count == 0) + { + _logger.MigrationsNotFound(this, _migrationsAssembly); + } + + foreach (var (key, typeInfo) in _migrationsAssembly.Migrations) + { + if (appliedMigrationEntrySet.Contains(key)) + { + appliedMigrations.Add(key, typeInfo); + } + else + { + unappliedMigrations.Add(key, typeInfo); + } + } + + IReadOnlyList migrationsToApply; + IReadOnlyList migrationsToRevert; + Migration? actualTargetMigration = null; + if (string.IsNullOrEmpty(targetMigration)) + { + migrationsToApply = unappliedMigrations + .OrderBy(m => m.Key) + .Select(p => _migrationsAssembly.CreateMigration(p.Value, _activeProvider)) + .ToList(); + migrationsToRevert = []; + } + else if (targetMigration == Migration.InitialDatabase) + { + migrationsToApply = []; + migrationsToRevert = appliedMigrations + .OrderByDescending(m => m.Key) + .Select(p => _migrationsAssembly.CreateMigration(p.Value, _activeProvider)) + .ToList(); + } + else + { + targetMigration = _migrationsAssembly.GetMigrationId(targetMigration); + migrationsToApply = unappliedMigrations + .Where(m => string.Compare(m.Key, targetMigration, StringComparison.OrdinalIgnoreCase) <= 0) + .OrderBy(m => m.Key) + .Select(p => _migrationsAssembly.CreateMigration(p.Value, _activeProvider)) + .ToList(); + migrationsToRevert = appliedMigrations + .Where(m => string.Compare(m.Key, targetMigration, StringComparison.OrdinalIgnoreCase) > 0) + .OrderByDescending(m => m.Key) + .Select(p => _migrationsAssembly.CreateMigration(p.Value, _activeProvider)) + .ToList(); + actualTargetMigration = appliedMigrations + .Where(m => string.Compare(m.Key, targetMigration, StringComparison.OrdinalIgnoreCase) == 0) + .Select(p => _migrationsAssembly.CreateMigration(p.Value, _activeProvider)) + .SingleOrDefault(); + } + + parameters = new MigratorData(migrationsToApply, migrationsToRevert, actualTargetMigration); + } + + protected virtual bool VerifyMigrationSucceeded( + string? targetMigration, MigrationExecutionState state) + => false; + + protected virtual Task VerifyMigrationSucceededAsync( + string? targetMigration, MigrationExecutionState state, CancellationToken cancellationToken) + => Task.FromResult(false); + + public virtual string GenerateScript( + string? fromMigration = null, + string? toMigration = null, + MigrationsSqlGenerationOptions options = MigrationsSqlGenerationOptions.Default) + { + options |= MigrationsSqlGenerationOptions.Script; + + var idempotent = options.HasFlag(MigrationsSqlGenerationOptions.Idempotent); + var noTransactions = options.HasFlag(MigrationsSqlGenerationOptions.NoTransactions); + + IEnumerable appliedMigrations; + if (string.IsNullOrEmpty(fromMigration) + || fromMigration == Migration.InitialDatabase) + { + appliedMigrations = Enumerable.Empty(); + } + else + { + var fromMigrationId = _migrationsAssembly.GetMigrationId(fromMigration); + appliedMigrations = _migrationsAssembly.Migrations + .Where(t => string.Compare(t.Key, fromMigrationId, StringComparison.OrdinalIgnoreCase) <= 0) + .Select(t => t.Key); + } + + PopulateMigrations(appliedMigrations, toMigration, out var migratorData); + + var builder = new IndentedStringBuilder(); + + if (fromMigration == Migration.InitialDatabase + || string.IsNullOrEmpty(fromMigration)) + { + builder + .Append(_historyRepository.GetCreateIfNotExistsScript()) + .Append(_sqlGenerationHelper.BatchTerminator); + } + + var idempotencyEnd = idempotent + ? _historyRepository.GetEndIfScript() + : null; + var migrationsToApply = migratorData.AppliedMigrations; + var migrationsToRevert = migratorData.RevertedMigrations; + var actualTargetMigration = migratorData.TargetMigration; + var transactionStarted = false; + for (var i = 0; i < migrationsToRevert.Count; i++) + { + var migration = migrationsToRevert[i]; + var previousMigration = i != migrationsToRevert.Count - 1 + ? migrationsToRevert[i + 1] + : actualTargetMigration; + + _logger.MigrationGeneratingDownScript(this, migration, fromMigration, toMigration, idempotent); + + var idempotencyCondition = idempotent + ? _historyRepository.GetBeginIfExistsScript(migration.GetId()) + : null; + + GenerateSqlScript( + GenerateDownSql(migration, previousMigration, options), + builder, _sqlGenerationHelper, ref transactionStarted, noTransactions, idempotencyCondition, idempotencyEnd); + } + + foreach (var migration in migrationsToApply) + { + _logger.MigrationGeneratingUpScript(this, migration, fromMigration, toMigration, idempotent); + + var idempotencyCondition = idempotent + ? _historyRepository.GetBeginIfNotExistsScript(migration.GetId()) + : null; + + GenerateSqlScript( + GenerateUpSql(migration, options), + builder, _sqlGenerationHelper, ref transactionStarted, noTransactions, idempotencyCondition, idempotencyEnd); + } + + if (transactionStarted) + { + builder + .AppendLine(_sqlGenerationHelper.CommitTransactionStatement) + .Append(_sqlGenerationHelper.BatchTerminator); + } + + return builder.ToString(); + } + + private static void GenerateSqlScript( + IEnumerable commands, + IndentedStringBuilder builder, + ISqlGenerationHelper sqlGenerationHelper, + ref bool transactionStarted, + bool noTransactions = false, + string? idempotencyCondition = null, + string? idempotencyEnd = null) + { + foreach (var command in commands) + { + if (!noTransactions) + { + if (!transactionStarted && !command.TransactionSuppressed) + { + builder + .AppendLine(sqlGenerationHelper.StartTransactionStatement); + transactionStarted = true; + } + + if (transactionStarted && command.TransactionSuppressed) + { + builder + .AppendLine(sqlGenerationHelper.CommitTransactionStatement) + .Append(sqlGenerationHelper.BatchTerminator); + transactionStarted = false; + } + } + + if (idempotencyCondition != null + && idempotencyEnd != null) + { + builder.AppendLine(idempotencyCondition); + using (builder.Indent()) + { + builder.AppendLines(command.CommandText); + } + + builder.Append(idempotencyEnd); + } + else + { + builder.Append(command.CommandText); + } + + if (!transactionStarted) + { + builder.Append(sqlGenerationHelper.BatchTerminator); + } + else + { + builder.Append(Environment.NewLine); + } + } + } + + protected virtual IReadOnlyList GenerateUpSql( + Migration migration, + MigrationsSqlGenerationOptions options = MigrationsSqlGenerationOptions.Default) + { + var insertCommand = _rawSqlCommandBuilder.Build( + _historyRepository.GetInsertScript(new HistoryRow(migration.GetId(), ProductInfo.GetVersion()))); + + var operations = _migrationsSqlGenerator + .Generate( + migration.UpOperations, + FinalizeModel(migration.TargetModel), + options); + + return + [ + .. operations, + new MigrationCommand(insertCommand, _currentContext.Context, _commandLogger, + transactionSuppressed: operations.Any(o => o.TransactionSuppressed)), + ]; + } + + protected virtual IReadOnlyList GenerateDownSql( + Migration migration, + Migration? previousMigration, + MigrationsSqlGenerationOptions options = MigrationsSqlGenerationOptions.Default) + { + var deleteCommand = _rawSqlCommandBuilder.Build( + _historyRepository.GetDeleteScript(migration.GetId())); + + var operations = _migrationsSqlGenerator + .Generate( + migration.DownOperations, + previousMigration == null ? null : FinalizeModel(previousMigration.TargetModel), + options); + + return [ + .. operations, + new MigrationCommand(deleteCommand, _currentContext.Context, _commandLogger, + transactionSuppressed: operations.Any(o => o.TransactionSuppressed)) + ]; + } + + private IModel? FinalizeModel(IModel? model) + => model == null + ? null + : _modelRuntimeInitializer.Initialize(model); + + public bool HasPendingModelChanges() + => _migrationsModelDiffer.HasDifferences( + FinalizeModel(_migrationsAssembly.ModelSnapshot?.Model)?.GetRelationalModel(), + _designTimeModel.Model.GetRelationalModel()); + } +#else + internal class MySQLMigrator : Migrator { private static readonly Dictionary> _customMigrationCommands = @@ -350,4 +1024,5 @@ INTO PRIMARY_KEY_COLUMN_NAME #endregion Custom SQL } +#endif } diff --git a/EFCore/src/Migrations/MySQLMigrationsSqlGenerator.cs b/EFCore/src/Migrations/MySQLMigrationsSqlGenerator.cs index 32a7491a5..e8e73db2f 100644 --- a/EFCore/src/Migrations/MySQLMigrationsSqlGenerator.cs +++ b/EFCore/src/Migrations/MySQLMigrationsSqlGenerator.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -128,7 +128,7 @@ protected override void Generate(RenameColumnOperation operation, IModel? model, var typeMapping = column.PropertyMappings.FirstOrDefault()?.TypeMapping; var converter = typeMapping?.Converter; - var clrType = (converter!.ProviderClrType ?? typeMapping!.ClrType).UnwrapNullableType(); + var clrType = (converter?.ProviderClrType ?? typeMapping!.ClrType).UnwrapNullableType(); var columnType = (string)(operation[RelationalAnnotationNames.ColumnType] ?? column[RelationalAnnotationNames.ColumnType])!; var isNullable = column.IsNullable; @@ -537,7 +537,12 @@ protected override void Generate( if (model?.GetRelationalModel().FindTable(operation.Name, operation.Schema) != null) { +#if !NET8_0_OR_GREATER var entity = model?.GetRelationalModel().FindTable(operation.Name, operation.Schema)!.EntityTypeMappings.FirstOrDefault()!.EntityType; +#else + var entity = model?.GetRelationalModel().FindTable(operation.Name, operation.Schema)!.EntityTypeMappings.FirstOrDefault()!.TypeBase; +#endif + var charset = entity?.FindAnnotation(MySQLAnnotationNames.Charset); if (charset != null) { diff --git a/EFCore/src/Migrations/Operations/CreateDatabaseOperation.cs b/EFCore/src/Migrations/Operations/CreateDatabaseOperation.cs index 6e0a422af..1e266a2ff 100644 --- a/EFCore/src/Migrations/Operations/CreateDatabaseOperation.cs +++ b/EFCore/src/Migrations/Operations/CreateDatabaseOperation.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/Migrations/Operations/DropDatabaseOperation.cs b/EFCore/src/Migrations/Operations/DropDatabaseOperation.cs index 3e1df9d00..bb9dc3bf0 100644 --- a/EFCore/src/Migrations/Operations/DropDatabaseOperation.cs +++ b/EFCore/src/Migrations/Operations/DropDatabaseOperation.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -40,4 +40,4 @@ internal class MySQLDropDatabaseOperation : MigrationOperation /// public virtual string Name { get; set; } = null!; } -} \ No newline at end of file +} diff --git a/EFCore/src/Migrations/Operations/MySQLDropPrimaryKeyAndRecreateForeignKeysOperation.cs b/EFCore/src/Migrations/Operations/MySQLDropPrimaryKeyAndRecreateForeignKeysOperation.cs index 68fcf8a10..1626aff58 100644 --- a/EFCore/src/Migrations/Operations/MySQLDropPrimaryKeyAndRecreateForeignKeysOperation.cs +++ b/EFCore/src/Migrations/Operations/MySQLDropPrimaryKeyAndRecreateForeignKeysOperation.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/Migrations/Operations/MySQLDropUniqueConstraintAndRecreateForeignKeysOperation.cs b/EFCore/src/Migrations/Operations/MySQLDropUniqueConstraintAndRecreateForeignKeysOperation.cs index 574d77ae6..005a01f4b 100644 --- a/EFCore/src/Migrations/Operations/MySQLDropUniqueConstraintAndRecreateForeignKeysOperation.cs +++ b/EFCore/src/Migrations/Operations/MySQLDropUniqueConstraintAndRecreateForeignKeysOperation.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/MySql.EntityFrameworkCore.csproj b/EFCore/src/MySql.EntityFrameworkCore.csproj index 379b4289a..8a96c4f35 100644 --- a/EFCore/src/MySql.EntityFrameworkCore.csproj +++ b/EFCore/src/MySql.EntityFrameworkCore.csproj @@ -7,10 +7,10 @@ MySql;.NET Connector;MySql Entity Framework Core;netcore;.Net Core;MySql Conector/Net Entity Framework Core;coreclr;C/NET;C/Net Core http://www.mysql.com/common/logos/logo-mysql-170x115.png https://github.com/mysql/mysql-connector-net - GPL-2.0-only + GPL-2.0-only WITH Universal-FOSS-exception-1.0 true - 10.0 - net6.0;net7.0;net8.0; + 13.0 + net9.0;net8.0; MySql.EntityFrameworkCore MySql.EntityFrameworkCore enable @@ -18,22 +18,27 @@ True ..\..\ConnectorNetPublicKey.snk true - $(NoWarn);CS1591;EF1001 + $(NoWarn);CS1591;EF1001;EF9100 + false - - - - + + $(TargetFrameworks);net10.0 + - - - + + + - - - + + + + + + + + diff --git a/EFCore/src/Properties/AssemblyInfo.cs b/EFCore/src/Properties/AssemblyInfo.cs index b9717d9db..48eeec93c 100644 --- a/EFCore/src/Properties/AssemblyInfo.cs +++ b/EFCore/src/Properties/AssemblyInfo.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -27,8 +27,25 @@ // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA using Microsoft.EntityFrameworkCore.Design; +using System.Reflection; +using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Security; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("MySql.EntityFrameworkCore")] +[assembly: AssemblyDescription("MySql.EntityFrameworkCore adds support for Microsoft Entity Framework Core (EF Core) 8 and 9.")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Oracle Corporation")] +[assembly: AssemblyProduct("MySQL Connector/NET")] +[assembly: AssemblyCopyright("Copyright © 2021, 2025, Oracle and/or its affiliates.")] +[assembly: AssemblyTrademark("Oracle®, Java, MySQL, and NetSuite are registered trademarks of Oracle and/or its affiliates.")] +[assembly: AssemblyCulture("")] +[assembly: SecurityRules(SecurityRuleSet.Level1)] +[assembly: CLSCompliant(false)] // Setting ComVisible to false makes the types in this assembly not visible to COM // components. If you need to access a type in this assembly from COM, set the ComVisible @@ -43,4 +60,4 @@ [assembly: InternalsVisibleTo("MySql.EntityFrameworkCore.Basic.Tests, PublicKey = 0024000004800000940000000602000000240000525341310004000001000100d973bda91f71752c78294126974a41a08643168271f65fc0fb3cd45f658da01fbca75ac74067d18e7afbf1467d7a519ce0248b13719717281bb4ddd4ecd71a580dfe0912dfc3690b1d24c7e1975bf7eed90e4ab14e10501eedf763bff8ac204f955c9c15c2cf4ebf6563d8320b6ea8d1ea3807623141f4b81ae30a6c886b3ee1")] [assembly: InternalsVisibleTo("MySql.EntityFrameworkCore.Design.Tests, PublicKey = 0024000004800000940000000602000000240000525341310004000001000100d973bda91f71752c78294126974a41a08643168271f65fc0fb3cd45f658da01fbca75ac74067d18e7afbf1467d7a519ce0248b13719717281bb4ddd4ecd71a580dfe0912dfc3690b1d24c7e1975bf7eed90e4ab14e10501eedf763bff8ac204f955c9c15c2cf4ebf6563d8320b6ea8d1ea3807623141f4b81ae30a6c886b3ee1")] [assembly: InternalsVisibleTo("MySql.EntityFrameworkCore.Migrations.Tests, PublicKey = 0024000004800000940000000602000000240000525341310004000001000100d973bda91f71752c78294126974a41a08643168271f65fc0fb3cd45f658da01fbca75ac74067d18e7afbf1467d7a519ce0248b13719717281bb4ddd4ecd71a580dfe0912dfc3690b1d24c7e1975bf7eed90e4ab14e10501eedf763bff8ac204f955c9c15c2cf4ebf6563d8320b6ea8d1ea3807623141f4b81ae30a6c886b3ee1")] -[assembly: DesignTimeProviderServices("MySql.EntityFrameworkCore.Design.Internal.MySQLDesignTimeServices")] \ No newline at end of file +[assembly: DesignTimeProviderServices("MySql.EntityFrameworkCore.Design.Internal.MySQLDesignTimeServices")] diff --git a/EFCore/src/Properties/VersionInfo.cs b/EFCore/src/Properties/VersionInfo.cs new file mode 100644 index 000000000..2613c8c80 --- /dev/null +++ b/EFCore/src/Properties/VersionInfo.cs @@ -0,0 +1,58 @@ +// Copyright © 2024, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using System.Reflection; +using System.Resources; + +// +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: + +#if NET8_0 +[assembly: AssemblyVersion("9.4.0")] +[assembly: AssemblyInformationalVersion("8.0.11.0+MySQL9.4.0")] +[assembly: AssemblyFileVersion("9.4.0.0")] +[assembly: NeutralResourcesLanguage("en-US")] +#elif NET9_0 +[assembly: AssemblyVersion("9.4.0")] +[assembly: AssemblyInformationalVersion("9.0.3.0+MySQL9.4.0")] +[assembly: AssemblyFileVersion("9.4.0.0")] +[assembly: NeutralResourcesLanguage("en-US")] +#elif NET10_0 +[assembly: AssemblyVersion("9.4.0")] +[assembly: AssemblyInformationalVersion("10.0.0.0-preview+MySQL9.4.0")] +[assembly: AssemblyFileVersion("9.4.0.0")] +[assembly: NeutralResourcesLanguage("en-US")] +#endif diff --git a/EFCore/src/Query/ExpressionTranslators/Internal/MySQLByteArrayMethodTranslator.cs b/EFCore/src/Query/ExpressionTranslators/Internal/MySQLByteArrayMethodTranslator.cs index e331121ca..61466321f 100644 --- a/EFCore/src/Query/ExpressionTranslators/Internal/MySQLByteArrayMethodTranslator.cs +++ b/EFCore/src/Query/ExpressionTranslators/Internal/MySQLByteArrayMethodTranslator.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/Query/ExpressionTranslators/Internal/MySQLDbFunctionsExtensionsMethodTranslator.cs b/EFCore/src/Query/ExpressionTranslators/Internal/MySQLDbFunctionsExtensionsMethodTranslator.cs index 9c477b19f..82688e6cf 100644 --- a/EFCore/src/Query/ExpressionTranslators/Internal/MySQLDbFunctionsExtensionsMethodTranslator.cs +++ b/EFCore/src/Query/ExpressionTranslators/Internal/MySQLDbFunctionsExtensionsMethodTranslator.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/Query/ExpressionTranslators/Internal/MySQLRegexIsMatchTranslator.cs b/EFCore/src/Query/ExpressionTranslators/Internal/MySQLRegexIsMatchTranslator.cs index 5b027f243..bda2f2990 100644 --- a/EFCore/src/Query/ExpressionTranslators/Internal/MySQLRegexIsMatchTranslator.cs +++ b/EFCore/src/Query/ExpressionTranslators/Internal/MySQLRegexIsMatchTranslator.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/Query/ExpressionTranslators/Internal/MySQLStringLengthTranslator.cs b/EFCore/src/Query/ExpressionTranslators/Internal/MySQLStringLengthTranslator.cs index 18b445d2d..64d23c763 100644 --- a/EFCore/src/Query/ExpressionTranslators/Internal/MySQLStringLengthTranslator.cs +++ b/EFCore/src/Query/ExpressionTranslators/Internal/MySQLStringLengthTranslator.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -66,4 +66,4 @@ public SqlExpression Translate(SqlExpression? instance, MemberInfo member, Type throw new NotImplementedException(); } } -} \ No newline at end of file +} diff --git a/EFCore/src/Query/Expressions/Internal/MySQLBinaryExpression.cs b/EFCore/src/Query/Expressions/Internal/MySQLBinaryExpression.cs index ccf5d69f2..9a3e30f10 100644 --- a/EFCore/src/Query/Expressions/Internal/MySQLBinaryExpression.cs +++ b/EFCore/src/Query/Expressions/Internal/MySQLBinaryExpression.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -32,6 +32,7 @@ using MySql.EntityFrameworkCore.Utils; using System; using System.Linq.Expressions; +using System.Reflection; namespace MySql.EntityFrameworkCore.Query.Expressions.Internal { @@ -60,6 +61,9 @@ public MySQLBinaryExpression( Right = right; } +#if NET9_0_OR_GREATER + private static ConstructorInfo? _quotingConstructor; +#endif public virtual MySQLBinaryExpressionOperatorType OperatorType { get; } public virtual SqlExpression Left { get; } public virtual SqlExpression Right { get; } @@ -77,6 +81,18 @@ protected override Expression VisitChildren(ExpressionVisitor visitor) return Update(left, right); } +#if NET9_0_OR_GREATER + /// + public override Expression Quote() => New( + _quotingConstructor ??= typeof(MySQLBinaryExpression).GetConstructor( + [typeof(ExpressionType), typeof(SqlExpression), typeof(SqlExpression), typeof(Type), typeof(RelationalTypeMapping)])!, + Constant(OperatorType), + Left.Quote(), + Right.Quote(), + Constant(Type), + RelationalExpressionQuotingUtilities.QuoteTypeMapping(TypeMapping)); +#endif + public virtual MySQLBinaryExpression Update(SqlExpression left, SqlExpression right) => left != Left || right != Right ? new MySQLBinaryExpression(OperatorType, left, right, Type, TypeMapping) diff --git a/EFCore/src/Query/Expressions/Internal/MySQLCollateExpression.cs b/EFCore/src/Query/Expressions/Internal/MySQLCollateExpression.cs index eac7aed15..123249735 100644 --- a/EFCore/src/Query/Expressions/Internal/MySQLCollateExpression.cs +++ b/EFCore/src/Query/Expressions/Internal/MySQLCollateExpression.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -32,6 +32,7 @@ using System; using System.Linq; using System.Linq.Expressions; +using System.Reflection; namespace MySql.EntityFrameworkCore.Query.Expressions.Internal { @@ -44,17 +45,31 @@ internal class MySQLCollateExpression : SqlExpression private readonly string _charset; private readonly string _collation; +#if NET9_0_OR_GREATER + private static ConstructorInfo? _quotingConstructor; +#endif + +#if NET9_0_OR_GREATER + public MySQLCollateExpression(SqlExpression operand, string collation) + : base(operand.Type, operand.TypeMapping) + { + Operand = operand; + Collation = collation; + } +#else public MySQLCollateExpression( - SqlExpression valueExpression, - string charset, - string collation, - RelationalTypeMapping? typeMapping) - : base(typeof(string), typeMapping) + SqlExpression valueExpression, + string charset, + string collation, + RelationalTypeMapping? typeMapping) + : base(typeof(string), typeMapping) { _valueExpression = valueExpression; _charset = charset; _collation = collation; } +#endif + /// /// The expression for which a collation is being specified. @@ -66,10 +81,21 @@ public MySQLCollateExpression( /// public virtual string Charset => _charset; +#if NET9_0_OR_GREATER + /// + /// The expression on which collation is applied. + /// + public virtual SqlExpression Operand { get; } + + public virtual string Collation { get; } +#else /// /// The collation that the string is being converted to. /// public virtual string Collation => _collation; +#endif + + /// /// Dispatches to the specific visit method for this node type. @@ -100,11 +126,24 @@ protected override Expression VisitChildren(ExpressionVisitor visitor) } +#if NET9_0_OR_GREATER + public virtual MySQLCollateExpression Update(SqlExpression operand) + => operand != Operand + ? new MySQLCollateExpression(operand, Collation) + : this; + /// + public override Expression Quote() => New( + _quotingConstructor ??= typeof(MySQLCollateExpression).GetConstructor([typeof(SqlExpression), typeof(string)])!, + Operand.Quote(), + Constant(Collation)); + +#else public virtual MySQLCollateExpression Update(SqlExpression valueExpression) => valueExpression != _valueExpression && valueExpression != null ? new MySQLCollateExpression(valueExpression, _charset, _collation, TypeMapping) : this; +#endif /// /// Tests if this object is considered equal to another. diff --git a/EFCore/src/Query/Expressions/Internal/MySQLColumnAliasReferenceExpression.cs b/EFCore/src/Query/Expressions/Internal/MySQLColumnAliasReferenceExpression.cs index f78459e79..50cfadc82 100644 --- a/EFCore/src/Query/Expressions/Internal/MySQLColumnAliasReferenceExpression.cs +++ b/EFCore/src/Query/Expressions/Internal/MySQLColumnAliasReferenceExpression.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -31,6 +31,7 @@ using Microsoft.EntityFrameworkCore.Storage; using System; using System.Linq.Expressions; +using System.Reflection; namespace MySql.EntityFrameworkCore.Query.Expressions.Internal { @@ -39,6 +40,10 @@ namespace MySql.EntityFrameworkCore.Query.Expressions.Internal /// internal class MySQLColumnAliasReferenceExpression : SqlExpression, IEquatable { +#if NET9_0_OR_GREATER + private static ConstructorInfo? _quotingConstructor; +#endif + [NotNull] public virtual string Alias { get; } @@ -67,6 +72,15 @@ public virtual MySQLColumnAliasReferenceExpression Update( ? this : new MySQLColumnAliasReferenceExpression(alias, expression, Type, TypeMapping!); +#if NET9_0_OR_GREATER + public override Expression Quote() => New( + _quotingConstructor ??= typeof(MySQLColumnAliasReferenceExpression).GetConstructor([typeof(SqlExpression), typeof(string)])!, + Constant(Alias), + Expression.Quote(), + Constant(Type), + RelationalExpressionQuotingUtilities.QuoteTypeMapping(TypeMapping)); +#endif + public override bool Equals(object? obj) => Equals(obj as MySQLColumnAliasReferenceExpression); diff --git a/EFCore/src/Query/Expressions/Internal/MySQLComplexFunctionArgumentExpression.cs b/EFCore/src/Query/Expressions/Internal/MySQLComplexFunctionArgumentExpression.cs index c15370204..2290f0b86 100644 --- a/EFCore/src/Query/Expressions/Internal/MySQLComplexFunctionArgumentExpression.cs +++ b/EFCore/src/Query/Expressions/Internal/MySQLComplexFunctionArgumentExpression.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -33,11 +33,17 @@ using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; +using System.Reflection; namespace MySql.EntityFrameworkCore.Query.Expressions.Internal { internal class MySQLComplexFunctionArgumentExpression : SqlExpression { + +#if NET9_0_OR_GREATER + private static ConstructorInfo? _quotingConstructor; +#endif + /// /// The arguments parts. /// @@ -74,6 +80,15 @@ protected override Expression VisitChildren(ExpressionVisitor visitor) return Update(argumentParts, Delimiter); } +#if NET9_0_OR_GREATER + public override Expression Quote() => New( + _quotingConstructor ??= typeof(MySQLComplexFunctionArgumentExpression).GetConstructor([typeof(SqlExpression), typeof(string)])!, + Constant(ArgumentParts), + Constant(Delimiter), + Constant(Type), + RelationalExpressionQuotingUtilities.QuoteTypeMapping(TypeMapping)); +#endif + public virtual MySQLComplexFunctionArgumentExpression Update(IReadOnlyList argumentParts, string delimiter) => !argumentParts.SequenceEqual(ArgumentParts) ? new MySQLComplexFunctionArgumentExpression(argumentParts, delimiter, Type, TypeMapping!) diff --git a/EFCore/src/Query/Expressions/Internal/MySQLJsonArrayIndexExpression.cs b/EFCore/src/Query/Expressions/Internal/MySQLJsonArrayIndexExpression.cs index ac6ad4501..a1f5f5ba2 100644 --- a/EFCore/src/Query/Expressions/Internal/MySQLJsonArrayIndexExpression.cs +++ b/EFCore/src/Query/Expressions/Internal/MySQLJsonArrayIndexExpression.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -31,6 +31,7 @@ using Microsoft.EntityFrameworkCore.Storage; using System; using System.Linq.Expressions; +using System.Reflection; namespace MySql.EntityFrameworkCore.Query.Expressions.Internal { @@ -39,6 +40,11 @@ namespace MySql.EntityFrameworkCore.Query.Expressions.Internal /// internal class MySQLJsonArrayIndexExpression : SqlExpression, IEquatable { + +#if NET9_0_OR_GREATER + private static ConstructorInfo? _quotingConstructor; +#endif + [NotNull] public virtual SqlExpression Expression { get; } @@ -54,6 +60,14 @@ public MySQLJsonArrayIndexExpression( protected override Expression VisitChildren(ExpressionVisitor visitor) => Update((SqlExpression)visitor.Visit(Expression)); +#if NET9_0_OR_GREATER + public override Expression Quote() => New( + _quotingConstructor ??= typeof(MySQLJsonArrayIndexExpression).GetConstructor([typeof(SqlExpression), typeof(string)])!, + Expression.Quote(), + Constant(Type), + RelationalExpressionQuotingUtilities.QuoteTypeMapping(TypeMapping)); +#endif + public virtual MySQLJsonArrayIndexExpression Update( [NotNull] SqlExpression expression) => expression == Expression diff --git a/EFCore/src/Query/Expressions/Internal/MySQLJsonTraversalExpression.cs b/EFCore/src/Query/Expressions/Internal/MySQLJsonTraversalExpression.cs index 2ad30e237..2b31cc35a 100644 --- a/EFCore/src/Query/Expressions/Internal/MySQLJsonTraversalExpression.cs +++ b/EFCore/src/Query/Expressions/Internal/MySQLJsonTraversalExpression.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -34,6 +34,7 @@ using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; +using System.Reflection; namespace MySql.EntityFrameworkCore.Query.Expressions.Internal { @@ -42,6 +43,10 @@ namespace MySql.EntityFrameworkCore.Query.Expressions.Internal /// internal class MySQLJsonTraversalExpression : SqlExpression, IEquatable { + +#if NET9_0_OR_GREATER + private static ConstructorInfo? _quotingConstructor; +#endif /// /// The JSON column. /// @@ -91,6 +96,15 @@ protected override Expression VisitChildren(ExpressionVisitor visitor) => Update((SqlExpression)visitor.Visit(Expression), Path.Select(p => (SqlExpression)visitor.Visit(p)).ToArray()); +#if NET9_0_OR_GREATER + public override Expression Quote() => New( + _quotingConstructor ??= typeof(MySQLJsonTraversalExpression).GetConstructor([typeof(SqlExpression), typeof(string)])!, + Expression.Quote(), + Constant(ReturnsText), + Constant(Type), + RelationalExpressionQuotingUtilities.QuoteTypeMapping(TypeMapping)); +#endif + public virtual MySQLJsonTraversalExpression Update( [NotNull] SqlExpression expression, [NotNull] IReadOnlyList path) diff --git a/EFCore/src/Query/Expressions/Internal/MySQLMatchExpression.cs b/EFCore/src/Query/Expressions/Internal/MySQLMatchExpression.cs index 5a3875b2c..6ada3a8d7 100644 --- a/EFCore/src/Query/Expressions/Internal/MySQLMatchExpression.cs +++ b/EFCore/src/Query/Expressions/Internal/MySQLMatchExpression.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -33,11 +33,17 @@ using MySql.EntityFrameworkCore.Utils; using System; using System.Linq.Expressions; +using System.Reflection; namespace MySql.EntityFrameworkCore.Query.Expressions.Internal { internal class MySQLMatchExpression : SqlExpression { + +#if NET9_0_OR_GREATER + private static ConstructorInfo? _quotingConstructor; +#endif + public MySQLMatchExpression( SqlExpression match, SqlExpression against, @@ -75,6 +81,16 @@ protected override Expression VisitChildren(ExpressionVisitor visitor) return Update(match, against); } +#if NET9_0_OR_GREATER + public override Expression Quote() => New( + _quotingConstructor ??= typeof(MySQLMatchExpression).GetConstructor([typeof(SqlExpression), typeof(string)])!, + Match.Quote(), + Against.Quote(), + Constant(SearchMode), + Constant(Type), + RelationalExpressionQuotingUtilities.QuoteTypeMapping(TypeMapping)); +#endif + public virtual MySQLMatchExpression Update(SqlExpression match, SqlExpression against) => match != Match || against != Against ? new MySQLMatchExpression( diff --git a/EFCore/src/Query/Expressions/Internal/MySQLRegexpExpression.cs b/EFCore/src/Query/Expressions/Internal/MySQLRegexpExpression.cs index 6cb14eaeb..e0e19feb6 100644 --- a/EFCore/src/Query/Expressions/Internal/MySQLRegexpExpression.cs +++ b/EFCore/src/Query/Expressions/Internal/MySQLRegexpExpression.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -31,11 +31,17 @@ using Microsoft.EntityFrameworkCore.Storage; using MySql.EntityFrameworkCore.Utils; using System.Linq.Expressions; +using System.Reflection; namespace MySql.EntityFrameworkCore.Query.Expressions.Internal { internal class MySQLRegexpExpression : SqlExpression { + +#if NET9_0_OR_GREATER + private static ConstructorInfo? _quotingConstructor; +#endif + public MySQLRegexpExpression( [NotNull] SqlExpression match, [NotNull] SqlExpression pattern, @@ -69,6 +75,15 @@ protected override Expression VisitChildren(ExpressionVisitor visitor) return Update(match, pattern); } +#if NET9_0_OR_GREATER + public override Expression Quote() => New( + _quotingConstructor ??= typeof(MySQLMatchExpression).GetConstructor([typeof(SqlExpression), typeof(string)])!, + Match.Quote(), + Pattern.Quote(), + Constant(Type), + RelationalExpressionQuotingUtilities.QuoteTypeMapping(TypeMapping)); +#endif + public virtual MySQLRegexpExpression Update(SqlExpression match, SqlExpression pattern) => match != Match || pattern != Pattern diff --git a/EFCore/src/Query/Expressions/Internal/MySQLStringComparisonMethodTranslator.cs b/EFCore/src/Query/Expressions/Internal/MySQLStringComparisonMethodTranslator.cs index a9427da6a..1af3ac2cb 100644 --- a/EFCore/src/Query/Expressions/Internal/MySQLStringComparisonMethodTranslator.cs +++ b/EFCore/src/Query/Expressions/Internal/MySQLStringComparisonMethodTranslator.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -34,6 +34,7 @@ using MySql.EntityFrameworkCore.Query.Internal; using System; using System.Collections.Generic; +using System.Linq; using System.Reflection; using System.Text; using static MySql.EntityFrameworkCore.Utils.Statics; @@ -165,6 +166,7 @@ public MySQLStringComparisonMethodTranslator(ISqlExpressionFactory sqlExpression } else { +#if !NET8_0_OR_GREATER return new CaseExpression( new[] { @@ -183,6 +185,26 @@ public MySQLStringComparisonMethodTranslator(ISqlExpressionFactory sqlExpression Utf8Bin(LCase(rightValue)) ) ); +#else + return new CaseExpression( + new[] + { + new CaseWhenClause( + _sqlExpressionFactory.In(stringComparison,(IReadOnlyList)_caseSensitiveComparisons), + // Case sensitive, accent sensitive + _sqlExpressionFactory.Equal( + leftValue, + Utf8Bin(rightValue) + ) + ) + }, + // Case insensitive, accent sensitive + _sqlExpressionFactory.Equal( + LCase(leftValue), + Utf8Bin(LCase(rightValue)) + ) + ); +#endif } } @@ -210,6 +232,7 @@ public MySQLStringComparisonMethodTranslator(ISqlExpressionFactory sqlExpression } else { +#if !NET8_0_OR_GREATER return new CaseExpression( new[] { @@ -229,6 +252,27 @@ public MySQLStringComparisonMethodTranslator(ISqlExpressionFactory sqlExpression Utf8Bin(LCase(prefix)) ) ); +#else + return new CaseExpression( + new[] + { + new CaseWhenClause( + _sqlExpressionFactory.In(stringComparison,(IReadOnlyList) _caseSensitiveComparisons), + // Case sensitive, accent sensitive + MakeStartsWithExpressionImpl( + target, + Utf8Bin(prefix), + originalPrefix: prefix + ) + ) + }, + // Case insensitive, accent sensitive + MakeStartsWithExpressionImpl( + LCase(target), + Utf8Bin(LCase(prefix)) + ) + ); +#endif } } @@ -237,7 +281,7 @@ private SqlBinaryExpression MakeStartsWithExpressionImpl( SqlExpression prefix, SqlExpression? originalPrefix = null) { - return _sqlExpressionFactory.AndAlso( + return (SqlBinaryExpression)_sqlExpressionFactory.AndAlso( _sqlExpressionFactory.Like( target, _sqlExpressionFactory.ApplyDefaultTypeMapping(_sqlExpressionFactory.Function( @@ -286,6 +330,7 @@ private SqlBinaryExpression MakeStartsWithExpressionImpl( } else { +#if !NET8_0_OR_GREATER return new CaseExpression( new[] { @@ -306,6 +351,28 @@ private SqlBinaryExpression MakeStartsWithExpressionImpl( suffix ) ); +#else + return new CaseExpression( + new[] + { + new CaseWhenClause( + _sqlExpressionFactory.In(stringComparison,(IReadOnlyList) _caseSensitiveComparisons), + // Case sensitive, accent sensitive + MakeEndsWithExpressionImpl( + target, + Utf8Bin(suffix), + suffix + ) + ) + }, + // Case insensitive, accent sensitive + MakeEndsWithExpressionImpl( + LCase(target), + Utf8Bin(LCase(suffix)), + suffix + ) + ); +#endif } } @@ -379,6 +446,7 @@ private SqlExpression MakeEndsWithExpressionImpl( } else { +#if !NET8_0_OR_GREATER return new CaseExpression( new[] { @@ -401,6 +469,30 @@ private SqlExpression MakeEndsWithExpressionImpl( e => Utf8Bin(LCase(e)) ) ); +#else + return new CaseExpression( + new[] + { + new CaseWhenClause( + _sqlExpressionFactory.In(stringComparison,(IReadOnlyList) _caseSensitiveComparisons), + // Case sensitive, accent sensitive + MakeContainsExpressionImpl( + target, + e => e, + search, + e => Utf8Bin(e) + ) + ) + }, + // Case insensitive, accent sensitive + MakeContainsExpressionImpl( + target, + e => LCase(e), + search, + e => Utf8Bin(LCase(e)) + ) + ); +#endif } } private SqlExpression MakeContainsExpressionImpl( @@ -473,14 +565,12 @@ private SqlExpression MakeContainsExpressionImpl( e => Utf8Bin(LCase(e)))); } +#if !NET8_0_OR_GREATER return _sqlExpressionFactory.Case( new[] { new CaseWhenClause( - _sqlExpressionFactory.In( - stringComparison, - _caseSensitiveComparisons, - false), + _sqlExpressionFactory.In(stringComparison, _caseSensitiveComparisons, false), // Case sensitive, accent sensitive MakeIndexOfExpressionImpl( target, @@ -494,6 +584,26 @@ private SqlExpression MakeContainsExpressionImpl( e => LCase(e), search, e => Utf8Bin(LCase(e)))); +#else + return _sqlExpressionFactory.Case( + new[] + { + new CaseWhenClause( + _sqlExpressionFactory.In(stringComparison, (IReadOnlyList)_caseSensitiveComparisons), + // Case sensitive, accent sensitive + MakeIndexOfExpressionImpl( + target, + e => e, + search, + e => Utf8Bin(e))) + }, + // Case insensitive, accent sensitive + MakeIndexOfExpressionImpl( + target, + e => LCase(e), + search, + e => Utf8Bin(LCase(e)))); +#endif } private SqlExpression MakeIndexOfExpressionImpl( diff --git a/EFCore/src/Query/Internal/MySQLCommandParser.cs b/EFCore/src/Query/Internal/MySQLCommandParser.cs index 0552eef3d..9b4a36f4a 100644 --- a/EFCore/src/Query/Internal/MySQLCommandParser.cs +++ b/EFCore/src/Query/Internal/MySQLCommandParser.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/Query/Internal/MySQLCompatibilityExpressionVisitor.cs b/EFCore/src/Query/Internal/MySQLCompatibilityExpressionVisitor.cs index f4207fbf2..492ed5957 100644 --- a/EFCore/src/Query/Internal/MySQLCompatibilityExpressionVisitor.cs +++ b/EFCore/src/Query/Internal/MySQLCompatibilityExpressionVisitor.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -100,4 +100,4 @@ protected virtual Expression CheckTranslated(Expression? translated, Expression return translated; } } -} \ No newline at end of file +} diff --git a/EFCore/src/Query/Internal/MySQLCompiledQueryCacheKeyGenerator.cs b/EFCore/src/Query/Internal/MySQLCompiledQueryCacheKeyGenerator.cs index d7ecb43d8..d4658704c 100644 --- a/EFCore/src/Query/Internal/MySQLCompiledQueryCacheKeyGenerator.cs +++ b/EFCore/src/Query/Internal/MySQLCompiledQueryCacheKeyGenerator.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/Query/Internal/MySQLConvertTranslator.cs b/EFCore/src/Query/Internal/MySQLConvertTranslator.cs index 062f6d04b..f600784a9 100644 --- a/EFCore/src/Query/Internal/MySQLConvertTranslator.cs +++ b/EFCore/src/Query/Internal/MySQLConvertTranslator.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -70,4 +70,4 @@ public MySQLConvertTranslator(ISqlExpressionFactory sqlExpressionFactory) : null; } } -} \ No newline at end of file +} diff --git a/EFCore/src/Query/Internal/MySQLDateDiffFunctionsTranslator.cs b/EFCore/src/Query/Internal/MySQLDateDiffFunctionsTranslator.cs index 1830ab451..439a3f2b3 100644 --- a/EFCore/src/Query/Internal/MySQLDateDiffFunctionsTranslator.cs +++ b/EFCore/src/Query/Internal/MySQLDateDiffFunctionsTranslator.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -283,4 +283,4 @@ public MySQLDateDiffFunctionsTranslator(ISqlExpressionFactory sqlExpressionFacto return null; } } -} \ No newline at end of file +} diff --git a/EFCore/src/Query/Internal/MySQLDateTimeMemberTranslator.cs b/EFCore/src/Query/Internal/MySQLDateTimeMemberTranslator.cs index db8db62a4..b2c62c561 100644 --- a/EFCore/src/Query/Internal/MySQLDateTimeMemberTranslator.cs +++ b/EFCore/src/Query/Internal/MySQLDateTimeMemberTranslator.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/Query/Internal/MySQLDateTimeMethodTranslator.cs b/EFCore/src/Query/Internal/MySQLDateTimeMethodTranslator.cs index e15e49787..dfb87f08c 100644 --- a/EFCore/src/Query/Internal/MySQLDateTimeMethodTranslator.cs +++ b/EFCore/src/Query/Internal/MySQLDateTimeMethodTranslator.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -100,7 +100,11 @@ public MySQLDateTimeMethodTranslator(ISqlExpressionFactory sqlExpressionFactory) typeof(string)) }, nullable: true, +#if !NET9_0_OR_GREATER argumentsPropagateNullability: TrueArrays[1], +#else + argumentsPropagateNullability: new[] { true, false }, +#endif instance!.Type, instance.TypeMapping); } @@ -157,4 +161,4 @@ sqlConstantExpression.Value is TimeOnly timeOnly && return null; } } -} \ No newline at end of file +} diff --git a/EFCore/src/Query/Internal/MySQLEvaluatableExpressionFilter.cs b/EFCore/src/Query/Internal/MySQLEvaluatableExpressionFilter.cs index f2a7de7b6..50d159ff5 100644 --- a/EFCore/src/Query/Internal/MySQLEvaluatableExpressionFilter.cs +++ b/EFCore/src/Query/Internal/MySQLEvaluatableExpressionFilter.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/Query/Internal/MySQLMathTranslator.cs b/EFCore/src/Query/Internal/MySQLMathTranslator.cs index e820a0179..ba3f30f38 100644 --- a/EFCore/src/Query/Internal/MySQLMathTranslator.cs +++ b/EFCore/src/Query/Internal/MySQLMathTranslator.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -134,4 +134,4 @@ public MySQLMathMethodTranslator(ISqlExpressionFactory sqlExpressionFactory) return null; } } -} \ No newline at end of file +} diff --git a/EFCore/src/Query/Internal/MySQLMemberTranslatorProvider.cs b/EFCore/src/Query/Internal/MySQLMemberTranslatorProvider.cs index d20c26c71..7d51db057 100644 --- a/EFCore/src/Query/Internal/MySQLMemberTranslatorProvider.cs +++ b/EFCore/src/Query/Internal/MySQLMemberTranslatorProvider.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/Query/Internal/MySQLMethodCallTranslatorProvider.cs b/EFCore/src/Query/Internal/MySQLMethodCallTranslatorProvider.cs index 52fbce65c..3538d2342 100644 --- a/EFCore/src/Query/Internal/MySQLMethodCallTranslatorProvider.cs +++ b/EFCore/src/Query/Internal/MySQLMethodCallTranslatorProvider.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/Query/Internal/MySQLNewGuidTranslator.cs b/EFCore/src/Query/Internal/MySQLNewGuidTranslator.cs index ddd0510b8..0a2cd57dd 100644 --- a/EFCore/src/Query/Internal/MySQLNewGuidTranslator.cs +++ b/EFCore/src/Query/Internal/MySQLNewGuidTranslator.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -59,4 +59,4 @@ public MySQLNewGuidTranslator(ISqlExpressionFactory sqlExpressionFactory) : null; } } -} \ No newline at end of file +} diff --git a/EFCore/src/Query/Internal/MySQLObjectToStringTranslator.cs b/EFCore/src/Query/Internal/MySQLObjectToStringTranslator.cs index 2ece1937b..d8455bff7 100644 --- a/EFCore/src/Query/Internal/MySQLObjectToStringTranslator.cs +++ b/EFCore/src/Query/Internal/MySQLObjectToStringTranslator.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -95,4 +95,4 @@ public MySQLObjectToStringTranslator(ISqlExpressionFactory sqlExpressionFactory) : null; } } -} \ No newline at end of file +} diff --git a/EFCore/src/Query/Internal/MySQLParameterBasedSqlProcessor.cs b/EFCore/src/Query/Internal/MySQLParameterBasedSqlProcessor.cs index 10dd9070f..18633c334 100644 --- a/EFCore/src/Query/Internal/MySQLParameterBasedSqlProcessor.cs +++ b/EFCore/src/Query/Internal/MySQLParameterBasedSqlProcessor.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -39,6 +39,7 @@ internal class MySQLParameterBasedSqlProcessor : RelationalParameterBasedSqlProc { private readonly IMySQLOptions _options; +#if !NET9_0_OR_GREATER public MySQLParameterBasedSqlProcessor( RelationalParameterBasedSqlProcessorDependencies dependencies, bool useRelationalNulls, @@ -47,29 +48,35 @@ public MySQLParameterBasedSqlProcessor( { _options = options; } +#else + public MySQLParameterBasedSqlProcessor( + RelationalParameterBasedSqlProcessorDependencies dependencies, + RelationalParameterBasedSqlProcessorParameters parameters, + IMySQLOptions options) + : base(dependencies, parameters) + { + _options = options; + } +#endif /// -#if NET6_0 - protected override SelectExpression ProcessSqlNullability( - SelectExpression selectExpression, IReadOnlyDictionary parametersValues, out bool canCache) +#if NET8_0 + protected override Expression ProcessSqlNullability( + Expression selectExpression, IReadOnlyDictionary parametersValues, out bool canCache) { Check.NotNull(selectExpression, nameof(selectExpression)); Check.NotNull(parametersValues, nameof(parametersValues)); - selectExpression = new MySQLSqlNullabilityProcessor(Dependencies, UseRelationalNulls).Process(selectExpression, parametersValues, out canCache); - - selectExpression = (SelectExpression)new MySQLCompatibilityExpressionVisitor(_options).Visit(selectExpression); - - return selectExpression; + return new MySQLSqlNullabilityProcessor(Dependencies, UseRelationalNulls).Process(selectExpression, parametersValues, out canCache); } -#elif NET7_0 || NET8_0 +#elif NET9_0_OR_GREATER protected override Expression ProcessSqlNullability( Expression selectExpression, IReadOnlyDictionary parametersValues, out bool canCache) { Check.NotNull(selectExpression, nameof(selectExpression)); Check.NotNull(parametersValues, nameof(parametersValues)); - return new MySQLSqlNullabilityProcessor(Dependencies, UseRelationalNulls).Process(selectExpression, parametersValues, out canCache); + return new MySQLSqlNullabilityProcessor(Dependencies, Parameters).Process(selectExpression, parametersValues, out canCache); } #endif } diff --git a/EFCore/src/Query/Internal/MySQLParameterBasedSqlProcessorFactory.cs b/EFCore/src/Query/Internal/MySQLParameterBasedSqlProcessorFactory.cs index 463096bb3..de50f63d1 100644 --- a/EFCore/src/Query/Internal/MySQLParameterBasedSqlProcessorFactory.cs +++ b/EFCore/src/Query/Internal/MySQLParameterBasedSqlProcessorFactory.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -42,7 +42,12 @@ public MySQLParameterBasedSqlProcessorFactory(RelationalParameterBasedSqlProcess _options = options; } +#if NET9_0_OR_GREATER + public RelationalParameterBasedSqlProcessor Create(RelationalParameterBasedSqlProcessorParameters parameters) + => new MySQLParameterBasedSqlProcessor(_dependencies, parameters, _options); +#else public virtual RelationalParameterBasedSqlProcessor Create(bool useRelationalNulls) => new MySQLParameterBasedSqlProcessor(_dependencies, useRelationalNulls, _options); +#endif } } diff --git a/EFCore/src/Query/Internal/MySQLQueryCompilationContext.cs b/EFCore/src/Query/Internal/MySQLQueryCompilationContext.cs index 79d755c11..821c3ac54 100644 --- a/EFCore/src/Query/Internal/MySQLQueryCompilationContext.cs +++ b/EFCore/src/Query/Internal/MySQLQueryCompilationContext.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/Query/Internal/MySQLQueryCompilationContextFactory.cs b/EFCore/src/Query/Internal/MySQLQueryCompilationContextFactory.cs index 707d5c19d..3629a6424 100644 --- a/EFCore/src/Query/Internal/MySQLQueryCompilationContextFactory.cs +++ b/EFCore/src/Query/Internal/MySQLQueryCompilationContextFactory.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/Query/Internal/MySQLQueryStringFactory.cs b/EFCore/src/Query/Internal/MySQLQueryStringFactory.cs index 112416908..caac3d8f1 100644 --- a/EFCore/src/Query/Internal/MySQLQueryStringFactory.cs +++ b/EFCore/src/Query/Internal/MySQLQueryStringFactory.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/Query/Internal/MySQLQueryTranslationPostprocessor.cs b/EFCore/src/Query/Internal/MySQLQueryTranslationPostprocessor.cs index 913ace28f..5112c5e0c 100644 --- a/EFCore/src/Query/Internal/MySQLQueryTranslationPostprocessor.cs +++ b/EFCore/src/Query/Internal/MySQLQueryTranslationPostprocessor.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -39,7 +39,7 @@ internal class MySQLQueryTranslationPostprocessor : RelationalQueryTranslationPo public MySQLQueryTranslationPostprocessor( QueryTranslationPostprocessorDependencies dependencies, RelationalQueryTranslationPostprocessorDependencies relationalDependencies, - QueryCompilationContext queryCompilationContext, + MySQLQueryCompilationContext queryCompilationContext, IMySQLOptions options) : base(dependencies, relationalDependencies, queryCompilationContext) { @@ -52,4 +52,4 @@ public override Expression Process(Expression query) return new MySQLCompatibilityExpressionVisitor(_options).Visit(query); } } -} \ No newline at end of file +} diff --git a/EFCore/src/Query/Internal/MySQLQueryTranslationPostprocessorFactory.cs b/EFCore/src/Query/Internal/MySQLQueryTranslationPostprocessorFactory.cs index 5bceb5265..147a36511 100644 --- a/EFCore/src/Query/Internal/MySQLQueryTranslationPostprocessorFactory.cs +++ b/EFCore/src/Query/Internal/MySQLQueryTranslationPostprocessorFactory.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -51,7 +51,8 @@ public virtual QueryTranslationPostprocessor Create(QueryCompilationContext quer => new MySQLQueryTranslationPostprocessor( _dependencies, _relationalDependencies, - queryCompilationContext, + (MySQLQueryCompilationContext)queryCompilationContext, _options); } + } diff --git a/EFCore/src/Query/Internal/MySQLSqlExpressionFactory.cs b/EFCore/src/Query/Internal/MySQLSqlExpressionFactory.cs index 270c91eea..da1883b17 100644 --- a/EFCore/src/Query/Internal/MySQLSqlExpressionFactory.cs +++ b/EFCore/src/Query/Internal/MySQLSqlExpressionFactory.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -141,11 +141,18 @@ public MySQLCollateExpression Collate( string charset, string collation) => (MySQLCollateExpression)ApplyDefaultTypeMapping( +#if NET9_0_OR_GREATER + new MySQLCollateExpression( + valueExpression, + collation) +#else new MySQLCollateExpression( valueExpression, charset, collation, - null)); + null) +#endif + ); public virtual MySQLBinaryExpression MySqlIntegerDivide( SqlExpression left, @@ -287,11 +294,15 @@ private MySQLCollateExpression ApplyTypeMappingOnCollate(MySQLCollateExpression var inferredTypeMapping = ExpressionExtensions.InferTypeMapping(collateExpression.ValueExpression) ?? _typeMappingSource.FindMapping(collateExpression.ValueExpression.Type); +#if NET9_0_OR_GREATER + return new MySQLCollateExpression(collateExpression.ValueExpression, collateExpression.Collation); +#else return new MySQLCollateExpression( ApplyTypeMapping(collateExpression.ValueExpression, inferredTypeMapping), collateExpression.Charset, collateExpression.Collation, inferredTypeMapping ?? collateExpression.TypeMapping); +#endif } private SqlExpression ApplyTypeMappingOnRegexp(MySQLRegexpExpression regexpExpression) diff --git a/EFCore/src/Query/Internal/MySQLSqlNullabilityProcessor.cs b/EFCore/src/Query/Internal/MySQLSqlNullabilityProcessor.cs index 020b6202f..351fba69f 100644 --- a/EFCore/src/Query/Internal/MySQLSqlNullabilityProcessor.cs +++ b/EFCore/src/Query/Internal/MySQLSqlNullabilityProcessor.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -37,6 +37,8 @@ internal class MySQLSqlNullabilityProcessor : SqlNullabilityProcessor { private readonly ISqlExpressionFactory _sqlExpressionFactory; + +#if !NET9_0_OR_GREATER /// /// Creates a new instance of the . /// @@ -47,7 +49,18 @@ public MySQLSqlNullabilityProcessor( bool useRelationalNulls) : base(dependencies, useRelationalNulls) => _sqlExpressionFactory = dependencies.SqlExpressionFactory; - +#else + /// + /// Creates a new instance of the . + /// + /// Parameter object containing dependencies for this class. + /// Parameter object containing parameters for this class. + public MySQLSqlNullabilityProcessor( + RelationalParameterBasedSqlProcessorDependencies dependencies, + RelationalParameterBasedSqlProcessorParameters parameters) + : base(dependencies, parameters) + => _sqlExpressionFactory = dependencies.SqlExpressionFactory; +#endif /// protected override SqlExpression VisitCustomSqlExpression( SqlExpression sqlExpression, bool allowOptimizedExpansion, out bool nullable) diff --git a/EFCore/src/Query/Internal/MySQLSqlTranslatingExpressionVisitor.cs b/EFCore/src/Query/Internal/MySQLSqlTranslatingExpressionVisitor.cs index 763fee196..6ee7e7c35 100644 --- a/EFCore/src/Query/Internal/MySQLSqlTranslatingExpressionVisitor.cs +++ b/EFCore/src/Query/Internal/MySQLSqlTranslatingExpressionVisitor.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -122,4 +122,4 @@ protected override Expression VisitUnary(UnaryExpression unaryExpression) private static string? GetProviderType(SqlExpression expression) => expression.TypeMapping?.StoreType; } -} \ No newline at end of file +} diff --git a/EFCore/src/Query/Internal/MySQLSqlTranslatingExpressionVisitorFactory.cs b/EFCore/src/Query/Internal/MySQLSqlTranslatingExpressionVisitorFactory.cs index 060d00609..7e476ba9d 100644 --- a/EFCore/src/Query/Internal/MySQLSqlTranslatingExpressionVisitorFactory.cs +++ b/EFCore/src/Query/Internal/MySQLSqlTranslatingExpressionVisitorFactory.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -45,7 +45,7 @@ public virtual RelationalSqlTranslatingExpressionVisitor Create( QueryableMethodTranslatingExpressionVisitor queryableMethodTranslatingExpressionVisitor) => new MySQLSqlTranslatingExpressionVisitor( _dependencies, - model, + (MySQLQueryCompilationContext)model, queryableMethodTranslatingExpressionVisitor); } } diff --git a/EFCore/src/Query/Internal/MySQLStringMemberTranslator.cs b/EFCore/src/Query/Internal/MySQLStringMemberTranslator.cs index b9a6a150c..1dee350d7 100644 --- a/EFCore/src/Query/Internal/MySQLStringMemberTranslator.cs +++ b/EFCore/src/Query/Internal/MySQLStringMemberTranslator.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/Query/Internal/MySQLStringMethodTranslator.cs b/EFCore/src/Query/Internal/MySQLStringMethodTranslator.cs index ed9a719be..c3697e56c 100644 --- a/EFCore/src/Query/Internal/MySQLStringMethodTranslator.cs +++ b/EFCore/src/Query/Internal/MySQLStringMethodTranslator.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -290,4 +290,4 @@ private SqlExpression ProcessTrimMethod(SqlExpression instance, SqlExpression? t typeof(string)); } } -} \ No newline at end of file +} diff --git a/EFCore/src/Query/MySQLJsonString.cs b/EFCore/src/Query/MySQLJsonString.cs index 0a4e01128..809869338 100644 --- a/EFCore/src/Query/MySQLJsonString.cs +++ b/EFCore/src/Query/MySQLJsonString.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/Query/Sql/Internal/MySQLQueryGeneratorFactory.cs b/EFCore/src/Query/Sql/Internal/MySQLQueryGeneratorFactory.cs index cc27aef05..75844a37e 100644 --- a/EFCore/src/Query/Sql/Internal/MySQLQueryGeneratorFactory.cs +++ b/EFCore/src/Query/Sql/Internal/MySQLQueryGeneratorFactory.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/Query/Sql/Internal/MySQLQuerySqlGenerator.cs b/EFCore/src/Query/Sql/Internal/MySQLQuerySqlGenerator.cs index e8f57ed72..e986d1f97 100644 --- a/EFCore/src/Query/Sql/Internal/MySQLQuerySqlGenerator.cs +++ b/EFCore/src/Query/Sql/Internal/MySQLQuerySqlGenerator.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/Scaffolding/Internal/MySQLCodeGenerator.cs b/EFCore/src/Scaffolding/Internal/MySQLCodeGenerator.cs index a56c916a4..51b081e41 100644 --- a/EFCore/src/Scaffolding/Internal/MySQLCodeGenerator.cs +++ b/EFCore/src/Scaffolding/Internal/MySQLCodeGenerator.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -55,4 +55,4 @@ public override MethodCallCodeFragment GenerateUseProvider(string connectionStri ? new object[] { connectionString } : new object[] { connectionString, new NestedClosureCodeFragment("x", providerOptions) }); } -} \ No newline at end of file +} diff --git a/EFCore/src/Scaffolding/Internal/MySQLDataReaderExtension.cs b/EFCore/src/Scaffolding/Internal/MySQLDataReaderExtension.cs index c6a31e83c..a68236874 100644 --- a/EFCore/src/Scaffolding/Internal/MySQLDataReaderExtension.cs +++ b/EFCore/src/Scaffolding/Internal/MySQLDataReaderExtension.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/Scaffolding/Internal/MySQLDatabaseModelFactory.cs b/EFCore/src/Scaffolding/Internal/MySQLDatabaseModelFactory.cs index a6da60526..9818f28dc 100644 --- a/EFCore/src/Scaffolding/Internal/MySQLDatabaseModelFactory.cs +++ b/EFCore/src/Scaffolding/Internal/MySQLDatabaseModelFactory.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/Storage/Internal/ByteArrayComparer.cs b/EFCore/src/Storage/Internal/ByteArrayComparer.cs index b76ee8cef..c99fda081 100644 --- a/EFCore/src/Storage/Internal/ByteArrayComparer.cs +++ b/EFCore/src/Storage/Internal/ByteArrayComparer.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -44,4 +44,4 @@ public ByteArrayComparer() { } } -} \ No newline at end of file +} diff --git a/EFCore/src/Storage/Internal/BytesToDateTimeConverter.cs b/EFCore/src/Storage/Internal/BytesToDateTimeConverter.cs index c3a588208..d92aefb1d 100644 --- a/EFCore/src/Storage/Internal/BytesToDateTimeConverter.cs +++ b/EFCore/src/Storage/Internal/BytesToDateTimeConverter.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -43,4 +43,4 @@ public BytesToDateTimeConverter() { } } -} \ No newline at end of file +} diff --git a/EFCore/src/Storage/Internal/IMySQLRelationalConnection.cs b/EFCore/src/Storage/Internal/IMySQLRelationalConnection.cs index 5e0e661b3..32a6c4ae9 100644 --- a/EFCore/src/Storage/Internal/IMySQLRelationalConnection.cs +++ b/EFCore/src/Storage/Internal/IMySQLRelationalConnection.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -34,4 +34,4 @@ internal interface IMySQLRelationalConnection : IRelationalConnection { IMySQLRelationalConnection CreateSourceConnection(); } -} \ No newline at end of file +} diff --git a/EFCore/src/Storage/Internal/MySQLBoolTypeMapping.cs b/EFCore/src/Storage/Internal/MySQLBoolTypeMapping.cs index e413ec50d..f1b7d2148 100644 --- a/EFCore/src/Storage/Internal/MySQLBoolTypeMapping.cs +++ b/EFCore/src/Storage/Internal/MySQLBoolTypeMapping.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -62,4 +62,4 @@ protected override RelationalTypeMapping Clone(RelationalTypeMappingParameters p protected override string GenerateNonNullSqlLiteral(object value) => (bool)value ? "TRUE" : "FALSE"; } -} \ No newline at end of file +} diff --git a/EFCore/src/Storage/Internal/MySQLByteArrayTypeMapping.cs b/EFCore/src/Storage/Internal/MySQLByteArrayTypeMapping.cs index d81006957..f95732c81 100644 --- a/EFCore/src/Storage/Internal/MySQLByteArrayTypeMapping.cs +++ b/EFCore/src/Storage/Internal/MySQLByteArrayTypeMapping.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -36,7 +36,7 @@ namespace MySql.EntityFrameworkCore.Storage.Internal { internal class MySQLByteArrayTypeMapping : ByteArrayTypeMapping { - private const int MaxSize = 8000; + private const int MaxSize = System.Int32.MaxValue; private readonly int _maxSpecificSize; @@ -117,4 +117,4 @@ protected override void ConfigureParameter(DbParameter parameter) /// protected override string GenerateNonNullSqlLiteral(object value) => ByteArrayFormatter.ToHex((byte[])value); } -} \ No newline at end of file +} diff --git a/EFCore/src/Storage/Internal/MySQLDatabaseCreator.cs b/EFCore/src/Storage/Internal/MySQLDatabaseCreator.cs index 613713a67..21ef77904 100644 --- a/EFCore/src/Storage/Internal/MySQLDatabaseCreator.cs +++ b/EFCore/src/Storage/Internal/MySQLDatabaseCreator.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -268,4 +268,4 @@ private IReadOnlyList CreateDropCommands() // invalid connection may now be valid. private void ClearPool() => MySqlConnection.ClearPool((MySqlConnection)_connection.DbConnection); } -} \ No newline at end of file +} diff --git a/EFCore/src/Storage/Internal/MySQLDateTimeOffsetTypeMapping.cs b/EFCore/src/Storage/Internal/MySQLDateTimeOffsetTypeMapping.cs index adf4c952f..d63ac03bf 100644 --- a/EFCore/src/Storage/Internal/MySQLDateTimeOffsetTypeMapping.cs +++ b/EFCore/src/Storage/Internal/MySQLDateTimeOffsetTypeMapping.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/Storage/Internal/MySQLDateTypeMapping.cs b/EFCore/src/Storage/Internal/MySQLDateTypeMapping.cs index 21e67c90e..68f939a73 100644 --- a/EFCore/src/Storage/Internal/MySQLDateTypeMapping.cs +++ b/EFCore/src/Storage/Internal/MySQLDateTypeMapping.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/Storage/Internal/MySQLDatetimeTypeMapping.cs b/EFCore/src/Storage/Internal/MySQLDatetimeTypeMapping.cs index 69ba0b5de..269566f6c 100644 --- a/EFCore/src/Storage/Internal/MySQLDatetimeTypeMapping.cs +++ b/EFCore/src/Storage/Internal/MySQLDatetimeTypeMapping.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -112,4 +112,4 @@ protected override void ConfigureParameter([NotNull] DbParameter parameter) } } } -} \ No newline at end of file +} diff --git a/EFCore/src/Storage/Internal/MySQLDecimalTypeMapping.cs b/EFCore/src/Storage/Internal/MySQLDecimalTypeMapping.cs index 50170708a..1520a8164 100644 --- a/EFCore/src/Storage/Internal/MySQLDecimalTypeMapping.cs +++ b/EFCore/src/Storage/Internal/MySQLDecimalTypeMapping.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/Storage/Internal/MySQLDoubleTypeMapping.cs b/EFCore/src/Storage/Internal/MySQLDoubleTypeMapping.cs index be2f8e4b6..401846f59 100644 --- a/EFCore/src/Storage/Internal/MySQLDoubleTypeMapping.cs +++ b/EFCore/src/Storage/Internal/MySQLDoubleTypeMapping.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/Storage/Internal/MySQLExecutionStrategy.cs b/EFCore/src/Storage/Internal/MySQLExecutionStrategy.cs index ba3fad038..cc0793aa7 100644 --- a/EFCore/src/Storage/Internal/MySQLExecutionStrategy.cs +++ b/EFCore/src/Storage/Internal/MySQLExecutionStrategy.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/Storage/Internal/MySQLExecutionStrategyFactory.cs b/EFCore/src/Storage/Internal/MySQLExecutionStrategyFactory.cs index a6663fba1..b7caac1b4 100644 --- a/EFCore/src/Storage/Internal/MySQLExecutionStrategyFactory.cs +++ b/EFCore/src/Storage/Internal/MySQLExecutionStrategyFactory.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -42,4 +42,4 @@ public MySQLExecutionStrategyFactory( protected override IExecutionStrategy CreateDefaultStrategy(ExecutionStrategyDependencies dependencies) => new MySQLExecutionStrategy(dependencies); } -} \ No newline at end of file +} diff --git a/EFCore/src/Storage/Internal/MySQLFloatTypeMapping.cs b/EFCore/src/Storage/Internal/MySQLFloatTypeMapping.cs index 497cb11d7..9db0bee5e 100644 --- a/EFCore/src/Storage/Internal/MySQLFloatTypeMapping.cs +++ b/EFCore/src/Storage/Internal/MySQLFloatTypeMapping.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/Storage/Internal/MySQLGeometryTypeMapping.cs b/EFCore/src/Storage/Internal/MySQLGeometryTypeMapping.cs index 73ad2d675..deb61e2c0 100644 --- a/EFCore/src/Storage/Internal/MySQLGeometryTypeMapping.cs +++ b/EFCore/src/Storage/Internal/MySQLGeometryTypeMapping.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -43,8 +43,13 @@ protected MySQLGeometryTypeMapping(RelationalTypeMappingParameters parameters) { } +#if NET8_0_OR_GREATER + public CoreTypeMapping Clone(ValueConverter? converter) + => new MySQLGeometryTypeMapping(Parameters.WithComposedConverter(converter,null,null,null,null)); +#else public override CoreTypeMapping Clone(ValueConverter? converter) => new MySQLGeometryTypeMapping(Parameters.WithComposedConverter(converter)); +#endif protected override void ConfigureParameter(DbParameter parameter) { @@ -67,4 +72,4 @@ public MySQLGeometryTypeMapping( protected override RelationalTypeMapping Clone(RelationalTypeMappingParameters parameters) => new MySQLGeometryTypeMapping(parameters); } -} \ No newline at end of file +} diff --git a/EFCore/src/Storage/Internal/MySQLGuidTypeMapping.cs b/EFCore/src/Storage/Internal/MySQLGuidTypeMapping.cs index aa0f06880..3aee65a32 100644 --- a/EFCore/src/Storage/Internal/MySQLGuidTypeMapping.cs +++ b/EFCore/src/Storage/Internal/MySQLGuidTypeMapping.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/Storage/Internal/MySQLJsonChangeTrackingOptions.cs b/EFCore/src/Storage/Internal/MySQLJsonChangeTrackingOptions.cs index 07a5cd07b..2e7ab243c 100644 --- a/EFCore/src/Storage/Internal/MySQLJsonChangeTrackingOptions.cs +++ b/EFCore/src/Storage/Internal/MySQLJsonChangeTrackingOptions.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/Storage/Internal/MySQLJsonTypeMapping.cs b/EFCore/src/Storage/Internal/MySQLJsonTypeMapping.cs index b8052d70d..332ca01ee 100644 --- a/EFCore/src/Storage/Internal/MySQLJsonTypeMapping.cs +++ b/EFCore/src/Storage/Internal/MySQLJsonTypeMapping.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/Storage/Internal/MySQLRelationalConnection.cs b/EFCore/src/Storage/Internal/MySQLRelationalConnection.cs index b2f2c0cb2..cc1e391e7 100644 --- a/EFCore/src/Storage/Internal/MySQLRelationalConnection.cs +++ b/EFCore/src/Storage/Internal/MySQLRelationalConnection.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -83,13 +83,17 @@ public virtual IMySQLRelationalConnection CreateSourceConnection() public override bool Open(bool errorsExpected = false) { + if (DbConnection.IsDisposed) + DbConnection = (MySqlConnection)CreateDbConnection(); var result = base.Open(errorsExpected); return result; } public override async Task OpenAsync(CancellationToken cancellationToken, bool errorsExpected = false) { + if (DbConnection.IsDisposed) + DbConnection = (MySqlConnection)CreateDbConnection(); return await base.OpenAsync(cancellationToken, errorsExpected).ConfigureAwait(false); } } -} \ No newline at end of file +} diff --git a/EFCore/src/Storage/Internal/MySQLScaffoldingConnectionSettings.cs b/EFCore/src/Storage/Internal/MySQLScaffoldingConnectionSettings.cs index 1f00a09e2..9f4b301f7 100644 --- a/EFCore/src/Storage/Internal/MySQLScaffoldingConnectionSettings.cs +++ b/EFCore/src/Storage/Internal/MySQLScaffoldingConnectionSettings.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/Storage/Internal/MySQLSqlGenerationHelper.cs b/EFCore/src/Storage/Internal/MySQLSqlGenerationHelper.cs index b50d44974..4bcb445f6 100644 --- a/EFCore/src/Storage/Internal/MySQLSqlGenerationHelper.cs +++ b/EFCore/src/Storage/Internal/MySQLSqlGenerationHelper.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -83,6 +83,6 @@ protected virtual string GetObjectName(string name, string schema) ? _options.SchemaNameTranslator(schema, name) : name; - protected virtual string? GetSchemaName(string name, string schema) => null; + protected virtual string? GetSchemaName(string name, string schema) => schema; } } diff --git a/EFCore/src/Storage/Internal/MySQLStringTypeMapping.cs b/EFCore/src/Storage/Internal/MySQLStringTypeMapping.cs index 711b103d0..4979b239f 100644 --- a/EFCore/src/Storage/Internal/MySQLStringTypeMapping.cs +++ b/EFCore/src/Storage/Internal/MySQLStringTypeMapping.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/Storage/Internal/MySQLTimeSpanMapping.cs b/EFCore/src/Storage/Internal/MySQLTimeSpanMapping.cs index ebcd357b5..9af35fb0a 100644 --- a/EFCore/src/Storage/Internal/MySQLTimeSpanMapping.cs +++ b/EFCore/src/Storage/Internal/MySQLTimeSpanMapping.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/Storage/Internal/MySQLTransientExceptionDetector.cs b/EFCore/src/Storage/Internal/MySQLTransientExceptionDetector.cs index d79c4bf49..d608ea6c7 100644 --- a/EFCore/src/Storage/Internal/MySQLTransientExceptionDetector.cs +++ b/EFCore/src/Storage/Internal/MySQLTransientExceptionDetector.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -41,4 +41,4 @@ public static bool ShouldRetryOn([NotNull] Exception ex) ? mySqlException.IsTransient : ex is TimeoutException; } -} \ No newline at end of file +} diff --git a/EFCore/src/Storage/Internal/MySQLTypeMapping.cs b/EFCore/src/Storage/Internal/MySQLTypeMapping.cs index b41ae11f4..94b3ba746 100644 --- a/EFCore/src/Storage/Internal/MySQLTypeMapping.cs +++ b/EFCore/src/Storage/Internal/MySQLTypeMapping.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/Storage/Internal/MySQLTypeMappingSource.cs b/EFCore/src/Storage/Internal/MySQLTypeMappingSource.cs index 229bf8ab2..831d01a94 100644 --- a/EFCore/src/Storage/Internal/MySQLTypeMappingSource.cs +++ b/EFCore/src/Storage/Internal/MySQLTypeMappingSource.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -187,12 +187,21 @@ protected void Initialize() { typeof(byte), _utinyint }, { typeof(sbyte), _tinyint }, + #if !NET8_0_OR_GREATER // DateTime { typeof(DateTime), _datetime.Clone(6, null) }, { typeof(DateOnly), _dateonly }, { typeof(DateTimeOffset), _datetimeoffset.Clone(6, null) }, { typeof(TimeSpan), _time.Clone(6, null) }, { typeof(TimeOnly), _timeonly }, + #else + // DateTime + { typeof(DateTime), _datetime.WithPrecisionAndScale(6, null) }, + { typeof(DateOnly), _dateonly }, + { typeof(DateTimeOffset), _datetimeoffset.Clone() }, + { typeof(TimeSpan), _time.WithPrecisionAndScale(6, null) }, + { typeof(TimeOnly), _timeonly }, + #endif // decimals { typeof(float), _float }, @@ -243,9 +252,15 @@ protected void Initialize() if (_storeTypeMappings.TryGetValue(storeTypeNameBase!, out mapping)) { +#if !NET8_0_OR_GREATER return clrType == null ? mapping[0].Clone(in mappingInfo) : mapping.FirstOrDefault(m => m.ClrType == clrType)?.Clone(in mappingInfo); +#else + return clrType == null + ? mapping[0].WithTypeMappingInfo(mappingInfo) + : mapping.FirstOrDefault(m => m.ClrType == clrType)?.WithTypeMappingInfo(mappingInfo); +#endif } } @@ -259,7 +274,11 @@ protected void Initialize() clrType == typeof(DateTimeOffset) || clrType == typeof(TimeSpan)) { +#if !NET8_0_OR_GREATER return mapping.Clone(mappingInfo.Precision.Value, null); +#else + return mapping.WithPrecisionAndScale(mappingInfo.Precision.Value, null); +#endif } } @@ -282,7 +301,11 @@ protected void Initialize() mapping = isFixedLength ? _charUnicode : size == null ? _longtextUnicode : _varcharUnicode; +#if !NET8_0_OR_GREATER return size == null ? mapping : mapping.Clone($"{mapping.StoreTypeNameBase}({size})", size); +#else + return size == null ? mapping : mapping.WithStoreTypeAndSize($"{mapping.StoreTypeNameBase}({size})", size); +#endif } else if (clrType == typeof(byte[])) { @@ -297,6 +320,7 @@ protected void Initialize() return null; } +#if !NET8_0_OR_GREATER protected override string ParseStoreTypeName(string? storeTypeName, out bool? unicode, out int? size, out int? precision, out int? scale) { var storeTypeBaseName = base.ParseStoreTypeName(storeTypeName, out unicode, out size, out precision, out scale); @@ -305,5 +329,15 @@ protected override string ParseStoreTypeName(string? storeTypeName, out bool? un ? storeTypeBaseName + " unsigned" : storeTypeBaseName!; } +#else + protected string ParseStoreTypeName(string? storeTypeName, ref bool? unicode, ref int? size, ref int? precision, ref int? scale) + { + var storeTypeBaseName = base.ParseStoreTypeName(storeTypeName, ref unicode, ref size, ref precision, ref scale); + + return (storeTypeName?.IndexOf("unsigned", StringComparison.OrdinalIgnoreCase) ?? -1) >= 0 + ? storeTypeBaseName + " unsigned" + : storeTypeBaseName!; + } +#endif } -} \ No newline at end of file +} diff --git a/EFCore/src/Update/IMySQLUpdateSqlGenerator.cs b/EFCore/src/Update/IMySQLUpdateSqlGenerator.cs index 30dcfd871..c27d2f48d 100644 --- a/EFCore/src/Update/IMySQLUpdateSqlGenerator.cs +++ b/EFCore/src/Update/IMySQLUpdateSqlGenerator.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -34,15 +34,6 @@ namespace MySql.EntityFrameworkCore.Update { -#if NET6_0 - internal interface IMySQLUpdateSqlGenerator : IUpdateSqlGenerator - { - ResultSetMapping AppendBulkInsertOperation( - [NotNull] StringBuilder commandStringBuilder, - [NotNull] IReadOnlyList modificationCommands, - int commandPosition); - } -#elif NET7_0 || NET8_0 /// /// /// The service lifetime is . This means a single instance @@ -70,6 +61,5 @@ ResultSetMapping AppendBulkInsertOperation( int commandPosition) => AppendBulkInsertOperation(commandStringBuilder, modificationCommands, commandPosition, out _); } -#endif } diff --git a/EFCore/src/Update/MySQLModificationCommandBatch.cs b/EFCore/src/Update/MySQLModificationCommandBatch.cs index 960e4f9f8..bb93a4762 100644 --- a/EFCore/src/Update/MySQLModificationCommandBatch.cs +++ b/EFCore/src/Update/MySQLModificationCommandBatch.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -49,158 +49,14 @@ internal class MySQLModificationCommandBatch : AffectedCountModificationCommandB private const int DefaultNetworkPacketSizeBytes = 4096; private const int MaxScriptLength = 65536 * DefaultNetworkPacketSizeBytes / 2; private const int MaxParameterCount = 2100; -#if NET6_0 - private const int MaxRowCount = 1000; - private int _parameterCount = 1; // Implicit parameter for the command text - private readonly int _maxBatchSize; - private readonly List _bulkInsertCommands = new List(); - private int _commandsLeftToLengthCheck = 50; -#elif NET7_0 || NET8_0 private readonly List _pendingBulkInsertCommands = new(); -#endif + protected new virtual IMySQLUpdateSqlGenerator UpdateSqlGenerator => (IMySQLUpdateSqlGenerator)base.UpdateSqlGenerator; -#if NET6_0 - public MySQLModificationCommandBatch( - [NotNull] ModificationCommandBatchFactoryDependencies dependencies, - int? maxBatchSize) - : base(dependencies) - { - if (maxBatchSize.HasValue - && maxBatchSize.Value <= 0) - { - throw new ArgumentOutOfRangeException(nameof(maxBatchSize), RelationalStrings.InvalidMaxBatchSize(maxBatchSize)); - } - - _maxBatchSize = Math.Min(maxBatchSize ?? int.MaxValue, MaxRowCount); - } - - protected override bool CanAddCommand(IReadOnlyModificationCommand modificationCommand) - { - if (ModificationCommands.Count >= _maxBatchSize) - { - return false; - } - - var additionalParameterCount = CountParameters(modificationCommand); - - if (_parameterCount + additionalParameterCount >= MaxParameterCount) - { - return false; - } - - _parameterCount += additionalParameterCount; - return true; - } - - private static int CountParameters(IReadOnlyModificationCommand modificationCommand) - { - var parameterCount = 0; - - foreach (var columnModification in modificationCommand.ColumnModifications) - { - if (columnModification.UseCurrentValueParameter) - { - parameterCount++; - } - - if (columnModification.UseOriginalValueParameter) - { - parameterCount++; - } - } - - return parameterCount; - } - - /// - protected override bool IsCommandTextValid() - { - if (--_commandsLeftToLengthCheck < 0) - { - var commandTextLength = GetCommandText().Length; - if (commandTextLength >= MaxScriptLength) - { - return false; - } - - var averageCommandLength = commandTextLength / ModificationCommands.Count; - var expectedAdditionalCommandCapacity = (MaxScriptLength - commandTextLength) / averageCommandLength; - _commandsLeftToLengthCheck = Math.Max(1, expectedAdditionalCommandCapacity / 4); - } - - return true; - } - - /// - protected override int GetParameterCount() - => _parameterCount; - - /// - protected override void ResetCommandText() - { - base.ResetCommandText(); - _bulkInsertCommands.Clear(); - } - - /// - protected override string GetCommandText() - => base.GetCommandText() + GetBulkInsertCommandText(ModificationCommands.Count); - - private string GetBulkInsertCommandText(int lastIndex) - { - if (_bulkInsertCommands.Count == 0) - { - return string.Empty; - } - - var stringBuilder = new StringBuilder(); - var resultSetMapping = UpdateSqlGenerator.AppendBulkInsertOperation( - stringBuilder, _bulkInsertCommands, lastIndex - _bulkInsertCommands.Count); - for (var i = lastIndex - _bulkInsertCommands.Count; i < lastIndex; i++) - { - CommandResultSet[i] = resultSetMapping; - } - - if (resultSetMapping != ResultSetMapping.NoResultSet) - { - CommandResultSet[lastIndex - 1] = ResultSetMapping.LastInResultSet; - } - - return stringBuilder.ToString(); - } - - /// - protected override void UpdateCachedCommandText(int commandPosition) - { - var newModificationCommand = ModificationCommands[commandPosition]; - if (newModificationCommand.EntityState == EntityState.Added) - { - if (_bulkInsertCommands.Count > 0 - && !CanBeInsertedInSameStatement(_bulkInsertCommands[0], (ModificationCommand)newModificationCommand)) - { - CachedCommandText.Append(GetBulkInsertCommandText(commandPosition)); - _bulkInsertCommands.Clear(); - } - - _bulkInsertCommands.Add((ModificationCommand)newModificationCommand); - - LastCachedCommandIndex = commandPosition; - } - else - { - CachedCommandText.Append(GetBulkInsertCommandText(commandPosition)); - _bulkInsertCommands.Clear(); - - base.UpdateCachedCommandText(commandPosition); - } - } - -#elif NET7_0 || NET8_0 /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in @@ -322,7 +178,6 @@ public override async Task ExecuteAsync(IRelationalConnection connection, Cancel throw new DbUpdateException(MySQLStrings.SaveChangesFailed, e.InnerException, e.Entries); } } -#endif private static bool CanBeInsertedInSameStatement( diff --git a/EFCore/src/Update/MySQLModificationCommandBatchFactory.cs b/EFCore/src/Update/MySQLModificationCommandBatchFactory.cs index 7991ef136..e03dd8e76 100644 --- a/EFCore/src/Update/MySQLModificationCommandBatchFactory.cs +++ b/EFCore/src/Update/MySQLModificationCommandBatchFactory.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/Update/MySQLUpdateSqlGenerator.cs b/EFCore/src/Update/MySQLUpdateSqlGenerator.cs index 3487e1cea..7caf477ec 100644 --- a/EFCore/src/Update/MySQLUpdateSqlGenerator.cs +++ b/EFCore/src/Update/MySQLUpdateSqlGenerator.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -50,190 +50,14 @@ namespace MySql.EntityFrameworkCore /// This service cannot depend on services registered as . /// /// - internal class MySQLUpdateSqlGenerator : UpdateSqlGenerator, IMySQLUpdateSqlGenerator + internal class MySQLUpdateSqlGenerator : UpdateAndSelectSqlGenerator, IMySQLUpdateSqlGenerator { public MySQLUpdateSqlGenerator([NotNull] UpdateSqlGeneratorDependencies dependencies) : base(dependencies) { } -#if NET6_0 - public virtual ResultSetMapping AppendBulkInsertOperation( - StringBuilder commandStringBuilder, - IReadOnlyList modificationCommands, - int commandPosition) - { - var table = StoreObjectIdentifier.Table(modificationCommands[0].TableName, modificationCommands[0].Schema); - if (modificationCommands.Count == 1 - && modificationCommands[0].ColumnModifications.All( - o => !o.IsKey - || !o.IsRead - || o.Property?.GetValueGenerationStrategy(table) == MySQLValueGenerationStrategy.IdentityColumn)) - { - return AppendInsertOperation(commandStringBuilder, modificationCommands[0], commandPosition); - } - - var readOperations = modificationCommands[0].ColumnModifications.Where(o => o.IsRead).ToList(); - var writeOperations = modificationCommands[0].ColumnModifications.Where(o => o.IsWrite).ToList(); - var keyOperations = modificationCommands[0].ColumnModifications.Where(o => o.IsKey).ToList(); - - var defaultValuesOnly = writeOperations.Count == 0; - var nonIdentityOperations = modificationCommands[0].ColumnModifications - .Where(o => o.Property?.GetValueGenerationStrategy(table) != MySQLValueGenerationStrategy.IdentityColumn) - .ToList(); - - if (defaultValuesOnly) - { - if (nonIdentityOperations.Count == 0 || readOperations.Count == 0) - { - foreach (var modification in modificationCommands) - { - AppendInsertOperation(commandStringBuilder, modification, commandPosition); - } - - return readOperations.Count == 0 - ? ResultSetMapping.NoResultSet - : ResultSetMapping.LastInResultSet; - } - - if (nonIdentityOperations.Count > 1) - { - nonIdentityOperations = new List { nonIdentityOperations.First() }; - } - } - - if (readOperations.Count == 0) - { - return AppendBulkInsertWithoutServerValues(commandStringBuilder, modificationCommands, writeOperations); - } - - foreach (var modification in modificationCommands) - { - AppendInsertOperation(commandStringBuilder, modification, commandPosition); - } - - return ResultSetMapping.LastInResultSet; - } - - private ResultSetMapping AppendBulkInsertWithoutServerValues( - StringBuilder commandStringBuilder, - IReadOnlyList modificationCommands, - List writeOperations) - { - Debug.Assert(writeOperations.Count > 0); - - var name = modificationCommands[0].TableName; - var schema = modificationCommands[0].Schema; - - AppendInsertCommandHeader(commandStringBuilder, name, schema, writeOperations); - AppendValuesHeader(commandStringBuilder, writeOperations); - AppendValues(commandStringBuilder, string.Empty, null, writeOperations); - for (var i = 1; i < modificationCommands.Count; i++) - { - commandStringBuilder.Append(",").AppendLine(); - AppendValues(commandStringBuilder, string.Empty, null, modificationCommands[i].ColumnModifications.Where(o => o.IsWrite).ToList()); - } - commandStringBuilder.Append(SqlGenerationHelper.StatementTerminator).AppendLine(); - - return ResultSetMapping.NoResultSet; - } - - protected override void AppendInsertCommandHeader( - [NotNull] StringBuilder commandStringBuilder, - [NotNull] string name, - string? schema, - [NotNull] IReadOnlyList operations) - { - Check.NotNull(commandStringBuilder, nameof(commandStringBuilder)); - Check.NotEmpty(name, nameof(name)); - Check.NotNull(operations, nameof(operations)); - - base.AppendInsertCommandHeader(commandStringBuilder, name, schema, operations); - - if (operations.Count <= 0) - { - commandStringBuilder.Append(" ()"); - } - } - - protected override void AppendValuesHeader( - [NotNull] StringBuilder commandStringBuilder, - [NotNull] IReadOnlyList operations) - { - Check.NotNull(commandStringBuilder, nameof(commandStringBuilder)); - Check.NotNull(operations, nameof(operations)); - - commandStringBuilder.AppendLine(); - commandStringBuilder.Append("VALUES "); - } - - protected override void AppendValues( - [NotNull] StringBuilder commandStringBuilder, - [NotNull] string name, - string? schema, - [NotNull] IReadOnlyList operations) - { - base.AppendValues(commandStringBuilder, name, schema, operations); - - if (operations.Count <= 0) - { - commandStringBuilder.Append("()"); - } - } - - protected override void AppendIdentityWhereCondition(StringBuilder commandStringBuilder, IColumnModification columnModification) - { - Check.NotNull(columnModification, "columnModification"); - Check.NotNull(commandStringBuilder, "commandStringBuilder"); - commandStringBuilder.AppendFormat("{0} = LAST_INSERT_ID()", SqlGenerationHelper.DelimitIdentifier(columnModification.ColumnName)); - } - - protected override void AppendRowsAffectedWhereCondition(StringBuilder commandStringBuilder, int expectedRowsAffected) - { - Check.NotNull(commandStringBuilder, "commandStringBuilder"); - commandStringBuilder - .Append("ROW_COUNT() = " + expectedRowsAffected.ToString(CultureInfo.InvariantCulture)); - } - - protected override ResultSetMapping AppendSelectAffectedCountCommand(StringBuilder commandStringBuilder, string name, string? schemaName, int commandPosition) - { - Check.NotNull(commandStringBuilder, "commandStringBuilder"); - Check.NotEmpty(name, "name"); - - commandStringBuilder - .Append("SELECT ROW_COUNT()") - .Append(SqlGenerationHelper.StatementTerminator).AppendLine() - .AppendLine(); - - return ResultSetMapping.LastInResultSet; - } - - protected override void AppendWhereAffectedClause( - [NotNull] StringBuilder commandStringBuilder, - [NotNull] IReadOnlyList operations) - { - Check.NotNull(commandStringBuilder, nameof(commandStringBuilder)); - Check.NotNull(operations, nameof(operations)); - - var nonDefaultOperations = operations - .Where( - o => !o.IsKey || - !o.IsRead || - o.Property == null || - !o.Property.ValueGenerated.HasFlag(ValueGenerated.OnAdd) || - MySQLPropertyExtensions.IsCompatibleAutoIncrementColumn(o.Property)) - .ToList() - .AsReadOnly(); - - base.AppendWhereAffectedClause(commandStringBuilder, nonDefaultOperations); - } - - internal enum ResultsGrouping - { - OneResultSet, - OneCommandPerResultSet - } -#elif NET7_0 || NET8_0 +#if NET8_0_OR_GREATER public virtual ResultSetMapping AppendBulkInsertOperation( StringBuilder commandStringBuilder, IReadOnlyList modificationCommands, @@ -250,7 +74,7 @@ public virtual ResultSetMapping AppendBulkInsertOperation( || !o.IsRead || o.Property?.GetValueGenerationStrategy(table) == MySQLValueGenerationStrategy.IdentityColumn)) { - return AppendInsertOperation(commandStringBuilder, firstCommand, commandPosition, false, out requiresTransaction); + return AppendInsertOperation(commandStringBuilder, firstCommand, commandPosition, out requiresTransaction); } var readOperations = firstCommand.ColumnModifications.Where(o => o.IsRead).ToList(); @@ -291,7 +115,7 @@ public virtual ResultSetMapping AppendBulkInsertOperation( foreach (var modification in modificationCommands) { - AppendInsertOperation(commandStringBuilder, modification, commandPosition, false, out requiresTransaction); + AppendInsertOperation(commandStringBuilder, modification, commandPosition, out requiresTransaction); } return ResultSetMapping.LastInResultSet; @@ -355,7 +179,7 @@ public virtual ResultSetMapping AppendInsertOperation( return AppendSelectAffectedCommand(commandStringBuilder, name, schema, readOperations, keyOperations); } - return readOperations.Count > 0 ? ResultSetMapping.LastInResultSet : ResultSetMapping.NoResults; + return AppendSelectAffectedCountCommand(commandStringBuilder, name, schema, commandPosition); } protected virtual void AppendInsertCommand( @@ -399,7 +223,7 @@ public override ResultSetMapping AppendUpdateOperation( return AppendSelectAffectedCommand(commandStringBuilder, name, schema, readOperations, keyOperations); } - return ResultSetMapping.NoResults; + return AppendSelectAffectedCountCommand(commandStringBuilder, name, schema, commandPosition); } public override ResultSetMapping AppendDeleteOperation( @@ -418,7 +242,7 @@ public override ResultSetMapping AppendDeleteOperation( AppendDeleteCommand(commandStringBuilder, name, schema, Array.Empty(), conditionOperations); - return ResultSetMapping.NoResults; + return AppendSelectAffectedCountCommand(commandStringBuilder, name, schema,commandPosition); } protected override void AppendValues( @@ -551,7 +375,20 @@ protected virtual void AppendWhereAffectedClause( } } - private void AppendRowsAffectedWhereCondition(StringBuilder commandStringBuilder, int expectedRowsAffected) + protected override void AppendReturningClause(StringBuilder commandStringBuilder, IReadOnlyList operations, string? additionalValues = null) + { + if (additionalValues is not null) + { + if (operations.Count > 0) + { + commandStringBuilder.Append(", "); + } + + commandStringBuilder.Append('1'); + } + } + + protected override void AppendRowsAffectedWhereCondition(StringBuilder commandStringBuilder, int expectedRowsAffected) { Check.NotNull(commandStringBuilder, "commandStringBuilder"); commandStringBuilder @@ -566,14 +403,25 @@ private void AppendRowsAffectedWhereCondition(StringBuilder commandStringBuilder protected virtual bool IsIdentityOperation(IColumnModification modification) => modification.IsKey && modification.IsRead; - private void AppendIdentityWhereCondition(StringBuilder commandStringBuilder, IColumnModification columnModification) + protected override void AppendIdentityWhereCondition(StringBuilder commandStringBuilder, IColumnModification columnModification) { Check.NotNull(columnModification, "columnModification"); Check.NotNull(commandStringBuilder, "commandStringBuilder"); commandStringBuilder.AppendFormat("{0} = LAST_INSERT_ID()", SqlGenerationHelper.DelimitIdentifier(columnModification.ColumnName)); } -#endif + protected override ResultSetMapping AppendSelectAffectedCountCommand(StringBuilder commandStringBuilder, string name, string? schemaName, int commandPosition) + { + Check.NotNull(commandStringBuilder, "commandStringBuilder"); + Check.NotEmpty(name, "name"); + + commandStringBuilder + .Append("SELECT ROW_COUNT()") + .Append(SqlGenerationHelper.StatementTerminator).AppendLine() + .AppendLine(); + return ResultSetMapping.ResultSetWithRowsAffectedOnly; + } +#endif } } diff --git a/EFCore/src/Utils/Check.cs b/EFCore/src/Utils/Check.cs index 8a3aed11d..2b6408fdb 100644 --- a/EFCore/src/Utils/Check.cs +++ b/EFCore/src/Utils/Check.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/Utils/CodeAnnotations.cs b/EFCore/src/Utils/CodeAnnotations.cs index 6556044ad..1ee0e5880 100644 --- a/EFCore/src/Utils/CodeAnnotations.cs +++ b/EFCore/src/Utils/CodeAnnotations.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/Utils/CodeAttributes.cs b/EFCore/src/Utils/CodeAttributes.cs index e7c921ba5..dda508d4f 100644 --- a/EFCore/src/Utils/CodeAttributes.cs +++ b/EFCore/src/Utils/CodeAttributes.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -35,4 +35,4 @@ internal sealed class NotNullAttribute : Attribute { } [AttributeUsage(AttributeTargets.All)] internal sealed class CanBeNullAttribute : Attribute { } -} \ No newline at end of file +} diff --git a/EFCore/src/Utils/SharedTypeExtensions.cs b/EFCore/src/Utils/SharedTypeExtensions.cs index 800bbbbea..b09c5b396 100644 --- a/EFCore/src/Utils/SharedTypeExtensions.cs +++ b/EFCore/src/Utils/SharedTypeExtensions.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -106,4 +106,4 @@ public static MethodInfo GetRequiredRuntimeMethod(this Type type, string name, p => type.GetTypeInfo().GetRuntimeMethod(name, parameters) ?? throw new InvalidOperationException($"Could not find method '{name}' on type '{type}'"); } -} \ No newline at end of file +} diff --git a/EFCore/src/Utils/Static.cs b/EFCore/src/Utils/Static.cs index 1d7578b46..42e67383d 100644 --- a/EFCore/src/Utils/Static.cs +++ b/EFCore/src/Utils/Static.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/Utils/StringBuilderExtensions.cs b/EFCore/src/Utils/StringBuilderExtensions.cs index 046478b17..1a431a88d 100644 --- a/EFCore/src/Utils/StringBuilderExtensions.cs +++ b/EFCore/src/Utils/StringBuilderExtensions.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/src/ValueGeneration/Internal/MySQLValueGeneratorSelector.cs b/EFCore/src/ValueGeneration/Internal/MySQLValueGeneratorSelector.cs index a991c381d..81137081b 100644 --- a/EFCore/src/ValueGeneration/Internal/MySQLValueGeneratorSelector.cs +++ b/EFCore/src/ValueGeneration/Internal/MySQLValueGeneratorSelector.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -52,7 +52,23 @@ public MySQLValueGeneratorSelector( } + #if NET8_0_OR_GREATER /// + public ValueGenerator Create(IProperty property, IEntityType entityType) + { + Check.NotNull(property, nameof(property)); + Check.NotNull(entityType, nameof(entityType)); + + var ret = property.ClrType.UnwrapNullableType() == typeof(Guid) + ? property.ValueGenerated == ValueGenerated.Never + || property.GetDefaultValueSql() != null + ? (ValueGenerator)new TemporaryGuidValueGenerator() + : new SequentialGuidValueGenerator() + : base.Create(property, entityType); + return ret; + } +#else + /// public override ValueGenerator Create(IProperty property, IEntityType entityType) { Check.NotNull(property, nameof(property)); @@ -66,5 +82,6 @@ public override ValueGenerator Create(IProperty property, IEntityType entityType : base.Create(property, entityType); return ret; } +#endif } } diff --git a/EFCore/tests/MySql.EFCore.Basic.Tests/BasicGuidTests.cs b/EFCore/tests/MySql.EFCore.Basic.Tests/BasicGuidTests.cs index c7f13937b..413d83328 100644 --- a/EFCore/tests/MySql.EFCore.Basic.Tests/BasicGuidTests.cs +++ b/EFCore/tests/MySql.EFCore.Basic.Tests/BasicGuidTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -30,6 +30,7 @@ using MySql.EntityFrameworkCore.Basic.Tests.Utils; using MySql.EntityFrameworkCore.Infrastructure.Internal; using NUnit.Framework; +using NUnit.Framework.Legacy; using System; using System.Linq; @@ -58,17 +59,17 @@ public void TestEmptyGUID() context.Database.EnsureCreated(); var filter = new[] { Guid.Empty }; var resultFilter = context.Guidtable.Where(t => filter.Contains(t.Uuid)).ToArray(); - Assert.IsNotNull(resultFilter); + Assert.That(resultFilter, Is.Not.Null); Random rnd = new Random(); var guid = Guid.NewGuid(); var record = new GuidTable { Id = rnd.Next(100), Uuid = guid }; context.Guidtable.Add(record); context.SaveChanges(); var rows = context.Guidtable.Count(); - Assert.AreEqual(1, rows); + Assert.That(rows, Is.EqualTo(1)); filter[0] = guid; var resultFilter2 = context.Guidtable.Where(t => filter.Contains(t.Uuid)).ToArray(); - Assert.AreEqual(1, resultFilter2.Count()); + Assert.That(resultFilter2.Count(), Is.EqualTo(1)); } } diff --git a/EFCore/tests/MySql.EFCore.Basic.Tests/ConcurrencyTests.cs b/EFCore/tests/MySql.EFCore.Basic.Tests/ConcurrencyTests.cs index fcc531c20..feb4024b3 100644 --- a/EFCore/tests/MySql.EFCore.Basic.Tests/ConcurrencyTests.cs +++ b/EFCore/tests/MySql.EFCore.Basic.Tests/ConcurrencyTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -31,6 +31,7 @@ using MySql.EntityFrameworkCore.Basic.Tests.DbContextClasses; using MySql.EntityFrameworkCore.Extensions; using NUnit.Framework; +using NUnit.Framework.Legacy; using System; using System.Linq; @@ -42,8 +43,7 @@ public class ConcurrencyTests public void CanHandleConcurrencyConflicts() { var serviceCollection = new ServiceCollection(); - serviceCollection.AddEntityFrameworkMySQL() - .AddDbContext(); + serviceCollection.AddEntityFrameworkMySQL().AddDbContext(); var serviceProvider = serviceCollection.BuildServiceProvider(); @@ -52,11 +52,11 @@ public void CanHandleConcurrencyConflicts() context.Database.EnsureDeleted(); context.Database.EnsureCreated(); - context.People.Add(new Person { Name = "Mike Redman", SocialSecurityNumber = "SSS1229932", PhoneNumber = "565665656" }); + context.People.Add(new Person { Name = "John Doe", PersonNumber = "3333333333", PhoneNumber = "1111111111" }); context.SaveChanges(); var person = context.People.Single(p => p.PersonId == 1); - person.SocialSecurityNumber = "SS15555"; + person.PersonNumber = "4444444444"; context.Database.ExecuteSqlInterpolated($"UPDATE People SET Name = 'Jane' WHERE PersonId = 1"); @@ -83,7 +83,7 @@ public void CanHandleConcurrencyConflicts() var originalValue = entry.Property(property.Name).OriginalValue; var databaseValue = databaseEntry.Property(property.Name).CurrentValue; entry.Property(property.Name).OriginalValue = databaseEntry.Property(property.Name).CurrentValue; - Assert.AreEqual("Jane", databaseValue); + Assert.That(databaseValue, Is.EqualTo("Jane")); } } } @@ -102,5 +102,91 @@ public void CanHandleConcurrencyConflicts() } } } + + [Test] + public void CanHandleUpdateConcurrencyConflicts() + { + var serviceCollection = new ServiceCollection(); + serviceCollection.AddEntityFrameworkMySQL().AddDbContext(); + + var serviceProvider = serviceCollection.BuildServiceProvider(); + + using (var context = serviceProvider.GetRequiredService()) + { + context.Database.EnsureDeleted(); + context.Database.EnsureCreated(); + + context.People.Add(new Person + { Name = "John Doe", PersonNumber = "3333333333", PhoneNumber = "1111111111" }); + context.SaveChanges(); + + var updatePerson1 = context.People.Single(p => p.PersonId == 1); + var updatePerson2 = context.People.Single(p => p.PersonId == 1); + + updatePerson1.PersonNumber = "2222222222"; + updatePerson1.PhoneNumber = "555555555"; + + context.SaveChanges(); + + var item = context.ChangeTracker.Entries().First(x => Object.ReferenceEquals(x.Entity, updatePerson2)); + item.OriginalValues["PersonNumber"] = "3333333333"; + updatePerson2.PersonNumber = "44444444"; + updatePerson2.PhoneNumber = "666666666"; + + TestDelegate action = () => context.SaveChanges(); + Assert.Throws(action); + } + } + + [Test] + public void CanHandleDeleteConcurrencyConflicts() + { + var serviceCollection = new ServiceCollection(); + serviceCollection.AddEntityFrameworkMySQL().AddDbContext(); + + var serviceProvider = serviceCollection.BuildServiceProvider(); + + using (var context = serviceProvider.GetRequiredService()) + { + context.Database.EnsureDeleted(); + context.Database.EnsureCreated(); + context.Remove(new Person { PersonId = 2 , PersonNumber = "88888888" }); + + TestDelegate action = () => context.SaveChanges(); + Assert.Throws(action); + } + } + + [Test] + public void CanHandleInsertConcurrencyConflicts() + { + var serviceCollection = new ServiceCollection(); + serviceCollection.AddEntityFrameworkMySQL().AddDbContext(); + + var serviceProvider = serviceCollection.BuildServiceProvider(); + + using (var context = serviceProvider.GetRequiredService()) + { + context.Database.EnsureDeleted(); + context.Database.EnsureCreated(); + context.People.Add(new Person + { Name = "John Doe", PersonNumber = "3333333333", PhoneNumber = "1111111111" }); + context.SaveChanges(); + + var insertedPerson1 = context.People.Single(p => p.PersonId == 1); + insertedPerson1.PersonNumber = "1111111111"; + + context.SaveChanges(); + + var item = context.ChangeTracker.Entries().First(x => Object.ReferenceEquals(x.Entity, insertedPerson1)); + item.OriginalValues["PersonNumber"] = "3333333333"; + + context.People.Add(new Person + { Name = "John Doe", PersonNumber = "3333333333", PhoneNumber = "1111111111" }); + + TestDelegate action = () => context.SaveChanges(); + Assert.Throws(action); + } + } } } diff --git a/EFCore/tests/MySql.EFCore.Basic.Tests/ConnectionTests.cs b/EFCore/tests/MySql.EFCore.Basic.Tests/ConnectionTests.cs index cfa678fe6..ef30d7d57 100644 --- a/EFCore/tests/MySql.EFCore.Basic.Tests/ConnectionTests.cs +++ b/EFCore/tests/MySql.EFCore.Basic.Tests/ConnectionTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -40,6 +40,7 @@ using MySql.EntityFrameworkCore.Internal; using MySql.EntityFrameworkCore.Storage.Internal; using NUnit.Framework; +using NUnit.Framework.Legacy; using System.Diagnostics; namespace MySql.EntityFrameworkCore.Basic.Tests @@ -84,7 +85,7 @@ public static RelationalConnectionDependencies CreateDependencies(DbContextOptio TestServiceFactory.Instance.Create(), new MySQLOptions())))); } -#elif NET7_0 || NET8_0 +#elif NET8_0 || NET9_0 public static RelationalConnectionDependencies CreateDependencies(DbContextOptions? options = null) { options ??= new DbContextOptionsBuilder() @@ -115,6 +116,38 @@ public static RelationalConnectionDependencies CreateDependencies(DbContextOptio TestServiceFactory.Instance.Create(), new MySQLOptions()), new ExceptionDetector()))); } +#elif NET10_0_OR_GREATER + public static RelationalConnectionDependencies CreateDependencies(DbContextOptions? options = null) + { + options ??= new DbContextOptionsBuilder() + .UseMySQL(MySQLTestStore.BaseConnectionString + "database=test;") + .Options; + + return new RelationalConnectionDependencies( + options, + new DiagnosticsLogger( + new LoggerFactory(), + new LoggingOptions(), + new DiagnosticListener("FakeDiagnosticListener"), + new MySQLLoggingDefinitions(), new NullDbContextLogger()), + new RelationalConnectionDiagnosticsLogger( + new LoggerFactory(), + new LoggingOptions(), + new DiagnosticListener("FakeDiagnosticListener"), + new TestRelationalLoggingDefinitions(), + new NullDbContextLogger(), + CreateOptions()), + new NamedConnectionStringResolver(options), + new RelationalTransactionFactory(new RelationalTransactionFactoryDependencies( + new RelationalSqlGenerationHelper(new RelationalSqlGenerationHelperDependencies()))), + new CurrentDbContext(new FakeDbContext()), + new RelationalCommandBuilderFactory(new RelationalCommandBuilderDependencies( + new MySQLTypeMappingSource( + TestServiceFactory.Instance.Create(), + TestServiceFactory.Instance.Create(), + new MySQLOptions()), new ExceptionDetector(), new LoggingOptions())), + new ExceptionDetector()); + } #endif @@ -136,7 +169,7 @@ public void CanCreateConnectionString() { using (var connection = CreateConnection(CreateOptions())) { - Assert.IsInstanceOf(connection.DbConnection); + Assert.That(connection.DbConnection, Is.InstanceOf()); } } @@ -149,10 +182,10 @@ public void CanCreateMainConnection() { var csb = new MySqlConnectionStringBuilder(source.ConnectionString); var csb1 = new MySqlConnectionStringBuilder(MySQLTestStore.BaseConnectionString); - Assert.True(csb.Database == csb1.Database); - Assert.True(csb.Port == csb1.Port); - Assert.True(csb.Server == csb1.Server); - Assert.True(csb.UserID == csb1.UserID); + Assert.That(csb.Database, Is.EqualTo(csb1.Database)); + Assert.That(csb.Port, Is.EqualTo(csb1.Port)); + Assert.That(csb.Server, Is.EqualTo(csb1.Server)); + Assert.That(csb.UserID, Is.EqualTo(csb1.UserID)); } } } diff --git a/EFCore/tests/MySql.EFCore.Basic.Tests/DataTests.cs b/EFCore/tests/MySql.EFCore.Basic.Tests/DataTests.cs index 8dc267629..c8c9f227e 100644 --- a/EFCore/tests/MySql.EFCore.Basic.Tests/DataTests.cs +++ b/EFCore/tests/MySql.EFCore.Basic.Tests/DataTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -30,6 +30,7 @@ using MySql.Data.MySqlClient; using MySql.EntityFrameworkCore.Basic.Tests.DbContextClasses; using NUnit.Framework; +using NUnit.Framework.Legacy; using System; using System.Linq; using System.Threading.Tasks; @@ -67,17 +68,17 @@ public async Task AsyncData() var result = context.SaveChangesAsync(); result.Wait(30_000); - Assert.IsNull(result.Exception); - Assert.AreEqual(4, result.Result); + Assert.That(result.Exception, Is.Null); + Assert.That(result.Result, Is.EqualTo(4)); } using (var context = new WorldContext()) { var continent = await context.FindAsync("AS"); - Assert.AreEqual("Asia", continent!.Name); + Assert.That(continent!.Name, Is.EqualTo("Asia")); var continents = await context.Continents.ToListAsync(); - Assert.AreEqual(4, continents.Count); + Assert.That(continents.Count, Is.EqualTo(4)); } } @@ -93,10 +94,10 @@ public void ZeroDatetime() context.Database.EnsureDeleted(); context.Database.EnsureCreated(); - Assert.AreEqual(1, context.Database.ExecuteSqlInterpolated($"INSERT IGNORE INTO MyTest (`Date`) VALUES('0000-00-00')")); + Assert.That(context.Database.ExecuteSqlInterpolated($"INSERT IGNORE INTO MyTest (`Date`) VALUES('0000-00-00')"), Is.EqualTo(1)); var item = context.MyTest.First(); - Assert.AreEqual(DateTime.MinValue, item.Date); + Assert.That(item.Date, Is.EqualTo(DateTime.MinValue)); } } diff --git a/EFCore/tests/MySql.EFCore.Basic.Tests/DbContextClasses/ConventionsContexts.cs b/EFCore/tests/MySql.EFCore.Basic.Tests/DbContextClasses/ConventionsContexts.cs index 1efda8333..c5f089188 100644 --- a/EFCore/tests/MySql.EFCore.Basic.Tests/DbContextClasses/ConventionsContexts.cs +++ b/EFCore/tests/MySql.EFCore.Basic.Tests/DbContextClasses/ConventionsContexts.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/tests/MySql.EFCore.Basic.Tests/DbContextClasses/EFFluentAPIContexts.cs b/EFCore/tests/MySql.EFCore.Basic.Tests/DbContextClasses/EFFluentAPIContexts.cs index 1bc3deca8..ea30b2019 100644 --- a/EFCore/tests/MySql.EFCore.Basic.Tests/DbContextClasses/EFFluentAPIContexts.cs +++ b/EFCore/tests/MySql.EFCore.Basic.Tests/DbContextClasses/EFFluentAPIContexts.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -27,6 +27,7 @@ // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; using MySql.EntityFrameworkCore.Basic.Tests.Utils; using MySql.EntityFrameworkCore.Extensions; using System; @@ -151,8 +152,7 @@ public class ConcurrencyTestsContext : MyTestContext protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity() - .Property(p => p.SocialSecurityNumber) - .IsConcurrencyToken(); + .Property(p => p.PersonNumber).IsConcurrencyToken(); } } -} \ No newline at end of file +} diff --git a/EFCore/tests/MySql.EFCore.Basic.Tests/DbContextClasses/EntitiesClasses.cs b/EFCore/tests/MySql.EFCore.Basic.Tests/DbContextClasses/EntitiesClasses.cs index 0f1652c0a..e63c36c4c 100644 --- a/EFCore/tests/MySql.EFCore.Basic.Tests/DbContextClasses/EntitiesClasses.cs +++ b/EFCore/tests/MySql.EFCore.Basic.Tests/DbContextClasses/EntitiesClasses.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -165,12 +165,26 @@ public class Person public int PersonId { get; set; } [ConcurrencyCheck] - public string? SocialSecurityNumber { get; set; } + public string? PersonNumber { get; set; } public string? PhoneNumber { get; set; } [ConcurrencyCheck] public string? Name { get; set; } } + public class Bug35392218_1 + { + public int Id { get; set; } + + public string? Name { get; set; } + } + + public class Bug35392218_2 + { + public int Id { get; set; } + + public string? Name { get; set; } + } + public class Guest { [Key] @@ -225,6 +239,15 @@ public class JsonData public string? jsoncol { get; set; } } + public partial class AllBlobTypes + { + public byte Id { get; set; } + public byte[]? Example1 { get; set; } + public byte[]? Example2 { get; set; } + public byte[]? Example3 { get; set; } + + } + public partial class AllDataTypes { public byte AddressNumber1 { get; set; } diff --git a/EFCore/tests/MySql.EFCore.Basic.Tests/DbContextClasses/SakilaLiteContext.cs b/EFCore/tests/MySql.EFCore.Basic.Tests/DbContextClasses/SakilaLiteContext.cs index 0845bcb50..25f240287 100644 --- a/EFCore/tests/MySql.EFCore.Basic.Tests/DbContextClasses/SakilaLiteContext.cs +++ b/EFCore/tests/MySql.EFCore.Basic.Tests/DbContextClasses/SakilaLiteContext.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/tests/MySql.EFCore.Basic.Tests/DbContextClasses/TestsContexts.cs b/EFCore/tests/MySql.EFCore.Basic.Tests/DbContextClasses/TestsContexts.cs index 7ec491f0a..2bed1347e 100644 --- a/EFCore/tests/MySql.EFCore.Basic.Tests/DbContextClasses/TestsContexts.cs +++ b/EFCore/tests/MySql.EFCore.Basic.Tests/DbContextClasses/TestsContexts.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -57,6 +57,53 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) } } + public class Bug35392218Context : DbContext + { + public Bug35392218Context() : base() + { + } + + public Bug35392218Context(DbContextOptions options) : base(options) + { + } + + public virtual DbSet NameList { get; set; } + + private string schemaName = "schema_bug35392218_1"; + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + + modelBuilder.Entity(entity => + { + entity.ToTable("bug35392218_table1", "schema_bug35392218_1"); + + entity.HasKey(e => e.Id).HasName("id"); + + entity.Property(e => e.Name) + .HasColumnType("varchar(40)") + .HasColumnName("name"); + }); + + modelBuilder.Entity(entity => + { + entity.ToTable("bug35392218_table2", "schema_bug35392218_2"); + + entity.HasKey(e => e.Id).HasName("id"); + + entity.Property(e => e.Name) + .HasColumnType("varchar(40)") + .HasColumnName("name"); + }); + } + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + optionsBuilder.UseMySQL(MySQLTestStore.GetContextConnectionStringWithName(schemaName)); + } + } + public class NoConfigurationContext : DbContext { public DbSet Blogs { get; set; } @@ -362,6 +409,36 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) } } + public partial class AllBlobTypesContext : MyTestContext + { + public virtual DbSet AllBlobTypes { get; set; } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity(entity => + { + entity.HasKey(e => e.Id) + .HasName("PRIMARY"); + + entity.ToTable("all_blob_types"); + + entity.Property(e => e.Example1) + .HasColumnName("blob_column") + .HasColumnType("blob"); + + entity.Property(e => e.Example2) + .HasColumnName("mediumblob_column") + .HasColumnType("mediumblob") + .HasMaxLength(65535); + + entity.Property(e => e.Example3) + .HasColumnName("longblob_column") + .HasColumnType("longblob") + .HasMaxLength(16777215); + }); + } + } + public class WorldContext : MyTestContext { public virtual DbSet Countries { get; set; } diff --git a/EFCore/tests/MySql.EFCore.Basic.Tests/DbFunctionsMySQLTest.cs b/EFCore/tests/MySql.EFCore.Basic.Tests/DbFunctionsMySQLTest.cs index 88ade0128..645045092 100644 --- a/EFCore/tests/MySql.EFCore.Basic.Tests/DbFunctionsMySQLTest.cs +++ b/EFCore/tests/MySql.EFCore.Basic.Tests/DbFunctionsMySQLTest.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -30,6 +30,7 @@ using MySql.EntityFrameworkCore.Basic.Tests.DbContextClasses; using MySql.EntityFrameworkCore.Extensions; using NUnit.Framework; +using NUnit.Framework.Legacy; using System; using System.Linq; @@ -67,7 +68,7 @@ public void DateDiffYear() var yearsDiff = DateTime.Now.Year - lastUpdate.Year; var count = context.Actor.Count(a => EF.Functions.DateDiffYear(a.LastUpdate, DateTime.Now) > 0); - Assert.AreEqual(200, count); + Assert.That(count, Is.EqualTo(200)); } } @@ -80,7 +81,7 @@ public void DateDiffMonth() var count = context.Actor .Count(a => EF.Functions.DateDiffMonth(a.LastUpdate, DateTime.Now) >= monthsDiff - 1); - Assert.AreEqual(200, count); + Assert.That(count, Is.EqualTo(200)); } } @@ -93,7 +94,7 @@ public void DateDiffDay() var count = context.Actor .Count(a => EF.Functions.DateDiffDay(a.LastUpdate, DateTime.Now) == daysDiff); - Assert.AreEqual(200, count, "TotalDays: " + daysDiff); + Assert.That(count, Is.EqualTo(200), "TotalDays: " + daysDiff); } } @@ -106,7 +107,7 @@ public void DateDiffHour() var count = context.Actor .Count(a => EF.Functions.DateDiffHour(a.LastUpdate, DateTime.Now) == hoursDiff); - Assert.AreEqual(200, count, "TotalHours: " + hoursDiff); + Assert.That(count, Is.EqualTo(200), "TotalHours: " + hoursDiff); } } @@ -119,7 +120,7 @@ public void DateDiffMinute() var count = context.Actor .Count(a => EF.Functions.DateDiffMinute(a.LastUpdate, DateTime.Now) == minutesDiff); - Assert.AreEqual(200, count, "TotalMinutes: " + minutesDiff); + Assert.That(count, Is.EqualTo(200), "TotalMinutes: " + minutesDiff); } } @@ -132,7 +133,7 @@ public void DateDiffSecond() var count = context.Actor .Count(a => EF.Functions.DateDiffSecond(a.LastUpdate, DateTime.Now) >= secondsDiff); - Assert.AreEqual(200, count, "TotalSeconds: " + secondsDiff); + Assert.That(count, Is.EqualTo(200), "TotalSeconds: " + secondsDiff); } } @@ -144,7 +145,7 @@ public void DateDiffMicrosecond() var count = context.Actor .Count(a => EF.Functions.DateDiffMicrosecond(a.LastUpdate, DateTime.Now) == 0); - Assert.AreEqual(0, count); + Assert.That(count, Is.EqualTo(0)); } } @@ -155,7 +156,7 @@ public void LikeIntLiteral() { var count = context.Actor.Count(o => EF.Functions.Like(o.ActorId, "%A%")); - Assert.AreEqual(0, count); + Assert.That(count, Is.EqualTo(0)); } } @@ -166,7 +167,7 @@ public void LikeDateTimeLiteral() { var count = context.Actor.Count(o => EF.Functions.Like(o.LastUpdate, "%A%")); - Assert.AreEqual(0, count); + Assert.That(count, Is.EqualTo(0)); } } @@ -177,7 +178,7 @@ public void LikeIntLiteralWithEscape() { var count = context.Actor.Count(o => EF.Functions.Like(o.ActorId, "!%", "!")); - Assert.AreEqual(0, count); + Assert.That(count, Is.EqualTo(0)); } } } diff --git a/EFCore/tests/MySql.EFCore.Basic.Tests/EFCoreTests.cs b/EFCore/tests/MySql.EFCore.Basic.Tests/EFCoreTests.cs index 5f9ff2254..35a7593a5 100644 --- a/EFCore/tests/MySql.EFCore.Basic.Tests/EFCoreTests.cs +++ b/EFCore/tests/MySql.EFCore.Basic.Tests/EFCoreTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -50,8 +50,8 @@ public void ExplicitlyCompiledQueries() using (SakilaLiteContext context = new SakilaLiteContext()) { var customer = _customerById(context, 9); - Assert.AreEqual(9, customer.CustomerId); - Assert.AreEqual("MOORE", customer.LastName); + Assert.That(customer.CustomerId, Is.EqualTo(9)); + Assert.That(customer.LastName, Is.EqualTo("MOORE")); } } @@ -67,14 +67,14 @@ public void GraphNewAndExistingEntities() context.Attach(actor = new Actor { ActorId = 21, FirstName = "KIRSTEN", LastName = "PALTROW" }); var changes = context.ChangeTracker.Entries(); - Assert.AreEqual(2, changes.Count()); + Assert.That(changes.Count(), Is.EqualTo(2)); Assert.That(changes.Select(c => c.State), Has.Exactly(1).Matches(state => state.Equals(EntityState.Added))); Assert.That(changes.Select(c => c.State), Has.Exactly(1).Matches(state => state.Equals(EntityState.Unchanged))); context.SaveChanges(); var list = context.Actor.ToList(); - Assert.AreEqual(1, list.Count); + Assert.That(list.Count, Is.EqualTo(1)); } } @@ -92,8 +92,8 @@ public void StringInterpolationInSqlCommands() context.Database.ExecuteSqlInterpolated($"INSERT INTO actor(actor_id, first_name, last_name, last_update) VALUES ({id}, {firstName}, {lastName}, {lastUpdate:u})"); Actor actor = context.Set().FromSqlInterpolated($"SELECT * FROM actor WHERE actor_id={id} and last_name={lastName}").First(); - Assert.AreEqual(id, actor.ActorId); - Assert.AreEqual(firstName, actor.FirstName); + Assert.That(actor.ActorId, Is.EqualTo(id)); + Assert.That(actor.FirstName, Is.EqualTo(firstName)); } } @@ -155,7 +155,7 @@ public void QueryWithDate() && w.LastUpdate >= DateTime.Today.AddDays(-15)); var res = scenario1.Count(); - Assert.AreEqual(0, res); + Assert.That(res, Is.EqualTo(0)); var dt = DateTime.Today.AddDays(-15); var scenario2 = context.Actor.Where( @@ -164,7 +164,7 @@ public void QueryWithDate() && w.LastUpdate >= dt); var res2 = scenario2.Count(); - Assert.AreEqual(0, res2); + Assert.That(res2, Is.EqualTo(0)); var scenario3 = context.Actor.Where( w => w.FirstName == "GARY" @@ -172,7 +172,7 @@ public void QueryWithDate() && w.LastUpdate >= DateTime.Today.AddDays(3)); var res3 = scenario3.Count(); - Assert.AreEqual(0, res3); + Assert.That(res3, Is.EqualTo(0)); } } @@ -200,5 +200,97 @@ public void DateTimeEqualityCheck() Assert.That(test.Count, Is.EqualTo(1)); } } + + /// + /// Bug#35392218 [bugfix schema name (specially usefull when use multiple schema..] + /// + [Test] + public void MultipleSchemaContext() + { + try + { + using (Bug35392218Context context = new Bug35392218Context()) + { + context.Database.EnsureDeleted(); + context.Database.EnsureCreated(); + + context.Add(new Bug35392218_1 { Id = 1, Name = "John Doe" }); + context.Add(new Bug35392218_2 { Id = 1, Name = "John Doe" }); + context.SaveChanges(); + + using (MySqlConnection connection = new MySqlConnection(MySQLTestStore.BaseConnectionString)) + { + connection.Open(); + + MySqlCommand command = connection.CreateCommand(); + command.CommandText = "SHOW DATABASES LIKE '%bug35392218%';"; + + MySqlDataReader reader = command.ExecuteReader(); + int rowCount = 0; + while (reader.Read()) + { + rowCount++; + } + + //Checking if 2 databases related to the bug number are created in the server; + Assert.That(rowCount, Is.EqualTo(2)); + reader.Close(); + } + + using (MySqlConnection connection = new MySqlConnection(MySQLTestStore.BaseConnectionString + "database=schema_bug35392218_1;")) + { + connection.Open(); + + MySqlCommand command = connection.CreateCommand(); + command.CommandText = "SELECT * FROM bug35392218_table1"; + + MySqlDataReader reader = command.ExecuteReader(); + int rowCount = 0; + while (reader.Read()) + { + rowCount++; + } + + //Checking if the data is available in 'schemaBug35392218_1' as its the default database definded in the context configuration. + Assert.That(rowCount, Is.EqualTo(1)); + Assert.That(reader.GetString(1), Is.EqualTo("John Doe")); + + reader.Close(); + } + + using (MySqlConnection connection = new MySqlConnection(MySQLTestStore.BaseConnectionString + "database=schema_bug35392218_2;")) + { + connection.Open(); + + MySqlCommand command = connection.CreateCommand(); + command.CommandText = "SELECT * FROM bug35392218_table2"; + + MySqlDataReader reader = command.ExecuteReader(); + int rowCount = 0; + while (reader.Read()) + { + rowCount++; + } + + //Checking if the same data is also inserted into 'schemaBug35392218_2' which is the other database defined in model creation. + Assert.That(rowCount, Is.EqualTo(1)); + Assert.That(reader.GetString(1), Is.EqualTo("John Doe")); + + reader.Close(); + } + } + } + finally + { + using (MySqlConnection connection = new MySqlConnection(MySQLTestStore.BaseConnectionString)) + { + connection.Open(); + + MySqlCommand command = connection.CreateCommand(); + command.CommandText = "DROP DATABASE IF EXISTS schema_bug35392218_2;DROP DATABASE IF EXISTS schema_bug35392218_1;"; + command.ExecuteNonQuery(); + } + } + } } } diff --git a/EFCore/tests/MySql.EFCore.Basic.Tests/FluentAPITests.cs b/EFCore/tests/MySql.EFCore.Basic.Tests/FluentAPITests.cs index e36acc2e7..37c27ffbb 100644 --- a/EFCore/tests/MySql.EFCore.Basic.Tests/FluentAPITests.cs +++ b/EFCore/tests/MySql.EFCore.Basic.Tests/FluentAPITests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -33,6 +33,7 @@ using MySql.EntityFrameworkCore.Basic.Tests.Utils; using MySql.EntityFrameworkCore.Extensions; using NUnit.Framework; +using NUnit.Framework.Legacy; using System; using System.Linq; using System.Text.RegularExpressions; @@ -56,10 +57,7 @@ public void OneTimeTearDown() [Test] public void EnsureRelationalPatterns() { - if (!TestUtils.IsAtLeast(5, 7, 0)) - { - Assert.Ignore(); - } + Assume.That(TestUtils.IsAtLeast(5, 7, 0)); var serviceCollection = new ServiceCollection(); serviceCollection.AddEntityFrameworkMySQL() @@ -75,7 +73,7 @@ public void EnsureRelationalPatterns() context.Employees.Add(e); context.SaveChanges(); var employeeComputedColumn = context.Employees.FirstOrDefault(); - Assert.True(employeeComputedColumn!.DisplayName!.Equals("Stuart Jos"), "Wrong computed column"); + Assert.That(employeeComputedColumn!.DisplayName!.Equals("Stuart Jos"), "Wrong computed column"); context.Database.EnsureDeleted(); } } @@ -100,7 +98,7 @@ public void CanUseModelWithDateTimeOffset() context.QuickEntity.Add(e); context.SaveChanges(); var row = context.QuickEntity.FirstOrDefault(); - Assert.AreEqual(dt, row!.Created); + Assert.That(row!.Created, Is.EqualTo(dt)); } finally { @@ -129,7 +127,7 @@ public async Task CanUseModelWithDateTimeOffsetAsync() context.QuickEntity.Add(e); context.SaveChanges(); var result = await context.QuickEntity.FirstOrDefaultAsync(); - Assert.AreEqual(dt, result!.Created); + Assert.That(result!.Created, Is.EqualTo(dt)); } catch (Exception) { @@ -163,7 +161,7 @@ public void CanNameAlternateKey() var reader = cmd.ExecuteReader(); while (reader.Read()) { - Assert.True(reader.GetString(1).ToString().Equals("AlternateKey_LicensePlate"), "Wrong index creation"); + Assert.That(reader.GetString(1).ToString().Equals("AlternateKey_LicensePlate"), "Wrong index creation"); } } } @@ -188,7 +186,7 @@ public void CanUseToTable() var reader = cmd.ExecuteReader(); while (reader.Read()) { - Assert.True(reader.GetString(0).ToString().Equals("somecars"), "Wrong table name"); + Assert.That(reader.GetString(0).ToString().Equals("somecars"), "Wrong table name"); } } context.Database.EnsureDeleted(); @@ -215,7 +213,7 @@ public void CanUseConcurrency() var reader = cmd.ExecuteReader(); while (reader.Read()) { - Assert.True(reader.GetString(0).ToString().Equals("somecars"), "Wrong table name"); + Assert.That(reader.GetString(0).ToString().Equals("somecars"), "Wrong table name"); } } context.Database.EnsureDeleted(); @@ -226,10 +224,7 @@ public void CanUseConcurrency() [Test] public void CanUseConcurrencyToken() { - if (!TestUtils.IsAtLeast(5, 7, 0)) - { - Assert.Ignore(); - } + Assume.That(TestUtils.IsAtLeast(5, 7, 0)); var serviceCollection = new ServiceCollection(); serviceCollection.AddEntityFrameworkMySQL() @@ -246,7 +241,7 @@ public void CanUseConcurrencyToken() context.Employees.Add(e); context.SaveChanges(); var employeeComputedColumn = context.Employees.SingleOrDefault(); - Assert.True(employeeComputedColumn!.DisplayName!.Equals("Stuart Jos"), "Wrong computed column"); + Assert.That(employeeComputedColumn!.DisplayName!.Equals("Stuart Jos"), "Wrong computed column"); context.Database.EnsureDeleted(); } } @@ -255,10 +250,7 @@ public void CanUseConcurrencyToken() [Test] public void CanUseContainsInQuery() { - if (!TestUtils.IsAtLeast(5, 7, 0)) - { - Assert.Ignore(); - } + Assume.That(TestUtils.IsAtLeast(5, 7, 0)); var serviceCollection = new ServiceCollection(); serviceCollection.AddEntityFrameworkMySQL() @@ -282,10 +274,7 @@ public void CanUseContainsInQuery() [Test] public void CanUseContainsVarInQuery() { - if (!TestUtils.IsAtLeast(5, 7, 0)) - { - Assert.Ignore(); - } + Assume.That(TestUtils.IsAtLeast(5, 7, 0)); var serviceCollection = new ServiceCollection(); serviceCollection.AddEntityFrameworkMySQL() @@ -310,10 +299,7 @@ public void CanUseContainsVarInQuery() [Test] public void CanUseContainsWithInvalidValue() { - if (!TestUtils.IsAtLeast(5, 7, 0)) - { - Assert.Ignore(); - } + Assume.That(TestUtils.IsAtLeast(5, 7, 0)); var serviceCollection = new ServiceCollection(); serviceCollection.AddEntityFrameworkMySQL() @@ -328,9 +314,9 @@ public void CanUseContainsWithInvalidValue() context.Employees.Add(e); context.SaveChanges(); var result = context.Employees.Where(t => t.FirstName!.Contains("XXXXXXXX$%^&*()!")).ToList(); - Assert.IsEmpty(result); + Assert.That(result, Is.Empty); result = context.Employees.Where(t => t.FirstName!.Contains("null")).ToList(); - Assert.IsEmpty(result); + Assert.That(result, Is.Empty); context.Database.EnsureDeleted(); } } @@ -339,10 +325,7 @@ public void CanUseContainsWithInvalidValue() [Test] public void CanUseContainsWithVariableInQuery() { - if (!TestUtils.IsAtLeast(5, 7, 0)) - { - Assert.Ignore(); - } + Assume.That(TestUtils.IsAtLeast(5, 7, 0)); var serviceCollection = new ServiceCollection(); serviceCollection.AddEntityFrameworkMySQL() @@ -377,10 +360,10 @@ public void TableAttributeTest() MySqlCommand cmd = new MySqlCommand("SHOW TABLES", conn); using (MySqlDataReader reader = cmd.ExecuteReader()) { - Assert.True(reader.Read()); - StringAssert.AreEqualIgnoringCase("continentlist", reader.GetString(0)); - Assert.True(reader.Read()); - StringAssert.AreEqualIgnoringCase("countrylist", reader.GetString(0)); + Assert.That(reader.Read()); + Assert.That(reader.GetString(0), Is.EqualTo("continentlist").IgnoreCase); + Assert.That(reader.Read()); + Assert.That(reader.GetString(0), Is.EqualTo("countrylist").IgnoreCase); } } @@ -406,7 +389,7 @@ public void CharsetTest() string createTable = reader.GetString(1); createTable = Regex.Replace(createTable, @"\t|\n|\r", string.Empty); string txt = "CREATE TABLE `testcharsetda` ( `TestCharsetDAId` varbinary(255) NOT NULL, PRIMARY KEY (`TestCharsetDAId`)) ENGINE=InnoDB DEFAULT CHARSET=ascii"; - StringAssert.AreEqualIgnoringCase(txt, createTable); + Assert.That(createTable, Is.EqualTo(txt).IgnoreCase); } cmd.CommandText = "SHOW CREATE TABLE `TestCharsetFA`"; @@ -421,12 +404,12 @@ public void CharsetTest() if (createTable.Contains("COLLATE latin7_general_ci")) { txt = "CREATE TABLE `testcharsetfa` ( `TestCharsetFAId` varchar(255) CHARACTER SET latin7 COLLATE latin7_general_ci NOT NULL, PRIMARY KEY (`TestCharsetFAId`)) ENGINE=InnoDB DEFAULT CHARSET=utf16"; - StringAssert.AreEqualIgnoringCase(txt, createTable); + Assert.That(createTable, Is.EqualTo(txt).IgnoreCase); } else { txt = "CREATE TABLE `testcharsetfa` ( `TestCharsetFAId` varchar(255) CHARACTER SET latin7 NOT NULL, PRIMARY KEY (`TestCharsetFAId`)) ENGINE=InnoDB DEFAULT CHARSET=utf16"; - StringAssert.AreEqualIgnoringCase(txt, createTable); + Assert.That(createTable, Is.EqualTo(txt).IgnoreCase); } } @@ -437,7 +420,7 @@ public void CharsetTest() string createTable = reader.GetString(1); createTable = Regex.Replace(createTable, @"\t|\n|\r", string.Empty); string txt = "CREATE TABLE `testcollationda` ( `TestCollationDAId` varchar(255) CHARACTER SET greek COLLATE greek_bin NOT NULL, PRIMARY KEY (`TestCollationDAId`)) ENGINE=InnoDB DEFAULT CHARSET=cp932 COLLATE=cp932_bin"; - StringAssert.AreEqualIgnoringCase(txt, createTable); + Assert.That(createTable, Is.EqualTo(txt).IgnoreCase); } cmd.CommandText = "SHOW CREATE TABLE `TestCollationFA`"; @@ -447,7 +430,7 @@ public void CharsetTest() string createTable = reader.GetString(1); createTable = Regex.Replace(createTable, @"\t|\n|\r", string.Empty); string txt = "CREATE TABLE `testcollationfa` ( `TestCollationFAId` varchar(255) CHARACTER SET ucs2 COLLATE ucs2_bin NOT NULL, PRIMARY KEY (`TestCollationFAId`)) ENGINE=InnoDB DEFAULT CHARSET=koi8u COLLATE=koi8u_bin"; - StringAssert.AreEqualIgnoringCase(txt, createTable); + Assert.That(createTable, Is.EqualTo(txt).IgnoreCase); } } } diff --git a/EFCore/tests/MySql.EFCore.Basic.Tests/FunctionalTests.cs b/EFCore/tests/MySql.EFCore.Basic.Tests/FunctionalTests.cs index 841407edc..b12e73b80 100644 --- a/EFCore/tests/MySql.EFCore.Basic.Tests/FunctionalTests.cs +++ b/EFCore/tests/MySql.EFCore.Basic.Tests/FunctionalTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -34,6 +34,7 @@ using MySql.EntityFrameworkCore.Basic.Tests.Utils; using MySql.EntityFrameworkCore.Extensions; using NUnit.Framework; +using NUnit.Framework.Legacy; using System; using System.Linq; @@ -61,7 +62,7 @@ public void CanConnectWithConnectionOnConfiguring() { context.Database.EnsureDeleted(); context.Database.EnsureCreated(); - Assert.True(context.Posts.Count() == 0); + Assert.That(context.Posts.Count(), Is.EqualTo(0)); context.Database.EnsureDeleted(); } } @@ -78,7 +79,7 @@ public void CanThrowExceptionWhenNoConfiguration() using (var context = serviceProvider.GetRequiredService()) { - Assert.AreEqual(CoreStrings.NoProviderConfigured, Assert.Throws(() => context.Blogs.Any())!.Message); + Assert.That(Assert.Throws(() => context.Blogs.Any())!.Message, Is.EqualTo(CoreStrings.NoProviderConfigured)); } } @@ -103,7 +104,7 @@ public void CreatedDb() var reader = cmd.ExecuteReader(); while (reader.Read()) { - Assert.True(string.Equals(dbname, reader.GetString(0), StringComparison.CurrentCultureIgnoreCase), "Database was not created"); + Assert.That(string.Equals(dbname, reader.GetString(0), StringComparison.CurrentCultureIgnoreCase), "Database was not created"); } } context.Database.EnsureDeleted(); @@ -131,7 +132,7 @@ public void EnsureRelationalPatterns() var reader = cmd.ExecuteReader(); while (reader.Read()) { - Assert.True(string.Equals(dbname, reader.GetString(0), StringComparison.CurrentCultureIgnoreCase), "Database was not created"); + Assert.That(string.Equals(dbname, reader.GetString(0), StringComparison.CurrentCultureIgnoreCase), "Database was not created"); } } context.Database.EnsureDeleted(); @@ -151,8 +152,8 @@ public void CanUseIgnoreEntity() using (var context = serviceProvider.GetRequiredService()) { context.Database.EnsureCreated(); - Assert.True(context.Model.GetEntityTypes().Count() == 2, "Wrong model generation"); - Assert.True(context.Blogs.ToList().Count == 0, ""); + Assert.That(context.Model.GetEntityTypes().Count(), Is.EqualTo(2), "Wrong model generation"); + Assert.That(context.Blogs.ToList().Count, Is.EqualTo(0), ""); context.Database.EnsureDeleted(); } } @@ -166,7 +167,7 @@ public void CanUseOptionsInDbContextCtor() new MySqlConnection(MySQLTestStore.CreateConnectionString("db-optionsindbcontext")))) { context.Database.EnsureCreated(); - Assert.True(context.Blogs.Count() == 0); + Assert.That(context.Blogs.Count(), Is.EqualTo(0)); context.Database.EnsureDeleted(); } @@ -204,11 +205,11 @@ public OptionsContext(DbContextOptions options, MySqlConnection connection) protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { - Assert.AreSame(_options, optionsBuilder.Options); + Assert.That(optionsBuilder.Options, Is.SameAs(_options)); optionsBuilder.UseMySQL(_connection); - Assert.AreNotSame(_options, optionsBuilder.Options); + Assert.That(optionsBuilder.Options, Is.Not.SameAs(_options)); } public override void Dispose() diff --git a/EFCore/tests/MySql.EFCore.Basic.Tests/LoadingRelatedDataTests.cs b/EFCore/tests/MySql.EFCore.Basic.Tests/LoadingRelatedDataTests.cs index d122a91f6..c73eb25c1 100644 --- a/EFCore/tests/MySql.EFCore.Basic.Tests/LoadingRelatedDataTests.cs +++ b/EFCore/tests/MySql.EFCore.Basic.Tests/LoadingRelatedDataTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -31,6 +31,7 @@ using MySql.EntityFrameworkCore.Basic.Tests.DbContextClasses; using MySql.EntityFrameworkCore.Basic.Tests.Utils; using NUnit.Framework; +using NUnit.Framework.Legacy; using System.Linq; namespace MySql.EntityFrameworkCore.Basic.Tests @@ -62,7 +63,7 @@ public void OneTimeTearDown() [Test] public void CanUseSkipAndTake() { - Assert.False(context.Database.EnsureCreated()); + Assert.That(!context.Database.EnsureCreated()); var people = context.Set() .Skip(2) @@ -75,56 +76,56 @@ var people [Test] public void CanIncludeAddressData() { - Assert.False(context.Database.EnsureCreated()); + Assert.That(!context.Database.EnsureCreated()); var people = context.Set() .Include(p => p.Address) .ToList(); - Assert.AreEqual(4, people.Count); - Assert.AreEqual(3, people.Count(p => p.Address != null)); + Assert.That(people.Count, Is.EqualTo(4)); + Assert.That(people.Count(p => p.Address != null), Is.EqualTo(3)); } [Test] public void CanIncludeGuestData() { - Assert.False(context.Database.EnsureCreated()); + Assert.That(!context.Database.EnsureCreated()); var ad = context.Set
() .Include(p => p.Guest) .ToList(); - Assert.AreEqual(3, ad.Count); + Assert.That(ad.Count, Is.EqualTo(3)); var rows = ad.Select(g => g.Guest).Where(a => a != null).ToList(); - Assert.AreEqual(3, rows.Count()); + Assert.That(rows.Count(), Is.EqualTo(3)); } [Test] public void CanIncludeGuestShadowProperty() { - Assert.False(context.Database.EnsureCreated()); + Assert.That(!context.Database.EnsureCreated()); var addressRelative = context.Set() .Include(a => a.Relative) .ToList(); - Assert.AreEqual(3, addressRelative.Count); - Assert.True(addressRelative.All(p => p.Relative != null)); + Assert.That(addressRelative.Count, Is.EqualTo(3)); + Assert.That(addressRelative.All(p => p.Relative != null)); } [Test] public void MixClientServerEvaluation() { - Assert.False(context.Database.EnsureCreated()); + Assert.That(!context.Database.EnsureCreated()); var list = context.Set
() .OrderByDescending(a => a.City) .Select(a => new { Id = a.IdAddress, City = SetCity(a.City!) }) .ToList(); - Assert.AreEqual(3, list.Count); - StringAssert.EndsWith(" city", list.First().City); + Assert.That(list.Count, Is.EqualTo(3)); + Assert.That(list.First().City, Does.EndWith(" city")); } private static string SetCity(string name) @@ -135,16 +136,16 @@ private static string SetCity(string name) [Test] public void RawSqlQueries() { - Assert.False(context.Database.EnsureCreated()); + Assert.That(!context.Database.EnsureCreated()); var guests = context.Set().FromSqlRaw("SELECT * FROM Guests") .ToList(); - Assert.AreEqual(4, guests.Count); + Assert.That(guests.Count, Is.EqualTo(4)); } [Test] public void UsingTransactions() { - Assert.False(context.Database.EnsureCreated()); + Assert.That(!context.Database.EnsureCreated()); using (var transaction = context.Database.BeginTransaction()) { context.Set().Add(new Guest() @@ -153,25 +154,22 @@ public void UsingTransactions() }); context.SaveChanges(); } - Assert.AreEqual(4, context.Set().Count()); + Assert.That(context.Set().Count(), Is.EqualTo(4)); } [Test] public void DbSetFind() { var address = context.Set
().Find(1); - Assert.NotNull(address); - Assert.AreEqual("Michigan", address!.City); + Assert.That(address, Is.Not.Null); + Assert.That(address!.City, Is.EqualTo("Michigan")); } [Test] public void JsonDataTest() { - if (!TestUtils.IsAtLeast(5, 7, 0)) - { - Assert.Ignore(); - } + Assume.That(TestUtils.IsAtLeast(5, 7, 0)); using (JsonContext context = new JsonContext()) { @@ -198,10 +196,10 @@ public void JsonDataTest() } //Adding "COLLATION" to the string validation at table creation (this happens since MySql 8.0.5 Server) if (jsonTableDesc.Contains("COLLATE=utf8mb4_0900_ai_ci")) - StringAssert.AreEqualIgnoringCase($"CREATE TABLE `jsonentity` (\n `Id` smallint{smallintWidth} NOT NULL AUTO_INCREMENT," + - $"\n `jsoncol` json DEFAULT NULL,\n PRIMARY KEY (`Id`)\n) ENGINE=InnoDB DEFAULT CHARSET={charset} COLLATE=utf8mb4_0900_ai_ci", jsonTableDesc); - else StringAssert.AreEqualIgnoringCase($"CREATE TABLE `jsonentity` (\n `Id` smallint{smallintWidth} NOT NULL AUTO_INCREMENT,\n `jsoncol` json DEFAULT NULL,\n PRIMARY KEY (`Id`)\n) " + - $"ENGINE=InnoDB DEFAULT CHARSET={charset}", jsonTableDesc); + Assert.That(jsonTableDesc, Is.EqualTo($"CREATE TABLE `jsonentity` (\n `Id` smallint{smallintWidth} NOT NULL AUTO_INCREMENT," + + $"\n `jsoncol` json DEFAULT NULL,\n PRIMARY KEY (`Id`)\n) ENGINE=InnoDB DEFAULT CHARSET={charset} COLLATE=utf8mb4_0900_ai_ci").IgnoreCase); + else Assert.That(jsonTableDesc, Is.EqualTo($"CREATE TABLE `jsonentity` (\n `Id` smallint{smallintWidth} NOT NULL AUTO_INCREMENT,\n `jsoncol` json DEFAULT NULL,\n PRIMARY KEY (`Id`)\n) " + + $"ENGINE=InnoDB DEFAULT CHARSET={charset}").IgnoreCase); } context.JsonEntity.Add(new JsonData() @@ -210,7 +208,7 @@ public void JsonDataTest() }); context.SaveChanges(); JsonData json = context.JsonEntity.First(); - Assert.AreEqual("{ \"name\": \"Ronald\", \"city\": \"Austin\" }", json.jsoncol); + Assert.That(json.jsoncol, Is.EqualTo("{ \"name\": \"Ronald\", \"city\": \"Austin\" }")); } } @@ -218,10 +216,7 @@ public void JsonDataTest() [Test] public void JsonInvalidData() { - if (!TestUtils.IsAtLeast(5, 7, 0)) - { - Assert.Ignore(); - } + Assume.That(TestUtils.IsAtLeast(5, 7, 0)); using (JsonContext context = new JsonContext()) { @@ -233,7 +228,7 @@ public void JsonInvalidData() }); var ex = Assert.Throws(() => context.SaveChanges())?.GetBaseException(); - Assert.AreEqual(3140, ((MySqlException)ex!).Number); + Assert.That(((MySqlException)ex!).Number, Is.EqualTo(3140)); } } @@ -241,10 +236,7 @@ public void JsonInvalidData() [Test] public void ComputedColumns() { - if (!TestUtils.IsAtLeast(5, 7, 0)) - { - Assert.Ignore(); - } + Assume.That(TestUtils.IsAtLeast(5, 7, 0)); using (FiguresContext context = new FiguresContext()) { @@ -265,8 +257,8 @@ public void ComputedColumns() context.Triangle.AddRange(data); context.Triangle.Add(data[1]); context.SaveChanges(); - Assert.AreEqual(75, data[0].Area); - Assert.AreEqual(50, data[1].Area); + Assert.That(data[0].Area, Is.EqualTo(75)); + Assert.That(data[1].Area, Is.EqualTo(50)); } } @@ -277,12 +269,12 @@ public void ExplicitLoading() { context.PopulateData(); var america = context.Continents.Single(c => c.Code == "AM"); - Assert.Null(america.Countries); + Assert.That(america.Countries, Is.Null); context.Entry(america) .Collection(c => c.Countries!) .Load(); - Assert.AreEqual(5, america.Countries!.Count); - Assert.AreEqual("United States", america.Countries.Single(c => c.Code == "US").Name); + Assert.That(america.Countries!.Count, Is.EqualTo(5)); + Assert.That(america.Countries.Single(c => c.Code == "US").Name, Is.EqualTo("United States")); } } @@ -293,7 +285,7 @@ public void ExplicitLoadingQueryingRelatedEntitites() { context.PopulateData(); var asia = context.Continents.Single(c => c.Code == "AS"); - Assert.Null(asia.Countries); + Assert.That(asia.Countries, Is.Null); var list = context.Entry(asia) .Collection(c => c.Countries!) .Query() diff --git a/EFCore/tests/MySql.EFCore.Basic.Tests/ModelingTests.cs b/EFCore/tests/MySql.EFCore.Basic.Tests/ModelingTests.cs index 1f696ae53..d20647d7b 100644 --- a/EFCore/tests/MySql.EFCore.Basic.Tests/ModelingTests.cs +++ b/EFCore/tests/MySql.EFCore.Basic.Tests/ModelingTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -30,6 +30,7 @@ using MySql.EntityFrameworkCore.Basic.Tests.DbContextClasses; using MySql.EntityFrameworkCore.Basic.Tests.Utils; using NUnit.Framework; +using NUnit.Framework.Legacy; using System; using System.Collections.Generic; using System.Linq; @@ -123,10 +124,10 @@ public void LikeFunction() using (SakilaLiteContext context = new SakilaLiteContext()) { var query = context.Actor.Where(c => EF.Functions.Like(c.LastName!, "A%")).ToList(); - Assert.IsNotEmpty(query); + Assert.That(query, Is.Not.Empty); foreach (Actor actor in query) { - StringAssert.StartsWith("A", actor.LastName); + Assert.That(actor.LastName, Does.StartWith("A")); } } } @@ -157,8 +158,8 @@ public void OwnedEntityTypes() context.SaveChanges(); var customer = context.Customer.Where(p => p.Address!.AddressId == 1).First(); - Assert.AreEqual(1, customer.CustomerId); - Assert.AreEqual("47 MySakila Drive", customer.Address!.Address); + Assert.That(customer.CustomerId, Is.EqualTo(1)); + Assert.That(customer.Address!.Address, Is.EqualTo("47 MySakila Drive")); } finally { @@ -172,8 +173,8 @@ public void ModelLevelQueryFilter() { using (SakilaLiteContext context = new SakilaLiteContext()) { - Assert.AreEqual(584, context.Customer.Count()); - Assert.AreEqual(599, context.Customer.IgnoreQueryFilters().Count()); + Assert.That(context.Customer.Count(), Is.EqualTo(584)); + Assert.That(context.Customer.IgnoreQueryFilters().Count(), Is.EqualTo(599)); } } @@ -189,12 +190,12 @@ public void ConvertToType() ls = context.Actor.OrderBy(a => a.ActorId).Select(b => new ActorTest { Number = Convert.ToInt32(b.ActorId), - Value = Convert.ToString(b.LastUpdate), + Value = b.LastUpdate.ToString(), Text = b.FirstName, }).ToList(); - Assert.IsNotEmpty(ls); + Assert.That(ls, Is.Not.Empty); } } } -} \ No newline at end of file +} diff --git a/EFCore/tests/MySql.EFCore.Basic.Tests/MultiSchemaTests.cs b/EFCore/tests/MySql.EFCore.Basic.Tests/MultiSchemaTests.cs index 59cba2e4f..8a82615aa 100644 --- a/EFCore/tests/MySql.EFCore.Basic.Tests/MultiSchemaTests.cs +++ b/EFCore/tests/MySql.EFCore.Basic.Tests/MultiSchemaTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -31,6 +31,7 @@ using MySql.EntityFrameworkCore.Basic.Tests.DbContextClasses; using MySql.EntityFrameworkCore.Basic.Tests.Utils; using NUnit.Framework; +using NUnit.Framework.Legacy; using System; using System.Collections.Generic; using System.Linq; @@ -76,11 +77,11 @@ public void MultiSchemaTest() { while (reader.Read()) { - Assert.Contains(reader.GetString(0), databases); + Assert.That(databases.Contains(reader.GetString(0))); count++; } } - Assert.AreEqual(3, count); + Assert.That(count, Is.EqualTo(3)); } } } @@ -136,9 +137,9 @@ public void LoadingData() }); context.SaveChanges(); - Assert.AreEqual(2, context.Car.Count()); - Assert.AreEqual(2, context.BodyShop.Count()); - Assert.AreEqual(2, context.Employee.Count()); + Assert.That(context.Car.Count(), Is.EqualTo(2)); + Assert.That(context.BodyShop.Count(), Is.EqualTo(2)); + Assert.That(context.Employee.Count(), Is.EqualTo(2)); } } @@ -155,4 +156,4 @@ private void PopulateData() } } } -} \ No newline at end of file +} diff --git a/EFCore/tests/MySql.EFCore.Basic.Tests/MySQLDatabaseFacadeTest.cs b/EFCore/tests/MySql.EFCore.Basic.Tests/MySQLDatabaseFacadeTest.cs index ffc9a6cb6..1c203cc07 100644 --- a/EFCore/tests/MySql.EFCore.Basic.Tests/MySQLDatabaseFacadeTest.cs +++ b/EFCore/tests/MySql.EFCore.Basic.Tests/MySQLDatabaseFacadeTest.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -34,6 +34,7 @@ using MySql.EntityFrameworkCore.Basic.Tests.Utils; using MySql.EntityFrameworkCore.Extensions; using NUnit.Framework; +using NUnit.Framework.Legacy; using System; namespace MySql.EntityFrameworkCore.Basic.Tests @@ -45,7 +46,7 @@ public void IsMySQLWhenUsingOnConfiguring() { using (var context = new MySQLOnConfiguringContext()) { - Assert.True(context.Database.IsMySql()); + Assert.That(context.Database.IsMySql()); } } @@ -55,7 +56,7 @@ public void IsMySQLInOnModelCreatingWhenUsingOnConfiguring() using (var context = new MySQLOnModelContext()) { var _ = context.Model; // Trigger context initialization - Assert.True(context.IsMySQLSet); + Assert.That(context.IsMySQLSet == true); } } @@ -65,7 +66,7 @@ public void IsMySQLInConstructorWhenUsingOnConfiguring() using (var context = new MySQLConstructorContext()) { var _ = context.Model; // Trigger context initialization - Assert.True(context.IsMySQLSet); + Assert.That(context.IsMySQLSet == true); } } @@ -74,13 +75,12 @@ public void CannotUseIsMySQLInOnConfiguring() { using (var context = new MySQLUseInOnConfiguringContext()) { - Assert.AreEqual( - CoreStrings.RecursiveOnConfiguring, + Assert.That( Assert.Throws( () => { var _ = context.Model; // Trigger context initialization - })!.Message); + })!.Message, Is.EqualTo(CoreStrings.RecursiveOnConfiguring)); } } @@ -92,7 +92,7 @@ public void IsMySQLWhenUsingConstructor() .UseInternalServiceProvider(MySQLFixture.DefaultServiceProvider) .UseMySQL("Database=Maltesers").Options)) { - Assert.True(context.Database.IsMySql()); + Assert.That(context.Database.IsMySql()); } } @@ -105,7 +105,7 @@ public void IsMySQLInOnModelCreatingWhenUsingConstructor() .UseMySQL("Database=Maltesers").Options)) { var _ = context.Model; // Trigger context initialization - Assert.True(context.IsMySQLSet); + Assert.That(context.IsMySQLSet == true); } } @@ -118,7 +118,7 @@ public void IsMySQLInConstructorWhenUsingConstructor() .UseMySQL("Database=Maltesers").Options)) { var _ = context.Model; // Trigger context initialization - Assert.True(context.IsMySQLSet); + Assert.That(context.IsMySQLSet == true); } } @@ -130,13 +130,12 @@ public void CannotUseIsMySQLInOnConfiguringWithConstructor() .UseInternalServiceProvider(MySQLFixture.DefaultServiceProvider) .UseMySQL("Database=Maltesers").Options)) { - Assert.AreEqual( - CoreStrings.RecursiveOnConfiguring, + Assert.That( Assert.Throws( () => { var _ = context.Model; // Trigger context initialization - })!.Message); + })!.Message, Is.EqualTo(CoreStrings.RecursiveOnConfiguring)); } } diff --git a/EFCore/tests/MySql.EFCore.Basic.Tests/MySQLTypeMapperTests.cs b/EFCore/tests/MySql.EFCore.Basic.Tests/MySQLTypeMapperTests.cs index 5738fc9d3..03a06aac0 100644 --- a/EFCore/tests/MySql.EFCore.Basic.Tests/MySQLTypeMapperTests.cs +++ b/EFCore/tests/MySql.EFCore.Basic.Tests/MySQLTypeMapperTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -31,6 +31,7 @@ using MySql.EntityFrameworkCore.Basic.Tests.DbContextClasses; using MySql.EntityFrameworkCore.Basic.Tests.Utils; using NUnit.Framework; +using NUnit.Framework.Legacy; using System; using System.Collections.Generic; using System.Linq; @@ -47,15 +48,14 @@ public void OneTimeTearDown() context.Database.EnsureDeleted(); using (var context = new StringTypesContext()) context.Database.EnsureDeleted(); + using (var context = new AllBlobTypesContext()) + context.Database.EnsureDeleted(); } [Test] public void InsertAllDataTypes() { - if (!TestUtils.IsAtLeast(5, 7, 0)) - { - Assert.Ignore(); - } + Assume.That(TestUtils.IsAtLeast(5, 7, 0)); DateTime now = new DateTime(DateTime.Today.AddSeconds(1).AddMilliseconds(1).AddTicks(10).Ticks); @@ -100,33 +100,75 @@ public void InsertAllDataTypes() using (var context = new AllDataTypesContext()) { var data = context.AllDataTypes.First(); - Assert.AreEqual(1, data.AddressNumber1); - Assert.AreEqual(2, data.AddressNumber2); - Assert.AreEqual(3, data.AddressNumber3); - Assert.AreEqual(4, data.AddressNumber4); - Assert.AreEqual((long)5, data.AddressNumber5); - Assert.AreEqual(6.36f, data.AddressNumber6); - Assert.AreEqual(7.49f, data.AddressNumber7); - Assert.AreEqual(8.64d, data.AddressNumber8); - Assert.AreEqual(9.81m, data.AddressNumber9); - Assert.AreEqual(10, data.AddressNumber10); - Assert.AreEqual("BuildingName1", data.BuildingName1); - Assert.AreEqual("BuildingName2", data.BuildingName2); - Assert.AreEqual("BuildingName3", data.BuildingName3); - Assert.AreEqual("BuildingName4", data.BuildingName4); - Assert.AreEqual("BuildingName5", data.BuildingName5); - Assert.AreEqual("BuildingName6".PadRight(120, '\0'), UTF8Encoding.UTF8.GetString(data.BuildingName6!)); - Assert.AreEqual("BuildingName7", UTF8Encoding.UTF8.GetString(data.BuildingName7!)); - Assert.AreEqual("BuildingName8", UTF8Encoding.UTF8.GetString(data.BuildingName8!)); - Assert.AreEqual("BuildingName9", UTF8Encoding.UTF8.GetString(data.BuildingName9!)); - Assert.AreEqual("BuildingName10", UTF8Encoding.UTF8.GetString(data.BuildingName10!)); - Assert.AreEqual("small", data.BuildingName11); - Assert.AreEqual("small,medium,large", data.BuildingName12); - Assert.AreEqual(now.Date, data.BuildingName13); - Assert.AreEqual(now, data.BuildingName14); - Assert.AreEqual(now.TimeOfDay, data.BuildingName15); - Assert.AreEqual(now, data.BuildingName16); - Assert.AreEqual(now.Year, data.BuildingName17); + Assert.That(data.AddressNumber1, Is.EqualTo(1)); + Assert.That(data.AddressNumber2, Is.EqualTo(2)); + Assert.That(data.AddressNumber3, Is.EqualTo(3)); + Assert.That(data.AddressNumber4, Is.EqualTo(4)); + Assert.That(data.AddressNumber5, Is.EqualTo((long)5)); + Assert.That(data.AddressNumber6, Is.EqualTo(6.36f)); + Assert.That(data.AddressNumber7, Is.EqualTo(7.49f)); + Assert.That(data.AddressNumber8, Is.EqualTo(8.64d)); + Assert.That(data.AddressNumber9, Is.EqualTo(9.81m)); + Assert.That(data.AddressNumber10, Is.EqualTo(10)); + Assert.That(data.BuildingName1, Is.EqualTo("BuildingName1")); + Assert.That(data.BuildingName2, Is.EqualTo("BuildingName2")); + Assert.That(data.BuildingName3, Is.EqualTo("BuildingName3")); + Assert.That(data.BuildingName4, Is.EqualTo("BuildingName4")); + Assert.That(data.BuildingName5, Is.EqualTo("BuildingName5")); + Assert.That(UTF8Encoding.UTF8.GetString(data.BuildingName6!), Is.EqualTo("BuildingName6".PadRight(120, '\0'))); + Assert.That(UTF8Encoding.UTF8.GetString(data.BuildingName7!), Is.EqualTo("BuildingName7")); + Assert.That(UTF8Encoding.UTF8.GetString(data.BuildingName8!), Is.EqualTo("BuildingName8")); + Assert.That(UTF8Encoding.UTF8.GetString(data.BuildingName9!), Is.EqualTo("BuildingName9")); + Assert.That(UTF8Encoding.UTF8.GetString(data.BuildingName10!), Is.EqualTo("BuildingName10")); + Assert.That(data.BuildingName11, Is.EqualTo("small")); + Assert.That(data.BuildingName12, Is.EqualTo("small,medium,large")); + Assert.That(data.BuildingName13, Is.EqualTo(now.Date)); + Assert.That(data.BuildingName14, Is.EqualTo(now)); + Assert.That(data.BuildingName15, Is.EqualTo(now.TimeOfDay)); + Assert.That(data.BuildingName16, Is.EqualTo(now)); + Assert.That(data.BuildingName17, Is.EqualTo(now.Year)); + } + } + + /// + /// Bug#36208913 Byte array type mapping has a fixed limit of 8000 in EFCore + /// + [Test] + public void LongBlobMapping() + { + using (var context = new AllBlobTypesContext()) + { + context.Database.EnsureDeleted(); + context.Database.EnsureCreated(); + + + var data1 = new byte[7000]; + var data2 = new byte[60000]; + var data3 = new byte[90000]; + + + context.AllBlobTypes.Add(new AllBlobTypes() + { + Id = 1, + Example1 = data1, + Example2 = data2, + Example3 = data3, + }); + context.SaveChanges(); + } + + using (var context = new AllBlobTypesContext()) + { + + var data1 = new byte[7000]; + var data2 = new byte[60000]; + var data3 = new byte[90000]; + + var data = context.AllBlobTypes.First(); + + Assert.That(data.Example1.Length, Is.EqualTo(data1.Length)); + Assert.That(data.Example2.Length, Is.EqualTo(data2.Length)); + Assert.That(data.Example3.Length, Is.EqualTo(data3.Length)); } } @@ -158,10 +200,10 @@ public void ValidateStringLength() { string field = reader.GetString("field"); string type = validation[field]; - Assert.AreEqual(type, reader.GetString("type")); + Assert.That(reader.GetString("type"), Is.EqualTo(type)); counter++; } - Assert.AreEqual(validation.Count, counter); + Assert.That(counter, Is.EqualTo(validation.Count)); } } } diff --git a/EFCore/tests/MySql.EFCore.Basic.Tests/MySql.EntityFrameworkCore.Basic.Tests.csproj b/EFCore/tests/MySql.EFCore.Basic.Tests/MySql.EntityFrameworkCore.Basic.Tests.csproj index 6fb99961f..f3c7b8036 100644 --- a/EFCore/tests/MySql.EFCore.Basic.Tests/MySql.EntityFrameworkCore.Basic.Tests.csproj +++ b/EFCore/tests/MySql.EFCore.Basic.Tests/MySql.EntityFrameworkCore.Basic.Tests.csproj @@ -2,7 +2,7 @@ MySql.EntityFrameworkCore.Basic.Tests Class Library - net6.0;net7.0;net8.0; + net9.0;net8.0; MySql.EntityFrameworkCore.Basic.Tests MySql.EntityFrameworkCore.Basic.Tests true @@ -13,22 +13,28 @@ CS1591,CS1701,CS1702,EF1001 - - + + $(TargetFrameworks);net10.0 + + + + - - + + - - + + - - - + + + + + diff --git a/EFCore/tests/MySql.EFCore.Basic.Tests/Properties/DatabaseSetup.sql b/EFCore/tests/MySql.EFCore.Basic.Tests/Properties/DatabaseSetup.sql index 8f78b919b..6a67848d2 100644 --- a/EFCore/tests/MySql.EFCore.Basic.Tests/Properties/DatabaseSetup.sql +++ b/EFCore/tests/MySql.EFCore.Basic.Tests/Properties/DatabaseSetup.sql @@ -1,17 +1,17 @@ /* -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -40,4 +40,4 @@ FLUSH PRIVILEGES; SET GLOBAL max_allowed_packet = 1048576; -FLUSH PRIVILEGES; \ No newline at end of file +FLUSH PRIVILEGES; diff --git a/EFCore/tests/MySql.EFCore.Basic.Tests/ShadowPropertiesTests.cs b/EFCore/tests/MySql.EFCore.Basic.Tests/ShadowPropertiesTests.cs index 979fe44b8..faf443047 100644 --- a/EFCore/tests/MySql.EFCore.Basic.Tests/ShadowPropertiesTests.cs +++ b/EFCore/tests/MySql.EFCore.Basic.Tests/ShadowPropertiesTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -32,6 +32,7 @@ using MySql.EntityFrameworkCore.Basic.Tests.DbContextClasses; using MySql.EntityFrameworkCore.Extensions; using NUnit.Framework; +using NUnit.Framework.Legacy; using System; using System.Data; using System.Linq; @@ -59,7 +60,7 @@ public ShadowPropertiesTests() [Test] public void CanUseShadowPropertyWhenUpdatingEntry() { - Assert.False(context.Database.EnsureCreated()); + Assert.That(!context.Database.EnsureCreated()); var ad = new Address { Street = "New street two", City = "Chicago" }; var g = new Guest { Name = "Guest number two", Address = ad }; context.Set().Add(g); @@ -67,7 +68,7 @@ public void CanUseShadowPropertyWhenUpdatingEntry() // update entry var entry = context.Set().Where(t => t.Name!.Equals("Guest number two")).First(); - Assert.False(entry == null); + Assert.That(entry, Is.Not.Null); entry!.Name = "Guest number two updated"; context.SaveChanges(); @@ -80,15 +81,15 @@ public void CanUseShadowPropertyWhenUpdatingEntry() var cmd = new MySqlCommand("Select UpdatedAt from Guests where IdGuest=" + entry.IdGuest, cnn); var updatedAt = cmd.ExecuteScalar(); - Assert.False(updatedAt == null); - Assert.True(((DateTime)updatedAt!).Date.CompareTo(DateTime.Now.Date) == 0); + Assert.That(updatedAt, Is.Not.Null); + Assert.That(((DateTime)updatedAt!).Date.CompareTo(DateTime.Now.Date) == 0); } } [Test] public void CanUseShadowPropertyWhenAddingEntry() { - Assert.False(context.Database.EnsureCreated()); + Assert.That(!context.Database.EnsureCreated()); var ad = new Address { Street = "New street", City = "Oregon" }; var g = new Guest { Name = "Guest number one", Address = ad }; context.Set().Add(g); @@ -103,8 +104,8 @@ public void CanUseShadowPropertyWhenAddingEntry() var cmd = new MySqlCommand("Select CreatedAt from Guests Limit 1", cnn); var createdAt = cmd.ExecuteScalar(); - Assert.False(createdAt == null); - Assert.True(((DateTime)createdAt!).Date.CompareTo(DateTime.Now.Date) == 0); + Assert.That(createdAt, Is.Not.Null); + Assert.That(((DateTime)createdAt!).Date.CompareTo(DateTime.Now.Date) == 0); } } diff --git a/EFCore/tests/MySql.EFCore.Basic.Tests/UpdateTests.cs b/EFCore/tests/MySql.EFCore.Basic.Tests/UpdateTests.cs new file mode 100644 index 000000000..0a95d864b --- /dev/null +++ b/EFCore/tests/MySql.EFCore.Basic.Tests/UpdateTests.cs @@ -0,0 +1,87 @@ +// Copyright © 2021, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using Microsoft.EntityFrameworkCore; +using MySql.EntityFrameworkCore.Basic.Tests.Utils; +using NUnit.Framework; +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace MySql.EntityFrameworkCore.Basic.Tests +{ + +#region Bug113443 + + [Table("Bug113443Table")] + public record Bug113443Record + { + [Key] + [Column("id")] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; init; } + [Column("name")] + public string? Name { get; set;} + + [Column("time_created", TypeName = "TIMESTAMP(6)")] + [DatabaseGenerated(DatabaseGeneratedOption.Computed)] + public DateTime TimeCreated { get; init; } + + [Column("time_updated", TypeName = "TIMESTAMP(6)")] + [DatabaseGenerated(DatabaseGeneratedOption.Computed)] + public DateTime TimeUpdated { get; init; } + } + + public class Bug113443Context : MyTestContext + { + public DbSet Bug113443 { get; set; } + } + +#endregion + + public class UpdateTests + { + [Test] + public void Bug113443() { + using var ctx = new Bug113443Context(); + ctx.Database.EnsureCreated(); + try + { + Bug113443Record data = new() { Name = "Sample1"}; + ctx.Bug113443.Add(data); + ctx.SaveChanges(); + data.Name = "Changed!"; + ctx.SaveChanges(); + } + finally + { + ctx.Database.EnsureDeleted(); + } + } + } +} diff --git a/EFCore/tests/MySql.EFCore.Basic.Tests/Utils/EntityTestsFixtureClass.cs b/EFCore/tests/MySql.EFCore.Basic.Tests/Utils/EntityTestsFixtureClass.cs index 5416d7114..2903470fa 100644 --- a/EFCore/tests/MySql.EFCore.Basic.Tests/Utils/EntityTestsFixtureClass.cs +++ b/EFCore/tests/MySql.EFCore.Basic.Tests/Utils/EntityTestsFixtureClass.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -30,6 +30,7 @@ using MySql.Data.MySqlClient; using MySql.EntityFrameworkCore.Basic.Tests.DbContextClasses; using NUnit.Framework; +using NUnit.Framework.Legacy; using System; using System.Diagnostics; using System.Text; @@ -92,7 +93,7 @@ protected internal void CheckSql(string sql, string refSql) foreach (char c in refSql) if (!Char.IsWhiteSpace(c)) str2.Append(c); - Assert.AreEqual(0, String.Compare(str1.ToString(), str2.ToString(), true)); + Assert.That(String.Compare(str1.ToString(), str2.ToString(), true), Is.EqualTo(0)); } diff --git a/EFCore/tests/MySql.EFCore.Basic.Tests/Utils/MySqlTestStore.cs b/EFCore/tests/MySql.EFCore.Basic.Tests/Utils/MySqlTestStore.cs index 7470d9c30..59b4bf5a7 100644 --- a/EFCore/tests/MySql.EFCore.Basic.Tests/Utils/MySqlTestStore.cs +++ b/EFCore/tests/MySql.EFCore.Basic.Tests/Utils/MySqlTestStore.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -34,6 +34,7 @@ using MySql.EntityFrameworkCore.Infrastructure.Internal; using System; using System.Data; +using System.Data.Common; namespace MySql.EntityFrameworkCore.Basic.Tests.Utils { @@ -88,6 +89,11 @@ internal static string GetContextConnectionString(Type type) return MySQLTestStore.RootConnectionString + $";database={name};"; } + internal static string GetContextConnectionStringWithName(string name) + { + return MySQLTestStore.RootConnectionString + $";database={name};"; + } + public static string Port() { var port = Environment.GetEnvironmentVariable("MYSQL_PORT"); @@ -225,21 +231,42 @@ public static void DeleteDatabase(string name) public override DbContextOptionsBuilder AddProviderOptions(DbContextOptionsBuilder builder) => builder.UseMySQL(GetContextConnectionString()); +#if NET9_0_OR_GREATER + public virtual void Clean(DbContext context) + => context.Database.EnsureDeleted(); +#else public override void Clean(DbContext context) => context.Database.EnsureDeleted(); +#endif - public static MySQLTestStore Create(string name) - => new MySQLTestStore(name); - public static MySQLTestStore GetOrCreate(string name) - => new MySQLTestStore(name); +#if NET9_0_OR_GREATER + private MySQLTestStore(string name, DbConnection connection) + : base(name, true, connection) + { + SslMode = true; + connection = new MySqlConnection(RootConnectionString); + } + public static MySQLTestStore Create(string name, DbConnection connection) + => new MySQLTestStore(name, connection); + + public static MySQLTestStore GetOrCreate(string name, DbConnection connection) + => new MySQLTestStore(name, connection); +#else private MySQLTestStore(string name) : base(name, true) { SslMode = true; Connection = new MySqlConnection(RootConnectionString); } + + public static MySQLTestStore Create(string name) + => new MySQLTestStore(name); + + public static MySQLTestStore GetOrCreate(string name) + => new MySQLTestStore(name); +#endif } public class MySQLTestStoreFactory : RelationalTestStoreFactory @@ -250,13 +277,25 @@ protected MySQLTestStoreFactory() { } +#if NET9_0_OR_GREATER + public override TestStore Create(string storeName) + => MySQLTestStore.Create(storeName, new MySqlConnection(MySQLTestStore.RootConnectionString)); + + public override TestStore GetOrCreate(string storeName) + => MySQLTestStore.GetOrCreate(storeName, new MySqlConnection(MySQLTestStore.RootConnectionString)); +#else public override TestStore Create(string storeName) => MySQLTestStore.Create(storeName); public override TestStore GetOrCreate(string storeName) => MySQLTestStore.GetOrCreate(storeName); +#endif + + + public override IServiceCollection AddProviderServices(IServiceCollection serviceCollection) => serviceCollection.AddEntityFrameworkMySQL(); + } } diff --git a/EFCore/tests/MySql.EFCore.Basic.Tests/Utils/TestUtils.cs b/EFCore/tests/MySql.EFCore.Basic.Tests/Utils/TestUtils.cs index 5c3b56c3e..7b9b59314 100644 --- a/EFCore/tests/MySql.EFCore.Basic.Tests/Utils/TestUtils.cs +++ b/EFCore/tests/MySql.EFCore.Basic.Tests/Utils/TestUtils.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/tests/MySql.EFCore.Design.Tests/Extensions.cs b/EFCore/tests/MySql.EFCore.Design.Tests/Extensions.cs index 0ed03a4ff..1543ee7ab 100644 --- a/EFCore/tests/MySql.EFCore.Design.Tests/Extensions.cs +++ b/EFCore/tests/MySql.EFCore.Design.Tests/Extensions.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/tests/MySql.EFCore.Design.Tests/MySQLAnnotationCodeGeneratorTest.cs b/EFCore/tests/MySql.EFCore.Design.Tests/MySQLAnnotationCodeGeneratorTest.cs index 820f6d806..7f0ed3e2a 100644 --- a/EFCore/tests/MySql.EFCore.Design.Tests/MySQLAnnotationCodeGeneratorTest.cs +++ b/EFCore/tests/MySql.EFCore.Design.Tests/MySQLAnnotationCodeGeneratorTest.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -36,6 +36,7 @@ using MySql.EntityFrameworkCore.Metadata.Internal; using MySql.EntityFrameworkCore.Storage.Internal; using NUnit.Framework; +using NUnit.Framework.Legacy; using System.Linq; namespace MySql.EntityFrameworkCore.Design.Tests @@ -64,8 +65,8 @@ public void GenerateFluentApiHasCharset(string mySQLAnnotation) var annotation = key?.FindAnnotation(mySQLAnnotation); var result = MySQLAnnotationCodeGenerator.GenFluentApi((Microsoft.EntityFrameworkCore.Metadata.IProperty)key!, annotation!); - Assert.AreEqual(mySQLAnnotation == MySQLAnnotationNames.Charset ? "ForMySQLHasCharset" : "ForMySQLHasCollation", result?.Method); - Assert.AreEqual(1, result?.Arguments.Count); + Assert.That(result?.Method, Is.EqualTo(mySQLAnnotation == MySQLAnnotationNames.Charset ? "ForMySQLHasCharset" : "ForMySQLHasCollation")); + Assert.That(result?.Arguments.Count, Is.EqualTo(1)); } } } diff --git a/EFCore/tests/MySql.EFCore.Design.Tests/MySQLCodeGeneratorTest.cs b/EFCore/tests/MySql.EFCore.Design.Tests/MySQLCodeGeneratorTest.cs index a91b2200c..42f3804c9 100644 --- a/EFCore/tests/MySql.EFCore.Design.Tests/MySQLCodeGeneratorTest.cs +++ b/EFCore/tests/MySql.EFCore.Design.Tests/MySQLCodeGeneratorTest.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -32,6 +32,7 @@ using MySql.EntityFrameworkCore.Infrastructure; using MySql.EntityFrameworkCore.Scaffolding.Internal; using NUnit.Framework; +using NUnit.Framework.Legacy; using System; using System.Linq; using System.Reflection; @@ -49,9 +50,9 @@ public virtual void UseProviderMethodIsGeneratedCorrectly() var result = codeGenerator.GenerateUseProvider("Data Source=Test", providerOptions: null); - Assert.AreEqual("UseMySQL", result.Method); + Assert.That(result.Method, Is.EqualTo("UseMySQL")); Assert.That(result.Arguments, Has.Exactly(1).EqualTo("Data Source=Test")); - Assert.Null(result.ChainedCall); + Assert.That(result.ChainedCall, Is.Null); } [Test] @@ -65,13 +66,13 @@ public virtual void UseProviderMethodIsGeneratedCorrectlyWithOptions() var result = codeGenerator.GenerateUseProvider("Data Source=Test", providerOptions); - Assert.AreEqual("UseMySQL", result.Method); + Assert.That(result.Method, Is.EqualTo("UseMySQL")); Assert.That(result.Arguments, Has.Exactly(1).EqualTo("Data Source=Test")); - Assert.IsInstanceOf(result.Arguments[1]); + Assert.That(result.Arguments[1], Is.InstanceOf()); NestedClosureCodeFragment nestedClosure = (NestedClosureCodeFragment)result.Arguments[1]!; - Assert.AreEqual("x", nestedClosure?.Parameter); - Assert.AreSame(providerOptions, nestedClosure?.MethodCalls[0]); - Assert.Null(result.ChainedCall); + Assert.That(nestedClosure?.Parameter, Is.EqualTo("x")); + Assert.That(nestedClosure?.MethodCalls[0], Is.SameAs(providerOptions)); + Assert.That(result.ChainedCall, Is.Null); } private static readonly MethodInfo UseMySqlServerMethodInfo diff --git a/EFCore/tests/MySql.EFCore.Design.Tests/MySQLDatabaseModelFactoryTest.cs b/EFCore/tests/MySql.EFCore.Design.Tests/MySQLDatabaseModelFactoryTest.cs index a63741fa9..beb0ab423 100644 --- a/EFCore/tests/MySql.EFCore.Design.Tests/MySQLDatabaseModelFactoryTest.cs +++ b/EFCore/tests/MySql.EFCore.Design.Tests/MySQLDatabaseModelFactoryTest.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -35,6 +35,7 @@ using MySql.EntityFrameworkCore.Diagnostics.Internal; using MySql.EntityFrameworkCore.Scaffolding.Internal; using NUnit.Framework; +using NUnit.Framework.Legacy; using System; using System.Collections.Generic; using System.Diagnostics; @@ -101,7 +102,7 @@ PRIMARY KEY (description, id) Assert.Multiple(() => { - Assert.AreEqual("blogman", dbModel.DatabaseName); + Assert.That(dbModel.DatabaseName, Is.EqualTo("blogman")); Assert.That(dbModel.Tables.Select(c => c.Name), Has.Exactly(1).Matches(table => table.Contains("blogs"))); }); @@ -110,27 +111,27 @@ PRIMARY KEY (description, id) Assert.That(columns.Where(n => n.Name == "id").Select(a => a.Name), Has.Exactly(1).Matches(name => name.Contains("id"))); Assert.That(columns.Where(n => n.Name == "id").Select(a => a.GetDataType()), Has.One.Items.EqualTo("int" + smallintWidth)); Assert.That(columns.Where(n => n.Name == "id").Select(a => a.GetPrimaryKeyOrdinal(2)), Has.One.Items.EqualTo(2)); - Assert.False(columns.Where(n => n.Name == "id").Select(a => a.IsNullable).FirstOrDefault()); + Assert.That(!columns.Where(n => n.Name == "id").Select(a => a.IsNullable).FirstOrDefault()); Assert.That(columns.Where(n => n.Name == "id").Select(a => a.GetOrdinal(0)), Has.One.Items.EqualTo(0)); - Assert.IsNull(columns.Where(n => n.Name == "id").Select(a => a.GetDefaultValue()).FirstOrDefault()); + Assert.That(columns.Where(n => n.Name == "id").Select(a => a.GetDefaultValue()).FirstOrDefault(), Is.Null); Assert.That(columns.Where(n => n.Name == "description").Select(a => a.Name), Has.Exactly(1).Matches(name => name.Contains("description"))); Assert.That(columns.Where(n => n.Name == "description").Select(a => a.GetDataType()), Has.One.Items.EqualTo("varchar(100)")); Assert.That(columns.Where(n => n.Name == "description").Select(a => a.GetPrimaryKeyOrdinal(1)), Has.One.Items.EqualTo(1)); - Assert.False(columns.Where(n => n.Name == "description").Select(a => a.IsNullable).FirstOrDefault()); + Assert.That(!columns.Where(n => n.Name == "description").Select(a => a.IsNullable).FirstOrDefault()); Assert.That(columns.Where(n => n.Name == "description").Select(a => a.GetOrdinal(1)), Has.One.Items.EqualTo(1)); - Assert.IsNull(columns.Where(n => n.Name == "description").Select(a => a.GetDefaultValue()).FirstOrDefault()); + Assert.That(columns.Where(n => n.Name == "description").Select(a => a.GetDefaultValue()).FirstOrDefault(), Is.Null); Assert.That(columns.Where(n => n.Name == "description").Select(a => a.GetMaxLength(100)), Has.One.Items.EqualTo(100)); Assert.That(columns.Where(n => n.Name == "rate").Select(a => a.Name), Has.Exactly(1).Matches(name => name.Contains("rate"))); Assert.That(columns.Where(n => n.Name == "rate").Select(a => a.GetDataType()), Has.One.Items.EqualTo("decimal(5,2)")); - Assert.IsNull(columns.Where(n => n.Name == "rate").Select(a => a.GetPrimaryKeyOrdinal(null)).FirstOrDefault()); - Assert.True(columns.Where(n => n.Name == "rate").Select(a => a.IsNullable).FirstOrDefault()); + Assert.That(columns.Where(n => n.Name == "rate").Select(a => a.GetPrimaryKeyOrdinal(null)).FirstOrDefault(), Is.Null); + Assert.That(columns.Where(n => n.Name == "rate").Select(a => a.IsNullable).FirstOrDefault()); Assert.That(columns.Where(n => n.Name == "rate").Select(a => a.GetOrdinal(2)), Has.One.Items.EqualTo(2)); - StringAssert.AreEqualIgnoringCase(columns.Where(n => n.Name == "rate").Select(a => a.GetDefaultValue()).FirstOrDefault(), "'0.00'"); + Assert.That("'0.00'", Is.EqualTo(columns.Where(n => n.Name == "rate").Select(a => a.GetDefaultValue()).FirstOrDefault()).IgnoreCase); Assert.That(columns.Where(n => n.Name == "rate").Select(a => a.GetPrecision(5)), Has.One.Items.EqualTo(5)); Assert.That(columns.Where(n => n.Name == "rate").Select(a => a.GetScale(2)), Has.One.Items.EqualTo(2)); - Assert.IsNull(columns.Where(n => n.Name == "rate").Select(a => a.GetMaxLength(null)).FirstOrDefault()); + Assert.That(columns.Where(n => n.Name == "rate").Select(a => a.GetMaxLength(null)).FirstOrDefault(), Is.Null); Assert.That(columns.Where(n => n.Name == "created").Select(a => a.Name), Has.Exactly(1).Matches(name => name.Contains("created"))); Assert.That(columns.Where(n => n.Name == "created").Select(a => a.GetDefaultValue()), Has.One.Items.EqualTo("CURRENT_TIMESTAMP")); @@ -162,14 +163,14 @@ KEY idx_fk_country_id (country_id), var dbModel = _fixture!.CreateModel("sakiladb", sql, new List { "city", "country" }, new List()); var fk = (dbModel.Tables.Single(t => t.ForeignKeys.Count > 0).ForeignKeys); - Assert.IsNotNull(fk); - Assert.AreEqual("sakiladb", fk[0].Table.Database!.DatabaseName); - Assert.AreEqual("city", fk[0].Table.Name); - Assert.AreEqual("sakiladb", fk[0].PrincipalTable.Database!.DatabaseName); - Assert.AreEqual("country", fk[0].PrincipalTable.Name); - Assert.AreEqual("country_id", fk[0].GetColumn().Name); - Assert.AreEqual("country_id", fk[0].GetPrincipalColumn().Name); - Assert.AreEqual(ReferentialAction.Restrict, fk[0].OnDelete); + Assert.That(fk, Is.Not.Null); + Assert.That(fk[0].Table.Database!.DatabaseName, Is.EqualTo("sakiladb")); + Assert.That(fk[0].Table.Name, Is.EqualTo("city")); + Assert.That(fk[0].PrincipalTable.Database!.DatabaseName, Is.EqualTo("sakiladb")); + Assert.That(fk[0].PrincipalTable.Name, Is.EqualTo("country")); + Assert.That(fk[0].GetColumn().Name, Is.EqualTo("country_id")); + Assert.That(fk[0].GetPrincipalColumn().Name, Is.EqualTo("country_id")); + Assert.That(fk[0].OnDelete, Is.EqualTo(ReferentialAction.Restrict)); } [Test] @@ -194,23 +195,23 @@ PRIMARY KEY(actor_id), Assert.Multiple(() => { var c = indexes[0]; - Assert.AreEqual("sakilaIndex", c.Table!.Database!.DatabaseName); - Assert.AreEqual("actor", c.Table.Name); + Assert.That(c.Table!.Database!.DatabaseName, Is.EqualTo("sakilaIndex")); + Assert.That(c.Table.Name, Is.EqualTo("actor")); }); Assert.Multiple(() => { var composite = indexes[0]; - Assert.AreEqual("idx_actor_first_last_name", composite.Name); - Assert.False(composite.IsUnique); - Assert.AreEqual(new List { "first_name", "last_name" }, composite.GetColumns().Select(c => c.GetColumn().Name).ToList()); + Assert.That(composite.Name, Is.EqualTo("idx_actor_first_last_name")); + Assert.That(!composite.IsUnique); + Assert.That(composite.GetColumns().Select(c => c.GetColumn().Name).ToList(), Is.EqualTo(new List { "first_name", "last_name" })); }); Assert.Multiple(() => { var onecolumn = indexes[1]; - Assert.AreEqual("last_name", onecolumn.GetColumn().Name); - Assert.True(onecolumn.IsUnique); + Assert.That(onecolumn.GetColumn().Name, Is.EqualTo("last_name")); + Assert.That(onecolumn.IsUnique); } ); } @@ -249,7 +250,7 @@ private void Test(string createSql, IEnumerable tables, IEnumerable tables, IEnumerable { "t1", "x1" }; var dbModel = _fixture!.CreateModel("testview", sql, selectionSet, new List()); - Assert.True(dbModel.Tables.Count == 2); + Assert.That(dbModel.Tables.Count == 2); } } -} \ No newline at end of file +} diff --git a/EFCore/tests/MySql.EFCore.Design.Tests/MySQLDatabaseModelFixture.cs b/EFCore/tests/MySql.EFCore.Design.Tests/MySQLDatabaseModelFixture.cs index 4cbb4bcda..fc586e967 100644 --- a/EFCore/tests/MySql.EFCore.Design.Tests/MySQLDatabaseModelFixture.cs +++ b/EFCore/tests/MySql.EFCore.Design.Tests/MySQLDatabaseModelFixture.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -75,4 +75,4 @@ public DatabaseModel CreateModel(string dbName, string sql, IEnumerable new DatabaseModelFactoryOptions(tables, schemas)); } } -} \ No newline at end of file +} diff --git a/EFCore/tests/MySql.EFCore.Design.Tests/MySQLDesignTimeProviderServicesTest.cs b/EFCore/tests/MySql.EFCore.Design.Tests/MySQLDesignTimeProviderServicesTest.cs index beb719f0d..8c30712d7 100644 --- a/EFCore/tests/MySql.EFCore.Design.Tests/MySQLDesignTimeProviderServicesTest.cs +++ b/EFCore/tests/MySql.EFCore.Design.Tests/MySQLDesignTimeProviderServicesTest.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -30,6 +30,7 @@ using MySql.EntityFrameworkCore.Design.Internal; using MySql.EntityFrameworkCore.Storage.Internal; using NUnit.Framework; +using NUnit.Framework.Legacy; using System; using System.Reflection; @@ -50,9 +51,9 @@ public void EnsureAssemblyIdentityMatches() var dtAttribute = runtimeAssembly.GetCustomAttribute(); var dtType = GetDesignTimeServicesType(); - Assert.NotNull(dtType); - Assert.NotNull(dtAttribute); - Assert.AreEqual(dtType.FullName, dtAttribute?.TypeName); + Assert.That(dtType, Is.Not.Null); + Assert.That(dtAttribute, Is.Not.Null); + Assert.That(dtAttribute?.TypeName, Is.EqualTo(dtType.FullName)); } } -} \ No newline at end of file +} diff --git a/EFCore/tests/MySql.EFCore.Design.Tests/MySql.EntityFrameworkCore.Design.Tests.csproj b/EFCore/tests/MySql.EFCore.Design.Tests/MySql.EntityFrameworkCore.Design.Tests.csproj index 7ce9788d5..632c8baa4 100644 --- a/EFCore/tests/MySql.EFCore.Design.Tests/MySql.EntityFrameworkCore.Design.Tests.csproj +++ b/EFCore/tests/MySql.EFCore.Design.Tests/MySql.EntityFrameworkCore.Design.Tests.csproj @@ -2,7 +2,7 @@ MySql.EntityFrameworkCore.Design.Tests Class Library - net6.0;net7.0;net8.0; + net9.0;net8.0; MySql.EntityFrameworkCore.Design.Tests MySql.EntityFrameworkCore.Design.Tests true @@ -13,6 +13,10 @@ $(NoWarn);CS1591,EF1001 + + $(TargetFrameworks);net10.0 + + @@ -24,10 +28,21 @@ - - - - + + + + + + + + + + + + + + + diff --git a/EFCore/tests/MySql.EFCore.Design.Tests/Properties/sakiladb-schema.sql b/EFCore/tests/MySql.EFCore.Design.Tests/Properties/sakiladb-schema.sql index 72c4e3812..33a025602 100644 --- a/EFCore/tests/MySql.EFCore.Design.Tests/Properties/sakiladb-schema.sql +++ b/EFCore/tests/MySql.EFCore.Design.Tests/Properties/sakiladb-schema.sql @@ -1,17 +1,17 @@ /* -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/tests/MySql.EFCore.Design.Tests/Properties/world.sql b/EFCore/tests/MySql.EFCore.Design.Tests/Properties/world.sql index 6d2e171ec..9374e9c57 100644 --- a/EFCore/tests/MySql.EFCore.Design.Tests/Properties/world.sql +++ b/EFCore/tests/MySql.EFCore.Design.Tests/Properties/world.sql @@ -1,17 +1,17 @@ /* -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EFCore/tests/MySql.EFCore.Migrations.Tests/MySQLHistoryRepositoryTests.cs b/EFCore/tests/MySql.EFCore.Migrations.Tests/MySQLHistoryRepositoryTests.cs index 148c3da26..6421977d3 100644 --- a/EFCore/tests/MySql.EFCore.Migrations.Tests/MySQLHistoryRepositoryTests.cs +++ b/EFCore/tests/MySql.EFCore.Migrations.Tests/MySQLHistoryRepositoryTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -34,6 +34,7 @@ using MySql.EntityFrameworkCore.Basic.Tests.Utils; using MySql.EntityFrameworkCore.Extensions; using NUnit.Framework; +using NUnit.Framework.Legacy; namespace MySql.EntityFrameworkCore.Migrations.Tests { @@ -80,9 +81,8 @@ public void CanCreateDatabase() var creator = context.GetService(); var cmdBuilder = context.GetService(); - Assert.False(creator.Exists()); - Assert.AreEqual("IF EXISTS(SELECT * FROM `__EFMigrationsHistory` WHERE `MigrationId` = 'MigrationId')\nBEGIN", - cmdBuilder.Build(repository.GetBeginIfExistsScript("MigrationId")).CommandText.Replace("\r", string.Empty)); + Assert.That(!creator.Exists()); + Assert.That(cmdBuilder.Build(repository.GetBeginIfExistsScript("MigrationId")).CommandText.Replace("\r", string.Empty), Is.EqualTo("IF EXISTS(SELECT * FROM `__EFMigrationsHistory` WHERE `MigrationId` = 'MigrationId')\nBEGIN")); } } } diff --git a/EFCore/tests/MySql.EFCore.Migrations.Tests/MySQLMigrationsTests.cs b/EFCore/tests/MySql.EFCore.Migrations.Tests/MySQLMigrationsTests.cs index c4ef3aec4..c19d102ca 100644 --- a/EFCore/tests/MySql.EFCore.Migrations.Tests/MySQLMigrationsTests.cs +++ b/EFCore/tests/MySql.EFCore.Migrations.Tests/MySQLMigrationsTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -31,7 +31,9 @@ using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.Extensions.DependencyInjection; using MySql.EntityFrameworkCore.Basic.Tests.Utils; +using MySql.EntityFrameworkCore.Migrations.Tests.TestData; using NUnit.Framework; +using System.Threading.Tasks; namespace MySql.EntityFrameworkCore.Migrations.Tests { @@ -51,5 +53,35 @@ public void Can_generate_migration_from_initial_database_to_initial() migrator.GenerateScript(fromMigration: Migration.InitialDatabase, toMigration: Migration.InitialDatabase); } } + + //Bug #37513445 Cannot Perform Database Migration using MySql.EntityFrameworkCore 9.0.0 + [Test] + public void TryPerformMigration() + { + var optionsBuilder = new DbContextOptionsBuilder(); + optionsBuilder.UseMySQL(MySQLTestStore.RootConnectionString + "database=test;"); + + using (var mytestContext = new MyTestContext(optionsBuilder.Options)) + { + mytestContext.Database.EnsureCreated(); + mytestContext.Database.EnsureDeleted(); + mytestContext.Database.Migrate(); + + Assert.That(mytestContext.Database.CanConnect(), Is.True); + mytestContext.Database.EnsureDeleted(); + } + } + + //Bug#37462099 MySql.EntityFrameworkCore 8.0.8 rename bug + [Test] + public async Task MigrationFailsWIthRenameColumn() + { + Bug37462099Context context = new Bug37462099Context(); + + context.Database.EnsureCreated(); + context.Database.EnsureDeleted(); + await context.Database.MigrateAsync(); + context.Database.EnsureDeleted(); + } } } diff --git a/EFCore/tests/MySql.EFCore.Migrations.Tests/MySql.EntityFrameworkCore.Migrations.Tests.csproj b/EFCore/tests/MySql.EFCore.Migrations.Tests/MySql.EntityFrameworkCore.Migrations.Tests.csproj index 820f237f9..dca0d5bed 100644 --- a/EFCore/tests/MySql.EFCore.Migrations.Tests/MySql.EntityFrameworkCore.Migrations.Tests.csproj +++ b/EFCore/tests/MySql.EFCore.Migrations.Tests/MySql.EntityFrameworkCore.Migrations.Tests.csproj @@ -2,7 +2,7 @@ MySql.EntityFrameworkCore.Migrations.Tests Class Library - net6.0;net7.0;net8.0; + net9.0;net8.0; MySql.EntityFrameworkCore.Migrations.Tests MySql.EntityFrameworkCore.Migrations.Tests true @@ -13,10 +13,14 @@ $(NoWarn);CS1591,EF1001 + + $(TargetFrameworks);net10.0 + + - - - + + + diff --git a/EFCore/tests/MySql.EFCore.Migrations.Tests/MySqlMigrationsGeneratorTest.cs b/EFCore/tests/MySql.EFCore.Migrations.Tests/MySqlMigrationsGeneratorTest.cs index 15d247903..53b36fcaa 100644 --- a/EFCore/tests/MySql.EFCore.Migrations.Tests/MySqlMigrationsGeneratorTest.cs +++ b/EFCore/tests/MySql.EFCore.Migrations.Tests/MySqlMigrationsGeneratorTest.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -33,6 +33,7 @@ using MySql.EntityFrameworkCore.Basic.Tests.Utils; using MySql.EntityFrameworkCore.Extensions; using NUnit.Framework; +using NUnit.Framework.Legacy; namespace MySql.EntityFrameworkCore.Migrations.Tests { @@ -71,7 +72,7 @@ public override void CreateTableOperation() ");" + EOL; string fullResult = result.Replace(" NULL,", ","); - Assert.True(result == Sql || fullResult == Sql); + Assert.That(result == Sql || fullResult == Sql); } [Test] @@ -80,28 +81,28 @@ public override void AddColumnOperation_with_maxLength() base.AddColumnOperation_with_maxLength(); string result = "ALTER TABLE `Person` ADD `Name` varchar(30);" + EOL; string fullResult = "ALTER TABLE `Person` ADD `Name` varchar(30) NULL;" + EOL; - Assert.True(result == Sql || fullResult == Sql); + Assert.That(result == Sql || fullResult == Sql); } [Test] public override void AddColumnOperationWithComputedValueSql() { base.AddColumnOperationWithComputedValueSql(); - Assert.AreEqual("ALTER TABLE `People` ADD `DisplayName` varchar(50) AS (CONCAT_WS(' ', LastName , FirstName));" + EOL, Sql); + Assert.That(Sql, Is.EqualTo("ALTER TABLE `People` ADD `DisplayName` varchar(50) AS (CONCAT_WS(' ', LastName , FirstName));" + EOL)); } [Test] public override void AddColumnOperationWithDefaultValueSql() { base.AddColumnOperationWithDefaultValueSql(); - Assert.AreEqual("ALTER TABLE `People` ADD `Timestamp` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP;" + EOL, Sql); + Assert.That(Sql, Is.EqualTo("ALTER TABLE `People` ADD `Timestamp` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP;" + EOL)); } [Test] public override void AlterColumnOperation() { base.AlterColumnOperation(); - Assert.AreEqual("ALTER TABLE `Person` MODIFY `Age` int NOT NULL DEFAULT 7;" + EOL, Sql); + Assert.That(Sql, Is.EqualTo("ALTER TABLE `Person` MODIFY `Age` int NOT NULL DEFAULT 7;" + EOL)); } @@ -109,21 +110,21 @@ public override void AlterColumnOperation() public override void AlterColumnOperationWithoutType() { base.AlterColumnOperationWithoutType(); - Assert.AreEqual("ALTER TABLE `Person` MODIFY `Age` int NOT NULL;" + EOL, Sql); + Assert.That(Sql, Is.EqualTo("ALTER TABLE `Person` MODIFY `Age` int NOT NULL;" + EOL)); } [Test] public override void RenameTableOperationInSchema() { base.RenameTableOperationInSchema(); - Assert.AreEqual("ALTER TABLE t1 RENAME t2;" + EOL, Sql); + Assert.That(Sql, Is.EqualTo("ALTER TABLE t1 RENAME t2;" + EOL)); } [Test] public override void CreateUniqueIndexOperation() { base.CreateUniqueIndexOperation(); - Assert.AreEqual("CREATE UNIQUE INDEX `IXPersonName` ON `Person` (`FirstName`, `LastName`);" + EOL, Sql); + Assert.That(Sql, Is.EqualTo("CREATE UNIQUE INDEX `IXPersonName` ON `Person` (`FirstName`, `LastName`);" + EOL)); } [Test] @@ -131,7 +132,7 @@ public override void CreateNonUniqueIndexOperation() { base.CreateNonUniqueIndexOperation(); - Assert.AreEqual("CREATE INDEX `IXPersonName` ON `Person` (`Name`);" + EOL, Sql); + Assert.That(Sql, Is.EqualTo("CREATE INDEX `IXPersonName` ON `Person` (`Name`);" + EOL)); } [Test] @@ -139,28 +140,28 @@ public override void CreateNonUniqueIndexOperation() public override void RenameIndexOperation() { base.RenameIndexOperation(); - Assert.AreEqual("DROP INDEX IXPersonName ON Person; CREATE INDEX IXNombre;" + EOL, Sql); + Assert.That(Sql, Is.EqualTo("DROP INDEX IXPersonName ON Person; CREATE INDEX IXNombre;" + EOL)); } [Test] public override void DropIndexOperation() { base.DropIndexOperation(); - Assert.AreEqual("DROP INDEX IXPersonName ON Person;" + EOL, Sql); + Assert.That(Sql, Is.EqualTo("DROP INDEX IXPersonName ON Person;" + EOL)); } [Test] public override void DropPrimaryKeyOperation() { base.DropPrimaryKeyOperation(); - Assert.AreEqual(string.Empty, Sql); + Assert.That(Sql, Is.EqualTo(string.Empty)); } [Test] public override void AddPrimaryKeyOperation() { base.AddPrimaryKeyOperation(); - Assert.AreEqual(string.Empty, Sql); + Assert.That(Sql, Is.EqualTo(string.Empty)); } } } diff --git a/EFCore/tests/MySql.EFCore.Migrations.Tests/MySqlMigrationsGeneratorTestBase.cs b/EFCore/tests/MySql.EFCore.Migrations.Tests/MySqlMigrationsGeneratorTestBase.cs index b67616ac8..402723c3e 100644 --- a/EFCore/tests/MySql.EFCore.Migrations.Tests/MySqlMigrationsGeneratorTestBase.cs +++ b/EFCore/tests/MySql.EFCore.Migrations.Tests/MySqlMigrationsGeneratorTestBase.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -33,6 +33,7 @@ using MySql.EntityFrameworkCore.Metadata.Internal; using MySql.EntityFrameworkCore.Migrations.Tests.Utilities; using NUnit.Framework; +using NUnit.Framework.Legacy; using System; using System.Linq; diff --git a/EFCore/tests/MySql.EFCore.Migrations.Tests/TestData/Bug37462099Context.cs b/EFCore/tests/MySql.EFCore.Migrations.Tests/TestData/Bug37462099Context.cs new file mode 100644 index 000000000..f01d4eb3a --- /dev/null +++ b/EFCore/tests/MySql.EFCore.Migrations.Tests/TestData/Bug37462099Context.cs @@ -0,0 +1,74 @@ +// Copyright © 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using Microsoft.EntityFrameworkCore; +using System; +using System.ComponentModel.DataAnnotations; +using MySql.EntityFrameworkCore.Basic.Tests.Utils; + +namespace MySql.EntityFrameworkCore.Migrations.Tests.TestData +{ + public class Bug37462099Context : DbContext + { + public DbSet Entity { get; set; } + + public Bug37462099Context() : base() + { + } + + public Bug37462099Context(DbContextOptions options) : base(options) + { + } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity(builder => + { + builder.ToTable("Bug37462099"); + + builder.HasKey(p => p.Id); + + builder.Property(p => p.Name); + + builder.Property(p => p.Created); + }); + } + + protected override void OnConfiguring(DbContextOptionsBuilder options) + => options.UseMySQL(MySQLTestStore.RootConnectionString + "database=test;"); + } + + public class Bug37462099 + { + [Key] + public int Id { get; set; } + public string? Name { get; set; } + public DateTimeOffset Created { get; set; } + + } +} diff --git a/EFCore/tests/MySql.EFCore.Migrations.Tests/TestData/Bug37462099ContextModelSnapshot.cs b/EFCore/tests/MySql.EFCore.Migrations.Tests/TestData/Bug37462099ContextModelSnapshot.cs new file mode 100644 index 000000000..41a49b529 --- /dev/null +++ b/EFCore/tests/MySql.EFCore.Migrations.Tests/TestData/Bug37462099ContextModelSnapshot.cs @@ -0,0 +1,68 @@ +// Copyright © 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace MySql.EntityFrameworkCore.Migrations.Tests.TestData +{ + [DbContext(typeof(Bug37462099Context))] + partial class Bug37462099ContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.3") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + modelBuilder.Entity("MySql.EntityFrameworkCore.Migrations.Tests.TestData.Bug37462099", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Created") + .HasColumnType("datetime"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("Bug37462099", (string)null); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/EFCore/tests/MySql.EFCore.Migrations.Tests/TestData/Bug37462099Migrations.Designer.cs b/EFCore/tests/MySql.EFCore.Migrations.Tests/TestData/Bug37462099Migrations.Designer.cs new file mode 100644 index 000000000..898193d40 --- /dev/null +++ b/EFCore/tests/MySql.EFCore.Migrations.Tests/TestData/Bug37462099Migrations.Designer.cs @@ -0,0 +1,71 @@ +// Copyright © 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace MySql.EntityFrameworkCore.Migrations.Tests.TestData +{ + [DbContext(typeof(Bug37462099Context))] + [Migration("Bug37462099Migrations")] + partial class Bug37462099Migrations + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.3") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + modelBuilder.Entity("MySql.EntityFrameworkCore.Migrations.Tests.TestData.Bug37462099", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Created") + .HasColumnType("datetime"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("Bug37462099", (string)null); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/EFCore/tests/MySql.EFCore.Migrations.Tests/TestData/Bug37462099Migrations.cs b/EFCore/tests/MySql.EFCore.Migrations.Tests/TestData/Bug37462099Migrations.cs new file mode 100644 index 000000000..9e85e86ac --- /dev/null +++ b/EFCore/tests/MySql.EFCore.Migrations.Tests/TestData/Bug37462099Migrations.cs @@ -0,0 +1,78 @@ +// Copyright © 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using System; +using Microsoft.EntityFrameworkCore.Migrations; +using MySql.EntityFrameworkCore.Metadata; + +#nullable disable + +namespace MySql.EntityFrameworkCore.Migrations.Tests.TestData +{ + /// + public partial class Bug37462099Migrations : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterDatabase() + .Annotation("MySQL:Charset", "utf8mb4"); + + migrationBuilder.CreateTable( + name: "Bug37462099", + columns: table => new + { + Id = table.Column(type: "int", nullable: false).Annotation("MySQL:ValueGenerationStrategy", MySQLValueGenerationStrategy.IdentityColumn), + Name = table.Column(type: "longtext", nullable: true), + Created = table.Column(type: "datetime", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Bug37462099", x => x.Id); + }) + .Annotation("MySQL:Charset", "utf8mb4"); + + migrationBuilder.RenameColumn( + name: "Name", + table: "Bug37462099", + newName: "ChangedName").Annotation("Relational:ColumnType", "LONGTEXT;"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Bug37462099"); + + migrationBuilder.RenameColumn( + name: "ChangedName", + table: "Bug37462099", + newName: "Name").Annotation("Relational:ColumnType", "LONGTEXT;"); + } + } +} diff --git a/EFCore/tests/MySql.EFCore.Migrations.Tests/Utilities/ContextUtils.cs b/EFCore/tests/MySql.EFCore.Migrations.Tests/Utilities/ContextUtils.cs index 24afa9349..813de5cde 100644 --- a/EFCore/tests/MySql.EFCore.Migrations.Tests/Utilities/ContextUtils.cs +++ b/EFCore/tests/MySql.EFCore.Migrations.Tests/Utilities/ContextUtils.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/src/EFMySqlCommand.cs b/EntityFramework/src/EFMySqlCommand.cs index 39cc3af41..9fcb1a1c9 100644 --- a/EntityFramework/src/EFMySqlCommand.cs +++ b/EntityFramework/src/EFMySqlCommand.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2008, 2021, Oracle and/or its affiliates. +// Copyright © 2008, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/src/EFMySqlDataReader.cs b/EntityFramework/src/EFMySqlDataReader.cs index 791fa4e8c..68d923bf4 100644 --- a/EntityFramework/src/EFMySqlDataReader.cs +++ b/EntityFramework/src/EFMySqlDataReader.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2008, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/src/Fragments/InputFragment.cs b/EntityFramework/src/Fragments/InputFragment.cs index 464932eac..f55461249 100644 --- a/EntityFramework/src/Fragments/InputFragment.cs +++ b/EntityFramework/src/Fragments/InputFragment.cs @@ -1,16 +1,16 @@ -// Copyright © 2008, 2017, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2008, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/src/Fragments/JoinFragment.cs b/EntityFramework/src/Fragments/JoinFragment.cs index a3cdb7492..dde7a8608 100644 --- a/EntityFramework/src/Fragments/JoinFragment.cs +++ b/EntityFramework/src/Fragments/JoinFragment.cs @@ -1,16 +1,16 @@ -// Copyright © 2008, 2017, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2008, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/src/Fragments/SqlFragment.cs b/EntityFramework/src/Fragments/SqlFragment.cs index 82aea8756..1e16b734f 100644 --- a/EntityFramework/src/Fragments/SqlFragment.cs +++ b/EntityFramework/src/Fragments/SqlFragment.cs @@ -1,16 +1,16 @@ -// Copyright © 2008, 2018, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2008, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/src/Fragments/TableFragment.cs b/EntityFramework/src/Fragments/TableFragment.cs index cd536d9d0..a0371d500 100644 --- a/EntityFramework/src/Fragments/TableFragment.cs +++ b/EntityFramework/src/Fragments/TableFragment.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2008, 2021, Oracle and/or its affiliates. +// Copyright © 2008, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -68,4 +68,4 @@ internal override void Accept(SqlFragmentVisitor visitor) visitor.Visit(this); } } -} \ No newline at end of file +} diff --git a/EntityFramework/src/Generators/DeleteGenerator.cs b/EntityFramework/src/Generators/DeleteGenerator.cs index 0a4a500d8..d23018443 100644 --- a/EntityFramework/src/Generators/DeleteGenerator.cs +++ b/EntityFramework/src/Generators/DeleteGenerator.cs @@ -1,16 +1,16 @@ -// Copyright © 2008, 2017, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2008, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/src/Generators/FunctionGenerator.cs b/EntityFramework/src/Generators/FunctionGenerator.cs index 968aefdb1..b5f9f6197 100644 --- a/EntityFramework/src/Generators/FunctionGenerator.cs +++ b/EntityFramework/src/Generators/FunctionGenerator.cs @@ -1,16 +1,16 @@ -// Copyright © 2008, 2017, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2008, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/src/Generators/FunctionProcessor.cs b/EntityFramework/src/Generators/FunctionProcessor.cs index bc0f1640e..0db93eafa 100644 --- a/EntityFramework/src/Generators/FunctionProcessor.cs +++ b/EntityFramework/src/Generators/FunctionProcessor.cs @@ -1,16 +1,16 @@ -// Copyright © 2008, 2018, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2008, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/src/Generators/InsertGenerator.cs b/EntityFramework/src/Generators/InsertGenerator.cs index 5968a2378..9dda3075a 100644 --- a/EntityFramework/src/Generators/InsertGenerator.cs +++ b/EntityFramework/src/Generators/InsertGenerator.cs @@ -1,16 +1,16 @@ -// Copyright © 2008, 2017, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2008, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/src/Generators/Scope.cs b/EntityFramework/src/Generators/Scope.cs index a73f12780..cf7b7d873 100644 --- a/EntityFramework/src/Generators/Scope.cs +++ b/EntityFramework/src/Generators/Scope.cs @@ -1,16 +1,16 @@ -// Copyright © 2008, 2018, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2008, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/src/Generators/SelectGenerator.cs b/EntityFramework/src/Generators/SelectGenerator.cs index 222c9fc0e..5ef0362af 100644 --- a/EntityFramework/src/Generators/SelectGenerator.cs +++ b/EntityFramework/src/Generators/SelectGenerator.cs @@ -1,16 +1,16 @@ -// Copyright © 2008, 2017, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2008, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/src/Generators/SqlGenerator.cs b/EntityFramework/src/Generators/SqlGenerator.cs index 14091317c..a7cf234d3 100644 --- a/EntityFramework/src/Generators/SqlGenerator.cs +++ b/EntityFramework/src/Generators/SqlGenerator.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2008, 2022, Oracle and/or its affiliates. +// Copyright © 2008, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/src/Generators/UpdateGenerator.cs b/EntityFramework/src/Generators/UpdateGenerator.cs index 7b309719b..ac8c1aee8 100644 --- a/EntityFramework/src/Generators/UpdateGenerator.cs +++ b/EntityFramework/src/Generators/UpdateGenerator.cs @@ -1,16 +1,16 @@ -// Copyright © 2008, 2018, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2008, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/src/Metadata.cs b/EntityFramework/src/Metadata.cs index 95cb3024d..414c4726f 100644 --- a/EntityFramework/src/Metadata.cs +++ b/EntityFramework/src/Metadata.cs @@ -1,16 +1,16 @@ -// Copyright © 2008, 2017, , Oracle and/or its affiliates. All rights reserved. +// Copyright © 2008, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/src/MySql.Data.EntityFramework.csproj b/EntityFramework/src/MySql.Data.EntityFramework.csproj index 3ad54520c..8f33df2a4 100644 --- a/EntityFramework/src/MySql.Data.EntityFramework.csproj +++ b/EntityFramework/src/MySql.Data.EntityFramework.csproj @@ -2,27 +2,36 @@ MySql.Data.EntityFramework - Copyright (c) 2016, 2023, Oracle and/or its affiliates. + Copyright © 2008, 2025, Oracle and/or its affiliates. en-US - 8.2.0 - Oracle - net462;netstandard2.1; + 9.4.0 + Oracle Corporation + net462;net48;netstandard2.1 $(NoWarn);CS1591 MySql.Data.EntityFramework MySql.Data.EntityFramework MySql;.NET Connector;MySql Connector/NET - http://www.mysql.com/common/logos/logo-mysql-170x115.png + logo-mysql-170x115.png + README.md https://dev.mysql.com/downloads/ - GPL-2.0-only + GPL-2.0-only WITH Universal-FOSS-exception-1.0 true - false - false - false - false - false - false + false + + + + + + + + + + + + + @@ -63,7 +72,7 @@ - + diff --git a/EntityFramework/src/MySqlConnectionFactory.cs b/EntityFramework/src/MySqlConnectionFactory.cs index 05385119c..6777c323f 100644 --- a/EntityFramework/src/MySqlConnectionFactory.cs +++ b/EntityFramework/src/MySqlConnectionFactory.cs @@ -1,16 +1,16 @@ -// Copyright © 2008, 2017, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2008, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -53,4 +53,4 @@ public DbConnection CreateConnection(string connectionString) return new MySqlConnection(connectionString); } } -} \ No newline at end of file +} diff --git a/EntityFramework/src/MySqlDependencyResolver.cs b/EntityFramework/src/MySqlDependencyResolver.cs index 478791e44..189c23353 100644 --- a/EntityFramework/src/MySqlDependencyResolver.cs +++ b/EntityFramework/src/MySqlDependencyResolver.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/src/MySqlEFConfiguration.cs b/EntityFramework/src/MySqlEFConfiguration.cs index abc7e2327..36ce383f7 100644 --- a/EntityFramework/src/MySqlEFConfiguration.cs +++ b/EntityFramework/src/MySqlEFConfiguration.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/src/MySqlExecutionStrategy.cs b/EntityFramework/src/MySqlExecutionStrategy.cs index 04dc463f6..1fa6a8348 100644 --- a/EntityFramework/src/MySqlExecutionStrategy.cs +++ b/EntityFramework/src/MySqlExecutionStrategy.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -244,4 +244,4 @@ public BackoffAlgorithmNdb() { } } -} \ No newline at end of file +} diff --git a/EntityFramework/src/MySqlHistoryContext.cs b/EntityFramework/src/MySqlHistoryContext.cs index b209507fd..8154745b2 100644 --- a/EntityFramework/src/MySqlHistoryContext.cs +++ b/EntityFramework/src/MySqlHistoryContext.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/src/MySqlLogger.cs b/EntityFramework/src/MySqlLogger.cs index 553d1b144..9b7863bf3 100644 --- a/EntityFramework/src/MySqlLogger.cs +++ b/EntityFramework/src/MySqlLogger.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/src/MySqlMigrationSqlGenerator.cs b/EntityFramework/src/MySqlMigrationSqlGenerator.cs index 8ca716a3e..5fc83f782 100644 --- a/EntityFramework/src/MySqlMigrationSqlGenerator.cs +++ b/EntityFramework/src/MySqlMigrationSqlGenerator.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2008, 2021, Oracle and/or its affiliates. +// Copyright © 2008, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/src/MySqlSpatialDataReader.cs b/EntityFramework/src/MySqlSpatialDataReader.cs index 5ae81d43b..8425a70da 100644 --- a/EntityFramework/src/MySqlSpatialDataReader.cs +++ b/EntityFramework/src/MySqlSpatialDataReader.cs @@ -1,16 +1,16 @@ -// Copyright © 2013, 2017, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/src/MySqlSpatialServices.cs b/EntityFramework/src/MySqlSpatialServices.cs index f9bb26f48..bd7071d35 100644 --- a/EntityFramework/src/MySqlSpatialServices.cs +++ b/EntityFramework/src/MySqlSpatialServices.cs @@ -1,16 +1,16 @@ -// Copyright © 2013, 2017, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/src/Properties/AssemblyInfo.cs b/EntityFramework/src/Properties/AssemblyInfo.cs index dc7661c9c..b99934a90 100644 --- a/EntityFramework/src/Properties/AssemblyInfo.cs +++ b/EntityFramework/src/Properties/AssemblyInfo.cs @@ -1,16 +1,16 @@ -// Copyright © 2008, 2023, Oracle and/or its affiliates. +// Copyright © 2008, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -30,19 +30,21 @@ using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System; -// General Information about an assembly is controlled through the following +// General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. -[assembly: AssemblyTitle("MySql.Data.EntityFramework for EF6")] -[assembly: AssemblyDescription("Entity Framework 6.0 supported")] - +[assembly: AssemblyTitle("MySql.Data.EntityFramework")] +[assembly: AssemblyDescription("MySql.Data.EntityFramework adds support for cross-platform application deployment with the Entity Framework 6.4 version.")] [assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Oracle")] -[assembly: AssemblyProduct("MySql.Data.EntityFramework")] -[assembly: AssemblyCopyright("Copyright © 2008, 2023, Oracle and/or its affiliates.")] -[assembly: AssemblyTrademark("")] +[assembly: AssemblyCompany("Oracle Corporation")] +[assembly: AssemblyProduct("MySQL Connector/NET")] +[assembly: AssemblyCopyright("Copyright © 2008, 2025, Oracle and/or its affiliates.")] +[assembly: AssemblyTrademark("Oracle®, Java, MySQL, and NetSuite are registered trademarks of Oracle and/or its affiliates.")] [assembly: AssemblyCulture("")] +[assembly: SecurityRules(SecurityRuleSet.Level1)] +[assembly: CLSCompliant(false)] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from diff --git a/EntityFramework/src/Properties/Resources.Designer.cs b/EntityFramework/src/Properties/Resources.Designer.cs index 8ecbdd21c..3dd3a9932 100644 --- a/EntityFramework/src/Properties/Resources.Designer.cs +++ b/EntityFramework/src/Properties/Resources.Designer.cs @@ -1,99 +1,99 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace MySql.Data.EntityFramework.Properties { - using System; - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Resources { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Resources() { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("MySql.Data.EntityFramework.Properties.Resources", typeof(Resources).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - /// - /// Looks up a localized string similar to The connection parameter must reference an object of type MySql.Data.MySqlConnection. - /// - internal static string ConnectionMustBeOfTypeMySqlConnection { - get { - return ResourceManager.GetString("ConnectionMustBeOfTypeMySqlConnection", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to There is no store type corresponding to the EDM type '{0}' of primitive type '{1}'.. - /// - internal static string NoStoreTypeForEdmType { - get { - return ResourceManager.GetString("NoStoreTypeForEdmType", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The underlying provider does not support the type '{0}'.. - /// - internal static string TypeNotSupported { - get { - return ResourceManager.GetString("TypeNotSupported", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Result type of a function is expected to be a collection of RowType or PrimitiveType. - /// - internal static string WrongFunctionResultType { - get { - return ResourceManager.GetString("WrongFunctionResultType", resourceCulture); - } - } - } -} +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace MySql.Data.EntityFramework.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("MySql.Data.EntityFramework.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to The connection parameter must reference an object of type MySql.Data.MySqlConnection. + /// + internal static string ConnectionMustBeOfTypeMySqlConnection { + get { + return ResourceManager.GetString("ConnectionMustBeOfTypeMySqlConnection", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to There is no store type corresponding to the EDM type '{0}' of primitive type '{1}'.. + /// + internal static string NoStoreTypeForEdmType { + get { + return ResourceManager.GetString("NoStoreTypeForEdmType", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The underlying provider does not support the type '{0}'.. + /// + internal static string TypeNotSupported { + get { + return ResourceManager.GetString("TypeNotSupported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Result type of a function is expected to be a collection of RowType or PrimitiveType. + /// + internal static string WrongFunctionResultType { + get { + return ResourceManager.GetString("WrongFunctionResultType", resourceCulture); + } + } + } +} diff --git a/EntityFramework/src/Properties/VersionInfo.cs b/EntityFramework/src/Properties/VersionInfo.cs new file mode 100644 index 000000000..e577111b1 --- /dev/null +++ b/EntityFramework/src/Properties/VersionInfo.cs @@ -0,0 +1,46 @@ +// Copyright © 2024, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using System.Reflection; +using System.Resources; + +// +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: + +[assembly: AssemblyVersion("9.4.0")] +[assembly: AssemblyInformationalVersion("9.4.0.0")] +[assembly: AssemblyFileVersion("9.4.0.0")] +[assembly: NeutralResourcesLanguage("en-US")] diff --git a/EntityFramework/src/ProviderManifest.cs b/EntityFramework/src/ProviderManifest.cs index 24ca857ba..e2cf1a83a 100644 --- a/EntityFramework/src/ProviderManifest.cs +++ b/EntityFramework/src/ProviderManifest.cs @@ -1,16 +1,16 @@ -// Copyright © 2008, 2018, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2008, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/src/ProviderServices.cs b/EntityFramework/src/ProviderServices.cs index a10f90a7a..e48803aad 100644 --- a/EntityFramework/src/ProviderServices.cs +++ b/EntityFramework/src/ProviderServices.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2014, 2020, Oracle and/or its affiliates. +// Copyright © 2014, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/src/Statements/DeleteStatement.cs b/EntityFramework/src/Statements/DeleteStatement.cs index 345578028..28dab1486 100644 --- a/EntityFramework/src/Statements/DeleteStatement.cs +++ b/EntityFramework/src/Statements/DeleteStatement.cs @@ -1,16 +1,16 @@ -// Copyright © 2008, 2017, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2008, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/src/Statements/InsertStatement.cs b/EntityFramework/src/Statements/InsertStatement.cs index 09cfa9370..0b22db824 100644 --- a/EntityFramework/src/Statements/InsertStatement.cs +++ b/EntityFramework/src/Statements/InsertStatement.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2008, 2022, Oracle and/or its affiliates. +// Copyright © 2008, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/src/Statements/SelectStatement.cs b/EntityFramework/src/Statements/SelectStatement.cs index c802edb45..cf355998e 100644 --- a/EntityFramework/src/Statements/SelectStatement.cs +++ b/EntityFramework/src/Statements/SelectStatement.cs @@ -1,16 +1,16 @@ -// Copyright (C) 2008, 2021, Oracle and/or its affiliates. +// Copyright © 2008, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -232,7 +232,7 @@ List GetDefaultColumnsForFragment(InputFragment input) if (generator.GetTopOp() == OpType.Join) { newColumn.ColumnAlias = cf.ColumnAlias; - newColumn.PushInput(cf.ColumnName); + newColumn.PushInput(cf.ActualColumnName); if (cf.TableName != null) newColumn.PushInput(cf.TableName); } diff --git a/EntityFramework/src/Statements/UpdateStatement.cs b/EntityFramework/src/Statements/UpdateStatement.cs index 3dc7db55d..110106dd4 100644 --- a/EntityFramework/src/Statements/UpdateStatement.cs +++ b/EntityFramework/src/Statements/UpdateStatement.cs @@ -1,16 +1,16 @@ -// Copyright © 2008, 2017, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2008, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/AggregateOperators.cs b/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/AggregateOperators.cs index ac55d9e3b..2a19d098a 100644 --- a/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/AggregateOperators.cs +++ b/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/AggregateOperators.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/CanonicalFunctions.cs b/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/CanonicalFunctions.cs index dc3cea487..1d9e66635 100644 --- a/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/CanonicalFunctions.cs +++ b/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/CanonicalFunctions.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -64,13 +64,13 @@ public void Bitwise() var context = ((IObjectContextAdapter)ctx).ObjectContext; ObjectQuery q = context.CreateQuery("BitwiseAnd(255,15)"); foreach (int i in q) - Assert.AreEqual(15, i); + Assert.That(i, Is.EqualTo(15)); q = context.CreateQuery("BitwiseOr(240,31)"); foreach (int i in q) - Assert.AreEqual(255, i); + Assert.That(i, Is.EqualTo(255)); q = context.CreateQuery("BitwiseXor(255,15)"); foreach (int i in q) - Assert.AreEqual(240, i); + Assert.That(i, Is.EqualTo(240)); } } @@ -85,9 +85,9 @@ public void CurrentDateTime() ObjectQuery q = context.CreateQuery("CurrentDateTime()"); foreach (DateTime dt in q) { - Assert.AreEqual(current.Year, dt.Year); - Assert.AreEqual(current.Month, dt.Month); - Assert.AreEqual(current.Day, dt.Day); + Assert.That(dt.Year, Is.EqualTo(current.Year)); + Assert.That(dt.Month, Is.EqualTo(current.Month)); + Assert.That(dt.Day, Is.EqualTo(current.Day)); // we don't check time as that will be always be different } } @@ -104,9 +104,9 @@ public void YearMonthDay() FROM Companies AS c WHERE c.Id=1"); foreach (DbDataRecord record in q) { - Assert.AreEqual(1996, record[1]); - Assert.AreEqual(11, record[2]); - Assert.AreEqual(15, record[3]); + Assert.That(record[1], Is.EqualTo(1996)); + Assert.That(record[2], Is.EqualTo(11)); + Assert.That(record[3], Is.EqualTo(15)); } } } @@ -122,9 +122,9 @@ public void HourMinuteSecond() FROM Companies AS c WHERE c.Id=1"); foreach (DbDataRecord record in q) { - Assert.AreEqual(5, record[1]); - Assert.AreEqual(18, record[2]); - Assert.AreEqual(23, record[3]); + Assert.That(record[1], Is.EqualTo(5)); + Assert.That(record[2], Is.EqualTo(18)); + Assert.That(record[3], Is.EqualTo(23)); } } } @@ -137,11 +137,11 @@ public void IndexOf() var context = ((IObjectContextAdapter)ctx).ObjectContext; ObjectQuery q = context.CreateQuery(@"IndexOf('needle', 'haystackneedle')"); foreach (int index in q) - Assert.AreEqual(9, index); + Assert.That(index, Is.EqualTo(9)); q = context.CreateQuery(@"IndexOf('haystack', 'needle')"); foreach (int index in q) - Assert.AreEqual(0, index); + Assert.That(index, Is.EqualTo(0)); } } @@ -154,17 +154,17 @@ public void LeftRight() string entitySQL = "CONCAT(LEFT('foo',3),RIGHT('bar',3))"; ObjectQuery query = context.CreateQuery(entitySQL); foreach (string s in query) - Assert.AreEqual("foobar", s); + Assert.That(s, Is.EqualTo("foobar")); entitySQL = "CONCAT(LEFT('foobar',3),RIGHT('barfoo',3))"; query = context.CreateQuery(entitySQL); foreach (string s in query) - Assert.AreEqual("foofoo", s); + Assert.That(s, Is.EqualTo("foofoo")); entitySQL = "CONCAT(LEFT('foobar',8),RIGHT('barfoo',8))"; query = context.CreateQuery(entitySQL); foreach (string s in query) - Assert.AreEqual("foobarbarfoo", s); + Assert.That(s, Is.EqualTo("foobarbarfoo")); } } @@ -177,7 +177,7 @@ public void Length() string entitySQL = "Length('abc')"; ObjectQuery query = context.CreateQuery(entitySQL); foreach (int len in query) - Assert.AreEqual(3, len); + Assert.That(len, Is.EqualTo(3)); } } @@ -189,13 +189,13 @@ public void Trims() var context = ((IObjectContextAdapter)ctx).ObjectContext; ObjectQuery query = context.CreateQuery("LTrim(' text ')"); foreach (string s in query) - Assert.AreEqual("text ", s); + Assert.That(s, Is.EqualTo("text ")); query = context.CreateQuery("RTrim(' text ')"); foreach (string s in query) - Assert.AreEqual(" text", s); + Assert.That(s, Is.EqualTo(" text")); query = context.CreateQuery("Trim(' text ')"); foreach (string s in query) - Assert.AreEqual("text", s); + Assert.That(s, Is.EqualTo("text")); } } @@ -213,11 +213,11 @@ public void Round() FROM Products AS p WHERE p.Id=1"); foreach (DbDataRecord r in q) { - Assert.AreEqual(1, r[0]); - Assert.AreEqual(8.865f, (float)r[1]); - Assert.AreEqual(9, Convert.ToInt32(r[2])); - Assert.AreEqual(8, Convert.ToInt32(r[3])); - Assert.AreEqual(9, Convert.ToInt32(r[4])); + Assert.That(r[0], Is.EqualTo(1)); + Assert.That((float)r[1], Is.EqualTo(8.865f)); + Assert.That(Convert.ToInt32(r[2]), Is.EqualTo(9)); + Assert.That(Convert.ToInt32(r[3]), Is.EqualTo(8)); + Assert.That(Convert.ToInt32(r[4]), Is.EqualTo(9)); } } } @@ -231,7 +231,7 @@ public void Substring() ObjectQuery query = context.CreateQuery("SUBSTRING('foobarfoo',4,3)"); query = context.CreateQuery("SUBSTRING('foobarfoo',4,30)"); foreach (string s in query) - Assert.AreEqual("barfoo", s); + Assert.That(s, Is.EqualTo("barfoo")); } } @@ -246,9 +246,9 @@ public void ToUpperToLowerReverse() Reverse(c.Name) FROM Companies AS c WHERE c.Id=1"); foreach (DbDataRecord r in q) { - Assert.AreEqual("HASBRO", r[0]); - Assert.AreEqual("hasbro", r[1]); - Assert.AreEqual("orbsaH", r[2]); + Assert.That(r[0], Is.EqualTo("HASBRO")); + Assert.That(r[1], Is.EqualTo("hasbro")); + Assert.That(r[2], Is.EqualTo("orbsaH")); } } } @@ -262,7 +262,7 @@ public void Replace() ObjectQuery q = context.CreateQuery( @"Replace('abcdefghi', 'def', 'zzz')"); foreach (string s in q) - Assert.AreEqual("abczzzghi", s); + Assert.That(s, Is.EqualTo("abczzzghi")); } } @@ -277,8 +277,8 @@ public void CanRoundToNonZeroDigits() Round(p.Weight, 2) AS [Rounded Weight] FROM Products AS p WHERE p.Id=1").First(); - Assert.AreEqual((float)8.865, (float)product[1]); - Assert.AreEqual((double)8.86, (double)product[2]); + Assert.That((float)product[1], Is.EqualTo((float)8.865)); + Assert.That((double)product[2], Is.EqualTo((double)8.86) ); } } diff --git a/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/DataTypeTests.cs b/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/DataTypeTests.cs index 8c0ca2e45..7e5471d39 100644 --- a/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/DataTypeTests.cs +++ b/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/DataTypeTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -57,7 +57,7 @@ public void TimeType() ctx.SaveChanges(); Child d = ctx.Children.Where(x => x.ChildId == "ABC").Single(); - Assert.AreEqual(birth, d.BirthTime); + Assert.That(d.BirthTime, Is.EqualTo(birth)); } } @@ -111,7 +111,7 @@ public void TimestampColumn() ctx.SaveChanges(); p = ctx.Products.First(); - Assert.AreEqual(now, p.CreatedDate); + Assert.That(p.CreatedDate, Is.EqualTo(now)); } } @@ -135,7 +135,7 @@ public void GuidType() ctx.SaveChanges(); Child d = ctx.Children.Where(x => x.ChildId == "GUID").Single(); - Assert.AreEqual(g, d.Label); + Assert.That(d.Label, Is.EqualTo(g)); } } @@ -156,7 +156,7 @@ public void CanSetDbTypeDecimalFromNewDecimalParameter() IsNullable = true }; - Assert.AreEqual(DbType.Decimal, newDecimalParameter.DbType); + Assert.That(newDecimalParameter.DbType, Is.EqualTo(DbType.Decimal)); } } } diff --git a/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/DatesTypesTests.cs b/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/DatesTypesTests.cs index c4fa0e221..801858c3c 100644 --- a/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/DatesTypesTests.cs +++ b/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/DatesTypesTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2011, 2023 Oracle and/or its affiliates. +// Copyright © 2011, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -74,10 +74,7 @@ public class DatesTypesTests : DefaultFixture [Test] public void CanCreateDBScriptWithDateTimePrecision() { - if (!Environment.OSVersion.Platform.ToString().StartsWith("Win")) - Assert.Ignore("Fix for Ubuntu. schema.Rows[3] -> System.IndexOutOfRangeException: There is no row at position 3."); - if (Version < new Version(5, 6, 5)) - Assert.Ignore("MySQL Server version no compatible"); + Assume.That(Version >= new Version(5, 6, 5)); using (var ctx = new TestContext(ConnectionString)) { @@ -89,12 +86,12 @@ public void CanCreateDBScriptWithDateTimePrecision() DataTable schema = Connection.GetSchema("COLUMNS", new string[] { null, Connection.Database, "widgets" }); DataRow row = schema.Rows[3]; - Assert.AreEqual("datetime", (string)row["DATA_TYPE"]); - Assert.AreEqual("NO", (string)row["IS_NULLABLE"]); + Assert.That((string)row["DATA_TYPE"], Is.EqualTo("datetime")); + Assert.That((string)row["IS_NULLABLE"], Is.EqualTo("NO")); if (Version < new Version(8, 0)) - Assert.AreEqual((uint)6, (UInt64)row["DATETIME_PRECISION"]); + Assert.That((UInt64)row["DATETIME_PRECISION"], Is.EqualTo((uint)6)); else - Assert.AreEqual((uint)6, (UInt32)row["DATETIME_PRECISION"]); + Assert.That((UInt32)row["DATETIME_PRECISION"], Is.EqualTo((uint)6)); } } } diff --git a/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/DefaultContext.cs b/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/DefaultContext.cs index 9632e679f..4c2b5ca82 100644 --- a/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/DefaultContext.cs +++ b/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/DefaultContext.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2014, 2022, Oracle and/or its affiliates. +// Copyright © 2014, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -149,4 +149,4 @@ public class LongDataTest [StringLength(15)] public string Data { get; set; } } -} \ No newline at end of file +} diff --git a/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/DefaultFixture.cs b/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/DefaultFixture.cs index 28c6b3f9c..8efdebde4 100644 --- a/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/DefaultFixture.cs +++ b/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/DefaultFixture.cs @@ -1,179 +1,179 @@ -// Copyright (c) 2013, 2020, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using System.Data.Entity.Core.Objects; -using System.Text.RegularExpressions; -using System.Data.Entity.Infrastructure; -using NUnit.Framework; -using System; -using MySql.Data.MySqlClient; - -namespace MySql.Data.EntityFramework.Tests -{ - public class DefaultFixture - { - public string host { get; set; } - public string user { get; set; } - public string password { get; set; } - public uint Port { get; set; } - public string database { get; set; } - public Version version { get; set; } - public MySqlConnection Connection { get; set; } - public string ConnectionString { get; set; } - public bool NeedSetup { get; set; } - - public DefaultFixture() - { - NeedSetup = true; - } - - [OneTimeSetUp] - public void OneTimeSetup() - { - if (NeedSetup) - { - NeedSetup = false; - - database = "db-" + this.GetType().Name.ToLower(); - if (database.Length > 32) - database = database.Substring(0, 32); - - MySqlConnectionStringBuilder sb = new MySqlConnectionStringBuilder(); - sb.Server = "localhost"; - string port = Environment.GetEnvironmentVariable("MYSQL_PORT"); - sb.Port = Port = string.IsNullOrEmpty(port) ? 3306 : uint.Parse(port); - sb.UserID = "root"; - sb.Pooling = false; - sb.AllowUserVariables = true; - sb.Database = database; - ConnectionString = sb.ToString(); - - using (DefaultContext ctx = new DefaultContext(ConnectionString)) - { - if (ctx.Database.Exists()) - ctx.Database.Delete(); - var context = ((IObjectContextAdapter)ctx).ObjectContext; - context.CreateDatabase(); - } - - Connection = new MySqlConnection(ConnectionString); - Connection.Open(); - LoadData(); - } - } - - [OneTimeTearDown] - public void OneTimeTearDown() - { - MySqlConnection.ClearAllPools(); - ExecSQL($"DROP DATABASE IF EXISTS `{Connection.Database}`"); - Connection.Close(); - } - - [SetUp] - public virtual void SetUp() - { - if (NeedSetup) - { - NeedSetup = false; - - using (DefaultContext ctx = new DefaultContext(ConnectionString)) - { - if (ctx.Database.Exists()) - ctx.Database.Delete(); - var context = ((IObjectContextAdapter)ctx).ObjectContext; - context.CreateDatabase(); - } - - LoadData(); - } - } - - [TearDown] - public virtual void TearDown() { } - - public virtual void LoadData() { } - - public Version Version - { - get - { - if (version == null) - { - string versionString = Connection.ServerVersion; - int i = 0; - while (i < versionString.Length && - (Char.IsDigit(versionString[i]) || versionString[i] == '.')) - i++; - - version = new Version(versionString.Substring(0, i)); - } - return version; - } - } - - public void ExecSQL(string sql) - { - MySqlCommand cmd = new MySqlCommand(sql, Connection); - cmd.ExecuteNonQuery(); - } - - public static void CheckSql(string actual, string expected) - { - var exp = Regex.Replace(expected, @"\s", string.Empty); - var act = Regex.Replace(actual, @"\s", string.Empty); - Assert.AreEqual(act, exp); - } - - public static void CheckSqlContains(string actual, string expected) - { - var exp = Regex.Replace(expected, @"\s", string.Empty); - var act = Regex.Replace(actual, @"\s", string.Empty); - Assert.True(act.Contains(exp)); - } - - public DefaultContext GetDefaultContext() - { - return new DefaultContext(ConnectionString); - } - - public void TestESql(string eSql, string expected, params ObjectParameter[] parms) - { - using (DefaultContext ctx = GetDefaultContext()) - { - var context = ((IObjectContextAdapter)ctx).ObjectContext; - ObjectQuery q = context.CreateQuery(eSql); - foreach (var p in parms) - q.Parameters.Add(p); - - string sql = q.ToTraceString(); - CheckSql(sql, expected); - } - } - } -} +// Copyright © 2013, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using System.Data.Entity.Core.Objects; +using System.Text.RegularExpressions; +using System.Data.Entity.Infrastructure; +using NUnit.Framework; +using System; +using MySql.Data.MySqlClient; + +namespace MySql.Data.EntityFramework.Tests +{ + public class DefaultFixture + { + public string host { get; set; } + public string user { get; set; } + public string password { get; set; } + public uint Port { get; set; } + public string database { get; set; } + public Version version { get; set; } + public MySqlConnection Connection { get; set; } + public string ConnectionString { get; set; } + public bool NeedSetup { get; set; } + + public DefaultFixture() + { + NeedSetup = true; + } + + [OneTimeSetUp] + public void OneTimeSetup() + { + if (NeedSetup) + { + NeedSetup = false; + + database = "db-" + this.GetType().Name.ToLower(); + if (database.Length > 32) + database = database.Substring(0, 32); + + MySqlConnectionStringBuilder sb = new MySqlConnectionStringBuilder(); + sb.Server = "localhost"; + string port = Environment.GetEnvironmentVariable("MYSQL_PORT"); + sb.Port = Port = string.IsNullOrEmpty(port) ? 3306 : uint.Parse(port); + sb.UserID = "root"; + sb.Pooling = false; + sb.AllowUserVariables = true; + sb.Database = database; + ConnectionString = sb.ToString(); + + using (DefaultContext ctx = new DefaultContext(ConnectionString)) + { + if (ctx.Database.Exists()) + ctx.Database.Delete(); + var context = ((IObjectContextAdapter)ctx).ObjectContext; + context.CreateDatabase(); + } + + Connection = new MySqlConnection(ConnectionString); + Connection.Open(); + LoadData(); + } + } + + [OneTimeTearDown] + public void OneTimeTearDown() + { + MySqlConnection.ClearAllPools(); + ExecSQL($"DROP DATABASE IF EXISTS `{Connection.Database}`"); + Connection.Close(); + } + + [SetUp] + public virtual void SetUp() + { + if (NeedSetup) + { + NeedSetup = false; + + using (DefaultContext ctx = new DefaultContext(ConnectionString)) + { + if (ctx.Database.Exists()) + ctx.Database.Delete(); + var context = ((IObjectContextAdapter)ctx).ObjectContext; + context.CreateDatabase(); + } + + LoadData(); + } + } + + [TearDown] + public virtual void TearDown() { } + + public virtual void LoadData() { } + + public Version Version + { + get + { + if (version == null) + { + string versionString = Connection.ServerVersion; + int i = 0; + while (i < versionString.Length && + (Char.IsDigit(versionString[i]) || versionString[i] == '.')) + i++; + + version = new Version(versionString.Substring(0, i)); + } + return version; + } + } + + public void ExecSQL(string sql) + { + MySqlCommand cmd = new MySqlCommand(sql, Connection); + cmd.ExecuteNonQuery(); + } + + public static void CheckSql(string actual, string expected) + { + var exp = Regex.Replace(expected, @"\s", string.Empty); + var act = Regex.Replace(actual, @"\s", string.Empty); + Assert.That(exp, Is.EqualTo(act)); + } + + public static void CheckSqlContains(string actual, string expected) + { + var exp = Regex.Replace(expected, @"\s", string.Empty); + var act = Regex.Replace(actual, @"\s", string.Empty); + Assert.That(act.Contains(exp)); + } + + public DefaultContext GetDefaultContext() + { + return new DefaultContext(ConnectionString); + } + + public void TestESql(string eSql, string expected, params ObjectParameter[] parms) + { + using (DefaultContext ctx = GetDefaultContext()) + { + var context = ((IObjectContextAdapter)ctx).ObjectContext; + ObjectQuery q = context.CreateQuery(eSql); + foreach (var p in parms) + q.Parameters.Add(p); + + string sql = q.ToTraceString(); + CheckSql(sql, expected); + } + } + } +} diff --git a/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/DeleteTests.cs b/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/DeleteTests.cs index 27aa0034c..8429f1f6f 100644 --- a/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/DeleteTests.cs +++ b/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/DeleteTests.cs @@ -1,136 +1,136 @@ -// Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using System.Linq; -using NUnit.Framework; -using System.Data; -using System.Data.Entity; -using System.Data.Entity.Infrastructure; - -namespace MySql.Data.EntityFramework.Tests -{ - - public class DeleteTests : DefaultFixture - { - public override void LoadData() - { - using (DefaultContext ctx = new DefaultContext(ConnectionString)) - { - ctx.Products.Add(new Product() { Name = "Garbage Truck", MinAge = 8 }); - ctx.Products.Add(new Product() { Name = "Fire Truck", MinAge = 12 }); - ctx.Products.Add(new Product() { Name = "Hula Hoop", MinAge = 18 }); - ctx.SaveChanges(); - } - } - - [Test] - public void SimpleDeleteAllRows() - { - using (DefaultContext ctx = new DefaultContext(ConnectionString)) - { - Assert.True(ctx.Products.Count() > 0); - - foreach (Product p in ctx.Products) - ctx.Products.Remove(p); - ctx.SaveChanges(); - - Assert.AreEqual(0, ctx.Products.Count()); - } - // set the flag that will cause the setup to happen again - // since we just blew away a table - NeedSetup = true; - } - - [Test] - public void SimpleDeleteRowByParameter() - { - using (DefaultContext ctx = new DefaultContext(ConnectionString)) - { - int total = ctx.Products.Count(); - int cntLeft = ctx.Products.Where(b => b.MinAge >= 18).Count(); - // make sure the test is valid - Assert.True(total > cntLeft); - - foreach (Product p in ctx.Products.Where(b => b.MinAge < 18).ToList()) - ctx.Products.Remove(p); - ctx.SaveChanges(); - Assert.AreEqual(cntLeft, ctx.Products.Count()); - } - // set the flag that will cause the setup to happen again - // since we just blew away a table - NeedSetup = true; - } - - - public class Widget - { - public int Id { get; set; } - public WidgetDetail Detail { get; set; } - } - - public class WidgetDetail - { - public int Id { get; set; } - public Widget Widget { get; set; } - } - - public class WidgetContext : DbContext - { - public WidgetContext(string connStr) : base(connStr) - { - Database.SetInitializer(null); - } - - protected override void OnModelCreating(DbModelBuilder modelBuilder) - { - base.OnModelCreating(modelBuilder); - modelBuilder.Entity() - .HasRequired(b => b.Widget) - .WithOptional(a => a.Detail) - .WillCascadeOnDelete(true); - } - } - - /// - /// Fix for bug Cascading delete using CreateDatabase in Entity Framework - /// (http://bugs.mysql.com/bug.php?id=64779) using ModelFirst. - /// - [Test] - public void XOnDeleteCascade() - { - using (WidgetContext ctx = new WidgetContext(ConnectionString)) - { - var context = ((IObjectContextAdapter)ctx).ObjectContext; - var sql = context.CreateDatabaseScript(); - CheckSqlContains(sql, - @"ALTER TABLE `WidgetDetails` ADD CONSTRAINT WidgetDetail_Widget - FOREIGN KEY (Id) REFERENCES `Widgets` (Id) ON DELETE Cascade ON UPDATE NO ACTION;"); - } - } - } -} +// Copyright © 2013, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using System.Linq; +using NUnit.Framework; +using System.Data; +using System.Data.Entity; +using System.Data.Entity.Infrastructure; + +namespace MySql.Data.EntityFramework.Tests +{ + + public class DeleteTests : DefaultFixture + { + public override void LoadData() + { + using (DefaultContext ctx = new DefaultContext(ConnectionString)) + { + ctx.Products.Add(new Product() { Name = "Garbage Truck", MinAge = 8 }); + ctx.Products.Add(new Product() { Name = "Fire Truck", MinAge = 12 }); + ctx.Products.Add(new Product() { Name = "Hula Hoop", MinAge = 18 }); + ctx.SaveChanges(); + } + } + + [Test] + public void SimpleDeleteAllRows() + { + using (DefaultContext ctx = new DefaultContext(ConnectionString)) + { + Assert.That(ctx.Products.Count() > 0); + + foreach (Product p in ctx.Products) + ctx.Products.Remove(p); + ctx.SaveChanges(); + + Assert.That(ctx.Products.Count(), Is.EqualTo(0)); + } + // set the flag that will cause the setup to happen again + // since we just blew away a table + NeedSetup = true; + } + + [Test] + public void SimpleDeleteRowByParameter() + { + using (DefaultContext ctx = new DefaultContext(ConnectionString)) + { + int total = ctx.Products.Count(); + int cntLeft = ctx.Products.Where(b => b.MinAge >= 18).Count(); + // make sure the test is valid + Assert.That(total > cntLeft); + + foreach (Product p in ctx.Products.Where(b => b.MinAge < 18).ToList()) + ctx.Products.Remove(p); + ctx.SaveChanges(); + Assert.That(ctx.Products.Count(), Is.EqualTo(cntLeft)); + } + // set the flag that will cause the setup to happen again + // since we just blew away a table + NeedSetup = true; + } + + + public class Widget + { + public int Id { get; set; } + public WidgetDetail Detail { get; set; } + } + + public class WidgetDetail + { + public int Id { get; set; } + public Widget Widget { get; set; } + } + + public class WidgetContext : DbContext + { + public WidgetContext(string connStr) : base(connStr) + { + Database.SetInitializer(null); + } + + protected override void OnModelCreating(DbModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + modelBuilder.Entity() + .HasRequired(b => b.Widget) + .WithOptional(a => a.Detail) + .WillCascadeOnDelete(true); + } + } + + /// + /// Fix for bug Cascading delete using CreateDatabase in Entity Framework + /// (http://bugs.mysql.com/bug.php?id=64779) using ModelFirst. + /// + [Test] + public void XOnDeleteCascade() + { + using (WidgetContext ctx = new WidgetContext(ConnectionString)) + { + var context = ((IObjectContextAdapter)ctx).ObjectContext; + var sql = context.CreateDatabaseScript(); + CheckSqlContains(sql, + @"ALTER TABLE `WidgetDetails` ADD CONSTRAINT WidgetDetail_Widget + FOREIGN KEY (Id) REFERENCES `Widgets` (Id) ON DELETE Cascade ON UPDATE NO ACTION;"); + } + } + } +} diff --git a/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/ExpressionTests.cs b/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/ExpressionTests.cs index 3e2fdc28b..44667e099 100644 --- a/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/ExpressionTests.cs +++ b/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/ExpressionTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2015, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -54,7 +54,7 @@ public void CheckStartsWithWhenUsingVariable() { string str = "Garbage"; var records = ctx.Products.Where(p => p.Name.StartsWith(str)).ToArray(); - Assert.AreEqual(1, records.Count()); + Assert.That(records.Count(), Is.EqualTo(1)); } } @@ -67,7 +67,7 @@ public void CheckStartsWithWhenUsingValue() using (DefaultContext ctx = new DefaultContext(ConnectionString)) { var records = ctx.Products.Where(p => p.Name.StartsWith("Garbage")).ToArray(); - Assert.AreEqual(1, records.Count()); + Assert.That(records.Count(), Is.EqualTo(1)); } } @@ -81,7 +81,7 @@ public void CheckEndsWithWhenUsingVariable() { string str = "Hoop"; var records = ctx.Products.Where(p => p.Name.EndsWith(str)).ToArray(); - Assert.AreEqual(1, records.Count()); + Assert.That(records.Count(), Is.EqualTo(1)); } } @@ -94,7 +94,7 @@ public void CheckEndsWithWhenUsingValue() using (DefaultContext ctx = new DefaultContext(ConnectionString)) { var records = ctx.Products.Where(p => p.Name.EndsWith("Hoop")).ToArray(); - Assert.AreEqual(1, records.Count()); + Assert.That(records.Count(), Is.EqualTo(1)); } } @@ -109,7 +109,7 @@ public void CheckContainsWhenUsingVariable() { string str = "bage"; var records = ctx.Products.Where(p => p.Name.Contains(str)).ToArray(); - Assert.AreEqual(1, records.Count()); + Assert.That(records.Count(), Is.EqualTo(1)); } } @@ -123,7 +123,7 @@ public void CheckContainsWhenUsingHardCodedValue() using (DefaultContext ctx = new DefaultContext(ConnectionString)) { var records = ctx.Products.Where(p => p.Name.Contains("bage")).ToArray(); - Assert.AreEqual(1, records.Count()); + Assert.That(records.Count(), Is.EqualTo(1)); } } @@ -136,7 +136,7 @@ public void CheckContainsWhenUsingHardCodedValueWithPercentageSymbol() using (DefaultContext ctx = new DefaultContext(ConnectionString)) { var records = ctx.Products.Where(p => p.Name.Contains("%")).ToArray(); - Assert.AreEqual(0, records.Count()); + Assert.That(records.Count(), Is.EqualTo(0)); } } diff --git a/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/GenericListener.cs b/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/GenericListener.cs index 9223458bb..dec000e96 100644 --- a/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/GenericListener.cs +++ b/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/GenericListener.cs @@ -1,87 +1,87 @@ -// Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using System.Text; -using System.Diagnostics; -using System.Collections.Specialized; - -namespace MySql.Data.EntityFramework.Tests -{ - public class GenericListener : TraceListener - { - - StringCollection strings; - StringBuilder partial; - - public GenericListener() - { - strings = new StringCollection(); - partial = new StringBuilder(); - } - - public StringCollection Strings - { - get { return strings; } - } - - public int Find(string sToFind) - { - int count = 0; - foreach (string s in strings) - if (s.IndexOf(sToFind) != -1) - count++; - return count; - } - - public void Clear() - { - partial.Remove(0, partial.Length); - strings.Clear(); - } - - public override void Write(string message) - { - partial.Append(message); - } - - public override void WriteLine(string message) - { - Write(message); - strings.Add(partial.ToString()); - partial.Remove(0, partial.Length); - } - - public int CountLinesContaining(string text) - { - int count = 0; - foreach (string s in strings) - if (s.Contains(text)) count++; - return count; - } - } -} +// Copyright © 2013, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using System.Text; +using System.Diagnostics; +using System.Collections.Specialized; + +namespace MySql.Data.EntityFramework.Tests +{ + public class GenericListener : TraceListener + { + + StringCollection strings; + StringBuilder partial; + + public GenericListener() + { + strings = new StringCollection(); + partial = new StringBuilder(); + } + + public StringCollection Strings + { + get { return strings; } + } + + public int Find(string sToFind) + { + int count = 0; + foreach (string s in strings) + if (s.IndexOf(sToFind) != -1) + count++; + return count; + } + + public void Clear() + { + partial.Remove(0, partial.Length); + strings.Clear(); + } + + public override void Write(string message) + { + partial.Append(message); + } + + public override void WriteLine(string message) + { + Write(message); + strings.Add(partial.ToString()); + partial.Remove(0, partial.Length); + } + + public int CountLinesContaining(string text) + { + int count = 0; + foreach (string s in strings) + if (s.Contains(text)) count++; + return count; + } + } +} diff --git a/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/InsertTests.cs b/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/InsertTests.cs index 8a447a7ed..2f1174097 100644 --- a/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/InsertTests.cs +++ b/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/InsertTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2022, Oracle and/or its affiliates. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -58,11 +58,11 @@ public void InsertSingleRow() ctx.Companies.Add(c); int result = ctx.SaveChanges(); - Assert.AreEqual(beforeCnt + 1, ctx.Companies.Count()); + Assert.That(ctx.Companies.Count(), Is.EqualTo(beforeCnt + 1)); Company d = ctx.Companies.Find(c.Id); d.Id = c.Id; - Assert.AreEqual(c, d); + Assert.That(d, Is.EqualTo(c)); } } @@ -93,12 +93,12 @@ public async Task ExecuteNonQueryAndScalarAsyncAwait() proc.CommandType = CommandType.StoredProcedure; int result = await proc.ExecuteNonQueryAsync(); - Assert.AreNotEqual(-1, result); + Assert.That(result, Is.Not.EqualTo(-1)); EFMySqlCommand cmd = new EFMySqlCommand() { CommandText = "SELECT COUNT(*) FROM NonQueryAndScalarAsyncAwaitTest;", Connection = Connection }; cmd.CommandType = CommandType.Text; object cnt = await cmd.ExecuteScalarAsync(); - Assert.AreEqual(100, Convert.ToInt32(cnt)); + Assert.That(Convert.ToInt32(cnt), Is.EqualTo(100)); } [Test] @@ -147,15 +147,15 @@ public void SqlModeReplacedByANSI() LongDataTest longData = new LongDataTest(); longData.Data = "This does fit."; ctx.LongDataTests.Add(longData); - Assert.IsTrue(ctx.SaveChanges() == 1); + Assert.That(ctx.SaveChanges() == 1); // Try to insert a value that is larger than the max lenght of the column longData.Data = "This does not fit in the column!!!"; ctx.LongDataTests.Add(longData); var ex = Assert.Throws(() => ctx.SaveChanges()); Assert.That(ex.InnerException.InnerException is MySqlException); - StringAssert.AreEqualIgnoringCase("Data too long for column 'Data' at row 1", ex.InnerException.InnerException.Message); + Assert.That(ex.InnerException.InnerException.Message, Is.EqualTo("Data too long for column 'Data' at row 1").IgnoreCase); } } } -} \ No newline at end of file +} diff --git a/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/JoinTests.cs b/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/JoinTests.cs index f31d10cd1..bad80f7c0 100644 --- a/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/JoinTests.cs +++ b/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/JoinTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2014, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -292,4 +292,4 @@ where b.Pages > 300 // } // } } -} \ No newline at end of file +} diff --git a/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/MySql.EntityFramework.Basic.Tests.csproj b/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/MySql.EntityFramework.Basic.Tests.csproj index fa40e0500..74db78daf 100644 --- a/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/MySql.EntityFramework.Basic.Tests.csproj +++ b/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/MySql.EntityFramework.Basic.Tests.csproj @@ -2,17 +2,17 @@ MySql.Data.EntityFramework.CodeFirTests - Copyright (c) 2016, 2023, Oracle and/or its affiliates. + Copyright © 2016, 2025, Oracle and/or its affiliates. en-US - 8.2.0 + 9.4.0 Oracle - net7.0 + net462;net48;net9.0 MySql.EntityFramework.Basic.Tests MySql.EntityFramework.Basic.Tests MySql;.NET Connector;MySql Connector/NET http://www.mysql.com/common/logos/logo-mysql-170x115.png http://dev.mysql.com/downloads/ - GPL-2.0-only + GPL-2.0-only WITH Universal-FOSS-exception-1.0 true false false @@ -25,6 +25,7 @@ ..\..\..\ConnectorNetPublicKey.snk MySql.EntityFramework.Basic.Tests CA2100 + latest @@ -33,21 +34,6 @@ - - - - - - - - TRACE;DEBUG;NET452; - - - - TRACE;RELEASE;NET452; - - - @@ -58,8 +44,20 @@ + + + + + + TRACE;DEBUG;NET462; + + + + TRACE;RELEASE;NET462; + + diff --git a/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/OrderingAndGrouping.cs b/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/OrderingAndGrouping.cs index 29f4f791e..c95c995df 100644 --- a/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/OrderingAndGrouping.cs +++ b/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/OrderingAndGrouping.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -106,4 +106,4 @@ public void OrdersTableDoesNotProvokeSyntaxError() //} } } -} \ No newline at end of file +} diff --git a/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/Paging.cs b/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/Paging.cs index 70d98a558..aab415d67 100644 --- a/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/Paging.cs +++ b/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/Paging.cs @@ -1,104 +1,104 @@ -// Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using System.Data; -using System.Linq; -using NUnit.Framework; - -namespace MySql.Data.EntityFramework.Tests -{ - public class Paging : DefaultFixture - { - public override void SetUp() - { - LoadData(); - } - - void LoadData() - { - using (DefaultContext ctx = new DefaultContext(ConnectionString)) - { - ctx.Products.Add(new Product() { Name = "Garbage Truck", MinAge = 8 }); - ctx.Products.Add(new Product() { Name = "Fire Truck", MinAge = 12 }); - ctx.Products.Add(new Product() { Name = "Hula Hoop", MinAge = 18 }); - ctx.SaveChanges(); - } - } - - [Test] - public void Take() - { - using (DefaultContext ctx = new DefaultContext(ConnectionString)) - { - var q = ctx.Books.Take(2); - var sql = q.ToString(); - CheckSql(sql, - @"SELECT `Id`, `Name`, `PubDate`, `Pages`, `Author_Id` FROM `Books` LIMIT 2"); - } - } - - [Test] - public void Skip() - { - using (DefaultContext ctx = new DefaultContext(ConnectionString)) - { - var q = ctx.Books.OrderBy(b=>b.Pages).Skip(3); - var sql = q.ToString(); - CheckSql(sql, - @"SELECT `Extent1`.`Id`, `Extent1`.`Name`, `Extent1`.`PubDate`, `Extent1`.`Pages`, `Extent1`.`Author_Id` - FROM `Books` AS `Extent1` ORDER BY `Extent1`.`Pages` ASC LIMIT 3,18446744073709551615"); - } - } - - [Test] - public void SkipAndTakeSimple() - { - using (DefaultContext ctx = new DefaultContext(ConnectionString)) - { - var q = ctx.Books.OrderBy(b => b.Pages).Skip(3).Take(4); - var sql = q.ToString(); - CheckSql(sql, - @"SELECT `Extent1`.`Id`, `Extent1`.`Name`, `Extent1`.`PubDate`, `Extent1`.`Pages`, `Extent1`.`Author_Id` - FROM `Books` AS `Extent1` ORDER BY `Extent1`.`Pages` ASC LIMIT 3,4"); - } - } - - // - // Tests fix for bug #64749 - Entity Framework - Take().Count() fails with EntityCommandCompilationException. - // - [Test] - public void TakeWithCount() - { - using (DefaultContext ctx = new DefaultContext(ConnectionString)) - { - int cnt = ctx.Products.Take(2).Count(); - Assert.AreEqual(2, cnt); - } - } - } -} \ No newline at end of file +// Copyright © 2014, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using System.Data; +using System.Linq; +using NUnit.Framework; + +namespace MySql.Data.EntityFramework.Tests +{ + public class Paging : DefaultFixture + { + public override void SetUp() + { + LoadData(); + } + + void LoadData() + { + using (DefaultContext ctx = new DefaultContext(ConnectionString)) + { + ctx.Products.Add(new Product() { Name = "Garbage Truck", MinAge = 8 }); + ctx.Products.Add(new Product() { Name = "Fire Truck", MinAge = 12 }); + ctx.Products.Add(new Product() { Name = "Hula Hoop", MinAge = 18 }); + ctx.SaveChanges(); + } + } + + [Test] + public void Take() + { + using (DefaultContext ctx = new DefaultContext(ConnectionString)) + { + var q = ctx.Books.Take(2); + var sql = q.ToString(); + CheckSql(sql, + @"SELECT `Id`, `Name`, `PubDate`, `Pages`, `Author_Id` FROM `Books` LIMIT 2"); + } + } + + [Test] + public void Skip() + { + using (DefaultContext ctx = new DefaultContext(ConnectionString)) + { + var q = ctx.Books.OrderBy(b=>b.Pages).Skip(3); + var sql = q.ToString(); + CheckSql(sql, + @"SELECT `Extent1`.`Id`, `Extent1`.`Name`, `Extent1`.`PubDate`, `Extent1`.`Pages`, `Extent1`.`Author_Id` + FROM `Books` AS `Extent1` ORDER BY `Extent1`.`Pages` ASC LIMIT 3,18446744073709551615"); + } + } + + [Test] + public void SkipAndTakeSimple() + { + using (DefaultContext ctx = new DefaultContext(ConnectionString)) + { + var q = ctx.Books.OrderBy(b => b.Pages).Skip(3).Take(4); + var sql = q.ToString(); + CheckSql(sql, + @"SELECT `Extent1`.`Id`, `Extent1`.`Name`, `Extent1`.`PubDate`, `Extent1`.`Pages`, `Extent1`.`Author_Id` + FROM `Books` AS `Extent1` ORDER BY `Extent1`.`Pages` ASC LIMIT 3,4"); + } + } + + // + // Tests fix for bug #64749 - Entity Framework - Take().Count() fails with EntityCommandCompilationException. + // + [Test] + public void TakeWithCount() + { + using (DefaultContext ctx = new DefaultContext(ConnectionString)) + { + int cnt = ctx.Products.Take(2).Count(); + Assert.That(cnt, Is.EqualTo(2)); + } + } + } +} diff --git a/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/ProceduresAndFunctions.cs b/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/ProceduresAndFunctions.cs index 1c8006bb1..6a23d1b88 100644 --- a/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/ProceduresAndFunctions.cs +++ b/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/ProceduresAndFunctions.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -53,7 +53,7 @@ public void CallStoredProcedure() using (DefaultContext ctx = new DefaultContext(ConnectionString)) { long count = ctx.Database.SqlQuery("call CallStoredProcedure").First(); - Assert.AreEqual(5, count); + Assert.That(count, Is.EqualTo(5)); } } @@ -69,7 +69,7 @@ public void UserDefinedFunction() using (DefaultContext ctx = new DefaultContext(ConnectionString)) { int val = ctx.Database.SqlQuery(@"SELECT spFunc()").Single(); - Assert.AreEqual(3, val); + Assert.That(val, Is.EqualTo(3)); } } @@ -94,4 +94,4 @@ public void CommandTimeout() } } } -} \ No newline at end of file +} diff --git a/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/Properties/AssemblyInfo.cs b/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/Properties/AssemblyInfo.cs index 270be36bb..2bd86ed8d 100644 --- a/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/Properties/AssemblyInfo.cs +++ b/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/Properties/AssemblyInfo.cs @@ -1,55 +1,55 @@ -// Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using System.Reflection; -using System.Runtime.InteropServices; -using NUnit.Framework; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("MySql.Data.EntityFramework.Tests")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Oracle")] -[assembly: AssemblyProduct("MySql.Data.EntityFramework.Tests")] -[assembly: AssemblyCopyright("Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved.")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("a4c0a8f2-5e48-4227-a712-bf8ae7446101")] - -//[assembly: InternalsVisibleTo("MySql.Data.EntityFramework.CodeFirTests, PublicKey = 0024000004800000940000000602000000240000525341310004000001000100d973bda91f71752c78294126974a41a08643168271f65fc0fb3cd45f658da01fbca75ac74067d18e7afbf1467d7a519ce0248b13719717281bb4ddd4ecd71a580dfe0912dfc3690b1d24c7e1975bf7eed90e4ab14e10501eedf763bff8ac204f955c9c15c2cf4ebf6563d8320b6ea8d1ea3807623141f4b81ae30a6c886b3ee1")] - -[assembly: NonParallelizable] \ No newline at end of file +// Copyright © 2008, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using System.Reflection; +using System.Runtime.InteropServices; +using NUnit.Framework; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("MySql.Data.EntityFramework.Tests")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Oracle")] +[assembly: AssemblyProduct("MySql.Data.EntityFramework.Tests")] +[assembly: AssemblyCopyright("Copyright © 2008, 2025, Oracle and/or its affiliates.")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("a4c0a8f2-5e48-4227-a712-bf8ae7446101")] + +//[assembly: InternalsVisibleTo("MySql.Data.EntityFramework.CodeFirTests, PublicKey = 0024000004800000940000000602000000240000525341310004000001000100d973bda91f71752c78294126974a41a08643168271f65fc0fb3cd45f658da01fbca75ac74067d18e7afbf1467d7a519ce0248b13719717281bb4ddd4ecd71a580dfe0912dfc3690b1d24c7e1975bf7eed90e4ab14e10501eedf763bff8ac204f955c9c15c2cf4ebf6563d8320b6ea8d1ea3807623141f4b81ae30a6c886b3ee1")] + +[assembly: NonParallelizable] diff --git a/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/ProviderManifestTests.cs b/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/ProviderManifestTests.cs index e99d76b52..aae8e618c 100644 --- a/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/ProviderManifestTests.cs +++ b/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/ProviderManifestTests.cs @@ -1,103 +1,103 @@ -// Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using System; -using MySql.Data.MySqlClient; -using System.Data.Entity.Core.Metadata.Edm; -using NUnit.Framework; - -namespace MySql.Data.EntityFramework.Tests -{ - public class ProviderManifestTests : DefaultFixture - { - [Test] - public void TestingMaxLengthFacet() - { - using (MySqlConnection connection = new MySqlConnection(ConnectionString)) - { - MySqlProviderManifest pm = new MySqlProviderManifest(Version.ToString()); - TypeUsage tu = TypeUsage.CreateStringTypeUsage( - PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.String), false, false); - TypeUsage result = pm.GetStoreType(tu); - Assert.AreEqual("longtext", result.EdmType.Name); - - tu = TypeUsage.CreateStringTypeUsage( - PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.String), false, false, Int32.MaxValue); - result = pm.GetStoreType(tu); - Assert.AreEqual("longtext", result.EdmType.Name); - - tu = TypeUsage.CreateStringTypeUsage( - PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.String), false, false, 70000); - result = pm.GetStoreType(tu); - Assert.AreEqual("mediumtext", result.EdmType.Name); - - } - } - - /// - /// Bug #62135 Connector/NET Incorrectly Maps PrimitiveTypeKind.Byte to "tinyint" - /// - /// + /// Bug #62135 Connector/NET Incorrectly Maps PrimitiveTypeKind.Byte to "tinyint" + /// + ///
( - "SELECT VALUE b FROM Books AS b WHERE b.Pages > @pages", - @"SELECT `Extent1`.`Id`, `Extent1`.`Name`, `Extent1`.`PubDate`, `Extent1`.`Pages`, - `Extent1`.`Author_Id` FROM `Books` AS `Extent1` WHERE `Extent1`.`Pages` > @pages", - new ObjectParameter("pages", 200)); - } - - [Test] - public void WhereLiteralOnRelation() - { - TestESql( - "SELECT VALUE a FROM Authors AS a WHERE a.Address.City = 'Dallas'", - @"SELECT `Extent1`.`Id`, `Extent1`.`Name`, `Extent1`.`Age`, `Extent1`.`Address_City`, - `Extent1`.`Address_Street`, `Extent1`.`Address_State`, `Extent1`.`Address_ZipCode` - FROM `Authors` AS `Extent1` WHERE `Extent1`.`Address_City` = @gp1"); - } - - [Test] - public void WhereWithRelatedEntities1() - { - TestESql( - "SELECT VALUE b FROM Books AS b WHERE b.Author.Address.State = 'TX'", - @"SELECT `Extent1`.`Id`, `Extent1`.`Name`, `Extent1`.`PubDate`, `Extent1`.`Pages`, - `Extent1`.`Author_Id` FROM `Books` AS `Extent1` INNER JOIN `Authors` AS `Extent2` - ON `Extent1`.`Author_Id` = `Extent2`.`Id` WHERE `Extent2`.`Address_State` = @gp1"); - } - - [Test] - public void Exists() - { - TestESql( - @"SELECT VALUE a FROM Authors AS a WHERE EXISTS( - SELECT b FROM a.Books AS b WHERE b.Pages > 200)", - @"SELECT `Extent1`.`Id`, `Extent1`.`Name`, `Extent1`.`Age`, `Extent1`.`Address_City`, - `Extent1`.`Address_Street`, `Extent1`.`Address_State`, `Extent1`.`Address_ZipCode` - FROM `Authors` AS `Extent1` WHERE EXISTS(SELECT 1 AS `C1` FROM `Books` AS `Extent2` - WHERE (`Extent1`.`Id` = `Extent2`.`Author_Id`) AND (`Extent2`.`Pages` > 200))"); - } - } -} \ No newline at end of file +// Copyright © 2013, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using System.Data.Entity.Core.Objects; +using NUnit.Framework; + +namespace MySql.Data.EntityFramework.Tests +{ + public class RestrictionOperators : DefaultFixture + { + [Test] + public void SimpleSelectWithParam() + { + TestESql( + "SELECT VALUE b FROM Books AS b WHERE b.Pages > @pages", + @"SELECT `Extent1`.`Id`, `Extent1`.`Name`, `Extent1`.`PubDate`, `Extent1`.`Pages`, + `Extent1`.`Author_Id` FROM `Books` AS `Extent1` WHERE `Extent1`.`Pages` > @pages", + new ObjectParameter("pages", 200)); + } + + [Test] + public void WhereLiteralOnRelation() + { + TestESql( + "SELECT VALUE a FROM Authors AS a WHERE a.Address.City = 'Dallas'", + @"SELECT `Extent1`.`Id`, `Extent1`.`Name`, `Extent1`.`Age`, `Extent1`.`Address_City`, + `Extent1`.`Address_Street`, `Extent1`.`Address_State`, `Extent1`.`Address_ZipCode` + FROM `Authors` AS `Extent1` WHERE `Extent1`.`Address_City` = @gp1"); + } + + [Test] + public void WhereWithRelatedEntities1() + { + TestESql( + "SELECT VALUE b FROM Books AS b WHERE b.Author.Address.State = 'TX'", + @"SELECT `Extent1`.`Id`, `Extent1`.`Name`, `Extent1`.`PubDate`, `Extent1`.`Pages`, + `Extent1`.`Author_Id` FROM `Books` AS `Extent1` INNER JOIN `Authors` AS `Extent2` + ON `Extent1`.`Author_Id` = `Extent2`.`Id` WHERE `Extent2`.`Address_State` = @gp1"); + } + + [Test] + public void Exists() + { + TestESql( + @"SELECT VALUE a FROM Authors AS a WHERE EXISTS( + SELECT b FROM a.Books AS b WHERE b.Pages > 200)", + @"SELECT `Extent1`.`Id`, `Extent1`.`Name`, `Extent1`.`Age`, `Extent1`.`Address_City`, + `Extent1`.`Address_Street`, `Extent1`.`Address_State`, `Extent1`.`Address_ZipCode` + FROM `Authors` AS `Extent1` WHERE EXISTS(SELECT 1 AS `C1` FROM `Books` AS `Extent2` + WHERE (`Extent1`.`Id` = `Extent2`.`Author_Id`) AND (`Extent2`.`Pages` > 200))"); + } + } +} diff --git a/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/SchemaInformation.cs b/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/SchemaInformation.cs index 6d5b4dbab..533520f5d 100644 --- a/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/SchemaInformation.cs +++ b/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/SchemaInformation.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2014, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/SetOperators.cs b/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/SetOperators.cs index 2826cb2dc..831028559 100644 --- a/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/SetOperators.cs +++ b/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/SetOperators.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2020 Oracle and/or its affiliates. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -78,7 +78,7 @@ public void FirstSimple() select p; Product product = q.First() as Product; - Assert.AreEqual(id, product.Id); + Assert.That(product.Id, Is.EqualTo(id)); } } @@ -94,8 +94,8 @@ public void FirstPredicate() where p.MinAge > 8 select p; Product product = q.First() as Product; - Assert.AreEqual(id, product.Id); + Assert.That(product.Id, Is.EqualTo(id)); } } } -} \ No newline at end of file +} diff --git a/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/SimpleQuery.cs b/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/SimpleQuery.cs index ee3e2c31e..5b5a5f857 100644 --- a/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/SimpleQuery.cs +++ b/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/SimpleQuery.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2014, 2021, Oracle and/or its affiliates. +// Copyright © 2014, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -84,8 +84,8 @@ public void TablesWithSchemaWithoutUsingProperty() context.SaveChanges(); var q = (from u in context.User select u).ToArray(); - Assert.IsTrue(q.Length == 2); + Assert.That(q.Length == 2); } } } -} \ No newline at end of file +} diff --git a/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/UpdateTests.cs b/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/UpdateTests.cs index df74ec178..887e14908 100644 --- a/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/UpdateTests.cs +++ b/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/UpdateTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -71,4 +71,4 @@ public void UpdateSimple() } } } -} \ No newline at end of file +} diff --git a/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/Wizard.cs b/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/Wizard.cs index 2d77db265..331db08b4 100644 --- a/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/Wizard.cs +++ b/EntityFramework/tests/MySql.EntityFramework.Basic.Tests/Wizard.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2014, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -45,17 +45,17 @@ public void GetDbProviderManifestTokenReturnsCorrectSchemaVersion() string token = services.GetProviderManifestToken(Connection); if (Version < new Version(5, 1)) - Assert.AreEqual("5.0", token); + Assert.That(token, Is.EqualTo("5.0")); else if (Version < new Version(5, 5)) - Assert.AreEqual("5.1", token); + Assert.That(token, Is.EqualTo("5.1")); else if (Version < new Version(5, 6)) - Assert.AreEqual("5.5", token); + Assert.That(token, Is.EqualTo("5.5")); else if (Version < new Version(5, 7)) - Assert.AreEqual("5.6", token); + Assert.That(token, Is.EqualTo("5.6")); else if (Version < new Version(8, 0)) - Assert.AreEqual("5.7", token); + Assert.That(token, Is.EqualTo("5.7")); else - Assert.AreEqual("8.0", token); + Assert.That(token, Is.EqualTo("8.0")); } [Test] @@ -64,8 +64,8 @@ public void GetStoreSchemaDescriptionDoesNotThrowForServer50OrGreater() MySqlProviderManifest manifest = new MySqlProviderManifest(Version.Major + "." + Version.Minor); using (XmlReader reader = manifest.GetInformation(DbXmlEnabledProviderManifest.StoreSchemaDefinition)) { - Assert.NotNull(reader); + Assert.That(reader, Is.Not.Null); } } } -} \ No newline at end of file +} diff --git a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/Blogs.cs b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/Blogs.cs index 6cfb76543..46654e07f 100644 --- a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/Blogs.cs +++ b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/Blogs.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2020 Oracle and/or its affiliates. +// Copyright © 2020, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/CodeFirstFixture.cs b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/CodeFirstFixture.cs index 6702b1fa9..95fe2c649 100644 --- a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/CodeFirstFixture.cs +++ b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/CodeFirstFixture.cs @@ -1,23 +1,29 @@ -// Copyright (c) 2013, 2021, Oracle and/or its affiliates. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // -// MySQL Connector/NET is licensed under the terms of the GPLv2 -// , like most -// MySQL Connectors. There are special exceptions to the terms and -// conditions of the GPLv2 as it is applied to this software, see the -// FLOSS License Exception -// . +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. // -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published -// by the Free Software Foundation; version 2 of the License. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -// for more details. +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. // -// You should have received a copy of the GNU General Public License along -// with this program; if not, write to the Free Software Foundation, Inc., +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA using MySql.Data.MySqlClient; @@ -120,6 +126,7 @@ public CodeFirstFixture() DeleteContext(); DeleteContext(); DeleteContext(); + DeleteContext(); DeleteContext(); DeleteContext(); DeleteContext(); @@ -168,20 +175,20 @@ private EntityConnection GetEntityConnection() foreach (char c in refSql) if (!Char.IsWhiteSpace(c)) str2.Append(c); - Assert.AreEqual(0, String.Compare(str1.ToString(), str2.ToString(), true)); + Assert.That(String.Compare(str1.ToString(), str2.ToString(), true), Is.EqualTo(0)); } private class AssertFailTraceListener : DefaultTraceListener { public override void Fail(string message) { - Assert.True(message == String.Empty, "Failure: " + message); + Assert.That(message == String.Empty, "Failure: " + message); } public override void Fail(string message, string detailMessage) { - Assert.True(message == String.Empty, "Failure: " + message); + Assert.That(message == String.Empty, "Failure: " + message); } } } -} \ No newline at end of file +} diff --git a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/CodeFirstTests.cs b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/CodeFirstTests.cs index 96089b3f0..5796c3e1e 100644 --- a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/CodeFirstTests.cs +++ b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/CodeFirstTests.cs @@ -1,2254 +1,2292 @@ -// Copyright (c) 2014, 2023, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data.EntityFramework.Tests; -using MySql.Data.MySqlClient; -using MySql.EntityFramework.CodeFirst.Tests; -using MySql.EntityFramework.CodeFirst.Tests.Properties; -using NUnit.Framework; -using System; -using System.Collections.Generic; -using System.Data; -using System.Data.Entity; -using System.Data.Entity.Infrastructure; -using System.Data.Entity.Spatial; -using System.Diagnostics; -using System.Linq; -using System.Text.RegularExpressions; -using System.Threading; - -namespace MySql.Data.EntityFramework.CodeFirst.Tests -{ - public class CodeFirstTests : CodeFirstFixture - { - /// - /// Tests for fix of http://bugs.mysql.com/bug.php?id=61230 - /// ("The provider did not return a ProviderManifestToken string."). - /// - [Test] - public void SimpleCodeFirstSelect() - { -#if DEBUG - Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); -#endif - MovieDBContext db = new MovieDBContext(); - db.Database.Initialize(true); - MovieDBInitialize.DoDataPopulation(db); - var l = db.Movies.ToList(); - int j = l.Count; - foreach (var i in l) - { - j--; - } - Assert.AreEqual(0, j); - } - - /// - /// Tests for fix of http://bugs.mysql.com/bug.php?id=62150 - /// ("EF4.1, Code First, CreateDatabaseScript() generates an invalid MySQL script."). - /// - [Test] - public void AlterTableTest() - { -#if DEBUG - Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); -#endif - MovieDBContext db = new MovieDBContext(); - db.Database.Initialize(true); - MovieDBInitialize.DoDataPopulation(db); - var l = db.MovieFormats.ToList(); - int j = l.Count; - foreach (var i in l) - { - j--; - } - Assert.AreEqual(0, j); - MovieFormat m = new MovieFormat(); - m.Format = 8.0f; - db.MovieFormats.Add(m); - db.SaveChanges(); - MovieFormat m2 = db.MovieFormats.Where(p => p.Format == 8.0f).FirstOrDefault(); - Assert.NotNull(m2); - Assert.AreEqual(8.0f, m2.Format); - } - - /// - /// Fix for "Connector/Net Generates Incorrect SELECT Clause after UPDATE" (MySql bug #62134, Oracle bug #13491689). - /// - [Test] - public void ConcurrencyCheckWithNonDbGeneratedColumn() - { -#if DEBUG - Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); -#endif - using (MovieDBContext db = new MovieDBContext()) - { - db.Database.Delete(); - db.Database.CreateIfNotExists(); - MovieDBInitialize.DoDataPopulation(db); - db.Database.ExecuteSqlCommand(@"DROP TABLE IF EXISTS `MovieReleases`"); - - db.Database.ExecuteSqlCommand( -@"CREATE TABLE IF NOT EXISTS `MovieReleases` ( - `Id` int(11) NOT NULL, - `Name` varbinary(45) NOT NULL, - `Timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - PRIMARY KEY (`Id`) -) ENGINE=InnoDB DEFAULT CHARSET=binary"); - MySqlTrace.Listeners.Clear(); - MySqlTrace.Switch.Level = SourceLevels.All; - GenericListener listener = new GenericListener(); - MySqlTrace.Listeners.Add(listener); - try - { - MovieRelease mr = db.MovieReleases.Create(); - mr.Id = 1; - mr.Name = "Commercial"; - db.MovieReleases.Add(mr); - db.SaveChanges(); - mr.Name = "Director's Cut"; - db.SaveChanges(); - } - finally - { - db.Database.ExecuteSqlCommand(@"DROP TABLE IF EXISTS `MovieReleases`"); - } - // Check sql - Regex rx = new Regex(@"Query Opened: (?UPDATE .*)", RegexOptions.Compiled | RegexOptions.Singleline); - foreach (string s in listener.Strings) - { - Match m = rx.Match(s); - if (m.Success) - { - CheckSql(m.Groups["item"].Value, SQLSyntax.UpdateWithSelectWithNonDbGeneratedLock); - //Assert.Pass(); - } - } - //Assert.Fail(); - } - } - - /// - /// This tests fix for http://bugs.mysql.com/bug.php?id=64216. - /// - [Test] - public void CheckByteArray() - { -#if DEBUG - Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); -#endif - MovieDBContext db = new MovieDBContext(); - db.Database.Initialize(true); - string dbCreationScript = - ((IObjectContextAdapter)db).ObjectContext.CreateDatabaseScript(); - Regex rx = new Regex(@"`Data` (?[^\),]*)", RegexOptions.Compiled | RegexOptions.Singleline); - Match m = rx.Match(dbCreationScript); - Assert.AreEqual("longblob", m.Groups["type"].Value); - } - - /// - /// Validates a stored procedure call using Code First - /// Bug #14008699 - [Test] - public void CallStoredProcedure() - { -#if DEBUG - Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); -#endif - using (MovieDBContext context = new MovieDBContext()) - { - context.Database.Initialize(true); - context.Database.ExecuteSqlCommand(@"drop procedure if exists `GetCount`"); - context.Database.ExecuteSqlCommand(@"create procedure `GetCount`() begin select 5; end;"); - long count = context.Database.SqlQuery("call GetCount").First(); - - Assert.AreEqual(5, count); - } - } - - /// - /// Tests for fix of http://bugs.mysql.com/bug.php?id=63920 - /// Maxlength error when it's used code-first and inheritance (discriminator generated column) - /// - [Test] - public void Bug63920_Test1() - { -#if DEBUG - Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); -#endif - using (VehicleDbContext context = new VehicleDbContext()) - { - context.Database.Delete(); - context.Database.Initialize(true); - - context.Vehicles.Add(new Car { Id = 1, Name = "Mustang", Year = 2012, CarProperty = "Car" }); - context.Vehicles.Add(new Bike { Id = 101, Name = "Mountain", Year = 2011, BikeProperty = "Bike" }); - context.SaveChanges(); - - var list = context.Vehicles.ToList(); - - int records = -1; - using (MySqlConnection conn = new MySqlConnection(context.Database.Connection.ConnectionString)) - { - conn.Open(); - MySqlCommand cmd = new MySqlCommand("SELECT COUNT(*) FROM Vehicles", conn); - records = Convert.ToInt32(cmd.ExecuteScalar()); - } - - Assert.AreEqual(context.Vehicles.Count(), records); - } - } - - /// - /// Tests for fix of http://bugs.mysql.com/bug.php?id=63920 - /// Key reference generation script error when it's used code-first and a single table for the inherited models - /// - [Test] - public void Bug63920_Test2() - { -#if DEBUG - Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); -#endif - using (VehicleDbContext2 context = new VehicleDbContext2()) - { - context.Database.Delete(); - context.Database.Initialize(true); - - context.Vehicles.Add(new Car2 { Id = 1, Name = "Mustang", Year = 2012, CarProperty = "Car" }); - context.Vehicles.Add(new Bike2 { Id = 101, Name = "Mountain", Year = 2011, BikeProperty = "Bike" }); - context.SaveChanges(); - - var list = context.Vehicles.ToList(); - - int records = -1; - using (MySqlConnection conn = new MySqlConnection(context.Database.Connection.ConnectionString)) - { - conn.Open(); - MySqlCommand cmd = new MySqlCommand("SELECT COUNT(*) FROM Vehicle2", conn); - records = Convert.ToInt32(cmd.ExecuteScalar()); - } - - Assert.AreEqual(context.Vehicles.Count(), records); - } - } - - /// - /// This test fix for precision customization for columns bug (http://bugs.mysql.com/bug.php?id=65001), - /// Trying to customize column precision in Code First does not work). - /// - [Test] - [Ignore("Fix this")] - public void TestPrecisionNscale() - { -#if DEBUG - Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); -#endif - MovieDBContext db = new MovieDBContext(); - db.Database.Initialize(true); - var l = db.Movies.ToList(); - using (MySqlDataReader r = new MySqlCommand($@"select numeric_precision, numeric_scale from information_schema.columns -where table_schema = '{Connection.Database}' and table_name = 'movies' and column_name = 'Price'", Connection).ExecuteReader()) - { - r.Read(); - Assert.AreEqual(16, r.GetInt32(0)); - Assert.AreEqual(2, r.GetInt32(1)); - } - } - - /// - /// Test String types to StoreType for String - /// A string with FixedLength=true will become a char - /// Max Length left empty will be char(max) - /// Max Length(100) will be char(100) - /// while FixedLength=false will result in nvarchar. - /// Max Length left empty will be nvarchar(max) - /// Max Length(100) will be nvarchar(100) - /// - [Test] - public void TestStringTypeToStoreType() - { -#if DEBUG - Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); -#endif - using (VehicleDbContext3 context = new VehicleDbContext3()) - { - if (context.Database.Exists()) context.Database.Delete(); - context.Database.CreateIfNotExists(); - context.Accessories.Add(new Accessory { Name = "Accesory One", Description = "Accesories descriptions", LongDescription = "Some long description" }); - context.SaveChanges(); - - using (MySqlConnection conn = new MySqlConnection(context.Database.Connection.ConnectionString)) - { - conn.Open(); - MySqlCommand query = new MySqlCommand("Select Column_name, Is_Nullable, Data_Type from information_schema.Columns where table_schema ='" + conn.Database + "' and table_name = 'Accessories' and column_name ='Description'", conn); - query.Connection = conn; - MySqlDataReader reader = query.ExecuteReader(); - while (reader.Read()) - { - Assert.AreEqual("Description", reader[0].ToString()); - Assert.AreEqual("NO", reader[1].ToString()); - Assert.AreEqual("mediumtext", reader[2].ToString()); - } - reader.Close(); - - query = new MySqlCommand("Select Column_name, Is_Nullable, Data_Type, character_maximum_length from information_schema.Columns where table_schema ='" + conn.Database + "' and table_name = 'Accessories' and column_name ='Name'", conn); - reader = query.ExecuteReader(); - while (reader.Read()) - { - Assert.AreEqual("Name", reader[0].ToString()); - Assert.AreEqual("NO", reader[1].ToString()); - Assert.AreEqual("varchar", reader[2].ToString()); - Assert.AreEqual("255", reader[3].ToString()); - } - reader.Close(); - - query = new MySqlCommand("Select Column_name, Is_Nullable, Data_Type, character_maximum_length from information_schema.Columns where table_schema ='" + conn.Database + "' and table_name = 'Accessories' and column_name ='LongDescription'", conn); - reader = query.ExecuteReader(); - while (reader.Read()) - { - Assert.AreEqual("LongDescription", reader[0].ToString()); - Assert.AreEqual("NO", reader[1].ToString()); - Assert.AreEqual("longtext", reader[2].ToString()); - Assert.AreEqual("4294967295", reader[3].ToString()); - } - } - } - } - - /// - /// Test fix for http://bugs.mysql.com/bug.php?id=66066 / http://clustra.no.oracle.com/orabugs/bug.php?id=14479715 - /// (Using EF, crash when generating insert with no values.). - /// - [Test] - public void AddingEmptyRow() - { -#if DEBUG - Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); -#endif - using (MovieDBContext ctx = new MovieDBContext()) - { - ctx.Database.Initialize(true); - ctx.EntitySingleColumns.Add(new EntitySingleColumn()); - ctx.SaveChanges(); - } - - using (MovieDBContext ctx2 = new MovieDBContext()) - { - var q = from esc in ctx2.EntitySingleColumns where esc.Id == 1 select esc; - Assert.AreEqual(1, q.Count()); - } - } - - /// - /// Test for identity columns when type is Integer or Guid (auto-generate - /// values) - /// - [Test] - public void IdentityTest() - { -#if DEBUG - Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); -#endif - using (VehicleDbContext context = new VehicleDbContext()) - { - context.Database.ExecuteSqlCommand("SET GLOBAL sql_mode='STRICT_ALL_TABLES'"); - if (context.Database.Exists()) context.Database.Delete(); - context.Database.CreateIfNotExists(); - - // Identity as Guid - Manufacturer nissan = new Manufacturer - { - Name = "Nissan" - }; - Manufacturer ford = new Manufacturer - { - Name = "Ford" - }; - context.Manufacturers.Add(nissan); - context.Manufacturers.Add(ford); - - // Identity as Integer - Distributor dis1 = new Distributor - { - Name = "Distributor1" - }; - Distributor dis2 = new Distributor - { - Name = "Distributor2" - }; - context.Distributors.Add(dis1); - context.Distributors.Add(dis2); - - context.SaveChanges(); - - using (MySqlConnection conn = new MySqlConnection(context.Database.Connection.ConnectionString)) - { - conn.Open(); - - // Validates Guid - MySqlCommand cmd = new MySqlCommand("SELECT * FROM Manufacturers", conn); - MySqlDataReader dr = cmd.ExecuteReader(); - Assert.False(!dr.HasRows, "No records found"); - - while (dr.Read()) - { - string name = dr.GetString(1); - switch (name) - { - case "Nissan": - Assert.AreEqual(dr.GetGuid(0), nissan.ManufacturerId); - Assert.AreEqual(dr.GetGuid(2), nissan.GroupIdentifier); - break; - case "Ford": - Assert.AreEqual(dr.GetGuid(0), ford.ManufacturerId); - Assert.AreEqual(dr.GetGuid(2), ford.GroupIdentifier); - break; - default: - //Assert.Fail(); - break; - } - } - dr.Close(); - - // Validates Integer - cmd = new MySqlCommand("SELECT * FROM Distributors", conn); - dr = cmd.ExecuteReader(); - if (!dr.HasRows) - //Assert.Fail("No records found"); - while (dr.Read()) - { - string name = dr.GetString(1); - switch (name) - { - case "Distributor1": - Assert.AreEqual(dr.GetInt32(0), dis1.DistributorId); - break; - case "Distributor2": - Assert.AreEqual(dr.GetInt32(0), dis2.DistributorId); - break; - default: - //Assert.Fail(); - break; - } - } - dr.Close(); - } - } - } - - /// - /// This test the fix for bug 67377. - /// - [Test] - public void FirstOrDefaultNested() - { -#if DEBUG - Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); -#endif - using (MovieDBContext ctx = new MovieDBContext()) - { - ctx.Database.Initialize(true); - MovieDBInitialize.DoDataPopulation(ctx); - int DirectorId = 1; - var q = ctx.Movies.Where(p => p.Director.ID == DirectorId).Select(p => - new - { - Id = p.ID, - FirstMovieFormat = p.Formats.Count == 0 ? 0.0 : p.Formats.FirstOrDefault().Format - }); - string sql = q.ToString(); -#if DEBUG - Debug.WriteLine(sql); -#endif - int j = q.Count(); - foreach (var r in q) - { - j--; - } - Assert.AreEqual(0, j); - } - } - - /// - /// This tests the fix for bug 73549, Generated Sql does not contain ORDER BY statement whose is requested by LINQ. - /// - [Test] - public void FirstOrDefaultNestedWithOrderBy() - { -#if DEBUG - Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); -#endif - using (SakilaDb db = new SakilaDb()) - { - var q = from cu in db.customers - let curAddr = db.addresses.OrderByDescending(p => p.address_id).Where(p => p.address_id == cu.address_id).FirstOrDefault() - join sto in db.stores on cu.store_id equals sto.store_id - orderby cu.customer_id descending - select new - { - curAddr.city.country.country1 - }; - string sql = q.ToString(); - CheckSql(sql, SQLSyntax.FirstOrDefaultNestedWithOrderBy); -#if DEBUG - Debug.WriteLine(sql); -#endif - int j = q.Count(); - foreach (var r in q) - { - //Debug.WriteLine( r.country1 ); - } - Assert.AreEqual(599, j); - } - } - - /// - /// SUPPORT FOR DATE TYPES WITH PRECISION - /// - [Test] - public void CanDefineDatesWithPrecisionFor56() - { -#if DEBUG - Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); -#endif - - if (Version < new Version(5, 6)) return; - - using (var db = new ProductsDbContext()) - { - db.Database.Initialize(true); - using (MySqlConnection conn = new MySqlConnection(db.Database.Connection.ConnectionString)) - { - conn.Open(); - MySqlCommand query = new MySqlCommand("Select Column_name, Is_Nullable, Data_Type, DateTime_Precision from information_schema.Columns where table_schema ='" + conn.Database + "' and table_name = 'Products' and column_name ='DateTimeWithPrecision'", conn); - query.Connection = conn; - MySqlDataReader reader = query.ExecuteReader(); - while (reader.Read()) - { - Assert.AreEqual("DateTimeWithPrecision", reader[0].ToString()); - Assert.AreEqual("NO", reader[1].ToString()); - Assert.AreEqual("datetime", reader[2].ToString()); - Assert.AreEqual("3", reader[3].ToString()); - } - reader.Close(); - - query = new MySqlCommand("Select Column_name, Is_Nullable, Data_Type, DateTime_Precision from information_schema.Columns where table_schema ='" + conn.Database + "' and table_name = 'Products' and column_name ='TimeStampWithPrecision'", conn); - query.Connection = conn; - reader = query.ExecuteReader(); - while (reader.Read()) - { - Assert.AreEqual("TimeStampWithPrecision", reader[0].ToString()); - Assert.AreEqual("NO", reader[1].ToString()); - Assert.AreEqual("timestamp", reader[2].ToString()); - Assert.AreEqual("3", reader[3].ToString()); - } - reader.Close(); - } - db.Database.Delete(); - } - } - - /// - /// Orabug #15935094 SUPPORT FOR CURRENT_TIMESTAMP AS DEFAULT FOR DATETIME WITH EF - /// - [Test] - [Ignore("Fix this")] - public void CanDefineDateTimeAndTimestampWithIdentity() - { -#if DEBUG - Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); -#endif - if (Version < new Version(5, 6)) return; - - using (var db = new ProductsDbContext()) - { - db.Database.Initialize(true); - MySqlConnection con = (MySqlConnection)db.Database.Connection; - MySqlCommand cmd = new MySqlCommand("set session sql_mode = '';", con); - con.Open(); - cmd.ExecuteNonQuery(); - con.Close(); - - Product product = new Product - { - //Omitting Identity Columns - DateTimeWithPrecision = DateTime.Now, - TimeStampWithPrecision = DateTime.Now - }; - - db.Products.Add(product); - db.SaveChanges(); - - var updateProduct = db.Products.First(); - updateProduct.DateTimeWithPrecision = new DateTime(2012, 3, 18, 23, 9, 7, 6); - db.SaveChanges(); - - Assert.NotNull(db.Products.First().Timestamp); - Assert.NotNull(db.Products.First().DateCreated); - Assert.AreEqual(new DateTime(2012, 3, 18, 23, 9, 7, 6), db.Products.First().DateTimeWithPrecision); - Assert.AreEqual(1, db.Products.Count()); - db.Database.Delete(); - } - } - - - /// - /// Test of fix for bug Support for EntityFramework 4.3 Code First Generated Identifiers (MySql Bug #67285, Oracle bug #16286397). - /// FKs are renamed to met http://dev.mysql.com/doc/refman/5.0/en/identifiers.html limitations. - /// - [Test] - public void LongIdentifiersInheritanceTPT() - { -#if DEBUG - Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); -#endif - using (DinosauriaDBContext db = new DinosauriaDBContext()) - { - db.Database.Initialize(true); - Tyrannosauridae ty = new Tyrannosauridae() { Id = 1, Name = "Genghis Rex", SpecieName = "TRex", Weight = 1000 }; - db.dinos.Add(ty); - Oviraptorosauria ovi = new Oviraptorosauria() { Id = 2, EggsPerYear = 100, Name = "John the Velociraptor", SpecieName = "Oviraptor" }; - db.dinos.Add(ovi); - db.SaveChanges(); - } - } - - - /// - /// Test fix for http://bugs.mysql.com/bug.php?id=67183 - /// (Malformed Query while eager loading with EF 4 due to multiple projections). - /// - [Test] - public void ShipTest() - { -#if DEBUG - Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); -#endif - using (var context = new ShipContext()) - { - context.Database.Initialize(true); - - var harbor = new Harbor - { - Ships = new HashSet - { - new Ship - { - CrewMembers = new HashSet - { - new CrewMember - { - Rank = new Rank { Description = "Rank A" }, - Clearance = new Clearance { Description = "Clearance A" }, - Description = "CrewMember A" - }, - new CrewMember - { - Rank = new Rank { Description = "Rank B" }, - Clearance = new Clearance { Description = "Clearance B" }, - Description = "CrewMember B" - } - }, - Description = "Ship AB" - }, - new Ship - { - CrewMembers = new HashSet - { - new CrewMember - { - Rank = new Rank { Description = "Rank C" }, - Clearance = new Clearance { Description = "Clearance C" }, - Description = "CrewMember C" - }, - new CrewMember - { - Rank = new Rank { Description = "Rank D" }, - Clearance = new Clearance { Description = "Clearance D" }, - Description = "CrewMember D" - } - }, - Description = "Ship CD" - } - }, - Description = "Harbor ABCD" - }; - - context.Harbors.Add(harbor); - context.SaveChanges(); - } - - using (var context = new ShipContext()) - { - DbSet dbSet = context.Set(); - IQueryable query = dbSet; - query = query.Include(entity => entity.Ships); - query = query.Include(entity => entity.Ships.Select(s => s.CrewMembers)); - query = query.Include(entity => entity.Ships.Select(s => s.CrewMembers.Select(cm => cm.Rank))); - query = query.Include(entity => entity.Ships.Select(s => s.CrewMembers.Select(cm => cm.Clearance))); - - string[] data = new string[] { - "1,Harbor ABCD,1,1,1,Ship AB,1,1,1,1,1,CrewMember A,1,Rank A,1,Clearance A", - "1,Harbor ABCD,1,1,1,Ship AB,1,2,1,2,2,CrewMember B,2,Rank B,2,Clearance B", - "1,Harbor ABCD,1,2,1,Ship CD,1,3,2,3,3,CrewMember C,3,Rank C,3,Clearance C", - "1,Harbor ABCD,1,2,1,Ship CD,1,4,2,4,4,CrewMember D,4,Rank D,4,Clearance D" - }; - Dictionary outData = new Dictionary(); - - var sqlString = query.ToString(); - CheckSql(sqlString, SQLSyntax.ShipQueryMalformedDueMultipleProjecttionsCorrectedEF6); - // see below for the generated SQL query - - var harbor = query.Single(); - - foreach (var ship in harbor.Ships) - { - foreach (var crewMember in ship.CrewMembers) - { - outData.Add(string.Format( - "{0},{1},1,{2},{3},{4},1,{5},{6},{7},{8},{9},{10},{11},{12},{13}", - harbor.HarborId, harbor.Description, ship.ShipId, harbor.HarborId, - ship.Description, crewMember.CrewMemberId, crewMember.ShipId, crewMember.RankId, - crewMember.ClearanceId, crewMember.Description, crewMember.Rank.RankId, - crewMember.Rank.Description, crewMember.Clearance.ClearanceId, - crewMember.Clearance.Description), null); - } - } - // check data integrity - Assert.AreEqual(outData.Count, data.Length); - for (int i = 0; i < data.Length; i++) - { - Assert.True(outData.ContainsKey(data[i])); - } - } - } - - /// - /// Tests fix for bug http://bugs.mysql.com/bug.php?id=68513, Error in LINQ to Entities query when using Distinct().Count(). - /// - [Test] - public void DistinctCount() - { -#if DEBUG - Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); -#endif - using (SiteDbContext ctx = new SiteDbContext()) - { - ctx.Database.Initialize(true); - visitante v1 = new visitante() { nCdSite = 1, nCdVisitante = 1, sDsIp = "x1" }; - visitante v2 = new visitante() { nCdSite = 1, nCdVisitante = 2, sDsIp = "x2" }; - site s1 = new site() { nCdSite = 1, sDsTitulo = "MyNewsPage" }; - site s2 = new site() { nCdSite = 2, sDsTitulo = "MySearchPage" }; - ctx.Visitante.Add(v1); - ctx.Visitante.Add(v2); - ctx.Site.Add(s1); - ctx.Site.Add(s2); - ctx.SaveChanges(); - - var q = (from vis in ctx.Visitante.Include("site") - group vis by vis.nCdSite into g - select new retorno - { - Key = g.Key, - Online = g.Select(e => e.sDsIp).Distinct().Count() - }); - string sql = q.ToString(); - CheckSql(sql, SQLSyntax.CountGroupBy); - var q2 = q.ToList(); - foreach (var row in q2) - { - } - } - } - - /// - /// Tests fix for bug http://bugs.mysql.com/bug.php?id=68513, Error in LINQ to Entities query when using Distinct().Count(). - /// - [Test] - public void DistinctCount2() - { -#if DEBUG - Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); -#endif - using (SiteDbContext ctx = new SiteDbContext()) - { - ctx.Database.Initialize(true); - visitante v1 = new visitante() { nCdSite = 1, nCdVisitante = 1, sDsIp = "x1" }; - visitante v2 = new visitante() { nCdSite = 1, nCdVisitante = 2, sDsIp = "x2" }; - site s1 = new site() { nCdSite = 1, sDsTitulo = "MyNewsPage" }; - site s2 = new site() { nCdSite = 2, sDsTitulo = "MySearchPage" }; - pagina p1 = new pagina() { nCdPagina = 1, nCdVisitante = 1, sDsTitulo = "index.html" }; - ctx.Visitante.Add(v1); - ctx.Visitante.Add(v2); - ctx.Site.Add(s1); - ctx.Site.Add(s2); - ctx.Pagina.Add(p1); - ctx.SaveChanges(); - - var q = (from pag in ctx.Pagina.Include("visitante").Include("site") - group pag by pag.visitante.nCdSite into g - select new retorno - { - Key = g.Key, - Online = g.Select(e => e.visitante.sDsIp).Distinct().Count() - }); - string sql = q.ToString(); - CheckSql(sql, SQLSyntax.CountGroupBy2); - var q2 = q.ToList(); - foreach (var row in q2) - { - } - } - } - - /// - /// Tests fix for bug http://bugs.mysql.com/bug.php?id=65723, MySql Provider for EntityFramework produces "bad" SQL for OrderBy. - /// - [Test] - public void BadOrderBy() - { -#if DEBUG - Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); -#endif - using (MovieDBContext db = new MovieDBContext()) - { - db.Database.Initialize(true); - MovieDBInitialize.DoDataPopulation(db); - DateTime filterDate = new DateTime(1986, 1, 1); - var q = db.Movies.Where(p => p.ReleaseDate >= filterDate). - OrderByDescending(p => p.ReleaseDate).Take(2); - string sql = q.ToString(); - CheckSql(SQLSyntax.NestedOrderBy, sql); - // Data integrity testing - Movie[] data = new Movie[] { - new Movie() { ID = 4, Title = "Star Wars, The Sith Revenge", ReleaseDate = new DateTime( 2005, 5, 19 ) }, - new Movie() { ID = 2, Title = "The Matrix", ReleaseDate = new DateTime( 1999, 3, 31 ) } - }; - int i = 0; - foreach (Movie m in q) - { - Assert.AreEqual(data[i].ID, m.ID); - Assert.AreEqual(data[i].Title, m.Title); - Assert.AreEqual(data[i].ReleaseDate, m.ReleaseDate); - i++; - } - Assert.AreEqual(2, i); - } - } - - /// - /// Tests fix for bug http://bugs.mysql.com/bug.php?id=69751, Invalid SQL query generated for query with Contains, OrderBy, and Take. - /// - [Test] - public void BadContainsOrderByTake() - { -#if DEBUG - Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); -#endif - using (MovieDBContext db = new MovieDBContext()) - { - db.Database.Initialize(true); - MovieDBInitialize.DoDataPopulation(db); - string title = "T"; - var q = from m in db.Movies - where m.Title.Contains(title) - orderby m.ID descending - select m; - var q1 = q.Take(10); - string sql = q1.ToString(); - - CheckSql(SQLSyntax.QueryWithOrderByTakeContains, sql); - - int i = 0; - foreach (var row in q1) - { - Assert.AreEqual(MovieDBInitialize.data[i].ID, row.ID); - Assert.AreEqual(MovieDBInitialize.data[i].Title, row.Title); - Assert.AreEqual(MovieDBInitialize.data[i].ReleaseDate, row.ReleaseDate); - i++; - } - } - } - - /// - /// Tests fix for bug http://bugs.mysql.com/bug.php?id=69922, Unknown column Extent1... - /// - [Test] - public void BadAliasTable() - { -#if DEBUG - Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); -#endif - using (PromotionsDB db = new PromotionsDB()) - { - db.Database.Initialize(true); - DateTime now = DateTime.Now; - var q = db - .HomePromoes - .Where(x => - x.Active - && - (x.ActiveFrom == null || x.ActiveFrom <= now) - && - (x.ActiveTo == null || x.ActiveTo >= now) - ) - .OrderBy(x => x.DisplayOrder).Select(d => d); - string sql = q.ToString(); - foreach (var row in q) - { - } - } - } - - /// - /// Tests other variants of bug http://bugs.mysql.com/bug.php?id=69751, Invalid SQL query generated for query with Contains, OrderBy, and Take. - /// - [Test] - public void BadContainsOrderByTake2() - { -#if DEBUG - Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); -#endif - using (MovieDBContext db = new MovieDBContext()) - { - db.Database.Initialize(true); - MovieDBInitialize.DoDataPopulation(db); - var q = db.Movies. - Where(m => !string.IsNullOrEmpty(m.Title) && m.Title.Contains("x")). - OrderByDescending(m => m.ID). - Skip(1). - Take(1); - string sql = q.ToString(); -#if DEBUG - Debug.WriteLine(sql); -#endif - List l = q.ToList(); - int j = l.Count; - foreach (Movie m in l) - { - j--; - } - Assert.AreEqual(0, j); - } - } - - /// - /// Tests other variants of bug http://bugs.mysql.com/bug.php?id=69751, Invalid SQL query generated for query with Contains, OrderBy, and Take. - /// - [Test] - public void BadContainsOrderByTake3() - { -#if DEBUG - Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); -#endif - using (MovieDBContext db = new MovieDBContext()) - { - db.Database.Initialize(true); - MovieDBInitialize.DoDataPopulation(db); - var q = db.Movies. - Where(m => !string.IsNullOrEmpty(m.Title) && m.Title.Contains("x")). - OrderByDescending(m => m.ID). - Skip(1). - Take(1).Select(m => new - { - Id = m.ID, - CriticsScore = ( - m.Title == "Terminator 1" ? "Good" : - m.Title == "Predator" ? "Sunday best, cheese" : - m.Title == "The Matrix" ? "Really Good" : - m.Title == "Star Wars, The Sith Revenge" ? "Really Good" : "Unknown") - }); - string sql = q.ToString(); -#if DEBUG - Debug.WriteLine(sql); -#endif - int j = q.Count(); - foreach (var row in q) - { - j--; - } - Assert.AreEqual(0, j); - } - } - - /// - /// Tests other variants of bug http://bugs.mysql.com/bug.php?id=69751, Invalid SQL query generated for query with Contains, OrderBy, and Take. - /// - [Test] - public void BadContainsOrderByTake4() - { -#if DEBUG - Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); -#endif - using (MovieDBContext db = new MovieDBContext()) - { - db.Database.Initialize(true); - MovieDBInitialize.DoDataPopulation(db); - bool q = db.Movies.Any(m => m.ReleaseDate.Year > 1985); - // string sql = q.ToString(); - //#if DEBUG - // Debug.WriteLine(sql); - //#endif - //foreach (var row in q) - //{ - //} - } - } - - /// - /// Tests other variants of bug http://bugs.mysql.com/bug.php?id=69751, Invalid SQL query generated for query with Contains, OrderBy, and Take. - /// - [Test] - public void BadContainsOrderByTake5() - { -#if DEBUG - Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); -#endif - using (MovieDBContext db = new MovieDBContext()) - { - db.Database.Initialize(true); - MovieDBInitialize.DoDataPopulation(db); - // TODO: add subquery like - // var shifts = Shifts.Where(s => !EmployeeShifts.Where(es => es.ShiftID == s.ShiftID).Any()); - bool q = db.Movies.Where(m => m.ReleaseDate.Month != 10).Any(m => m.ReleaseDate.Year > 1985); - // string sql = q.ToString(); - //#if DEBUG - // Debug.WriteLine(sql); - //#endif - // foreach (var row in q) - // { - // } - } - } - - /// - /// Tests other variants of bug http://bugs.mysql.com/bug.php?id=69751, Invalid SQL query generated for query with Contains, OrderBy, and Take. - /// - [Test] - public void BadContainsOrderByTake6() - { -#if DEBUG - Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); -#endif - using (MovieDBContext db = new MovieDBContext()) - { - db.Database.Initialize(true); - MovieDBInitialize.DoDataPopulation(db); - var q = from m in db.Movies - where m.Title.Contains("x") && db.Medias.Where(mm => mm.Format == "Digital").Any() - select m; - string sql = q.ToString(); -#if DEBUG - Debug.WriteLine(sql); -#endif - int j = q.Count(); - foreach (var row in q) - { - j--; - } - Assert.AreEqual(0, j); - } - } - - /// - /// Test for Mysql Bug 70602: http://bugs.mysql.com/bug.php?id=70602 - /// - [Test] - public void AutoIncrementBug() - { -#if DEBUG - Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); -#endif - AutoIncrementBugContext dbContext = new AutoIncrementBugContext(); - - dbContext.Database.Initialize(true); - dbContext.AutoIncrementBug.Add(new AutoIncrementBug() { Description = "Test" }); - dbContext.SaveChanges(); - using (var reader = MySqlHelper.ExecuteReader(dbContext.Database.Connection.ConnectionString, - $"SHOW COLUMNS FROM {nameof(dbContext.AutoIncrementBug)}s WHERE UPPER(EXTRA) LIKE '%AUTO_INCREMENT%'")) - { - Assert.True(reader.HasRows); - } - dbContext.Database.Delete(); - } - - [Test] - public void SimpleCodeFirstSelectCbc() - { - MovieCodedBasedConfigDBContext db = new MovieCodedBasedConfigDBContext(); - db.Database.Initialize(true); - var l = db.Movies.ToList(); - foreach (var i in l) - { - Console.WriteLine(i); - } - } - - [Test] - [Ignore("Need to check. Bad statemen: CALL `MovieCodedBasedConfigDBContext`.``insert_movie``(@movie_name, @ReleaseDate, @Genre, @Price)")] - public void TestStoredProcedureMapping() - { - using (var db = new MovieCodedBasedConfigDBContext()) - { - db.Database.Initialize(true); - var movie = new MovieCBC() - { - Title = "Sharknado", - Genre = "Documental", - Price = 1.50M, - ReleaseDate = DateTime.Parse("01/07/2013") - }; - - db.Movies.Add(movie); - db.SaveChanges(); - movie.Genre = "Fiction"; - db.SaveChanges(); - db.Movies.Remove(movie); - db.SaveChanges(); - } - } - - [Test] - public void MigrationHistoryConfigurationTest() - { - MovieCodedBasedConfigDBContext db = new MovieCodedBasedConfigDBContext(); - db.Database.Initialize(true); - var l = db.Movies.ToList(); - foreach (var i in l) - { - } - var result = MySqlHelper.ExecuteScalar($"server=localhost;User Id=root;database={db.Database.Connection.Database};logging=true; port=" + Port + ";", "SELECT COUNT(_MigrationId) FROM __MySqlMigrations;"); - Assert.AreEqual(1, int.Parse(result.ToString())); - } - - [Test] - public void DbSetRangeTest() - { - using (MovieDBContext db = new MovieDBContext()) - { - db.Database.Initialize(true); - Movie m1 = new Movie() { Title = "Terminator 1", ReleaseDate = new DateTime(1984, 10, 26) }; - Movie m2 = new Movie() { Title = "The Matrix", ReleaseDate = new DateTime(1999, 3, 31) }; - Movie m3 = new Movie() { Title = "Predator", ReleaseDate = new DateTime(1987, 6, 12) }; - Movie m4 = new Movie() { Title = "Star Wars, The Sith Revenge", ReleaseDate = new DateTime(2005, 5, 19) }; - db.Movies.AddRange(new Movie[] { m1, m2, m3, m4 }); - db.SaveChanges(); - var q = from m in db.Movies select m; - Assert.AreEqual(4, q.Count()); - foreach (var row in q) - { - } - db.Movies.RemoveRange(q.ToList()); - db.SaveChanges(); - var q2 = from m in db.Movies select m; - Assert.AreEqual(0, q2.Count()); - } - } - - [Test] - public void EnumSupportTest() - { - using (var dbCtx = new EnumTestSupportContext()) - { - dbCtx.Database.Initialize(true); - dbCtx.SchoolSchedules.Add(new SchoolSchedule() { TeacherName = "Pako", Subject = SchoolSubject.History }); - dbCtx.SaveChanges(); - - var schedule = (from s in dbCtx.SchoolSchedules - where s.Subject == SchoolSubject.History - select s).FirstOrDefault(); - - Assert.AreNotEqual(null, schedule); - Assert.AreEqual(SchoolSubject.History, schedule.Subject); - } - } - - - [Test] - [Ignore("This test needs MicrosoftSqlServer.Types which is not available for all the target frameworks.")] - public void SpatialSupportTest() - { - using (var dbCtx = new JourneyContext()) - { - dbCtx.Database.Initialize(true); - dbCtx.MyPlaces.Add(new MyPlace() - { - name = "JFK INTERNATIONAL AIRPORT OF NEW YORK", - location = DbGeometry.FromText("POINT(40.644047 -73.782291)"), - }); - dbCtx.MyPlaces.Add(new MyPlace - { - name = "ALLEY POND PARK", - location = DbGeometry.FromText("POINT(40.745696 -73.742638)") - }); - dbCtx.MyPlaces.Add(new MyPlace - { - name = "CUNNINGHAM PARK", - location = DbGeometry.FromText("POINT(40.735031 -73.768387)") - }); - dbCtx.MyPlaces.Add(new MyPlace - { - name = "QUEENS VILLAGE STATION", - location = DbGeometry.FromText("POINT(40.717957 -73.736501)") - }); - dbCtx.SaveChanges(); - - var place = (from p in dbCtx.MyPlaces - where p.name == "JFK INTERNATIONAL AIRPORT OF NEW YORK" - select p).FirstOrDefault(); - - var point = DbGeometry.FromText("POINT(40.717957 -73.736501)"); - - var distance = (point.Distance(place.location) * 100); - - Assert.AreNotEqual(null, place); - Assert.AreEqual(8.6944880240295852D, distance.Value); - - var points = from p in dbCtx.MyPlaces - select new { name = p.name, location = p.location }; - foreach (var item in points) - { - var distanceX = DbGeometry.FromText("POINT(40.717957 -73.736501)").Distance(item.location) * 100; - Assert.IsNotNull(distanceX); - } - - foreach (MyPlace p in dbCtx.MyPlaces) - dbCtx.MyPlaces.Remove(p); - dbCtx.SaveChanges(); - - dbCtx.MyPlaces.Add(new MyPlace - { - name = "AGraphic Design Institute", - location = DbGeometry.FromText(string.Format("POINT({0} {1})", -122.336106, 47.605049), 101) - }); - - dbCtx.MyPlaces.Add(new MyPlace - { - name = "AGraphic Design Institute", - location = DbGeometry.FromText("POINT(-123.336106 47.605049)", 102) - }); - - dbCtx.MyPlaces.Add(new MyPlace - { - name = "BGraphic Design Institute", - location = DbGeometry.FromText("POINT(-113.336106 47.605049)", 103) - }); - - dbCtx.MyPlaces.Add(new MyPlace - { - name = "Graphic Design Institute", - location = DbGeometry.FromText(string.Format("POINT({0} {1})", 51.5, -1.28), 4326) - }); - dbCtx.SaveChanges(); - - var result = (from u in dbCtx.MyPlaces select u.location.CoordinateSystemId).ToList(); - foreach (var item in result) - Assert.IsNotNull(item); - var res = dbCtx.MyPlaces.OrderBy(q => q.name.Take(1).Skip(1).ToList()); - Assert.IsNotNull(res); - - var pointA1 = DbGeometry.FromText(string.Format("POINT(40.644047 -73.782291)")); - var pointB1 = DbGeometry.FromText("POINT(40.717957 -73.736501)"); - var distance1 = pointA1.Distance(pointB1); - - var pointA2 = DbGeometry.FromText("POINT(2.5 2.5)"); - var pointB2 = DbGeometry.FromText("POINT(4 0.8)"); - var distance2 = pointA2.Distance(pointB2); - - var pointA3 = DbGeometry.FromText("POINT(3 -4)"); - var pointB3 = DbGeometry.FromText("POINT(-1 3)"); - var distance3 = pointA3.Distance(pointB3); - - Assert.True(distance1.Value == 0.086944880240295855 && distance2.Value == 2.2671568097509267 && - distance3.Value == 8.06225774829855); - - } - } - - [Test] - public void BeginTransactionSupportTest() - { - using (var dbcontext = new MovieCodedBasedConfigDBContext()) - { - dbcontext.Database.Initialize(true); - using (var transaction = dbcontext.Database.BeginTransaction()) - { - try - { - dbcontext.Movies.Add(new MovieCBC() - { - Title = "Sharknado", - Genre = "Documental", - Price = 1.50M, - ReleaseDate = DateTime.Parse("01/07/2013") - }); - - dbcontext.SaveChanges(); - var result = MySqlHelper.ExecuteScalar("server=localhost;User Id=root;database=test;logging=true;port=" + Port + ";", "select COUNT(*) from moviecbcs;"); - Assert.AreEqual(0, int.Parse(result.ToString())); - - transaction.Commit(); - - result = MySqlHelper.ExecuteScalar("server=localhost;User Id=root;database=test;logging=true; port=" + Port + ";", "select COUNT(*) from moviecbcs;"); - Assert.AreEqual(1, int.Parse(result.ToString())); - } - catch (Exception) - { - transaction.Rollback(); - } - } - } - } - - /// - /// This test covers two new features on EF6: - /// 1- "DbContext.Database.UseTransaction, that use a transaction created from an open connection" - /// 2- "DbContext can now be created with a DbConnection that is already opened" - /// - [Test] - public void UseTransactionSupportTest() - { - using (var context = new MovieCodedBasedConfigDBContext()) - { - context.Database.CreateIfNotExists(); - } - using (var connection = new MySqlConnection($"server=localhost;User Id=root;database={nameof(MovieCodedBasedConfigDBContext)};logging=true; port=" + Port + ";")) - { - connection.Open(); - using (var transaction = connection.BeginTransaction()) - { - try - { - using (var dbcontext = new MovieCodedBasedConfigDBContext(connection, contextOwnsConnection: false)) - { - dbcontext.Database.Initialize(true); - dbcontext.Database.UseTransaction(transaction); - dbcontext.Movies.Add(new MovieCBC() - { - Title = "Sharknado", - Genre = "Documental", - Price = 1.50M, - ReleaseDate = DateTime.Parse("01/07/2013") - }); - - dbcontext.SaveChanges(); - } - var result = MySqlHelper.ExecuteScalar("server=localhost;User Id=root;database=test;logging=true; port=" + Port + ";", "select COUNT(*) from moviecbcs;"); - Assert.AreEqual(0, int.Parse(result.ToString())); - - transaction.Commit(); - - result = MySqlHelper.ExecuteScalar("server=localhost;User Id=root;database=test;logging=true; port=" + Port + ";", "select COUNT(*) from moviecbcs;"); - Assert.AreEqual(1, int.Parse(result.ToString())); - } - catch (Exception) - { - transaction.Rollback(); - } - } - } - } - - [Test] - [Ignore("Need to check. Bad statemen: CALL `MovieCodedBasedConfigDBContext`.``insert_movie``(@movie_name, @ReleaseDate, @Genre, @Price)")] - public void HasChangesSupportTest() - { - using (var dbcontext = new MovieCodedBasedConfigDBContext()) - { - dbcontext.Database.Initialize(true); - - dbcontext.Movies.Add(new MovieCBC() - { - Title = "Sharknado", - Genre = "Documental", - Price = 1.50M, - ReleaseDate = DateTime.Parse("01/07/2013") - }); - - Assert.True(dbcontext.ChangeTracker.HasChanges()); - dbcontext.SaveChanges(); - Assert.False(dbcontext.ChangeTracker.HasChanges()); - } - } - - [Test] - [Ignore("Need to check. Bad statemen: CALL `MovieCodedBasedConfigDBContext`.``insert_movie``(@movie_name, @ReleaseDate, @Genre, @Price)")] - public void MySqlLoggingToFileSupportTest() - { - string logName = "mysql.log"; - //if (System.IO.File.Exists(logName)) - // System.IO.File.Delete(logName); - - using (var dbcontext = new MovieCodedBasedConfigDBContext()) - { - dbcontext.Database.Log = MySqlLogger.Logger(logName, true).Write; - - dbcontext.Database.Initialize(true); - dbcontext.Movies.Add(new MovieCBC() - { - Title = "Sharknado", - Genre = "Documental", - Price = 1.50M, - ReleaseDate = DateTime.Parse("01/07/2013") - }); - dbcontext.SaveChanges(); - } - - Assert.AreEqual(true, System.IO.File.Exists(logName)); - } - - [Test] - [Ignore("Need to check. Bad statemen: CALL `MovieCodedBasedConfigDBContext`.``insert_movie``(@movie_name, @ReleaseDate, @Genre, @Price)")] - public void MySqlLoggingToConsoleSupportTest() - { - string logName = "mysql_2.log"; - if (System.IO.File.Exists(logName)) - System.IO.File.Delete(logName); - - System.IO.FileStream file; - System.IO.StreamWriter writer; - System.IO.TextWriter txtOut = Console.Out; - try - { - file = new System.IO.FileStream(logName, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.Write); - writer = new System.IO.StreamWriter(file); - } - catch (Exception e) - { - throw e; - } - Console.SetOut(writer); - - using (var dbcontext = new MovieCodedBasedConfigDBContext()) - { - dbcontext.Database.Log = new MySqlLogger(s => Console.Write(s)).Write; - - dbcontext.Database.Initialize(true); - dbcontext.Movies.Add(new MovieCBC() - { - Title = "Sharknado", - Genre = "Documental", - Price = 1.50M, - ReleaseDate = DateTime.Parse("01/07/2013") - }); - dbcontext.SaveChanges(); - } - Console.SetOut(txtOut); - writer.Close(); - file.Close(); - - Assert.AreEqual(true, System.IO.File.Exists(logName)); - } - - [Test] - public void EntityAndComplexTypeSupportTest() - { - using (var dbContext = new EntityAndComplexTypeContext()) - { - dbContext.Database.Initialize(true); - dbContext.Students.Add( - new Student() - { - Name = "Pakorasu Pakolas", - Address = new Address() { City = "Mazatlan", Street = "Tierra de Venados 440" }, - Schedule = new List() { new SchoolSchedule() { TeacherName = "Pako", Subject = SchoolSubject.History } } - }); - dbContext.SaveChanges(); - - var student = (from s in dbContext.Students - select s).FirstOrDefault(); - - Assert.AreNotEqual(null, student); - Assert.AreNotEqual(null, student.Schedule); - Assert.AreNotEqual(true, string.IsNullOrEmpty(student.Address.Street)); - Assert.AreNotEqual(0, student.Schedule.Count()); - } - } - - /// - /// TO RUN THIS TEST ITS NECESSARY TO ENABLE THE EXECUTION STRATEGY IN THE CLASS MySqlEFConfiguration (Source\MySql.Data.Entity\MySqlConfiguration.cs) AS WELL AS START A MYSQL SERVER INSTACE WITH THE OPTION "--max_connections=3" - /// WHY 3?: 1)For main process (User: root, DB: mysql). 2)For Setup Class. 3)For the connections in this test. - /// The expected result is that opening a third connection and trying to open a fourth(with an asynchronous task) the execution strategy implementation handle the reconnection process until the third one is closed. - /// - //[Test] //<---DON'T FORGET ME TO RUN! =D - public void ExecutionStrategyTest() - { - var connection = new MySqlConnection("server=localhost;User Id=root;logging=true; port=" + Port + ";"); - using (var dbcontext = new MovieCodedBasedConfigDBContext()) - { - dbcontext.Database.Initialize(true); - dbcontext.Movies.Add(new MovieCBC() - { - Title = "Sharknado", - Genre = "Documental", - Price = 1.50M, - ReleaseDate = DateTime.Parse("01/07/2013") - }); - connection.Open(); - System.Threading.Tasks.Task.Factory.StartNew(() => { dbcontext.SaveChanges(); }); - Thread.Sleep(1000); - connection.Close(); - connection.Dispose(); - } - var result = MySqlHelper.ExecuteScalar("server=localhost;User Id=root;database=test;logging=true; port=" + Port + ";", "select COUNT(*) from moviecbcs;"); - Assert.AreEqual(1, int.Parse(result.ToString())); - } - - [Test] - public void UnknownProjectC1() - { -#if DEBUG - Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); -#endif - using (MovieDBContext db = new MovieDBContext()) - { - db.Database.Initialize(true); - MovieDBInitialize.DoDataPopulation(db); - long myKey = 20; - var q = (from r in db.Movies where (r.ID == myKey) select (long)r.ID).OrderBy(p => p); - string sql = q.ToString(); - CheckSql(sql, SQLSyntax.UnknownProjectC1EF6); - -#if DEBUG - Debug.WriteLine(sql); -#endif - long[] array = (from r in db.Movies where (r.ID == myKey) select (long)r.ID).OrderBy(p => p).ToArray(); - } - } - - [Test] - public void StartsWithTest() - { -#if DEBUG - Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); -#endif - MovieDBContext db = new MovieDBContext(); - db.Database.Initialize(true); - MovieDBInitialize.DoDataPopulation(db); - string term = "The"; - var l = db.Movies.Where(p => p.Title.StartsWith(term)); - - string sql = l.ToString(); - - CheckSql(sql, SQLSyntax.QueryWithStartsWith); - -#if DEBUG - Debug.WriteLine(sql); -#endif - int j = l.Count(); - foreach (var i in l) - { - j--; - } - Assert.AreEqual(0, j); - } - - [Test] - public void EndsWithTest() - { -#if DEBUG - Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); -#endif - MovieDBContext db = new MovieDBContext(); - db.Database.Initialize(true); - MovieDBInitialize.DoDataPopulation(db); - string term = "The"; - var l = db.Movies.Where(p => p.Title.EndsWith(term)); - - string sql = l.ToString(); - - CheckSql(sql, SQLSyntax.QueryWithEndsWith); - -#if DEBUG - Debug.WriteLine(sql); -#endif - int j = l.Count(); - foreach (var i in l) - { - j--; - } - Assert.AreEqual(0, j); - } - - [Test] - public void ContainsTest() - { -#if DEBUG - Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); -#endif - MovieDBContext db = new MovieDBContext(); - db.Database.Initialize(true); - MovieDBInitialize.DoDataPopulation(db); - string term = "The"; - var l = db.Movies.Where(p => p.Title.Contains(term)); - - string sql = l.ToString(); - CheckSql(sql, SQLSyntax.QueryWithContains); - -#if DEBUG - Debug.WriteLine(sql); -#endif - int j = l.Count(); - foreach (var i in l) - { - j--; - } - Assert.AreEqual(0, j); - } - - - /// - /// Test to reproduce bug http://bugs.mysql.com/bug.php?id=73643, Exception when using IEnumera.Contains(model.property) in Where predicate - /// - [Test] - public void TestContainsListWithCast() - { -#if DEBUG - Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); -#endif - using (MovieDBContext db = new MovieDBContext()) - { - db.Database.Initialize(true); - - long[] longs = new long[] { 1, 2, 3 }; - var q = db.Movies.Where(p => longs.Contains((long)p.ID)); - string sql = q.ToString(); - CheckSql(sql, SQLSyntax.TestContainsListWithCast); -#if DEBUG - Debug.WriteLine(sql); -#endif - var l = q.ToList(); - } - } - - /// - /// Test to reproduce bug http://bugs.mysql.com/bug.php?id=73643, Exception when using IEnumera.Contains(model.property) in Where predicate - /// - [Test] - public void TestContainsListWitConstant() - { -#if DEBUG - Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); -#endif - using (MovieDBContext db = new MovieDBContext()) - { - db.Database.Initialize(true); - - List strIds = new List(new string[] { "two" }); - var q = db.Movies.Where(p => strIds.Contains("two")); - string sql = q.ToString(); - CheckSql(sql, SQLSyntax.TestContainsListWitConstant); -#if DEBUG - Debug.WriteLine(sql); -#endif - var l = q.ToList(); - } - } - - /// - /// Test to reproduce bug http://bugs.mysql.com/bug.php?id=73643, Exception when using IEnumera.Contains(model.property) in Where predicate - /// - [Test] - public void TestContainsListWithParameterReference() - { -#if DEBUG - Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); -#endif - using (MovieDBContext db = new MovieDBContext()) - { - db.Database.Initialize(true); - - long[] longs = new long[] { 1, 2, 3 }; - int myNum = 1; - var q = db.Movies.Where(p => longs.Contains(myNum)); - string sql = q.ToString(); - CheckSql(sql, SQLSyntax.TestContainsListWithParameterReference); -#if DEBUG - Debug.WriteLine(sql); -#endif - var l = q.ToList(); - } - } - - [Test] - public void ReplaceTableNameVisitor() - { - using (SakilaDb context = new SakilaDb()) - { - var date = new DateTime(2005, 6, 1); - var rentals = context.customers.Where(t => t.rentals.Any(r => r.rental_date < date)).OrderBy(o => o.customer_id); - string sql = rentals.ToString(); - CheckSql(sql, SQLSyntax.ReplaceNameVisitorQuery); -#if DEBUG - Debug.WriteLine(sql); -#endif - var result = rentals.ToList(); - Assert.AreEqual(520, rentals.Count()); - } - } - - - /// - /// Bug #70941 - Invalid SQL query when eager loading two nested collections - /// - [Test] - public void InvalidQuery() - { - using (UsingUnionContext context = new UsingUnionContext()) - { - if (context.Database.Exists()) - context.Database.Delete(); - - context.Database.Create(); - - for (int i = 1; i <= 3; i++) - { - var order = new Order(); - var items = new List(); - - items.Add(new Item { Id = 1 }); - items.Add(new Item { Id = 2 }); - items.Add(new Item { Id = 3 }); - - order.Items = items; - var client = new Client { Id = i }; - client.Orders = new List(); - client.Orders.Add(order); - - context.Clients.Add(client); - } - context.SaveChanges(); - - var clients = context.Clients - .Include(c => c.Orders.Select(o => o.Items)) - .Include(c => c.Orders.Select(o => o.Discounts)).ToList(); - - Assert.AreEqual(clients.Count(), 3); - Assert.AreEqual(clients.Where(t => t.Id == 1).Single().Orders.Count(), 1); - Assert.AreEqual(clients.Where(t => t.Id == 1).Single().Orders.Where(j => j.Id == 1).Single().Items.Count(), 3); - } - } - - /// - /// Bug #28095165 - CONTRIBUTION: FIX CONCURRENCYCHECK + DATABASEGENERATEDOPTION.COMPUTED - /// - [Test] - public void ConcurrencyCheckWithDbGeneratedColumn() - { -#if DEBUG - Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); -#endif - using (MovieDBContext db = new MovieDBContext()) - { - db.Database.Delete(); - db.Database.CreateIfNotExists(); - db.Database.Log = (e) => Debug.WriteLine(e); - db.Database.ExecuteSqlCommand(@"DROP TABLE IF EXISTS `MovieReleases2`"); - - db.Database.ExecuteSqlCommand( - @"CREATE TABLE IF NOT EXISTS `MovieRelease2` ( - `Id` int(11) NOT NULL, - `Name` varchar(45) NOT NULL, - `Timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - `RowVersion` bigint NOT NULL DEFAULT 0, - PRIMARY KEY (`Id`) - ) ENGINE=InnoDB DEFAULT CHARSET=binary"); - - db.Database.ExecuteSqlCommand( - @"CREATE TRIGGER `trg_MovieRelease2_before_update` - BEFORE UPDATE ON `MovieRelease2` - FOR EACH ROW SET NEW.RowVersion = OLD.RowVersion + 1;"); - - MySqlTrace.Listeners.Clear(); - MySqlTrace.Switch.Level = SourceLevels.All; - GenericListener listener = new GenericListener(); - MySqlTrace.Listeners.Add(listener); - - try - { - MovieRelease2 mr = db.MovieReleases2.Create(); - mr.Id = 1; - mr.Name = "Commercial"; - db.MovieReleases2.Add(mr); - Assert.AreEqual(mr.RowVersion, 0); - db.SaveChanges(); // ADD - Assert.AreEqual(mr.RowVersion, 0); - - mr.Name = "Director's Cut"; - db.SaveChanges(); // UPDATE #1 - Assert.AreEqual(mr.RowVersion, 1); - - mr.Name = "Avengers"; - db.SaveChanges(); // UPDATE #2 - Assert.AreEqual(mr.RowVersion, 2); - } - finally - { - db.Database.ExecuteSqlCommand(@"DROP TABLE IF EXISTS `MovieReleases2`"); - } - // Check sql - Regex rx = new Regex(@"Query Opened: (?UPDATE .*)", RegexOptions.Compiled | RegexOptions.Singleline); - int n = 0; - foreach (string s in listener.Strings) - { - Match m = rx.Match(s); - if (m.Success) - { - if (n++ == 0) - { - CheckSql(m.Groups["item"].Value, SQLSyntax.UpdateWithSelectWithDbGeneratedLock1); - } - else - { - CheckSql(m.Groups["item"].Value, SQLSyntax.UpdateWithSelectWithDbGeneratedLock2); - } - } - } - } - } - - /// - /// Bug #31323788 - EF6 CODE FIRST - TABLE SCHEMAS ARE LOST, BUT AUTOMATIC MIGRATIONS USES THEM - /// - [Test] - public void TablesWithSchema() - { - using (BlogContext context = new BlogContext()) - { - var blog = new Blog { Title = "Blog_1" }; - context.Blog.Add(blog); - - blog = new Blog { Title = "Blog_2" }; - context.Blog.Add(blog); - - context.SaveChanges(); - Assert.AreEqual(2, context.Blog.Count()); - Assert.AreEqual(2, context.Blog.First(b => b.Title == "Blog_2").BlogId); - - context.Blog.Remove(blog); - context.SaveChanges(); - Assert.AreEqual(1, context.Blog.Count()); - Assert.AreEqual("Blog_1", context.Blog.First().Title); - } - } - - [Test, Description("UNION SYNTAX MISSING REQUIRED PARENTHESIS")] - public void UnionSyntax() - { - using (var context = new ContextForString()) - { - context.Database.Delete(); - context.Database.Create(); - context.StringUsers.Add(new StringUser - { - StringUserId = 1, - Name50 = "Juan", - Name100 = "100", - Name200 = "200", - Name300 = "300" - }); - context.StringUsers.Add(new StringUser - { - StringUserId = 2, - Name50 = "Pedro", - Name100 = "cien", - Name200 = "doscientos", - Name300 = "trescientos" - }); - context.StringUsers.Add(new StringUser - { - StringUserId = 3, - Name50 = "Lupe", - Name100 = "101", - Name200 = "cxvbx", - Name300 = "301" - }); - context.StringUsers.Add(new StringUser - { - StringUserId = 4, - Name50 = "Luis", - Name100 = "asdf", - Name200 = "wrwe", - Name300 = "xcvb" - }); - context.StringUsers.Add(new StringUser - { - StringUserId = 5, - Name50 = "Pepe", - Name100 = "asdf", - Name200 = "zxvz", - Name300 = "fgsd" - }); - context.SaveChanges(); - - var query1 = context.StringUsers; - var query2 = query1.Take(0).Concat(query1); - var query3 = query1.Concat(query1.Take(0)); - Assert.True((query1.Count() == 5) & (query2.Count() == 5) & (query3.Count() == 5)); - } - } - - [Test, Description("FK name ,longer than 64 chars are named to FK_")] - public void NormalForeignKey() - { - using (var context = new ContextForNormalFk()) - { - context.Database.Initialize(true); - using (MySqlConnection conn = new MySqlConnection(context.Database.Connection.ConnectionString)) - { - conn.Open(); - var cmd = new MySqlCommand(); - var entityName = (context.Permisos.GetType().FullName.Split(',')[0]).Substring(66).ToLowerInvariant(); - var contextName = context.GetType().Name.ToLowerInvariant(); - cmd.Connection = conn; - cmd.CommandText = - $"SELECT CONSTRAINT_NAME FROM information_schema.REFERENTIAL_CONSTRAINTS WHERE CONSTRAINT_SCHEMA = '{contextName}' and TABLE_NAME = '{entityName}';"; - cmd.ExecuteNonQuery(); - - using (var reader = cmd.ExecuteReader()) - { - while (reader.Read()) - { - var val = reader.GetValue(0); - Assert.True(val.ToString().Contains("FK_")); - } - } - } - } - } - - [Test, Description("FK name ,longer than 64 chars are named to FK_")] - public void LongForeignKey() - { - using (var context = new ContextForLongFk()) - { - context.Database.Initialize(true); - var entityName = (context.Permisos.GetType().FullName.Split(',')[0]).Substring(66).ToLowerInvariant(); - var contextName = context.GetType().Name.ToLowerInvariant(); - using (MySqlConnection conn = new MySqlConnection(context.Database.Connection.ConnectionString)) - { - conn.Open(); - var cmd = new MySqlCommand(); - cmd.Connection = conn; - cmd.CommandText = - $"SELECT CONSTRAINT_NAME FROM information_schema.REFERENTIAL_CONSTRAINTS WHERE CONSTRAINT_SCHEMA = '{contextName}' and TABLE_NAME = '{entityName}';"; - cmd.ExecuteNonQuery(); - - using (var reader = cmd.ExecuteReader()) - { - while (reader.Read()) - { - var val = reader.GetValue(0); - Assert.True(val.ToString().Contains("FK_")); - } - } - } - } - } - - [Test, Description("Verify that Null Reference Exception is not thrown when try to save entity with TINYINT AS PK ")] - public void SaveTinyIntAsPK() - { - using (var context = new ContextForTinyPk()) - { - context.Database.Delete(); - context.Database.Create(); - context.TinyPkUseRs.Add(new TinyPkUser - { - StringUserId = 1, - Name50 = "Juan", - Name100 = "100", - Name200 = "200", - Name300 = "300" - }); - - context.TinyPkUseRs.Add(new TinyPkUser - { - StringUserId = 2, - Name50 = "Pedro", - Name100 = "cien", - Name200 = "doscientos", - Name300 = "trescientos" - }); - - context.TinyPkUseRs.Add(new TinyPkUser - { - StringUserId = 3, - Name50 = "Lupe", - Name100 = "101", - Name200 = "cxvbx", - Name300 = "301" - }); - - context.TinyPkUseRs.Add(new TinyPkUser - { - StringUserId = 4, - Name50 = "Luis", - Name100 = "asdf", - Name200 = "wrwe", - Name300 = "xcvb" - }); - - context.TinyPkUseRs.Add(new TinyPkUser - { - StringUserId = 5, - Name50 = "Pepe", - Name100 = "asdf", - Name200 = "zxvz", - Name300 = "fgsd" - }); - context.SaveChanges(); - var query1 = context.TinyPkUseRs; - var query2 = query1.Take(0).Concat(query1); - var query3 = query1.Concat(query1.Take(0)); - Assert.True((query1.Count() == 5) & (query2.Count() == 5) & (query3.Count() == 5)); - } - } - - [Test, Description("Verify that Null Reference Exception is not thrown when try to save entity with BIGINT AS PK ")] - public void SaveBigIntAsPK() - { - using (var context = new ContextForBigIntPk()) - { - context.Database.Delete(); - context.Database.Create(); - context.BigIntPkUseRs.Add(new BigIntPkUser - { - StringUserId = 934157136952, - Name50 = "Juan", - Name100 = "100", - Name200 = "200", - Name300 = "300" - }); - - context.BigIntPkUseRs.Add(new BigIntPkUser - { - StringUserId = 934157136953, - Name50 = "Pedro", - Name100 = "cien", - Name200 = "doscientos", - Name300 = "trescientos" - }); - - context.BigIntPkUseRs.Add(new BigIntPkUser - { - StringUserId = 9223372036854775807, - Name50 = "Lupe", - Name100 = "101", - Name200 = "cxvbx", - Name300 = "301" - }); - - context.BigIntPkUseRs.Add(new BigIntPkUser - { - StringUserId = 0, - Name50 = "Luis", - Name100 = "asdf", - Name200 = "wrwe", - Name300 = "xcvb" - }); - - context.BigIntPkUseRs.Add(new BigIntPkUser - { - StringUserId = -9223372036854775808, - Name50 = "Pepe", - Name100 = "asdf", - Name200 = "zxvz", - Name300 = "fgsd" - }); - context.SaveChanges(); - var query1 = context.BigIntPkUseRs; - var query2 = query1.Take(0).Concat(query1); - var query3 = query1.Concat(query1.Take(0)); - Assert.True((query1.Count() == 5) & (query2.Count() == 5) & (query3.Count() == 5)); - } - } - - [Test, Description("TRANSACTION AFTER A FAILED TRANSACTION((USING BeginTransaction)) Commit")] - public void BeginTransNested() - { - using (var context = new EnumTestSupportContext()) - { - using (var trans = context.Database.BeginTransaction()) - { - Thread.Sleep(5000); - Assert.Catch(() => context.Database.ExecuteSqlCommand("update table schoolschedule")); - trans.Commit(); - } - using (var trans = context.Database.BeginTransaction()) - { - context.SchoolSchedules.Add(new SchoolSchedule - { - TeacherName = "Ruben", - Subject = SchoolSubject.History - }); - ; - - context.SchoolSchedules.Add(new SchoolSchedule - { - TeacherName = "Peter", - Subject = SchoolSubject.Chemistry - }); - ; - - context.SchoolSchedules.Add(new SchoolSchedule - { - TeacherName = "Juan", - Subject = SchoolSubject.Math - }); - ; - context.SaveChanges(); - trans.Commit(); - } - var count = context.SchoolSchedules.Count(); - Assert.AreEqual(3, count); - //Rollback - using (var trans = context.Database.BeginTransaction()) - { - Assert.Catch(() => context.Database.ExecuteSqlCommand("update table schoolschedule")); - trans.Rollback(); - } - using (var trans = context.Database.BeginTransaction()) - { - context.SchoolSchedules.Add(new SchoolSchedule - { - TeacherName = "Andrew", - Subject = SchoolSubject.History - }); ; - ; - context.SaveChanges(); - trans.Commit(); - } - count = context.SchoolSchedules.Count(); - Assert.AreEqual(4, count); - } - - } - - [Test, Description("TRANSACTION AFTER A FAILED TRANSACTION((USING BeginTransaction)) Stress Test")] - public void TransactionAfterFailStressTest() - { - for (var i = 0; i < 100; i++) - { - using (var context = new EnumTestSupportContext()) - { - using (var trans = context.Database.BeginTransaction()) - { - Assert.Catch(() => context.Database.ExecuteSqlCommand("update table schoolschedule")); - trans.Commit(); - } - using (var trans = context.Database.BeginTransaction()) - { - context.SchoolSchedules.Add(new SchoolSchedule - { - TeacherName = "Ruben", - Subject = SchoolSubject.History - }); - ; - - context.SchoolSchedules.Add(new SchoolSchedule - { - TeacherName = "Peter", - Subject = SchoolSubject.Chemistry - }); - ; - - context.SchoolSchedules.Add(new SchoolSchedule - { - TeacherName = "Juan", - Subject = SchoolSubject.Math - }); - context.SaveChanges(); - trans.Commit(); - var count = context.SchoolSchedules.Count(); - Assert.True(count > 0); - } - } - } - } - - - [Test, Description("Wrong SQL Statement to set primary key ")] - public void WrongSQLStatementPK() - { - using (var context = new EducationContext()) - { - context.Database.Delete(); - context.Database.Create(); - context.Passports.Add(new Passport { Key = 1 }); - context.SaveChanges(); - context.Database.ExecuteSqlCommand("ALTER TABLE `passports` CHANGE `Key` `Key1` int NOT NULL AUTO_INCREMENT UNIQUE"); - context.Database.ExecuteSqlCommand("ALTER TABLE `passports` DROP PRIMARY KEY"); - } - - using (var context = new EducationContext()) - { - context.Passports.Add(new Passport { Key = 1 }); - Exception ex = Assert.Catch(() => context.SaveChanges()); - context.Database.Delete(); - } - } - - /// - /// Bug #34498485 [MySQL.Data.EntityFramework does not handle LIKE (Edm.IndexOf) cases] - /// - [Test] - public void TestListMatchingLike() - { - using (VehicleDbContext2 context = new VehicleDbContext2()) - { - context.Database.Delete(); - context.Database.Initialize(true); - - context.Vehicles.Add(new Car2 { Id = 1, Name = "Mustang", Year = 2012, CarProperty = "Car" }); - context.Vehicles.Add(new Bike2 { Id = 101, Name = "Mountain", Year = 2011, BikeProperty = "Bike" }); - context.SaveChanges(); - - string[] matchText = new string[] { "must", "tan" }; - var list = context.Vehicles.Where(v => matchText.Any(t => v.Name.Contains(t))); - Assert.AreEqual(1, list.Count()); - - matchText = new string[] { "mus't", "tan" }; - list = context.Vehicles.Where(v => matchText.Any(t => v.Name.Contains(t))); - Assert.AreEqual(1, list.Count()); - - matchText = new string[] { "%" }; - list = context.Vehicles.Where(v => matchText.Any(t => v.Name.Contains(t))); - Assert.AreEqual(0, list.Count()); - - matchText = new string[] { "tan" }; - list = context.Vehicles.Where(v => matchText.Any(t => v.Name.Contains(t))); - Assert.AreEqual(1, list.Count()); - - matchText = new string[] { "_" }; - list = context.Vehicles.Where(v => matchText.Any(t => v.Name.Contains(t))); - Assert.AreEqual(0, list.Count()); - } - } - } -} \ No newline at end of file +// Copyright © 2014, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data.EntityFramework.Tests; +using MySql.Data.MySqlClient; +using MySql.EntityFramework.CodeFirst.Tests; +using MySql.EntityFramework.CodeFirst.Tests.Properties; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Data; +using System.Data.Entity; +using System.Data.Entity.Infrastructure; +using System.Data.Entity.Spatial; +using System.Diagnostics; +using System.Linq; +using System.Text.RegularExpressions; +using System.Threading; + +namespace MySql.Data.EntityFramework.CodeFirst.Tests +{ + public class CodeFirstTests : CodeFirstFixture + { + /// + /// Tests for fix of http://bugs.mysql.com/bug.php?id=61230 + /// ("The provider did not return a ProviderManifestToken string."). + /// + [Test] + public void SimpleCodeFirstSelect() + { +#if DEBUG + Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); +#endif + MovieDBContext db = new MovieDBContext(); + db.Database.Initialize(true); + MovieDBInitialize.DoDataPopulation(db); + var l = db.Movies.ToList(); + int j = l.Count; + foreach (var i in l) + { + j--; + } + Assert.That(j, Is.EqualTo(0)); + } + + /// + /// Tests for fix of http://bugs.mysql.com/bug.php?id=62150 + /// ("EF4.1, Code First, CreateDatabaseScript() generates an invalid MySQL script."). + /// + [Test] + public void AlterTableTest() + { +#if DEBUG + Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); +#endif + MovieDBContext db = new MovieDBContext(); + db.Database.Initialize(true); + MovieDBInitialize.DoDataPopulation(db); + var l = db.MovieFormats.ToList(); + int j = l.Count; + foreach (var i in l) + { + j--; + } + Assert.That(j, Is.EqualTo(0)); + MovieFormat m = new MovieFormat(); + m.Format = 8.0f; + db.MovieFormats.Add(m); + db.SaveChanges(); + MovieFormat m2 = db.MovieFormats.Where(p => p.Format == 8.0f).FirstOrDefault(); + Assert.That(m2, Is.Not.Null); + Assert.That(m2.Format, Is.EqualTo(8.0f)); + } + + /// + /// Fix for "Connector/Net Generates Incorrect SELECT Clause after UPDATE" (MySql bug #62134, Oracle bug #13491689). + /// + [Test] + public void ConcurrencyCheckWithNonDbGeneratedColumn() + { +#if DEBUG + Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); +#endif + using (MovieDBContext db = new MovieDBContext()) + { + db.Database.Delete(); + db.Database.CreateIfNotExists(); + MovieDBInitialize.DoDataPopulation(db); + db.Database.ExecuteSqlCommand(@"DROP TABLE IF EXISTS `MovieReleases`"); + + db.Database.ExecuteSqlCommand( +@"CREATE TABLE IF NOT EXISTS `MovieReleases` ( + `Id` int(11) NOT NULL, + `Name` varbinary(45) NOT NULL, + `Timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`Id`) +) ENGINE=InnoDB DEFAULT CHARSET=binary"); + MySqlTrace.Listeners.Clear(); + MySqlTrace.Switch.Level = SourceLevels.All; + GenericListener listener = new GenericListener(); + MySqlTrace.Listeners.Add(listener); + try + { + MovieRelease mr = db.MovieReleases.Create(); + mr.Id = 1; + mr.Name = "Commercial"; + db.MovieReleases.Add(mr); + db.SaveChanges(); + mr.Name = "Director's Cut"; + db.SaveChanges(); + } + finally + { + db.Database.ExecuteSqlCommand(@"DROP TABLE IF EXISTS `MovieReleases`"); + } + // Check sql + Regex rx = new Regex(@"Query Opened: (?UPDATE .*)", RegexOptions.Compiled | RegexOptions.Singleline); + foreach (string s in listener.Strings) + { + Match m = rx.Match(s); + if (m.Success) + { + CheckSql(m.Groups["item"].Value, SQLSyntax.UpdateWithSelectWithNonDbGeneratedLock); + //Assert.Pass(); + } + } + //Assert.Fail(); + } + } + + /// + /// This tests fix for http://bugs.mysql.com/bug.php?id=64216. + /// + [Test] + public void CheckByteArray() + { +#if DEBUG + Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); +#endif + MovieDBContext db = new MovieDBContext(); + db.Database.Initialize(true); + string dbCreationScript = + ((IObjectContextAdapter)db).ObjectContext.CreateDatabaseScript(); + Regex rx = new Regex(@"`Data` (?[^\),]*)", RegexOptions.Compiled | RegexOptions.Singleline); + Match m = rx.Match(dbCreationScript); + Assert.That(m.Groups["type"].Value, Is.EqualTo("longblob")); + } + + /// + /// Validates a stored procedure call using Code First + /// Bug #14008699 + [Test] + public void CallStoredProcedure() + { +#if DEBUG + Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); +#endif + using (MovieDBContext context = new MovieDBContext()) + { + context.Database.Initialize(true); + context.Database.ExecuteSqlCommand(@"drop procedure if exists `GetCount`"); + context.Database.ExecuteSqlCommand(@"create procedure `GetCount`() begin select 5; end;"); + long count = context.Database.SqlQuery("call GetCount").First(); + + Assert.That(count, Is.EqualTo(5)); + } + } + + /// + /// Tests for fix of http://bugs.mysql.com/bug.php?id=116028 + /// Incorrect discriminator generated column values when it's used code-first, inheritance and in a join statement + /// + [Test] + public void Bug116028_Test1() + { + List vehicles; + using (VehicleDbContext4 context = new VehicleDbContext4()) + { + context.Database.Delete(); + context.Database.Initialize(true); + var manuf = context.Manufacturers.Add(new Manufacturer4 { Name = "ACME" }); + context.Vehicles.Add(new Car4 { Id = 1, Name = "Mustang", Year = 2012, CarProperty = "Car", Manufacturer = manuf }); + context.Vehicles.Add(new Bike4 { Id = 101, Name = "Mountain", Year = 2011, BikeProperty = "Bike", Manufacturer = manuf }); + context.SaveChanges(); + + vehicles = context.Manufacturers.SelectMany(v => v.Vehicles).ToList(); + + int records = -1; + using (MySqlConnection conn = new MySqlConnection(context.Database.Connection.ConnectionString)) + { + conn.Open(); + MySqlCommand cmd = new MySqlCommand("SELECT COUNT(*) FROM Vehicles", conn); + records = Convert.ToInt32(cmd.ExecuteScalar()); + } + + Assert.That(records, Is.EqualTo(context.Vehicles.Count())); + } + using (VehicleDbContext4 context = new VehicleDbContext4()) + { + var vehiclesfromdb = context.Manufacturers.SelectMany(v => v.Vehicles).ToList(); + Assert.That(vehiclesfromdb.OfType().Single().CarProperty, Is.EqualTo(vehicles.OfType().Single().CarProperty)); + Assert.That(vehiclesfromdb.OfType().Single().BikeProperty, Is.EqualTo(vehicles.OfType().Single().BikeProperty)); + } + } + + /// + /// Tests for fix of http://bugs.mysql.com/bug.php?id=63920 + /// Maxlength error when it's used code-first and inheritance (discriminator generated column) + /// + [Test] + public void Bug63920_Test1() + { +#if DEBUG + Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); +#endif + using (VehicleDbContext context = new VehicleDbContext()) + { + context.Database.Delete(); + context.Database.Initialize(true); + + context.Vehicles.Add(new Car { Id = 1, Name = "Mustang", Year = 2012, CarProperty = "Car" }); + context.Vehicles.Add(new Bike { Id = 101, Name = "Mountain", Year = 2011, BikeProperty = "Bike" }); + context.SaveChanges(); + + var list = context.Vehicles.ToList(); + + int records = -1; + using (MySqlConnection conn = new MySqlConnection(context.Database.Connection.ConnectionString)) + { + conn.Open(); + MySqlCommand cmd = new MySqlCommand("SELECT COUNT(*) FROM Vehicles", conn); + records = Convert.ToInt32(cmd.ExecuteScalar()); + } + + Assert.That(records, Is.EqualTo(context.Vehicles.Count())); + } + } + + /// + /// Tests for fix of http://bugs.mysql.com/bug.php?id=63920 + /// Key reference generation script error when it's used code-first and a single table for the inherited models + /// + [Test] + public void Bug63920_Test2() + { +#if DEBUG + Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); +#endif + using (VehicleDbContext2 context = new VehicleDbContext2()) + { + context.Database.Delete(); + context.Database.Initialize(true); + + context.Vehicles.Add(new Car2 { Id = 1, Name = "Mustang", Year = 2012, CarProperty = "Car" }); + context.Vehicles.Add(new Bike2 { Id = 101, Name = "Mountain", Year = 2011, BikeProperty = "Bike" }); + context.SaveChanges(); + + var list = context.Vehicles.ToList(); + + int records = -1; + using (MySqlConnection conn = new MySqlConnection(context.Database.Connection.ConnectionString)) + { + conn.Open(); + MySqlCommand cmd = new MySqlCommand("SELECT COUNT(*) FROM Vehicle2", conn); + records = Convert.ToInt32(cmd.ExecuteScalar()); + } + + Assert.That(records, Is.EqualTo(context.Vehicles.Count())); + } + } + + /// + /// This test fix for precision customization for columns bug (http://bugs.mysql.com/bug.php?id=65001), + /// Trying to customize column precision in Code First does not work). + /// + [Test] + [Ignore("Fix this")] + public void TestPrecisionNscale() + { +#if DEBUG + Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); +#endif + MovieDBContext db = new MovieDBContext(); + db.Database.Initialize(true); + var l = db.Movies.ToList(); + using (MySqlDataReader r = new MySqlCommand($@"select numeric_precision, numeric_scale from information_schema.columns +where table_schema = '{Connection.Database}' and table_name = 'movies' and column_name = 'Price'", Connection).ExecuteReader()) + { + r.Read(); + Assert.That(r.GetInt32(0), Is.EqualTo(16)); + Assert.That(r.GetInt32(1), Is.EqualTo(2)); + } + } + + /// + /// Test String types to StoreType for String + /// A string with FixedLength=true will become a char + /// Max Length left empty will be char(max) + /// Max Length(100) will be char(100) + /// while FixedLength=false will result in nvarchar. + /// Max Length left empty will be nvarchar(max) + /// Max Length(100) will be nvarchar(100) + /// + [Test] + public void TestStringTypeToStoreType() + { +#if DEBUG + Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); +#endif + using (VehicleDbContext3 context = new VehicleDbContext3()) + { + if (context.Database.Exists()) context.Database.Delete(); + context.Database.CreateIfNotExists(); + context.Accessories.Add(new Accessory { Name = "Accesory One", Description = "Accesories descriptions", LongDescription = "Some long description" }); + context.SaveChanges(); + + using (MySqlConnection conn = new MySqlConnection(context.Database.Connection.ConnectionString)) + { + conn.Open(); + MySqlCommand query = new MySqlCommand("Select Column_name, Is_Nullable, Data_Type from information_schema.Columns where table_schema ='" + conn.Database + "' and table_name = 'Accessories' and column_name ='Description'", conn); + query.Connection = conn; + MySqlDataReader reader = query.ExecuteReader(); + while (reader.Read()) + { + Assert.That(reader[0].ToString(), Is.EqualTo("Description")); + Assert.That(reader[1].ToString(), Is.EqualTo("NO")); + Assert.That(reader[2].ToString(), Is.EqualTo("mediumtext")); + } + reader.Close(); + + query = new MySqlCommand("Select Column_name, Is_Nullable, Data_Type, character_maximum_length from information_schema.Columns where table_schema ='" + conn.Database + "' and table_name = 'Accessories' and column_name ='Name'", conn); + reader = query.ExecuteReader(); + while (reader.Read()) + { + Assert.That(reader[0].ToString(), Is.EqualTo("Name")); + Assert.That(reader[1].ToString(), Is.EqualTo("NO")); + Assert.That(reader[2].ToString(), Is.EqualTo("varchar")); + Assert.That(reader[3].ToString(), Is.EqualTo("255")); + } + reader.Close(); + + query = new MySqlCommand("Select Column_name, Is_Nullable, Data_Type, character_maximum_length from information_schema.Columns where table_schema ='" + conn.Database + "' and table_name = 'Accessories' and column_name ='LongDescription'", conn); + reader = query.ExecuteReader(); + while (reader.Read()) + { + Assert.That(reader[0].ToString(), Is.EqualTo("LongDescription")); + Assert.That(reader[1].ToString(), Is.EqualTo("NO")); + Assert.That(reader[2].ToString(), Is.EqualTo("longtext")); + Assert.That(reader[3].ToString(), Is.EqualTo("4294967295")); + } + } + } + } + + /// + /// Test fix for http://bugs.mysql.com/bug.php?id=66066 / http://clustra.no.oracle.com/orabugs/bug.php?id=14479715 + /// (Using EF, crash when generating insert with no values.). + /// + [Test] + public void AddingEmptyRow() + { +#if DEBUG + Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); +#endif + using (MovieDBContext ctx = new MovieDBContext()) + { + ctx.Database.Initialize(true); + ctx.EntitySingleColumns.Add(new EntitySingleColumn()); + ctx.SaveChanges(); + } + + using (MovieDBContext ctx2 = new MovieDBContext()) + { + var q = from esc in ctx2.EntitySingleColumns where esc.Id == 1 select esc; + Assert.That(q.Count(), Is.EqualTo(1)); + } + } + + /// + /// Test for identity columns when type is Integer or Guid (auto-generate + /// values) + /// + [Test] + public void IdentityTest() + { +#if DEBUG + Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); +#endif + using (VehicleDbContext context = new VehicleDbContext()) + { + context.Database.ExecuteSqlCommand("SET GLOBAL sql_mode='STRICT_ALL_TABLES'"); + if (context.Database.Exists()) context.Database.Delete(); + context.Database.CreateIfNotExists(); + + // Identity as Guid + Manufacturer nissan = new Manufacturer + { + Name = "Nissan" + }; + Manufacturer ford = new Manufacturer + { + Name = "Ford" + }; + context.Manufacturers.Add(nissan); + context.Manufacturers.Add(ford); + + // Identity as Integer + Distributor dis1 = new Distributor + { + Name = "Distributor1" + }; + Distributor dis2 = new Distributor + { + Name = "Distributor2" + }; + context.Distributors.Add(dis1); + context.Distributors.Add(dis2); + + context.SaveChanges(); + + using (MySqlConnection conn = new MySqlConnection(context.Database.Connection.ConnectionString)) + { + conn.Open(); + + // Validates Guid + MySqlCommand cmd = new MySqlCommand("SELECT * FROM Manufacturers", conn); + MySqlDataReader dr = cmd.ExecuteReader(); + Assert.That(dr.HasRows, "No records found"); + + while (dr.Read()) + { + string name = dr.GetString(1); + switch (name) + { + case "Nissan": + Assert.That(nissan.ManufacturerId, Is.EqualTo(dr.GetGuid(0))); + Assert.That(nissan.GroupIdentifier, Is.EqualTo(dr.GetGuid(2))); + break; + case "Ford": + Assert.That(ford.ManufacturerId, Is.EqualTo(dr.GetGuid(0))); + Assert.That(ford.GroupIdentifier, Is.EqualTo(dr.GetGuid(2))); + break; + default: + //Assert.Fail(); + break; + } + } + dr.Close(); + + // Validates Integer + cmd = new MySqlCommand("SELECT * FROM Distributors", conn); + dr = cmd.ExecuteReader(); + if (!dr.HasRows) + //Assert.Fail("No records found"); + while (dr.Read()) + { + string name = dr.GetString(1); + switch (name) + { + case "Distributor1": + Assert.That(dis1.DistributorId, Is.EqualTo(dr.GetInt32(0))); + break; + case "Distributor2": + Assert.That(dis2.DistributorId, Is.EqualTo(dr.GetInt32(0))); + break; + default: + //Assert.Fail(); + break; + } + } + dr.Close(); + } + } + } + + /// + /// This test the fix for bug 67377. + /// + [Test] + public void FirstOrDefaultNested() + { +#if DEBUG + Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); +#endif + using (MovieDBContext ctx = new MovieDBContext()) + { + ctx.Database.Initialize(true); + MovieDBInitialize.DoDataPopulation(ctx); + int DirectorId = 1; + var q = ctx.Movies.Where(p => p.Director.ID == DirectorId).Select(p => + new + { + Id = p.ID, + FirstMovieFormat = p.Formats.Count == 0 ? 0.0 : p.Formats.FirstOrDefault().Format + }); + string sql = q.ToString(); +#if DEBUG + Debug.WriteLine(sql); +#endif + int j = q.Count(); + foreach (var r in q) + { + j--; + } + Assert.That(j, Is.EqualTo(0)); + } + } + + /// + /// This tests the fix for bug 73549, Generated Sql does not contain ORDER BY statement whose is requested by LINQ. + /// + [Test] + public void FirstOrDefaultNestedWithOrderBy() + { +#if DEBUG + Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); +#endif + using (SakilaDb db = new SakilaDb()) + { + var q = from cu in db.customers + let curAddr = db.addresses.OrderByDescending(p => p.address_id).Where(p => p.address_id == cu.address_id).FirstOrDefault() + join sto in db.stores on cu.store_id equals sto.store_id + orderby cu.customer_id descending + select new + { + curAddr.city.country.country1 + }; + string sql = q.ToString(); + CheckSql(sql, SQLSyntax.FirstOrDefaultNestedWithOrderBy); +#if DEBUG + Debug.WriteLine(sql); +#endif + int j = q.Count(); + foreach (var r in q) + { + //Debug.WriteLine( r.country1 ); + } + Assert.That(j, Is.EqualTo(599)); + } + } + + /// + /// SUPPORT FOR DATE TYPES WITH PRECISION + /// + [Test] + public void CanDefineDatesWithPrecisionFor56() + { +#if DEBUG + Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); +#endif + + if (Version < new Version(5, 6)) return; + + using (var db = new ProductsDbContext()) + { + db.Database.Initialize(true); + using (MySqlConnection conn = new MySqlConnection(db.Database.Connection.ConnectionString)) + { + conn.Open(); + MySqlCommand query = new MySqlCommand("Select Column_name, Is_Nullable, Data_Type, DateTime_Precision from information_schema.Columns where table_schema ='" + conn.Database + "' and table_name = 'Products' and column_name ='DateTimeWithPrecision'", conn); + query.Connection = conn; + MySqlDataReader reader = query.ExecuteReader(); + while (reader.Read()) + { + Assert.That(reader[0].ToString(), Is.EqualTo("DateTimeWithPrecision")); + Assert.That(reader[1].ToString(), Is.EqualTo("NO")); + Assert.That(reader[2].ToString(), Is.EqualTo("datetime")); + Assert.That(reader[3].ToString(), Is.EqualTo("3")); + } + reader.Close(); + + query = new MySqlCommand("Select Column_name, Is_Nullable, Data_Type, DateTime_Precision from information_schema.Columns where table_schema ='" + conn.Database + "' and table_name = 'Products' and column_name ='TimeStampWithPrecision'", conn); + query.Connection = conn; + reader = query.ExecuteReader(); + while (reader.Read()) + { + Assert.That(reader[0].ToString(), Is.EqualTo("TimeStampWithPrecision")); + Assert.That(reader[1].ToString(), Is.EqualTo("NO")); + Assert.That(reader[2].ToString(), Is.EqualTo("timestamp")); + Assert.That(reader[3].ToString(), Is.EqualTo("3")); + } + reader.Close(); + } + db.Database.Delete(); + } + } + + /// + /// Orabug #15935094 SUPPORT FOR CURRENT_TIMESTAMP AS DEFAULT FOR DATETIME WITH EF + /// + [Test] + [Ignore("Fix this")] + public void CanDefineDateTimeAndTimestampWithIdentity() + { +#if DEBUG + Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); +#endif + if (Version < new Version(5, 6)) return; + + using (var db = new ProductsDbContext()) + { + db.Database.Initialize(true); + MySqlConnection con = (MySqlConnection)db.Database.Connection; + MySqlCommand cmd = new MySqlCommand("set session sql_mode = '';", con); + con.Open(); + cmd.ExecuteNonQuery(); + con.Close(); + + Product product = new Product + { + //Omitting Identity Columns + DateTimeWithPrecision = DateTime.Now, + TimeStampWithPrecision = DateTime.Now + }; + + db.Products.Add(product); + db.SaveChanges(); + + var updateProduct = db.Products.First(); + updateProduct.DateTimeWithPrecision = new DateTime(2012, 3, 18, 23, 9, 7, 6); + db.SaveChanges(); + + Assert.That(db.Products.First().Timestamp, Is.Not.Empty); + Assert.That(db.Products.First().DateCreated, Is.Not.Empty); + Assert.That(db.Products.First().DateTimeWithPrecision, Is.EqualTo(new DateTime(2012, 3, 18, 23, 9, 7, 6))); + Assert.That(db.Products.Count(), Is.EqualTo(1)); + db.Database.Delete(); + } + } + + + /// + /// Test of fix for bug Support for EntityFramework 4.3 Code First Generated Identifiers (MySql Bug #67285, Oracle bug #16286397). + /// FKs are renamed to met http://dev.mysql.com/doc/refman/5.0/en/identifiers.html limitations. + /// + [Test] + public void LongIdentifiersInheritanceTPT() + { +#if DEBUG + Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); +#endif + using (DinosauriaDBContext db = new DinosauriaDBContext()) + { + db.Database.Initialize(true); + Tyrannosauridae ty = new Tyrannosauridae() { Id = 1, Name = "Genghis Rex", SpecieName = "TRex", Weight = 1000 }; + db.dinos.Add(ty); + Oviraptorosauria ovi = new Oviraptorosauria() { Id = 2, EggsPerYear = 100, Name = "John the Velociraptor", SpecieName = "Oviraptor" }; + db.dinos.Add(ovi); + db.SaveChanges(); + } + } + + + /// + /// Test fix for http://bugs.mysql.com/bug.php?id=67183 + /// (Malformed Query while eager loading with EF 4 due to multiple projections). + /// + [Test] + public void ShipTest() + { +#if DEBUG + Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); +#endif + using (var context = new ShipContext()) + { + context.Database.Initialize(true); + + var harbor = new Harbor + { + Ships = new HashSet + { + new Ship + { + CrewMembers = new HashSet + { + new CrewMember + { + Rank = new Rank { Description = "Rank A" }, + Clearance = new Clearance { Description = "Clearance A" }, + Description = "CrewMember A" + }, + new CrewMember + { + Rank = new Rank { Description = "Rank B" }, + Clearance = new Clearance { Description = "Clearance B" }, + Description = "CrewMember B" + } + }, + Description = "Ship AB" + }, + new Ship + { + CrewMembers = new HashSet + { + new CrewMember + { + Rank = new Rank { Description = "Rank C" }, + Clearance = new Clearance { Description = "Clearance C" }, + Description = "CrewMember C" + }, + new CrewMember + { + Rank = new Rank { Description = "Rank D" }, + Clearance = new Clearance { Description = "Clearance D" }, + Description = "CrewMember D" + } + }, + Description = "Ship CD" + } + }, + Description = "Harbor ABCD" + }; + + context.Harbors.Add(harbor); + context.SaveChanges(); + } + + using (var context = new ShipContext()) + { + DbSet dbSet = context.Set(); + IQueryable query = dbSet; + query = query.Include(entity => entity.Ships); + query = query.Include(entity => entity.Ships.Select(s => s.CrewMembers)); + query = query.Include(entity => entity.Ships.Select(s => s.CrewMembers.Select(cm => cm.Rank))); + query = query.Include(entity => entity.Ships.Select(s => s.CrewMembers.Select(cm => cm.Clearance))); + + string[] data = new string[] { + "1,Harbor ABCD,1,1,1,Ship AB,1,1,1,1,1,CrewMember A,1,Rank A,1,Clearance A", + "1,Harbor ABCD,1,1,1,Ship AB,1,2,1,2,2,CrewMember B,2,Rank B,2,Clearance B", + "1,Harbor ABCD,1,2,1,Ship CD,1,3,2,3,3,CrewMember C,3,Rank C,3,Clearance C", + "1,Harbor ABCD,1,2,1,Ship CD,1,4,2,4,4,CrewMember D,4,Rank D,4,Clearance D" + }; + Dictionary outData = new Dictionary(); + + var sqlString = query.ToString(); + CheckSql(sqlString, SQLSyntax.ShipQueryMalformedDueMultipleProjecttionsCorrectedEF6); + // see below for the generated SQL query + + var harbor = query.Single(); + + foreach (var ship in harbor.Ships) + { + foreach (var crewMember in ship.CrewMembers) + { + outData.Add(string.Format( + "{0},{1},1,{2},{3},{4},1,{5},{6},{7},{8},{9},{10},{11},{12},{13}", + harbor.HarborId, harbor.Description, ship.ShipId, harbor.HarborId, + ship.Description, crewMember.CrewMemberId, crewMember.ShipId, crewMember.RankId, + crewMember.ClearanceId, crewMember.Description, crewMember.Rank.RankId, + crewMember.Rank.Description, crewMember.Clearance.ClearanceId, + crewMember.Clearance.Description), null); + } + } + // check data integrity + Assert.That(data.Length, Is.EqualTo(outData.Count)); + for (int i = 0; i < data.Length; i++) + { + Assert.That(outData.ContainsKey(data[i])); + } + } + } + + /// + /// Tests fix for bug http://bugs.mysql.com/bug.php?id=68513, Error in LINQ to Entities query when using Distinct().Count(). + /// + [Test] + public void DistinctCount() + { +#if DEBUG + Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); +#endif + using (SiteDbContext ctx = new SiteDbContext()) + { + ctx.Database.Initialize(true); + visitante v1 = new visitante() { nCdSite = 1, nCdVisitante = 1, sDsIp = "x1" }; + visitante v2 = new visitante() { nCdSite = 1, nCdVisitante = 2, sDsIp = "x2" }; + site s1 = new site() { nCdSite = 1, sDsTitulo = "MyNewsPage" }; + site s2 = new site() { nCdSite = 2, sDsTitulo = "MySearchPage" }; + ctx.Visitante.Add(v1); + ctx.Visitante.Add(v2); + ctx.Site.Add(s1); + ctx.Site.Add(s2); + ctx.SaveChanges(); + + var q = (from vis in ctx.Visitante.Include("site") + group vis by vis.nCdSite into g + select new retorno + { + Key = g.Key, + Online = g.Select(e => e.sDsIp).Distinct().Count() + }); + string sql = q.ToString(); + CheckSql(sql, SQLSyntax.CountGroupBy); + var q2 = q.ToList(); + foreach (var row in q2) + { + } + } + } + + /// + /// Tests fix for bug http://bugs.mysql.com/bug.php?id=68513, Error in LINQ to Entities query when using Distinct().Count(). + /// + [Test] + public void DistinctCount2() + { +#if DEBUG + Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); +#endif + using (SiteDbContext ctx = new SiteDbContext()) + { + ctx.Database.Initialize(true); + visitante v1 = new visitante() { nCdSite = 1, nCdVisitante = 1, sDsIp = "x1" }; + visitante v2 = new visitante() { nCdSite = 1, nCdVisitante = 2, sDsIp = "x2" }; + site s1 = new site() { nCdSite = 1, sDsTitulo = "MyNewsPage" }; + site s2 = new site() { nCdSite = 2, sDsTitulo = "MySearchPage" }; + pagina p1 = new pagina() { nCdPagina = 1, nCdVisitante = 1, sDsTitulo = "index.html" }; + ctx.Visitante.Add(v1); + ctx.Visitante.Add(v2); + ctx.Site.Add(s1); + ctx.Site.Add(s2); + ctx.Pagina.Add(p1); + ctx.SaveChanges(); + + var q = (from pag in ctx.Pagina.Include("visitante").Include("site") + group pag by pag.visitante.nCdSite into g + select new retorno + { + Key = g.Key, + Online = g.Select(e => e.visitante.sDsIp).Distinct().Count() + }); + string sql = q.ToString(); + CheckSql(sql, SQLSyntax.CountGroupBy2); + var q2 = q.ToList(); + foreach (var row in q2) + { + } + } + } + + /// + /// Tests fix for bug http://bugs.mysql.com/bug.php?id=65723, MySql Provider for EntityFramework produces "bad" SQL for OrderBy. + /// + [Test] + public void BadOrderBy() + { +#if DEBUG + Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); +#endif + using (MovieDBContext db = new MovieDBContext()) + { + db.Database.Initialize(true); + MovieDBInitialize.DoDataPopulation(db); + DateTime filterDate = new DateTime(1986, 1, 1); + var q = db.Movies.Where(p => p.ReleaseDate >= filterDate). + OrderByDescending(p => p.ReleaseDate).Take(2); + string sql = q.ToString(); + CheckSql(SQLSyntax.NestedOrderBy, sql); + // Data integrity testing + Movie[] data = new Movie[] { + new Movie() { ID = 4, Title = "Star Wars, The Sith Revenge", ReleaseDate = new DateTime( 2005, 5, 19 ) }, + new Movie() { ID = 2, Title = "The Matrix", ReleaseDate = new DateTime( 1999, 3, 31 ) } + }; + int i = 0; + foreach (Movie m in q) + { + Assert.That(m.ID, Is.EqualTo(data[i].ID)); + Assert.That(m.Title, Is.EqualTo(data[i].Title)); + Assert.That(m.ReleaseDate, Is.EqualTo(data[i].ReleaseDate)); + i++; + } + Assert.That(i, Is.EqualTo(2)); + } + } + + /// + /// Tests fix for bug http://bugs.mysql.com/bug.php?id=69751, Invalid SQL query generated for query with Contains, OrderBy, and Take. + /// + [Test] + public void BadContainsOrderByTake() + { +#if DEBUG + Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); +#endif + using (MovieDBContext db = new MovieDBContext()) + { + db.Database.Initialize(true); + MovieDBInitialize.DoDataPopulation(db); + string title = "T"; + var q = from m in db.Movies + where m.Title.Contains(title) + orderby m.ID descending + select m; + var q1 = q.Take(10); + string sql = q1.ToString(); + + CheckSql(SQLSyntax.QueryWithOrderByTakeContains, sql); + + int i = 0; + foreach (var row in q1) + { + Assert.That(row.ID, Is.EqualTo(MovieDBInitialize.data[i].ID)); + Assert.That(row.Title, Is.EqualTo(MovieDBInitialize.data[i].Title)); + Assert.That(row.ReleaseDate, Is.EqualTo(MovieDBInitialize.data[i].ReleaseDate)); + i++; + } + } + } + + /// + /// Tests fix for bug http://bugs.mysql.com/bug.php?id=69922, Unknown column Extent1... + /// + [Test] + public void BadAliasTable() + { +#if DEBUG + Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); +#endif + using (PromotionsDB db = new PromotionsDB()) + { + db.Database.Initialize(true); + DateTime now = DateTime.Now; + var q = db + .HomePromoes + .Where(x => + x.Active + && + (x.ActiveFrom == null || x.ActiveFrom <= now) + && + (x.ActiveTo == null || x.ActiveTo >= now) + ) + .OrderBy(x => x.DisplayOrder).Select(d => d); + string sql = q.ToString(); + foreach (var row in q) + { + } + } + } + + /// + /// Tests other variants of bug http://bugs.mysql.com/bug.php?id=69751, Invalid SQL query generated for query with Contains, OrderBy, and Take. + /// + [Test] + public void BadContainsOrderByTake2() + { +#if DEBUG + Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); +#endif + using (MovieDBContext db = new MovieDBContext()) + { + db.Database.Initialize(true); + MovieDBInitialize.DoDataPopulation(db); + var q = db.Movies. + Where(m => !string.IsNullOrEmpty(m.Title) && m.Title.Contains("x")). + OrderByDescending(m => m.ID). + Skip(1). + Take(1); + string sql = q.ToString(); +#if DEBUG + Debug.WriteLine(sql); +#endif + List l = q.ToList(); + int j = l.Count; + foreach (Movie m in l) + { + j--; + } + Assert.That(j, Is.EqualTo(0)); + } + } + + /// + /// Tests other variants of bug http://bugs.mysql.com/bug.php?id=69751, Invalid SQL query generated for query with Contains, OrderBy, and Take. + /// + [Test] + public void BadContainsOrderByTake3() + { +#if DEBUG + Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); +#endif + using (MovieDBContext db = new MovieDBContext()) + { + db.Database.Initialize(true); + MovieDBInitialize.DoDataPopulation(db); + var q = db.Movies. + Where(m => !string.IsNullOrEmpty(m.Title) && m.Title.Contains("x")). + OrderByDescending(m => m.ID). + Skip(1). + Take(1).Select(m => new + { + Id = m.ID, + CriticsScore = ( + m.Title == "Terminator 1" ? "Good" : + m.Title == "Predator" ? "Sunday best, cheese" : + m.Title == "The Matrix" ? "Really Good" : + m.Title == "Star Wars, The Sith Revenge" ? "Really Good" : "Unknown") + }); + string sql = q.ToString(); +#if DEBUG + Debug.WriteLine(sql); +#endif + int j = q.Count(); + foreach (var row in q) + { + j--; + } + Assert.That(j, Is.EqualTo(0)); + } + } + + /// + /// Tests other variants of bug http://bugs.mysql.com/bug.php?id=69751, Invalid SQL query generated for query with Contains, OrderBy, and Take. + /// + [Test] + public void BadContainsOrderByTake4() + { +#if DEBUG + Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); +#endif + using (MovieDBContext db = new MovieDBContext()) + { + db.Database.Initialize(true); + MovieDBInitialize.DoDataPopulation(db); + bool q = db.Movies.Any(m => m.ReleaseDate.Year > 1985); + // string sql = q.ToString(); + //#if DEBUG + // Debug.WriteLine(sql); + //#endif + //foreach (var row in q) + //{ + //} + } + } + + /// + /// Tests other variants of bug http://bugs.mysql.com/bug.php?id=69751, Invalid SQL query generated for query with Contains, OrderBy, and Take. + /// + [Test] + public void BadContainsOrderByTake5() + { +#if DEBUG + Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); +#endif + using (MovieDBContext db = new MovieDBContext()) + { + db.Database.Initialize(true); + MovieDBInitialize.DoDataPopulation(db); + // TODO: add subquery like + // var shifts = Shifts.Where(s => !EmployeeShifts.Where(es => es.ShiftID == s.ShiftID).Any()); + bool q = db.Movies.Where(m => m.ReleaseDate.Month != 10).Any(m => m.ReleaseDate.Year > 1985); + // string sql = q.ToString(); + //#if DEBUG + // Debug.WriteLine(sql); + //#endif + // foreach (var row in q) + // { + // } + } + } + + /// + /// Tests other variants of bug http://bugs.mysql.com/bug.php?id=69751, Invalid SQL query generated for query with Contains, OrderBy, and Take. + /// + [Test] + public void BadContainsOrderByTake6() + { +#if DEBUG + Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); +#endif + using (MovieDBContext db = new MovieDBContext()) + { + db.Database.Initialize(true); + MovieDBInitialize.DoDataPopulation(db); + var q = from m in db.Movies + where m.Title.Contains("x") && db.Medias.Where(mm => mm.Format == "Digital").Any() + select m; + string sql = q.ToString(); +#if DEBUG + Debug.WriteLine(sql); +#endif + int j = q.Count(); + foreach (var row in q) + { + j--; + } + Assert.That(j, Is.EqualTo(0)); + } + } + + /// + /// Test for Mysql Bug 70602: http://bugs.mysql.com/bug.php?id=70602 + /// + [Test] + public void AutoIncrementBug() + { +#if DEBUG + Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); +#endif + AutoIncrementBugContext dbContext = new AutoIncrementBugContext(); + + dbContext.Database.Initialize(true); + dbContext.AutoIncrementBug.Add(new AutoIncrementBug() { Description = "Test" }); + dbContext.SaveChanges(); + using (var reader = MySqlHelper.ExecuteReader(dbContext.Database.Connection.ConnectionString, + $"SHOW COLUMNS FROM {nameof(dbContext.AutoIncrementBug)}s WHERE UPPER(EXTRA) LIKE '%AUTO_INCREMENT%'")) + { + Assert.That(reader.HasRows); + } + dbContext.Database.Delete(); + } + + [Test] + public void SimpleCodeFirstSelectCbc() + { + MovieCodedBasedConfigDBContext db = new MovieCodedBasedConfigDBContext(); + db.Database.Initialize(true); + var l = db.Movies.ToList(); + foreach (var i in l) + { + Console.WriteLine(i); + } + } + + [Test] + [Ignore("Need to check. Bad statemen: CALL `MovieCodedBasedConfigDBContext`.``insert_movie``(@movie_name, @ReleaseDate, @Genre, @Price)")] + public void TestStoredProcedureMapping() + { + using (var db = new MovieCodedBasedConfigDBContext()) + { + db.Database.Initialize(true); + var movie = new MovieCBC() + { + Title = "Sharknado", + Genre = "Documental", + Price = 1.50M, + ReleaseDate = DateTime.Parse("01/07/2013") + }; + + db.Movies.Add(movie); + db.SaveChanges(); + movie.Genre = "Fiction"; + db.SaveChanges(); + db.Movies.Remove(movie); + db.SaveChanges(); + } + } + + [Test] + public void MigrationHistoryConfigurationTest() + { + MovieCodedBasedConfigDBContext db = new MovieCodedBasedConfigDBContext(); + db.Database.Initialize(true); + var l = db.Movies.ToList(); + foreach (var i in l) + { + } + var result = MySqlHelper.ExecuteScalar($"server=localhost;User Id=root;database={db.Database.Connection.Database};logging=true; port=" + Port + ";", "SELECT COUNT(_MigrationId) FROM __MySqlMigrations;"); + Assert.That(int.Parse(result.ToString()), Is.EqualTo(1)); + } + + [Test] + public void DbSetRangeTest() + { + using (MovieDBContext db = new MovieDBContext()) + { + db.Database.Initialize(true); + Movie m1 = new Movie() { Title = "Terminator 1", ReleaseDate = new DateTime(1984, 10, 26) }; + Movie m2 = new Movie() { Title = "The Matrix", ReleaseDate = new DateTime(1999, 3, 31) }; + Movie m3 = new Movie() { Title = "Predator", ReleaseDate = new DateTime(1987, 6, 12) }; + Movie m4 = new Movie() { Title = "Star Wars, The Sith Revenge", ReleaseDate = new DateTime(2005, 5, 19) }; + db.Movies.AddRange(new Movie[] { m1, m2, m3, m4 }); + db.SaveChanges(); + var q = from m in db.Movies select m; + Assert.That(q.Count(), Is.EqualTo(4)); + foreach (var row in q) + { + } + db.Movies.RemoveRange(q.ToList()); + db.SaveChanges(); + var q2 = from m in db.Movies select m; + Assert.That(q2.Count(), Is.EqualTo(0)); + } + } + + [Test] + public void EnumSupportTest() + { + using (var dbCtx = new EnumTestSupportContext()) + { + dbCtx.Database.Initialize(true); + dbCtx.SchoolSchedules.Add(new SchoolSchedule() { TeacherName = "Pako", Subject = SchoolSubject.History }); + dbCtx.SaveChanges(); + + var schedule = (from s in dbCtx.SchoolSchedules + where s.Subject == SchoolSubject.History + select s).FirstOrDefault(); + + Assert.That(schedule, Is.Not.EqualTo(null)); + Assert.That(schedule.Subject, Is.EqualTo(SchoolSubject.History)); + } + } + + + [Test] + [Ignore("This test needs MicrosoftSqlServer.Types which is not available for all the target frameworks.")] + public void SpatialSupportTest() + { + using (var dbCtx = new JourneyContext()) + { + dbCtx.Database.Initialize(true); + dbCtx.MyPlaces.Add(new MyPlace() + { + name = "JFK INTERNATIONAL AIRPORT OF NEW YORK", + location = DbGeometry.FromText("POINT(40.644047 -73.782291)"), + }); + dbCtx.MyPlaces.Add(new MyPlace + { + name = "ALLEY POND PARK", + location = DbGeometry.FromText("POINT(40.745696 -73.742638)") + }); + dbCtx.MyPlaces.Add(new MyPlace + { + name = "CUNNINGHAM PARK", + location = DbGeometry.FromText("POINT(40.735031 -73.768387)") + }); + dbCtx.MyPlaces.Add(new MyPlace + { + name = "QUEENS VILLAGE STATION", + location = DbGeometry.FromText("POINT(40.717957 -73.736501)") + }); + dbCtx.SaveChanges(); + + var place = (from p in dbCtx.MyPlaces + where p.name == "JFK INTERNATIONAL AIRPORT OF NEW YORK" + select p).FirstOrDefault(); + + var point = DbGeometry.FromText("POINT(40.717957 -73.736501)"); + + var distance = (point.Distance(place.location) * 100); + + Assert.That(place, Is.Not.Null); + Assert.That(distance.Value, Is.EqualTo(8.6944880240295852D)); + + var points = from p in dbCtx.MyPlaces + select new { name = p.name, location = p.location }; + foreach (var item in points) + { + var distanceX = DbGeometry.FromText("POINT(40.717957 -73.736501)").Distance(item.location) * 100; + Assert.That(distanceX, Is.Not.Null); + } + + foreach (MyPlace p in dbCtx.MyPlaces) + dbCtx.MyPlaces.Remove(p); + dbCtx.SaveChanges(); + + dbCtx.MyPlaces.Add(new MyPlace + { + name = "AGraphic Design Institute", + location = DbGeometry.FromText(string.Format("POINT({0} {1})", -122.336106, 47.605049), 101) + }); + + dbCtx.MyPlaces.Add(new MyPlace + { + name = "AGraphic Design Institute", + location = DbGeometry.FromText("POINT(-123.336106 47.605049)", 102) + }); + + dbCtx.MyPlaces.Add(new MyPlace + { + name = "BGraphic Design Institute", + location = DbGeometry.FromText("POINT(-113.336106 47.605049)", 103) + }); + + dbCtx.MyPlaces.Add(new MyPlace + { + name = "Graphic Design Institute", + location = DbGeometry.FromText(string.Format("POINT({0} {1})", 51.5, -1.28), 4326) + }); + dbCtx.SaveChanges(); + + var result = (from u in dbCtx.MyPlaces select u.location.CoordinateSystemId).ToList(); + foreach (var item in result) + Assert.That(item, Is.Not.Empty); + var res = dbCtx.MyPlaces.OrderBy(q => q.name.Take(1).Skip(1).ToList()); + Assert.That(res, Is.Not.Null); + + var pointA1 = DbGeometry.FromText(string.Format("POINT(40.644047 -73.782291)")); + var pointB1 = DbGeometry.FromText("POINT(40.717957 -73.736501)"); + var distance1 = pointA1.Distance(pointB1); + + var pointA2 = DbGeometry.FromText("POINT(2.5 2.5)"); + var pointB2 = DbGeometry.FromText("POINT(4 0.8)"); + var distance2 = pointA2.Distance(pointB2); + + var pointA3 = DbGeometry.FromText("POINT(3 -4)"); + var pointB3 = DbGeometry.FromText("POINT(-1 3)"); + var distance3 = pointA3.Distance(pointB3); + + Assert.That(distance1.Value == 0.086944880240295855 && distance2.Value == 2.2671568097509267 && + distance3.Value == 8.06225774829855); + + } + } + + [Test] + public void BeginTransactionSupportTest() + { + using (var dbcontext = new MovieCodedBasedConfigDBContext()) + { + dbcontext.Database.Initialize(true); + using (var transaction = dbcontext.Database.BeginTransaction()) + { + try + { + dbcontext.Movies.Add(new MovieCBC() + { + Title = "Sharknado", + Genre = "Documental", + Price = 1.50M, + ReleaseDate = DateTime.Parse("01/07/2013") + }); + + dbcontext.SaveChanges(); + var result = MySqlHelper.ExecuteScalar("server=localhost;User Id=root;database=test;logging=true;port=" + Port + ";", "select COUNT(*) from moviecbcs;"); + Assert.That(int.Parse(result.ToString()), Is.EqualTo(0)); + + transaction.Commit(); + + result = MySqlHelper.ExecuteScalar("server=localhost;User Id=root;database=test;logging=true; port=" + Port + ";", "select COUNT(*) from moviecbcs;"); + Assert.That(int.Parse(result.ToString()), Is.EqualTo(1)); + } + catch (Exception) + { + transaction.Rollback(); + } + } + } + } + + /// + /// This test covers two new features on EF6: + /// 1- "DbContext.Database.UseTransaction, that use a transaction created from an open connection" + /// 2- "DbContext can now be created with a DbConnection that is already opened" + /// + [Test] + public void UseTransactionSupportTest() + { + using (var context = new MovieCodedBasedConfigDBContext()) + { + context.Database.CreateIfNotExists(); + } + using (var connection = new MySqlConnection($"server=localhost;User Id=root;database={nameof(MovieCodedBasedConfigDBContext)};logging=true; port=" + Port + ";")) + { + connection.Open(); + using (var transaction = connection.BeginTransaction()) + { + try + { + using (var dbcontext = new MovieCodedBasedConfigDBContext(connection, contextOwnsConnection: false)) + { + dbcontext.Database.Initialize(true); + dbcontext.Database.UseTransaction(transaction); + dbcontext.Movies.Add(new MovieCBC() + { + Title = "Sharknado", + Genre = "Documental", + Price = 1.50M, + ReleaseDate = DateTime.Parse("01/07/2013") + }); + + dbcontext.SaveChanges(); + } + var result = MySqlHelper.ExecuteScalar("server=localhost;User Id=root;database=test;logging=true; port=" + Port + ";", "select COUNT(*) from moviecbcs;"); + Assert.That(int.Parse(result.ToString()), Is.EqualTo(0)); + + transaction.Commit(); + + result = MySqlHelper.ExecuteScalar("server=localhost;User Id=root;database=test;logging=true; port=" + Port + ";", "select COUNT(*) from moviecbcs;"); + Assert.That(int.Parse(result.ToString()), Is.EqualTo(1)); + } + catch (Exception) + { + transaction.Rollback(); + } + } + } + } + + [Test] + [Ignore("Need to check. Bad statemen: CALL `MovieCodedBasedConfigDBContext`.``insert_movie``(@movie_name, @ReleaseDate, @Genre, @Price)")] + public void HasChangesSupportTest() + { + using (var dbcontext = new MovieCodedBasedConfigDBContext()) + { + dbcontext.Database.Initialize(true); + + dbcontext.Movies.Add(new MovieCBC() + { + Title = "Sharknado", + Genre = "Documental", + Price = 1.50M, + ReleaseDate = DateTime.Parse("01/07/2013") + }); + + Assert.That(dbcontext.ChangeTracker.HasChanges()); + dbcontext.SaveChanges(); + Assert.That(!dbcontext.ChangeTracker.HasChanges()); + } + } + + [Test] + [Ignore("Need to check. Bad statemen: CALL `MovieCodedBasedConfigDBContext`.``insert_movie``(@movie_name, @ReleaseDate, @Genre, @Price)")] + public void MySqlLoggingToFileSupportTest() + { + string logName = "mysql.log"; + //if (System.IO.File.Exists(logName)) + // System.IO.File.Delete(logName); + + using (var dbcontext = new MovieCodedBasedConfigDBContext()) + { + dbcontext.Database.Log = MySqlLogger.Logger(logName, true).Write; + + dbcontext.Database.Initialize(true); + dbcontext.Movies.Add(new MovieCBC() + { + Title = "Sharknado", + Genre = "Documental", + Price = 1.50M, + ReleaseDate = DateTime.Parse("01/07/2013") + }); + dbcontext.SaveChanges(); + } + + Assert.That(System.IO.File.Exists(logName), Is.EqualTo(true)); + } + + [Test] + [Ignore("Need to check. Bad statemen: CALL `MovieCodedBasedConfigDBContext`.``insert_movie``(@movie_name, @ReleaseDate, @Genre, @Price)")] + public void MySqlLoggingToConsoleSupportTest() + { + string logName = "mysql_2.log"; + if (System.IO.File.Exists(logName)) + System.IO.File.Delete(logName); + + System.IO.FileStream file; + System.IO.StreamWriter writer; + System.IO.TextWriter txtOut = Console.Out; + try + { + file = new System.IO.FileStream(logName, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.Write); + writer = new System.IO.StreamWriter(file); + } + catch (Exception e) + { + throw e; + } + Console.SetOut(writer); + + using (var dbcontext = new MovieCodedBasedConfigDBContext()) + { + dbcontext.Database.Log = new MySqlLogger(s => Console.Write(s)).Write; + + dbcontext.Database.Initialize(true); + dbcontext.Movies.Add(new MovieCBC() + { + Title = "Sharknado", + Genre = "Documental", + Price = 1.50M, + ReleaseDate = DateTime.Parse("01/07/2013") + }); + dbcontext.SaveChanges(); + } + Console.SetOut(txtOut); + writer.Close(); + file.Close(); + + Assert.That(System.IO.File.Exists(logName), Is.EqualTo(true)); + } + + [Test] + public void EntityAndComplexTypeSupportTest() + { + using (var dbContext = new EntityAndComplexTypeContext()) + { + dbContext.Database.Initialize(true); + dbContext.Students.Add( + new Student() + { + Name = "Pakorasu Pakolas", + Address = new Address() { City = "Mazatlan", Street = "Tierra de Venados 440" }, + Schedule = new List() { new SchoolSchedule() { TeacherName = "Pako", Subject = SchoolSubject.History } } + }); + dbContext.SaveChanges(); + + var student = (from s in dbContext.Students + select s).FirstOrDefault(); + + Assert.That(student, Is.Not.Null); + Assert.That(student.Schedule, Is.Not.Null); + Assert.That(student.Address.Street, Is.Not.Null); + Assert.That(student.Address.Street, Is.Not.Empty); + Assert.That(student.Schedule.Count(), Is.Not.EqualTo(0)); + } + } + + /// + /// TO RUN THIS TEST ITS NECESSARY TO ENABLE THE EXECUTION STRATEGY IN THE CLASS MySqlEFConfiguration (Source\MySql.Data.Entity\MySqlConfiguration.cs) AS WELL AS START A MYSQL SERVER INSTACE WITH THE OPTION "--max_connections=3" + /// WHY 3?: 1)For main process (User: root, DB: mysql). 2)For Setup Class. 3)For the connections in this test. + /// The expected result is that opening a third connection and trying to open a fourth(with an asynchronous task) the execution strategy implementation handle the reconnection process until the third one is closed. + /// + //[Test] //<---DON'T FORGET ME TO RUN! =D + public void ExecutionStrategyTest() + { + var connection = new MySqlConnection("server=localhost;User Id=root;logging=true; port=" + Port + ";"); + using (var dbcontext = new MovieCodedBasedConfigDBContext()) + { + dbcontext.Database.Initialize(true); + dbcontext.Movies.Add(new MovieCBC() + { + Title = "Sharknado", + Genre = "Documental", + Price = 1.50M, + ReleaseDate = DateTime.Parse("01/07/2013") + }); + connection.Open(); + System.Threading.Tasks.Task.Factory.StartNew(() => { dbcontext.SaveChanges(); }); + Thread.Sleep(1000); + connection.Close(); + connection.Dispose(); + } + var result = MySqlHelper.ExecuteScalar("server=localhost;User Id=root;database=test;logging=true; port=" + Port + ";", "select COUNT(*) from moviecbcs;"); + Assert.That(int.Parse(result.ToString()), Is.EqualTo(1)); + } + + [Test] + public void UnknownProjectC1() + { +#if DEBUG + Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); +#endif + using (MovieDBContext db = new MovieDBContext()) + { + db.Database.Initialize(true); + MovieDBInitialize.DoDataPopulation(db); + long myKey = 20; + var q = (from r in db.Movies where (r.ID == myKey) select (long)r.ID).OrderBy(p => p); + string sql = q.ToString(); + CheckSql(sql, SQLSyntax.UnknownProjectC1EF6); + +#if DEBUG + Debug.WriteLine(sql); +#endif + long[] array = (from r in db.Movies where (r.ID == myKey) select (long)r.ID).OrderBy(p => p).ToArray(); + } + } + + [Test] + public void StartsWithTest() + { +#if DEBUG + Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); +#endif + MovieDBContext db = new MovieDBContext(); + db.Database.Initialize(true); + MovieDBInitialize.DoDataPopulation(db); + string term = "The"; + var l = db.Movies.Where(p => p.Title.StartsWith(term)); + + string sql = l.ToString(); + + CheckSql(sql, SQLSyntax.QueryWithStartsWith); + +#if DEBUG + Debug.WriteLine(sql); +#endif + int j = l.Count(); + foreach (var i in l) + { + j--; + } + Assert.That(j, Is.EqualTo(0)); + } + + [Test] + public void EndsWithTest() + { +#if DEBUG + Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); +#endif + MovieDBContext db = new MovieDBContext(); + db.Database.Initialize(true); + MovieDBInitialize.DoDataPopulation(db); + string term = "The"; + var l = db.Movies.Where(p => p.Title.EndsWith(term)); + + string sql = l.ToString(); + + CheckSql(sql, SQLSyntax.QueryWithEndsWith); + +#if DEBUG + Debug.WriteLine(sql); +#endif + int j = l.Count(); + foreach (var i in l) + { + j--; + } + Assert.That(j, Is.EqualTo(0)); + } + + [Test] + public void ContainsTest() + { +#if DEBUG + Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); +#endif + MovieDBContext db = new MovieDBContext(); + db.Database.Initialize(true); + MovieDBInitialize.DoDataPopulation(db); + string term = "The"; + var l = db.Movies.Where(p => p.Title.Contains(term)); + + string sql = l.ToString(); + CheckSql(sql, SQLSyntax.QueryWithContains); + +#if DEBUG + Debug.WriteLine(sql); +#endif + int j = l.Count(); + foreach (var i in l) + { + j--; + } + Assert.That(j, Is.EqualTo(0)); + } + + + /// + /// Test to reproduce bug http://bugs.mysql.com/bug.php?id=73643, Exception when using IEnumera.Contains(model.property) in Where predicate + /// + [Test] + public void TestContainsListWithCast() + { +#if DEBUG + Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); +#endif + using (MovieDBContext db = new MovieDBContext()) + { + db.Database.Initialize(true); + + long[] longs = new long[] { 1, 2, 3 }; + var q = db.Movies.Where(p => longs.Contains((long)p.ID)); + string sql = q.ToString(); + CheckSql(sql, SQLSyntax.TestContainsListWithCast); +#if DEBUG + Debug.WriteLine(sql); +#endif + var l = q.ToList(); + } + } + + /// + /// Test to reproduce bug http://bugs.mysql.com/bug.php?id=73643, Exception when using IEnumera.Contains(model.property) in Where predicate + /// + [Test] + public void TestContainsListWitConstant() + { +#if DEBUG + Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); +#endif + using (MovieDBContext db = new MovieDBContext()) + { + db.Database.Initialize(true); + + List strIds = new List(new string[] { "two" }); + var q = db.Movies.Where(p => strIds.Contains("two")); + string sql = q.ToString(); + CheckSql(sql, SQLSyntax.TestContainsListWitConstant); +#if DEBUG + Debug.WriteLine(sql); +#endif + var l = q.ToList(); + } + } + + /// + /// Test to reproduce bug http://bugs.mysql.com/bug.php?id=73643, Exception when using IEnumera.Contains(model.property) in Where predicate + /// + [Test] + public void TestContainsListWithParameterReference() + { +#if DEBUG + Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); +#endif + using (MovieDBContext db = new MovieDBContext()) + { + db.Database.Initialize(true); + + long[] longs = new long[] { 1, 2, 3 }; + int myNum = 1; + var q = db.Movies.Where(p => longs.Contains(myNum)); + string sql = q.ToString(); + CheckSql(sql, SQLSyntax.TestContainsListWithParameterReference); +#if DEBUG + Debug.WriteLine(sql); +#endif + var l = q.ToList(); + } + } + + [Test] + public void ReplaceTableNameVisitor() + { + using (SakilaDb context = new SakilaDb()) + { + var date = new DateTime(2005, 6, 1); + var rentals = context.customers.Where(t => t.rentals.Any(r => r.rental_date < date)).OrderBy(o => o.customer_id); + string sql = rentals.ToString(); + CheckSql(sql, SQLSyntax.ReplaceNameVisitorQuery); +#if DEBUG + Debug.WriteLine(sql); +#endif + var result = rentals.ToList(); + Assert.That(rentals.Count(), Is.EqualTo(520)); + } + } + + + /// + /// Bug #70941 - Invalid SQL query when eager loading two nested collections + /// + [Test] + public void InvalidQuery() + { + using (UsingUnionContext context = new UsingUnionContext()) + { + if (context.Database.Exists()) + context.Database.Delete(); + + context.Database.Create(); + + for (int i = 1; i <= 3; i++) + { + var order = new Order(); + var items = new List(); + + items.Add(new Item { Id = 1 }); + items.Add(new Item { Id = 2 }); + items.Add(new Item { Id = 3 }); + + order.Items = items; + var client = new Client { Id = i }; + client.Orders = new List(); + client.Orders.Add(order); + + context.Clients.Add(client); + } + context.SaveChanges(); + + var clients = context.Clients + .Include(c => c.Orders.Select(o => o.Items)) + .Include(c => c.Orders.Select(o => o.Discounts)).ToList(); + + Assert.That(3, Is.EqualTo(clients.Count())); + Assert.That(1, Is.EqualTo(clients.Where(t => t.Id == 1).Single().Orders.Count())); + Assert.That(3, Is.EqualTo(clients.Where(t => t.Id == 1).Single().Orders.Where(j => j.Id == 1).Single().Items.Count())); + } + } + + /// + /// Bug #28095165 - CONTRIBUTION: FIX CONCURRENCYCHECK + DATABASEGENERATEDOPTION.COMPUTED + /// + [Test] + public void ConcurrencyCheckWithDbGeneratedColumn() + { +#if DEBUG + Debug.WriteLine(new StackTrace().GetFrame(0).GetMethod().Name); +#endif + using (MovieDBContext db = new MovieDBContext()) + { + db.Database.Delete(); + db.Database.CreateIfNotExists(); + db.Database.Log = (e) => Debug.WriteLine(e); + db.Database.ExecuteSqlCommand(@"DROP TABLE IF EXISTS `MovieReleases2`"); + + db.Database.ExecuteSqlCommand( + @"CREATE TABLE IF NOT EXISTS `MovieRelease2` ( + `Id` int(11) NOT NULL, + `Name` varchar(45) NOT NULL, + `Timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `RowVersion` bigint NOT NULL DEFAULT 0, + PRIMARY KEY (`Id`) + ) ENGINE=InnoDB DEFAULT CHARSET=binary"); + + db.Database.ExecuteSqlCommand( + @"CREATE TRIGGER `trg_MovieRelease2_before_update` + BEFORE UPDATE ON `MovieRelease2` + FOR EACH ROW SET NEW.RowVersion = OLD.RowVersion + 1;"); + + MySqlTrace.Listeners.Clear(); + MySqlTrace.Switch.Level = SourceLevels.All; + GenericListener listener = new GenericListener(); + MySqlTrace.Listeners.Add(listener); + + try + { + MovieRelease2 mr = db.MovieReleases2.Create(); + mr.Id = 1; + mr.Name = "Commercial"; + db.MovieReleases2.Add(mr); + Assert.That(0, Is.EqualTo(mr.RowVersion)); + db.SaveChanges(); // ADD + Assert.That(0, Is.EqualTo(mr.RowVersion)); + + mr.Name = "Director's Cut"; + db.SaveChanges(); // UPDATE #1 + Assert.That(1, Is.EqualTo(mr.RowVersion)); + + mr.Name = "Avengers"; + db.SaveChanges(); // UPDATE #2 + Assert.That(2, Is.EqualTo(mr.RowVersion)); + } + finally + { + db.Database.ExecuteSqlCommand(@"DROP TABLE IF EXISTS `MovieReleases2`"); + } + // Check sql + Regex rx = new Regex(@"Query Opened: (?UPDATE .*)", RegexOptions.Compiled | RegexOptions.Singleline); + int n = 0; + foreach (string s in listener.Strings) + { + Match m = rx.Match(s); + if (m.Success) + { + if (n++ == 0) + { + CheckSql(m.Groups["item"].Value, SQLSyntax.UpdateWithSelectWithDbGeneratedLock1); + } + else + { + CheckSql(m.Groups["item"].Value, SQLSyntax.UpdateWithSelectWithDbGeneratedLock2); + } + } + } + } + } + + /// + /// Bug #31323788 - EF6 CODE FIRST - TABLE SCHEMAS ARE LOST, BUT AUTOMATIC MIGRATIONS USES THEM + /// + [Test] + public void TablesWithSchema() + { + using (BlogContext context = new BlogContext()) + { + var blog = new Blog { Title = "Blog_1" }; + context.Blog.Add(blog); + + blog = new Blog { Title = "Blog_2" }; + context.Blog.Add(blog); + + context.SaveChanges(); + Assert.That(context.Blog.Count(), Is.EqualTo(2)); + Assert.That(context.Blog.First(b => b.Title == "Blog_2").BlogId, Is.EqualTo(2)); + + context.Blog.Remove(blog); + context.SaveChanges(); + Assert.That(context.Blog.Count(), Is.EqualTo(1)); + Assert.That(context.Blog.First().Title, Is.EqualTo("Blog_1")); + } + } + + [Test, Description("UNION SYNTAX MISSING REQUIRED PARENTHESIS")] + public void UnionSyntax() + { + using (var context = new ContextForString()) + { + context.Database.Delete(); + context.Database.Create(); + context.StringUsers.Add(new StringUser + { + StringUserId = 1, + Name50 = "Juan", + Name100 = "100", + Name200 = "200", + Name300 = "300" + }); + context.StringUsers.Add(new StringUser + { + StringUserId = 2, + Name50 = "Pedro", + Name100 = "cien", + Name200 = "doscientos", + Name300 = "trescientos" + }); + context.StringUsers.Add(new StringUser + { + StringUserId = 3, + Name50 = "Lupe", + Name100 = "101", + Name200 = "cxvbx", + Name300 = "301" + }); + context.StringUsers.Add(new StringUser + { + StringUserId = 4, + Name50 = "Luis", + Name100 = "asdf", + Name200 = "wrwe", + Name300 = "xcvb" + }); + context.StringUsers.Add(new StringUser + { + StringUserId = 5, + Name50 = "Pepe", + Name100 = "asdf", + Name200 = "zxvz", + Name300 = "fgsd" + }); + context.SaveChanges(); + + var query1 = context.StringUsers; + var query2 = query1.Take(0).Concat(query1); + var query3 = query1.Concat(query1.Take(0)); + Assert.That((query1.Count() == 5) & (query2.Count() == 5) & (query3.Count() == 5)); + } + } + + [Test, Description("FK name ,longer than 64 chars are named to FK_")] + public void NormalForeignKey() + { + using (var context = new ContextForNormalFk()) + { + context.Database.Initialize(true); + using (MySqlConnection conn = new MySqlConnection(context.Database.Connection.ConnectionString)) + { + conn.Open(); + var cmd = new MySqlCommand(); + var entityName = (context.Permisos.GetType().FullName.Split(',')[0]).Substring(66).ToLowerInvariant(); + var contextName = context.GetType().Name.ToLowerInvariant(); + cmd.Connection = conn; + cmd.CommandText = + $"SELECT CONSTRAINT_NAME FROM information_schema.REFERENTIAL_CONSTRAINTS WHERE CONSTRAINT_SCHEMA = '{contextName}' and TABLE_NAME = '{entityName}';"; + cmd.ExecuteNonQuery(); + + using (var reader = cmd.ExecuteReader()) + { + while (reader.Read()) + { + var val = reader.GetValue(0); + Assert.That(val.ToString().Contains("FK_")); + } + } + } + } + } + + [Test, Description("FK name ,longer than 64 chars are named to FK_")] + public void LongForeignKey() + { + using (var context = new ContextForLongFk()) + { + context.Database.Initialize(true); + var entityName = (context.Permisos.GetType().FullName.Split(',')[0]).Substring(66).ToLowerInvariant(); + var contextName = context.GetType().Name.ToLowerInvariant(); + using (MySqlConnection conn = new MySqlConnection(context.Database.Connection.ConnectionString)) + { + conn.Open(); + var cmd = new MySqlCommand(); + cmd.Connection = conn; + cmd.CommandText = + $"SELECT CONSTRAINT_NAME FROM information_schema.REFERENTIAL_CONSTRAINTS WHERE CONSTRAINT_SCHEMA = '{contextName}' and TABLE_NAME = '{entityName}';"; + cmd.ExecuteNonQuery(); + + using (var reader = cmd.ExecuteReader()) + { + while (reader.Read()) + { + var val = reader.GetValue(0); + Assert.That(val.ToString().Contains("FK_")); + } + } + } + } + } + + [Test, Description("Verify that Null Reference Exception is not thrown when try to save entity with TINYINT AS PK ")] + public void SaveTinyIntAsPK() + { + using (var context = new ContextForTinyPk()) + { + context.Database.Delete(); + context.Database.Create(); + context.TinyPkUseRs.Add(new TinyPkUser + { + StringUserId = 1, + Name50 = "Juan", + Name100 = "100", + Name200 = "200", + Name300 = "300" + }); + + context.TinyPkUseRs.Add(new TinyPkUser + { + StringUserId = 2, + Name50 = "Pedro", + Name100 = "cien", + Name200 = "doscientos", + Name300 = "trescientos" + }); + + context.TinyPkUseRs.Add(new TinyPkUser + { + StringUserId = 3, + Name50 = "Lupe", + Name100 = "101", + Name200 = "cxvbx", + Name300 = "301" + }); + + context.TinyPkUseRs.Add(new TinyPkUser + { + StringUserId = 4, + Name50 = "Luis", + Name100 = "asdf", + Name200 = "wrwe", + Name300 = "xcvb" + }); + + context.TinyPkUseRs.Add(new TinyPkUser + { + StringUserId = 5, + Name50 = "Pepe", + Name100 = "asdf", + Name200 = "zxvz", + Name300 = "fgsd" + }); + context.SaveChanges(); + var query1 = context.TinyPkUseRs; + var query2 = query1.Take(0).Concat(query1); + var query3 = query1.Concat(query1.Take(0)); + Assert.That((query1.Count() == 5) & (query2.Count() == 5) & (query3.Count() == 5)); + } + } + + [Test, Description("Verify that Null Reference Exception is not thrown when try to save entity with BIGINT AS PK ")] + public void SaveBigIntAsPK() + { + using (var context = new ContextForBigIntPk()) + { + context.Database.Delete(); + context.Database.Create(); + context.BigIntPkUseRs.Add(new BigIntPkUser + { + StringUserId = 934157136952, + Name50 = "Juan", + Name100 = "100", + Name200 = "200", + Name300 = "300" + }); + + context.BigIntPkUseRs.Add(new BigIntPkUser + { + StringUserId = 934157136953, + Name50 = "Pedro", + Name100 = "cien", + Name200 = "doscientos", + Name300 = "trescientos" + }); + + context.BigIntPkUseRs.Add(new BigIntPkUser + { + StringUserId = 9223372036854775807, + Name50 = "Lupe", + Name100 = "101", + Name200 = "cxvbx", + Name300 = "301" + }); + + context.BigIntPkUseRs.Add(new BigIntPkUser + { + StringUserId = 0, + Name50 = "Luis", + Name100 = "asdf", + Name200 = "wrwe", + Name300 = "xcvb" + }); + + context.BigIntPkUseRs.Add(new BigIntPkUser + { + StringUserId = -9223372036854775808, + Name50 = "Pepe", + Name100 = "asdf", + Name200 = "zxvz", + Name300 = "fgsd" + }); + context.SaveChanges(); + var query1 = context.BigIntPkUseRs; + var query2 = query1.Take(0).Concat(query1); + var query3 = query1.Concat(query1.Take(0)); + Assert.That((query1.Count() == 5) & (query2.Count() == 5) & (query3.Count() == 5)); + } + } + + [Test, Description("TRANSACTION AFTER A FAILED TRANSACTION((USING BeginTransaction)) Commit")] + public void BeginTransNested() + { + using (var context = new EnumTestSupportContext()) + { + using (var trans = context.Database.BeginTransaction()) + { + Thread.Sleep(5000); + Assert.Catch(() => context.Database.ExecuteSqlCommand("update table schoolschedule")); + trans.Commit(); + } + using (var trans = context.Database.BeginTransaction()) + { + context.SchoolSchedules.Add(new SchoolSchedule + { + TeacherName = "Ruben", + Subject = SchoolSubject.History + }); + ; + + context.SchoolSchedules.Add(new SchoolSchedule + { + TeacherName = "Peter", + Subject = SchoolSubject.Chemistry + }); + ; + + context.SchoolSchedules.Add(new SchoolSchedule + { + TeacherName = "Juan", + Subject = SchoolSubject.Math + }); + ; + context.SaveChanges(); + trans.Commit(); + } + var count = context.SchoolSchedules.Count(); + Assert.That(count, Is.EqualTo(3)); + //Rollback + using (var trans = context.Database.BeginTransaction()) + { + Assert.Catch(() => context.Database.ExecuteSqlCommand("update table schoolschedule")); + trans.Rollback(); + } + using (var trans = context.Database.BeginTransaction()) + { + context.SchoolSchedules.Add(new SchoolSchedule + { + TeacherName = "Andrew", + Subject = SchoolSubject.History + }); ; + ; + context.SaveChanges(); + trans.Commit(); + } + count = context.SchoolSchedules.Count(); + Assert.That(count, Is.EqualTo(4)); + } + + } + + [Test, Description("TRANSACTION AFTER A FAILED TRANSACTION((USING BeginTransaction)) Stress Test")] + public void TransactionAfterFailStressTest() + { + for (var i = 0; i < 100; i++) + { + using (var context = new EnumTestSupportContext()) + { + using (var trans = context.Database.BeginTransaction()) + { + Assert.Catch(() => context.Database.ExecuteSqlCommand("update table schoolschedule")); + trans.Commit(); + } + using (var trans = context.Database.BeginTransaction()) + { + context.SchoolSchedules.Add(new SchoolSchedule + { + TeacherName = "Ruben", + Subject = SchoolSubject.History + }); + ; + + context.SchoolSchedules.Add(new SchoolSchedule + { + TeacherName = "Peter", + Subject = SchoolSubject.Chemistry + }); + ; + + context.SchoolSchedules.Add(new SchoolSchedule + { + TeacherName = "Juan", + Subject = SchoolSubject.Math + }); + context.SaveChanges(); + trans.Commit(); + var count = context.SchoolSchedules.Count(); + Assert.That(count > 0); + } + } + } + } + + + [Test, Description("Wrong SQL Statement to set primary key ")] + public void WrongSQLStatementPK() + { + using (var context = new EducationContext()) + { + context.Database.Delete(); + context.Database.Create(); + context.Passports.Add(new Passport { Key = 1 }); + context.SaveChanges(); + context.Database.ExecuteSqlCommand("ALTER TABLE `passports` CHANGE `Key` `Key1` int NOT NULL AUTO_INCREMENT UNIQUE"); + context.Database.ExecuteSqlCommand("ALTER TABLE `passports` DROP PRIMARY KEY"); + } + + using (var context = new EducationContext()) + { + context.Passports.Add(new Passport { Key = 1 }); + Exception ex = Assert.Catch(() => context.SaveChanges()); + context.Database.Delete(); + } + } + + /// + /// Bug #34498485 [MySQL.Data.EntityFramework does not handle LIKE (Edm.IndexOf) cases] + /// + [Test] + public void TestListMatchingLike() + { + using (VehicleDbContext2 context = new VehicleDbContext2()) + { + context.Database.Delete(); + context.Database.Initialize(true); + + context.Vehicles.Add(new Car2 { Id = 1, Name = "Mustang", Year = 2012, CarProperty = "Car" }); + context.Vehicles.Add(new Bike2 { Id = 101, Name = "Mountain", Year = 2011, BikeProperty = "Bike" }); + context.SaveChanges(); + + string[] matchText = new string[] { "must", "tan" }; + var list = context.Vehicles.Where(v => matchText.Any(t => v.Name.Contains(t))); + Assert.That(list.Count(), Is.EqualTo(1)); + + matchText = new string[] { "mus't", "tan" }; + list = context.Vehicles.Where(v => matchText.Any(t => v.Name.Contains(t))); + Assert.That(list.Count(), Is.EqualTo(1)); + + matchText = new string[] { "%" }; + list = context.Vehicles.Where(v => matchText.Any(t => v.Name.Contains(t))); + Assert.That(list.Count(), Is.EqualTo(0)); + + matchText = new string[] { "tan" }; + list = context.Vehicles.Where(v => matchText.Any(t => v.Name.Contains(t))); + Assert.That(list.Count(), Is.EqualTo(1)); + + matchText = new string[] { "_" }; + list = context.Vehicles.Where(v => matchText.Any(t => v.Name.Contains(t))); + Assert.That(list.Count(), Is.EqualTo(0)); + } + } + } +} diff --git a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/ContextForNormalFk.cs b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/ContextForNormalFk.cs index af0011378..4f867370d 100644 --- a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/ContextForNormalFk.cs +++ b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/ContextForNormalFk.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021 Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/ContextForString.cs b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/ContextForString.cs index e856ae228..131e32d2b 100644 --- a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/ContextForString.cs +++ b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/ContextForString.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021 Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/Dinosauria.cs b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/Dinosauria.cs index c8eee7e95..fcbd96de0 100644 --- a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/Dinosauria.cs +++ b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/Dinosauria.cs @@ -1,89 +1,89 @@ -// Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.ComponentModel.DataAnnotations; -using System.Data.Entity; -using System.ComponentModel.DataAnnotations.Schema; - - - -namespace MySql.Data.EntityFramework.CodeFirst.Tests -{ - /* - * This data model tests very long names to break FK limit of 64 chars. - * Also uses Table per Type inheritance (TPT). - * */ - public class Animalia_Chordata_Dinosauria_Eusaurischia_Theropoda - { - [Key, DatabaseGenerated(DatabaseGeneratedOption.None)] - public int Id { get; set; } - - [MaxLength(40)] - public string Name { get; set; } - } - - [Table("Tyrannosauridaes")] - public class Tyrannosauridae : Animalia_Chordata_Dinosauria_Eusaurischia_Theropoda - { - public string SpecieName { get; set; } - public float Weight { get; set; } - } - - [Table("Oviraptorosaurias")] - public class Oviraptorosauria : Animalia_Chordata_Dinosauria_Eusaurischia_Theropoda - { - public string SpecieName { get; set; } - public int EggsPerYear { get; set; } - } - - [DbConfigurationType(typeof(MySqlEFConfiguration))] - public class DinosauriaDBContext : DbContext - { - public DbSet dinos { get; set; } - - public DinosauriaDBContext() : base(CodeFirstFixture.GetEFConnectionString()) - { - Database.SetInitializer(new DinosauriaDBInitializer()); - } - - protected override void OnModelCreating(DbModelBuilder modelBuilder) - { - modelBuilder.Entity().ToTable("Tyrannosauridaes"); - modelBuilder.Entity().ToTable("Oviraptorosaurias"); - } - } - - public class DinosauriaDBInitializer : DropCreateDatabaseReallyAlways - { - } -} +// Copyright © 2014, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.ComponentModel.DataAnnotations; +using System.Data.Entity; +using System.ComponentModel.DataAnnotations.Schema; + + + +namespace MySql.Data.EntityFramework.CodeFirst.Tests +{ + /* + * This data model tests very long names to break FK limit of 64 chars. + * Also uses Table per Type inheritance (TPT). + * */ + public class Animalia_Chordata_Dinosauria_Eusaurischia_Theropoda + { + [Key, DatabaseGenerated(DatabaseGeneratedOption.None)] + public int Id { get; set; } + + [MaxLength(40)] + public string Name { get; set; } + } + + [Table("Tyrannosauridaes")] + public class Tyrannosauridae : Animalia_Chordata_Dinosauria_Eusaurischia_Theropoda + { + public string SpecieName { get; set; } + public float Weight { get; set; } + } + + [Table("Oviraptorosaurias")] + public class Oviraptorosauria : Animalia_Chordata_Dinosauria_Eusaurischia_Theropoda + { + public string SpecieName { get; set; } + public int EggsPerYear { get; set; } + } + + [DbConfigurationType(typeof(MySqlEFConfiguration))] + public class DinosauriaDBContext : DbContext + { + public DbSet dinos { get; set; } + + public DinosauriaDBContext() : base(CodeFirstFixture.GetEFConnectionString()) + { + Database.SetInitializer(new DinosauriaDBInitializer()); + } + + protected override void OnModelCreating(DbModelBuilder modelBuilder) + { + modelBuilder.Entity().ToTable("Tyrannosauridaes"); + modelBuilder.Entity().ToTable("Oviraptorosaurias"); + } + } + + public class DinosauriaDBInitializer : DropCreateDatabaseReallyAlways + { + } +} diff --git a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/Movie.cs b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/Movie.cs index 36548776d..e7a03477e 100644 --- a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/Movie.cs +++ b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/Movie.cs @@ -1,176 +1,176 @@ -// Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - - -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Linq; -using System.Text; -using System.Data.Entity; -using System.Data.Entity.ModelConfiguration.Conventions; -using System.Data.Entity.Migrations; -using System.ComponentModel.DataAnnotations.Schema; - - -namespace MySql.Data.EntityFramework.CodeFirst.Tests -{ - public class Movie - { - public int ID { get; set; } - public string Title { get; set; } - public DateTime ReleaseDate { get; set; } - public string Genre { get; set; } - public decimal Price { get; set; } - public Director Director { get; set; } - public virtual ICollection Formats { get; set; } - public virtual ICollection Medias { get; set; } - public byte[] Data { get; set; } - } - - public class MovieMedia - { - public int ID { get; set; } - public int MovieID { get; set; } - public string Format { get; set; } - } - - public class Director - { - public int ID { get; set; } - public string Name { get; set; } - public int YearBorn { get; set; } - } - - public class MovieFormat - { - [Key] - public float Format { get; set; } - } - - [DbConfigurationType(typeof(MySqlEFConfiguration))] - public class MovieDBContext : DbContext - { - public DbSet Movies { get; set; } - public DbSet MovieFormats { get; set; } - public DbSet MovieReleases { get; set; } - public DbSet MovieReleases2 { get; set; } - public DbSet EntitySingleColumns { get; set; } - public DbSet Medias { get; set; } - - - - public MovieDBContext() : base(CodeFirstFixture.GetEFConnectionString()) - { - //Database.SetInitializer(new MigrateDatabaseToLatestVersion>()); - Database.SetInitializer(new DropCreateDatabaseAlways()); - } - - protected override void OnModelCreating(DbModelBuilder modelBuilder) - { - base.OnModelCreating(modelBuilder); - modelBuilder.Configurations.AddFromAssembly(System.Reflection.Assembly.GetExecutingAssembly()); - modelBuilder.Entity().Property(x => x.Price).HasPrecision(16, 2); - modelBuilder.Entity().HasMany(p => p.Formats); - modelBuilder.Entity().HasMany( p => p.Medias ); -} - } - - public class EntitySingleColumn - { - public int Id { get; set; } - } - - public class MovieRelease - { - [Key, DatabaseGenerated(DatabaseGeneratedOption.None)] - public virtual int Id { get; set; } - - [DatabaseGenerated(DatabaseGeneratedOption.Computed)] - public virtual DateTime Timestamp { get; set; } - - // Test: ConcurrencyCheck + Not Computed - [ConcurrencyCheck, Required, MaxLength(45)] - public virtual string Name { get; set; } - } - - public class MovieRelease2 - { - [Key, DatabaseGenerated(DatabaseGeneratedOption.None)] - public virtual int Id { get; set; } - - //[DatabaseGenerated(DatabaseGeneratedOption.Computed)] - //public virtual DateTime Timestamp { get; set; } - - // Test: non computed column - [Required, MaxLength(45)] - public virtual string Name { get; set; } - - // Test: ConcurrencyCheck + Computed - [ConcurrencyCheck, DatabaseGenerated(DatabaseGeneratedOption.Computed)] - [Column(TypeName = "bigint")] - public virtual long RowVersion { get; set; } - } - - public class MovieDBInitialize : DropCreateDatabaseReallyAlways - { - public static Movie[] data = new Movie[] { - new Movie() { ID = 4, Title = "Star Wars, The Sith Revenge", ReleaseDate = new DateTime( 2005, 5, 19 ) }, - new Movie() { ID = 3, Title = "Predator", ReleaseDate = new DateTime(1987, 6, 12) }, - new Movie() { ID = 2, Title = "The Matrix", ReleaseDate = new DateTime( 1999, 3, 31 ) }, - new Movie() { ID = 1, Title = "Terminator 1", ReleaseDate = new DateTime(1984, 10, 26) } - }; - - internal static void DoDataPopulation( MovieDBContext ctx ) - { - ctx.Database.ExecuteSqlCommand("CREATE PROCEDURE GetCount() BEGIN SELECT 5; END"); - Movie m1 = new Movie() { Title = "Terminator 1", ReleaseDate = new DateTime(1984, 10, 26) }; - Movie m2 = new Movie() { Title = "The Matrix", ReleaseDate = new DateTime(1999, 3, 31) }; - Movie m3 = new Movie() { Title = "Predator", ReleaseDate = new DateTime(1987, 6, 12) }; - Movie m4 = new Movie() { Title = "Star Wars, The Sith Revenge", ReleaseDate = new DateTime(2005, 5, 19) }; - ctx.Movies.Add(m1); - ctx.Movies.Add(m2); - ctx.Movies.Add(m3); - ctx.Movies.Add(m4); - ctx.SaveChanges(); - ctx.Entry(m1).Collection(p => p.Medias).Load(); - m1.Medias.Add( new MovieMedia() { Format = "DVD" } ); - m1.Medias.Add( new MovieMedia() { Format = "BlueRay" } ); - ctx.Entry(m2).Collection(p => p.Medias).Load(); - m2.Medias.Add(new MovieMedia() { Format = "DVD" }); - m2.Medias.Add(new MovieMedia() { Format = "Digital" }); - ctx.Entry(m3).Collection(p => p.Medias).Load(); - m3.Medias.Add(new MovieMedia() { Format = "DVD" }); - m3.Medias.Add(new MovieMedia() { Format = "VHS" }); - ctx.Entry(m4).Collection(p => p.Medias).Load(); - m4.Medias.Add(new MovieMedia() { Format = "Digital" }); - m4.Medias.Add(new MovieMedia() { Format = "VHS" }); - ctx.SaveChanges(); - } - } -} \ No newline at end of file +// Copyright © 2014, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using System.Data.Entity; +using System.Data.Entity.ModelConfiguration.Conventions; +using System.Data.Entity.Migrations; +using System.ComponentModel.DataAnnotations.Schema; + + +namespace MySql.Data.EntityFramework.CodeFirst.Tests +{ + public class Movie + { + public int ID { get; set; } + public string Title { get; set; } + public DateTime ReleaseDate { get; set; } + public string Genre { get; set; } + public decimal Price { get; set; } + public Director Director { get; set; } + public virtual ICollection Formats { get; set; } + public virtual ICollection Medias { get; set; } + public byte[] Data { get; set; } + } + + public class MovieMedia + { + public int ID { get; set; } + public int MovieID { get; set; } + public string Format { get; set; } + } + + public class Director + { + public int ID { get; set; } + public string Name { get; set; } + public int YearBorn { get; set; } + } + + public class MovieFormat + { + [Key] + public float Format { get; set; } + } + + [DbConfigurationType(typeof(MySqlEFConfiguration))] + public class MovieDBContext : DbContext + { + public DbSet Movies { get; set; } + public DbSet MovieFormats { get; set; } + public DbSet MovieReleases { get; set; } + public DbSet MovieReleases2 { get; set; } + public DbSet EntitySingleColumns { get; set; } + public DbSet Medias { get; set; } + + + + public MovieDBContext() : base(CodeFirstFixture.GetEFConnectionString()) + { + //Database.SetInitializer(new MigrateDatabaseToLatestVersion>()); + Database.SetInitializer(new DropCreateDatabaseAlways()); + } + + protected override void OnModelCreating(DbModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + modelBuilder.Configurations.AddFromAssembly(System.Reflection.Assembly.GetExecutingAssembly()); + modelBuilder.Entity().Property(x => x.Price).HasPrecision(16, 2); + modelBuilder.Entity().HasMany(p => p.Formats); + modelBuilder.Entity().HasMany( p => p.Medias ); +} + } + + public class EntitySingleColumn + { + public int Id { get; set; } + } + + public class MovieRelease + { + [Key, DatabaseGenerated(DatabaseGeneratedOption.None)] + public virtual int Id { get; set; } + + [DatabaseGenerated(DatabaseGeneratedOption.Computed)] + public virtual DateTime Timestamp { get; set; } + + // Test: ConcurrencyCheck + Not Computed + [ConcurrencyCheck, Required, MaxLength(45)] + public virtual string Name { get; set; } + } + + public class MovieRelease2 + { + [Key, DatabaseGenerated(DatabaseGeneratedOption.None)] + public virtual int Id { get; set; } + + //[DatabaseGenerated(DatabaseGeneratedOption.Computed)] + //public virtual DateTime Timestamp { get; set; } + + // Test: non computed column + [Required, MaxLength(45)] + public virtual string Name { get; set; } + + // Test: ConcurrencyCheck + Computed + [ConcurrencyCheck, DatabaseGenerated(DatabaseGeneratedOption.Computed)] + [Column(TypeName = "bigint")] + public virtual long RowVersion { get; set; } + } + + public class MovieDBInitialize : DropCreateDatabaseReallyAlways + { + public static Movie[] data = new Movie[] { + new Movie() { ID = 4, Title = "Star Wars, The Sith Revenge", ReleaseDate = new DateTime( 2005, 5, 19 ) }, + new Movie() { ID = 3, Title = "Predator", ReleaseDate = new DateTime(1987, 6, 12) }, + new Movie() { ID = 2, Title = "The Matrix", ReleaseDate = new DateTime( 1999, 3, 31 ) }, + new Movie() { ID = 1, Title = "Terminator 1", ReleaseDate = new DateTime(1984, 10, 26) } + }; + + internal static void DoDataPopulation( MovieDBContext ctx ) + { + ctx.Database.ExecuteSqlCommand("CREATE PROCEDURE GetCount() BEGIN SELECT 5; END"); + Movie m1 = new Movie() { Title = "Terminator 1", ReleaseDate = new DateTime(1984, 10, 26) }; + Movie m2 = new Movie() { Title = "The Matrix", ReleaseDate = new DateTime(1999, 3, 31) }; + Movie m3 = new Movie() { Title = "Predator", ReleaseDate = new DateTime(1987, 6, 12) }; + Movie m4 = new Movie() { Title = "Star Wars, The Sith Revenge", ReleaseDate = new DateTime(2005, 5, 19) }; + ctx.Movies.Add(m1); + ctx.Movies.Add(m2); + ctx.Movies.Add(m3); + ctx.Movies.Add(m4); + ctx.SaveChanges(); + ctx.Entry(m1).Collection(p => p.Medias).Load(); + m1.Medias.Add( new MovieMedia() { Format = "DVD" } ); + m1.Medias.Add( new MovieMedia() { Format = "BlueRay" } ); + ctx.Entry(m2).Collection(p => p.Medias).Load(); + m2.Medias.Add(new MovieMedia() { Format = "DVD" }); + m2.Medias.Add(new MovieMedia() { Format = "Digital" }); + ctx.Entry(m3).Collection(p => p.Medias).Load(); + m3.Medias.Add(new MovieMedia() { Format = "DVD" }); + m3.Medias.Add(new MovieMedia() { Format = "VHS" }); + ctx.Entry(m4).Collection(p => p.Medias).Load(); + m4.Medias.Add(new MovieMedia() { Format = "Digital" }); + m4.Medias.Add(new MovieMedia() { Format = "VHS" }); + ctx.SaveChanges(); + } + } +} diff --git a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/MovieContextCodeBasedConfiguration.cs b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/MovieContextCodeBasedConfiguration.cs index 5e8d55cf6..eba30e4e5 100644 --- a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/MovieContextCodeBasedConfiguration.cs +++ b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/MovieContextCodeBasedConfiguration.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -282,4 +282,4 @@ protected override void OnModelCreating(DbModelBuilder modelBuilder) } } #endregion -} \ No newline at end of file +} diff --git a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/MySql.EntityFramework.CodeFirst.Tests.csproj b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/MySql.EntityFramework.CodeFirst.Tests.csproj index 394433997..f1a6065cc 100644 --- a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/MySql.EntityFramework.CodeFirst.Tests.csproj +++ b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/MySql.EntityFramework.CodeFirst.Tests.csproj @@ -2,17 +2,17 @@ MySql.Data.EntityFramework.CodeFirst.Tests - Copyright (c) 2016, 2023, Oracle and/or its affiliates. + Copyright © 2016, 2025, Oracle and/or its affiliates. en-US - 8.2.0 + 9.4.0 Oracle - net7.0 + net462;net48;net9.0 MySql.EntityFramework.CodeFirst.Tests MySql.EntityFramework.CodeFirst.Tests MySql;.NET Connector;MySql Connector/NET http://www.mysql.com/common/logos/logo-mysql-170x115.png http://dev.mysql.com/downloads/ - GPL-2.0-only + GPL-2.0-only WITH Universal-FOSS-exception-1.0 true false false @@ -25,6 +25,7 @@ True ..\..\..\ConnectorNetPublicKey.snk CA2100 + latest @@ -48,21 +49,6 @@ - - - - - - - - true - - - - true - - - @@ -74,8 +60,20 @@ + + + + + + true + + + + true + + True diff --git a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/PromotionsDB.cs b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/PromotionsDB.cs index fa8c0c36f..9ac820133 100644 --- a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/PromotionsDB.cs +++ b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/PromotionsDB.cs @@ -1,89 +1,89 @@ -// Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Data.Entity; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; - -namespace MySql.Data.EntityFramework.CodeFirst.Tests -{ - [DbConfigurationType(typeof(MySqlEFConfiguration))] - public class PromotionsDB : DbContext - { - private bool disposed = false; - - public virtual DbSet HomePromoes { get; set; } - - public PromotionsDB() : base(CodeFirstFixture.GetEFConnectionString()) - { - Database.SetInitializer(new PromotionsDBInitializer()); - } - - protected override void Dispose(bool disposing) - { - if (disposed) - return; - - if (disposing) - { - Database.Delete(); - } - - base.Dispose(disposing); - disposed = true; - } - } - - public class PromotionsDBInitializer : DropCreateDatabaseReallyAlways - { - } - - public class HomePromo - { - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - [Key] - public int ID { get; set; } - - public string Image { get; set; } - - public string Url { get; set; } - - public int DisplayOrder { get; set; } - - [Column("Active")] - public bool Active { get; set; } - [Column("ActiveFrom")] - public DateTime? ActiveFrom { get; set; } - [Column("ActiveTo")] - public DateTime? ActiveTo { get; set; } - } -} +// Copyright © 2014, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Data.Entity; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace MySql.Data.EntityFramework.CodeFirst.Tests +{ + [DbConfigurationType(typeof(MySqlEFConfiguration))] + public class PromotionsDB : DbContext + { + private bool disposed = false; + + public virtual DbSet HomePromoes { get; set; } + + public PromotionsDB() : base(CodeFirstFixture.GetEFConnectionString()) + { + Database.SetInitializer(new PromotionsDBInitializer()); + } + + protected override void Dispose(bool disposing) + { + if (disposed) + return; + + if (disposing) + { + Database.Delete(); + } + + base.Dispose(disposing); + disposed = true; + } + } + + public class PromotionsDBInitializer : DropCreateDatabaseReallyAlways + { + } + + public class HomePromo + { + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + [Key] + public int ID { get; set; } + + public string Image { get; set; } + + public string Url { get; set; } + + public int DisplayOrder { get; set; } + + [Column("Active")] + public bool Active { get; set; } + [Column("ActiveFrom")] + public DateTime? ActiveFrom { get; set; } + [Column("ActiveTo")] + public DateTime? ActiveTo { get; set; } + } +} diff --git a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/Properties/AssemblyInfo.cs b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/Properties/AssemblyInfo.cs index 0dac870b6..deb966b88 100644 --- a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/Properties/AssemblyInfo.cs +++ b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/Properties/AssemblyInfo.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2014, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -38,7 +38,7 @@ [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Oracle")] [assembly: AssemblyProduct("MySql.EntityFramework.CodeFirst.Tests")] -[assembly: AssemblyCopyright("Copyright © 2011, 2019, Oracle and/or its affiliates. All rights reserved.")] +[assembly: AssemblyCopyright("Copyright © 2011, 2025, Oracle and/or its affiliates.")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] @@ -53,4 +53,4 @@ #if !DEBUG [assembly: AssemblyKeyName("ConnectorNet")] #endif -[assembly: NonParallelizable] \ No newline at end of file +[assembly: NonParallelizable] diff --git a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/Properties/SQLSyntax.Designer.cs b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/Properties/SQLSyntax.Designer.cs index 4c020c55a..f96530dd5 100644 --- a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/Properties/SQLSyntax.Designer.cs +++ b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/Properties/SQLSyntax.Designer.cs @@ -1,383 +1,383 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace MySql.EntityFramework.CodeFirst.Tests.Properties { - using System; - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class SQLSyntax { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal SQLSyntax() { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("MySql.EntityFramework.CodeFirst.Tests.Properties.SQLSyntax", typeof(SQLSyntax).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - /// - /// Looks up a localized string similar to SELECT - ///1 AS `C1`, - ///`Project3`.`nCdSite`, - ///`Project3`.`C1` AS `C2` - ///FROM (SELECT - ///`visitante`.`nCdSite`, - ///COUNT(DISTINCT `visitante`.`sDsIp`) AS `C1` - ///FROM `visitante` - /// GROUP BY - ///`visitante`.`nCdSite`) AS `Project3`. - /// - internal static string CountGroupBy { - get { - return ResourceManager.GetString("CountGroupBy", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to SELECT - ///1 AS `C1`, - ///`Project3`.`nCdSite`, - ///`Project3`.`C1` AS `C2` - ///FROM (SELECT - ///`Extent4`.`nCdSite`, - ///COUNT(DISTINCT `Extent4`.`sDsIp`) AS `C1` - ///FROM `pagina` AS `Extent3` INNER JOIN `visitante` AS `Extent4` ON `Extent3`.`nCdVisitante` = `Extent4`.`nCdVisitante` - /// GROUP BY - ///`Extent4`.`nCdSite`) AS `Project3`. - /// - internal static string CountGroupBy2 { - get { - return ResourceManager.GetString("CountGroupBy2", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to SELECT - /// `Apply1`.`customer_id`, - /// `Extent5`.`country` - /// FROM (SELECT - /// `Extent1`.`customer_id`, - /// `Extent1`.`store_id`, - /// `Extent1`.`first_name`, - /// `Extent1`.`last_name`, - /// `Extent1`.`email`, - /// `Extent1`.`address_id`, - /// `Extent1`.`active`, - /// `Extent1`.`create_date`, - /// `Extent1`.`last_update`, - /// (SELECT - /// `Project1`.`address_id` - /// FROM `address` AS `Project1` - /// WHERE `Project1`.`address_id` = `Extent1`.`address_id` - /// ORDER BY - /// `Project1`.`address_id` DESC LIMIT 1) AS `ADDRESS [rest of string was truncated]";. - /// - internal static string FirstOrDefaultNestedWithOrderBy { - get { - return ResourceManager.GetString("FirstOrDefaultNestedWithOrderBy", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to SELECT - /// `Project1`.`ID`, - /// `Project1`.`Title`, - /// `Project1`.`ReleaseDate`, - /// `Project1`.`Genre`, - /// `Project1`.`Price`, - /// `Project1`.`Data`, - /// `Project1`.`Director_ID` - /// FROM `Movies` AS `Project1` - /// WHERE `Project1`.`ReleaseDate` >= @p__linq__0 - /// ORDER BY - /// `Project1`.`ReleaseDate` DESC LIMIT 2. - /// - internal static string NestedOrderBy { - get { - return ResourceManager.GetString("NestedOrderBy", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to SELECT - ///`Extent1`.`ID`, - ///`Extent1`.`Title`, - ///`Extent1`.`ReleaseDate`, - ///`Extent1`.`Genre`, - ///`Extent1`.`Price`, - ///`Extent1`.`Data`, - ///`Extent1`.`Director_ID` - ///FROM `Movies` AS `Extent1` - /// WHERE `Extent1`.`Title` LIKE @p__linq__0. - /// - internal static string QueryWithContains { - get { - return ResourceManager.GetString("QueryWithContains", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to SELECT - ///`Extent1`.`ID`, - ///`Extent1`.`Title`, - ///`Extent1`.`ReleaseDate`, - ///`Extent1`.`Genre`, - ///`Extent1`.`Price`, - ///`Extent1`.`Data`, - ///`Extent1`.`Director_ID` - ///FROM `Movies` AS `Extent1` - /// WHERE `Extent1`.`Title` LIKE @p__linq__0. - /// - internal static string QueryWithEndsWith { - get { - return ResourceManager.GetString("QueryWithEndsWith", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to SELECT - ///`Project1`.`ID`, - ///`Project1`.`Title`, - ///`Project1`.`ReleaseDate`, - ///`Project1`.`Genre`, - ///`Project1`.`Price`, - ///`Project1`.`Data`, - ///`Project1`.`Director_ID` - ///FROM `Movies` AS `Project1` - /// WHERE `Project1`.`Title` LIKE @p__linq__0 - /// ORDER BY - ///`Project1`.`ID` DESC LIMIT 10. - /// - internal static string QueryWithOrderByTakeContains { - get { - return ResourceManager.GetString("QueryWithOrderByTakeContains", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to SELECT - ///`Extent1`.`ID`, - ///`Extent1`.`Title`, - ///`Extent1`.`ReleaseDate`, - ///`Extent1`.`Genre`, - ///`Extent1`.`Price`, - ///`Extent1`.`Data`, - ///`Extent1`.`Director_ID` - ///FROM `Movies` AS `Extent1` - /// WHERE `Extent1`.`Title` LIKE @p__linq__0. - /// - internal static string QueryWithStartsWith { - get { - return ResourceManager.GetString("QueryWithStartsWith", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to SELECT - /// `Project2`.`customer_id`, - /// `Project2`.`store_id`, - /// `Project2`.`first_name`, - /// `Project2`.`last_name`, - /// `Project2`.`email`, - /// `Project2`.`address_id`, - /// `Project2`.`active`, - /// `Project2`.`create_date`, - /// `Project2`.`last_update` - /// FROM `customer` AS `Project2` - /// WHERE EXISTS(SELECT - /// 1 AS `C1` - /// FROM `rental` AS `Extent2` - /// WHERE (`Project2`.`customer_id` = `Extent2`.`customer_id`) AND (`Extent2`.`rental_date` < @p__linq__0)) - /// ORDER BY - /// `Project2`.`customer_id` ASC. - /// - internal static string ReplaceNameVisitorQuery { - get { - return ResourceManager.GetString("ReplaceNameVisitorQuery", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to SELECT - ///`Project1`.`HarborId`, - ///`Project1`.`Description`, - ///`Project1`.`C2` AS `C1`, - ///`Project1`.`ShipId`, - ///`Project1`.`HarborId1`, - ///`Project1`.`Description1`, - ///`Project1`.`C1` AS `C2`, - ///`Project1`.`CrewMemberId`, - ///`Project1`.`ShipId1`, - ///`Project1`.`RankId`, - ///`Project1`.`ClearanceId`, - ///`Project1`.`Description2`, - ///`Project1`.`RankId1`, - ///`Project1`.`Description3`, - ///`Project1`.`ClearanceId1`, - ///`Project1`.`Description4` - ///FROM (SELECT - ///`Extent1`.`HarborId`, - ///`Extent1`.`Description`, - ///`Join3`.`Shi [rest of string was truncated]";. - /// - internal static string ShipQueryMalformedDueMultipleProjecttionsCorrectedEF6 { - get { - return ResourceManager.GetString("ShipQueryMalformedDueMultipleProjecttionsCorrectedEF6", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to SELECT - /// `Extent1`.`ID`, - /// `Extent1`.`Title`, - /// `Extent1`.`ReleaseDate`, - /// `Extent1`.`Genre`, - /// `Extent1`.`Price`, - /// `Extent1`.`Data`, - /// `Extent1`.`Director_ID` - /// FROM `Movies` AS `Extent1` - /// WHERE (@gp1 IN ( @gp2 )) AND (@gp3 IS NOT NULL). - /// - internal static string TestContainsListWitConstant { - get { - return ResourceManager.GetString("TestContainsListWitConstant", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to SELECT - /// `Extent1`.`ID`, - /// `Extent1`.`Title`, - /// `Extent1`.`ReleaseDate`, - /// `Extent1`.`Genre`, - /// `Extent1`.`Price`, - /// `Extent1`.`Data`, - /// `Extent1`.`Director_ID` - /// FROM `Movies` AS `Extent1` - /// WHERE (`Extent1`.`ID` IN ( 1,2,3 )) AND (`Extent1`.`ID` IS NOT NULL). - /// - internal static string TestContainsListWithCast { - get { - return ResourceManager.GetString("TestContainsListWithCast", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to SELECT - ///`Extent1`.`ID`, - ///`Extent1`.`Title`, - ///`Extent1`.`ReleaseDate`, - ///`Extent1`.`Genre`, - ///`Extent1`.`Price`, - ///`Extent1`.`Data`, - ///`Extent1`.`Director_ID` - ///FROM `Movies` AS `Extent1` - /// WHERE @p__linq__0 IN ( 1,2,3 ). - /// - internal static string TestContainsListWithParameterReference { - get { - return ResourceManager.GetString("TestContainsListWithParameterReference", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to SELECT - /// `Project1`.`ID` AS `C1` - /// FROM `Movies` AS `Project1` - /// WHERE (`Project1`.`ID`) = @p__linq__0 - /// ORDER BY - /// `Project1`.`ID` ASC. - /// - internal static string UnknownProjectC1 { - get { - return ResourceManager.GetString("UnknownProjectC1", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to SELECT - ///`Project1`.`ID` AS `C1` - ///FROM `Movies` AS `Project1` - /// WHERE (`Project1`.`ID`) = @p__linq__0 - /// ORDER BY - ///`Project1`.`ID` ASC. - /// - internal static string UnknownProjectC1EF6 { - get { - return ResourceManager.GetString("UnknownProjectC1EF6", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to UPDATE `MovieRelease2` SET `Name`='Director\'s Cut' WHERE (`Id` = 1) AND (`RowVersion` = 0); SELECT `RowVersion` FROM `MovieRelease2` WHERE row_count() = 1 and (`Id` = 1). - /// - internal static string UpdateWithSelectWithDbGeneratedLock1 { - get { - return ResourceManager.GetString("UpdateWithSelectWithDbGeneratedLock1", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to UPDATE `MovieRelease2` SET `Name`='Avengers' WHERE (`Id` = 1) AND (`RowVersion` = 1); SELECT `RowVersion` FROM `MovieRelease2` WHERE row_count() = 1 and (`Id` = 1). - /// - internal static string UpdateWithSelectWithDbGeneratedLock2 { - get { - return ResourceManager.GetString("UpdateWithSelectWithDbGeneratedLock2", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to UPDATE `MovieReleases` SET `Name`='Director\'s Cut' WHERE (`Id` = 1) AND (`Name` = 'Commercial'); SELECT `Timestamp` FROM `MovieReleases` WHERE row_count() = 1 and ((`Id` = 1) AND (`Name` = 'Director\'s Cut')). - /// - internal static string UpdateWithSelectWithNonDbGeneratedLock { - get { - return ResourceManager.GetString("UpdateWithSelectWithNonDbGeneratedLock", resourceCulture); - } - } - } -} +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace MySql.EntityFramework.CodeFirst.Tests.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class SQLSyntax { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal SQLSyntax() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("MySql.EntityFramework.CodeFirst.Tests.Properties.SQLSyntax", typeof(SQLSyntax).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to SELECT + ///1 AS `C1`, + ///`Project3`.`nCdSite`, + ///`Project3`.`C1` AS `C2` + ///FROM (SELECT + ///`visitante`.`nCdSite`, + ///COUNT(DISTINCT `visitante`.`sDsIp`) AS `C1` + ///FROM `visitante` + /// GROUP BY + ///`visitante`.`nCdSite`) AS `Project3`. + /// + internal static string CountGroupBy { + get { + return ResourceManager.GetString("CountGroupBy", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SELECT + ///1 AS `C1`, + ///`Project3`.`nCdSite`, + ///`Project3`.`C1` AS `C2` + ///FROM (SELECT + ///`Extent4`.`nCdSite`, + ///COUNT(DISTINCT `Extent4`.`sDsIp`) AS `C1` + ///FROM `pagina` AS `Extent3` INNER JOIN `visitante` AS `Extent4` ON `Extent3`.`nCdVisitante` = `Extent4`.`nCdVisitante` + /// GROUP BY + ///`Extent4`.`nCdSite`) AS `Project3`. + /// + internal static string CountGroupBy2 { + get { + return ResourceManager.GetString("CountGroupBy2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SELECT + /// `Apply1`.`customer_id`, + /// `Extent5`.`country` + /// FROM (SELECT + /// `Extent1`.`customer_id`, + /// `Extent1`.`store_id`, + /// `Extent1`.`first_name`, + /// `Extent1`.`last_name`, + /// `Extent1`.`email`, + /// `Extent1`.`address_id`, + /// `Extent1`.`active`, + /// `Extent1`.`create_date`, + /// `Extent1`.`last_update`, + /// (SELECT + /// `Project1`.`address_id` + /// FROM `address` AS `Project1` + /// WHERE `Project1`.`address_id` = `Extent1`.`address_id` + /// ORDER BY + /// `Project1`.`address_id` DESC LIMIT 1) AS `ADDRESS [rest of string was truncated]";. + /// + internal static string FirstOrDefaultNestedWithOrderBy { + get { + return ResourceManager.GetString("FirstOrDefaultNestedWithOrderBy", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SELECT + /// `Project1`.`ID`, + /// `Project1`.`Title`, + /// `Project1`.`ReleaseDate`, + /// `Project1`.`Genre`, + /// `Project1`.`Price`, + /// `Project1`.`Data`, + /// `Project1`.`Director_ID` + /// FROM `Movies` AS `Project1` + /// WHERE `Project1`.`ReleaseDate` >= @p__linq__0 + /// ORDER BY + /// `Project1`.`ReleaseDate` DESC LIMIT 2. + /// + internal static string NestedOrderBy { + get { + return ResourceManager.GetString("NestedOrderBy", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SELECT + ///`Extent1`.`ID`, + ///`Extent1`.`Title`, + ///`Extent1`.`ReleaseDate`, + ///`Extent1`.`Genre`, + ///`Extent1`.`Price`, + ///`Extent1`.`Data`, + ///`Extent1`.`Director_ID` + ///FROM `Movies` AS `Extent1` + /// WHERE `Extent1`.`Title` LIKE @p__linq__0. + /// + internal static string QueryWithContains { + get { + return ResourceManager.GetString("QueryWithContains", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SELECT + ///`Extent1`.`ID`, + ///`Extent1`.`Title`, + ///`Extent1`.`ReleaseDate`, + ///`Extent1`.`Genre`, + ///`Extent1`.`Price`, + ///`Extent1`.`Data`, + ///`Extent1`.`Director_ID` + ///FROM `Movies` AS `Extent1` + /// WHERE `Extent1`.`Title` LIKE @p__linq__0. + /// + internal static string QueryWithEndsWith { + get { + return ResourceManager.GetString("QueryWithEndsWith", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SELECT + ///`Project1`.`ID`, + ///`Project1`.`Title`, + ///`Project1`.`ReleaseDate`, + ///`Project1`.`Genre`, + ///`Project1`.`Price`, + ///`Project1`.`Data`, + ///`Project1`.`Director_ID` + ///FROM `Movies` AS `Project1` + /// WHERE `Project1`.`Title` LIKE @p__linq__0 + /// ORDER BY + ///`Project1`.`ID` DESC LIMIT 10. + /// + internal static string QueryWithOrderByTakeContains { + get { + return ResourceManager.GetString("QueryWithOrderByTakeContains", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SELECT + ///`Extent1`.`ID`, + ///`Extent1`.`Title`, + ///`Extent1`.`ReleaseDate`, + ///`Extent1`.`Genre`, + ///`Extent1`.`Price`, + ///`Extent1`.`Data`, + ///`Extent1`.`Director_ID` + ///FROM `Movies` AS `Extent1` + /// WHERE `Extent1`.`Title` LIKE @p__linq__0. + /// + internal static string QueryWithStartsWith { + get { + return ResourceManager.GetString("QueryWithStartsWith", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SELECT + /// `Project2`.`customer_id`, + /// `Project2`.`store_id`, + /// `Project2`.`first_name`, + /// `Project2`.`last_name`, + /// `Project2`.`email`, + /// `Project2`.`address_id`, + /// `Project2`.`active`, + /// `Project2`.`create_date`, + /// `Project2`.`last_update` + /// FROM `customer` AS `Project2` + /// WHERE EXISTS(SELECT + /// 1 AS `C1` + /// FROM `rental` AS `Extent2` + /// WHERE (`Project2`.`customer_id` = `Extent2`.`customer_id`) AND (`Extent2`.`rental_date` < @p__linq__0)) + /// ORDER BY + /// `Project2`.`customer_id` ASC. + /// + internal static string ReplaceNameVisitorQuery { + get { + return ResourceManager.GetString("ReplaceNameVisitorQuery", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SELECT + ///`Project1`.`HarborId`, + ///`Project1`.`Description`, + ///`Project1`.`C2` AS `C1`, + ///`Project1`.`ShipId`, + ///`Project1`.`HarborId1`, + ///`Project1`.`Description1`, + ///`Project1`.`C1` AS `C2`, + ///`Project1`.`CrewMemberId`, + ///`Project1`.`ShipId1`, + ///`Project1`.`RankId`, + ///`Project1`.`ClearanceId`, + ///`Project1`.`Description2`, + ///`Project1`.`RankId1`, + ///`Project1`.`Description3`, + ///`Project1`.`ClearanceId1`, + ///`Project1`.`Description4` + ///FROM (SELECT + ///`Extent1`.`HarborId`, + ///`Extent1`.`Description`, + ///`Join3`.`Shi [rest of string was truncated]";. + /// + internal static string ShipQueryMalformedDueMultipleProjecttionsCorrectedEF6 { + get { + return ResourceManager.GetString("ShipQueryMalformedDueMultipleProjecttionsCorrectedEF6", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SELECT + /// `Extent1`.`ID`, + /// `Extent1`.`Title`, + /// `Extent1`.`ReleaseDate`, + /// `Extent1`.`Genre`, + /// `Extent1`.`Price`, + /// `Extent1`.`Data`, + /// `Extent1`.`Director_ID` + /// FROM `Movies` AS `Extent1` + /// WHERE (@gp1 IN ( @gp2 )) AND (@gp3 IS NOT NULL). + /// + internal static string TestContainsListWitConstant { + get { + return ResourceManager.GetString("TestContainsListWitConstant", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SELECT + /// `Extent1`.`ID`, + /// `Extent1`.`Title`, + /// `Extent1`.`ReleaseDate`, + /// `Extent1`.`Genre`, + /// `Extent1`.`Price`, + /// `Extent1`.`Data`, + /// `Extent1`.`Director_ID` + /// FROM `Movies` AS `Extent1` + /// WHERE (`Extent1`.`ID` IN ( 1,2,3 )) AND (`Extent1`.`ID` IS NOT NULL). + /// + internal static string TestContainsListWithCast { + get { + return ResourceManager.GetString("TestContainsListWithCast", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SELECT + ///`Extent1`.`ID`, + ///`Extent1`.`Title`, + ///`Extent1`.`ReleaseDate`, + ///`Extent1`.`Genre`, + ///`Extent1`.`Price`, + ///`Extent1`.`Data`, + ///`Extent1`.`Director_ID` + ///FROM `Movies` AS `Extent1` + /// WHERE @p__linq__0 IN ( 1,2,3 ). + /// + internal static string TestContainsListWithParameterReference { + get { + return ResourceManager.GetString("TestContainsListWithParameterReference", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SELECT + /// `Project1`.`ID` AS `C1` + /// FROM `Movies` AS `Project1` + /// WHERE (`Project1`.`ID`) = @p__linq__0 + /// ORDER BY + /// `Project1`.`ID` ASC. + /// + internal static string UnknownProjectC1 { + get { + return ResourceManager.GetString("UnknownProjectC1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SELECT + ///`Project1`.`ID` AS `C1` + ///FROM `Movies` AS `Project1` + /// WHERE (`Project1`.`ID`) = @p__linq__0 + /// ORDER BY + ///`Project1`.`ID` ASC. + /// + internal static string UnknownProjectC1EF6 { + get { + return ResourceManager.GetString("UnknownProjectC1EF6", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to UPDATE `MovieRelease2` SET `Name`='Director\'s Cut' WHERE (`Id` = 1) AND (`RowVersion` = 0); SELECT `RowVersion` FROM `MovieRelease2` WHERE row_count() = 1 and (`Id` = 1). + /// + internal static string UpdateWithSelectWithDbGeneratedLock1 { + get { + return ResourceManager.GetString("UpdateWithSelectWithDbGeneratedLock1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to UPDATE `MovieRelease2` SET `Name`='Avengers' WHERE (`Id` = 1) AND (`RowVersion` = 1); SELECT `RowVersion` FROM `MovieRelease2` WHERE row_count() = 1 and (`Id` = 1). + /// + internal static string UpdateWithSelectWithDbGeneratedLock2 { + get { + return ResourceManager.GetString("UpdateWithSelectWithDbGeneratedLock2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to UPDATE `MovieReleases` SET `Name`='Director\'s Cut' WHERE (`Id` = 1) AND (`Name` = 'Commercial'); SELECT `Timestamp` FROM `MovieReleases` WHERE row_count() = 1 and ((`Id` = 1) AND (`Name` = 'Director\'s Cut')). + /// + internal static string UpdateWithSelectWithNonDbGeneratedLock { + get { + return ResourceManager.GetString("UpdateWithSelectWithNonDbGeneratedLock", resourceCulture); + } + } + } +} diff --git a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/Properties/sakila-data.sql b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/Properties/sakila-data.sql index 644fc65fe..8d8cf971f 100644 --- a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/Properties/sakila-data.sql +++ b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/Properties/sakila-data.sql @@ -1,8 +1,7 @@ -- Sakila Sample Database Data -- Version 1.0 --- Copyright (c) 2006, 2015, Oracle and/or its affiliates. --- All rights reserved. +-- Copyright © 2006, 2025, Oracle and/or its affiliates. -- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/Properties/sakila-schema.sql b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/Properties/sakila-schema.sql index 8754868a1..27d72af88 100644 --- a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/Properties/sakila-schema.sql +++ b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/Properties/sakila-schema.sql @@ -1,8 +1,7 @@ -- Sakila Sample Database Schema -- Version 1.0 --- Copyright (c) 2006, 2015, Oracle and/or its affiliates. --- All rights reserved. +-- Copyright © 2006, 2025, Oracle and/or its affiliates. -- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/SakilaDb.cs b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/SakilaDb.cs index 77487489c..f85c5e1aa 100644 --- a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/SakilaDb.cs +++ b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/SakilaDb.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2015, 2020 Oracle and/or its affiliates. +// Copyright © 2015, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/actor.cs b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/actor.cs index 06acff9ef..593109cba 100644 --- a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/actor.cs +++ b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/actor.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2014, 2020 Oracle and/or its affiliates. +// Copyright © 2014, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/actor_info.cs b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/actor_info.cs index 7a8042fc8..6d67e3e3b 100644 --- a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/actor_info.cs +++ b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/actor_info.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2014, 2020 Oracle and/or its affiliates. +// Copyright © 2014, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/address.cs b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/address.cs index 883c274ec..57de2b153 100644 --- a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/address.cs +++ b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/address.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2014, 2020 Oracle and/or its affiliates. +// Copyright © 2014, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/category.cs b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/category.cs index a930c8ba5..ef201da34 100644 --- a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/category.cs +++ b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/category.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2014, 2020 Oracle and/or its affiliates. +// Copyright © 2014, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/city.cs b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/city.cs index 5c07e4e8d..6df411949 100644 --- a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/city.cs +++ b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/city.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2014, 2020 Oracle and/or its affiliates. +// Copyright © 2014, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/country.cs b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/country.cs index 37e775527..85a4613db 100644 --- a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/country.cs +++ b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/country.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2014, 2020 Oracle and/or its affiliates. +// Copyright © 2014, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/customer.cs b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/customer.cs index 9caceab99..5d6fbbeca 100644 --- a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/customer.cs +++ b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/customer.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2014, 2020 Oracle and/or its affiliates. +// Copyright © 2014, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/customer_list.cs b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/customer_list.cs index ed634812e..a0440407f 100644 --- a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/customer_list.cs +++ b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/customer_list.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2014, 2020 Oracle and/or its affiliates. +// Copyright © 2014, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/film.cs b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/film.cs index 49ca54a03..715aa9f60 100644 --- a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/film.cs +++ b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/film.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2014, 2020 Oracle and/or its affiliates. +// Copyright © 2014, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/film_actor.cs b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/film_actor.cs index 5483a11de..572dd915f 100644 --- a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/film_actor.cs +++ b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/film_actor.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2014, 2020 Oracle and/or its affiliates. +// Copyright © 2014, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/film_category.cs b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/film_category.cs index 9c4d8dafb..f76371277 100644 --- a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/film_category.cs +++ b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/film_category.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2014, 2020 Oracle and/or its affiliates. +// Copyright © 2014, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/film_list.cs b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/film_list.cs index 5603836b7..cfb3c6c80 100644 --- a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/film_list.cs +++ b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/film_list.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2014, 2020 Oracle and/or its affiliates. +// Copyright © 2014, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/film_text.cs b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/film_text.cs index 4dcd0b851..327a9b74e 100644 --- a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/film_text.cs +++ b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/film_text.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2014, 2020 Oracle and/or its affiliates. +// Copyright © 2014, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/inventory.cs b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/inventory.cs index e86f0b342..c8506e285 100644 --- a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/inventory.cs +++ b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/inventory.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2014, 2020 Oracle and/or its affiliates. +// Copyright © 2014, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/language.cs b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/language.cs index c95c93c1e..f725d5b97 100644 --- a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/language.cs +++ b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/language.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2014, 2020 Oracle and/or its affiliates. +// Copyright © 2014, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/nicer_but_slower_film_list.cs b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/nicer_but_slower_film_list.cs index ae11f853b..c6bbcc04f 100644 --- a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/nicer_but_slower_film_list.cs +++ b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/nicer_but_slower_film_list.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2014, 2020 Oracle and/or its affiliates. +// Copyright © 2014, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/payment.cs b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/payment.cs index c3f42f3a1..5e2f44097 100644 --- a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/payment.cs +++ b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/payment.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2014, 2020 Oracle and/or its affiliates. +// Copyright © 2014, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/rental.cs b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/rental.cs index 0ee2ad063..676725c55 100644 --- a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/rental.cs +++ b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/rental.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2014, 2020 Oracle and/or its affiliates. +// Copyright © 2014, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/sales_by_film_category.cs b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/sales_by_film_category.cs index dc09c05b7..92f6a88a8 100644 --- a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/sales_by_film_category.cs +++ b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/sales_by_film_category.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2014, 2020 Oracle and/or its affiliates. +// Copyright © 2014, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/sales_by_store.cs b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/sales_by_store.cs index 1895eab8f..d6c5e81dc 100644 --- a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/sales_by_store.cs +++ b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/sales_by_store.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2014, 2020 Oracle and/or its affiliates. +// Copyright © 2014, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/staff.cs b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/staff.cs index 74c055f33..d117df6ff 100644 --- a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/staff.cs +++ b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/staff.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2014, 2020 Oracle and/or its affiliates. +// Copyright © 2014, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/staff_list.cs b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/staff_list.cs index fbc560777..3ed986485 100644 --- a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/staff_list.cs +++ b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/staff_list.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2014, 2020 Oracle and/or its affiliates. +// Copyright © 2014, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/store.cs b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/store.cs index e8874bf6e..e32a13c0c 100644 --- a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/store.cs +++ b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SakilaModel/store.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2014, 2020 Oracle and/or its affiliates. +// Copyright © 2014, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/Ship.cs b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/Ship.cs index 67b7b304b..b25950334 100644 --- a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/Ship.cs +++ b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/Ship.cs @@ -1,99 +1,99 @@ -// Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Data.Entity; - - -namespace MySql.Data.EntityFramework.CodeFirst.Tests -{ - public class Harbor - { - public int HarborId { get; set; } - public virtual ICollection Ships { get; set; } - - public string Description { get; set; } - } - - public class Ship - { - public int ShipId { get; set; } - public int HarborId { get; set; } - public virtual Harbor Harbor { get; set; } - public virtual ICollection CrewMembers { get; set; } - - public string Description { get; set; } - } - - public class CrewMember - { - public int CrewMemberId { get; set; } - public int ShipId { get; set; } - public virtual Ship Ship { get; set; } - public int RankId { get; set; } - public virtual Rank Rank { get; set; } - public int ClearanceId { get; set; } - public virtual Clearance Clearance { get; set; } - - public string Description { get; set; } - } - - public class Rank - { - public int RankId { get; set; } - public virtual ICollection CrewMembers { get; set; } - - public string Description { get; set; } - } - - public class Clearance - { - public int ClearanceId { get; set; } - public virtual ICollection CrewMembers { get; set; } - - public string Description { get; set; } - } - - [DbConfigurationType(typeof(MySqlEFConfiguration))] - public class ShipContext : DbContext - { - public DbSet Harbors { get; set; } - public DbSet Ships { get; set; } - public DbSet CrewMembers { get; set; } - public DbSet Ranks { get; set; } - public DbSet Clearances { get; set; } - - public ShipContext() : base(CodeFirstFixture.GetEFConnectionString()) - { - Database.SetInitializer(new DropCreateDatabaseAlways()); - } - } -} +// Copyright © 2013, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Data.Entity; + + +namespace MySql.Data.EntityFramework.CodeFirst.Tests +{ + public class Harbor + { + public int HarborId { get; set; } + public virtual ICollection Ships { get; set; } + + public string Description { get; set; } + } + + public class Ship + { + public int ShipId { get; set; } + public int HarborId { get; set; } + public virtual Harbor Harbor { get; set; } + public virtual ICollection CrewMembers { get; set; } + + public string Description { get; set; } + } + + public class CrewMember + { + public int CrewMemberId { get; set; } + public int ShipId { get; set; } + public virtual Ship Ship { get; set; } + public int RankId { get; set; } + public virtual Rank Rank { get; set; } + public int ClearanceId { get; set; } + public virtual Clearance Clearance { get; set; } + + public string Description { get; set; } + } + + public class Rank + { + public int RankId { get; set; } + public virtual ICollection CrewMembers { get; set; } + + public string Description { get; set; } + } + + public class Clearance + { + public int ClearanceId { get; set; } + public virtual ICollection CrewMembers { get; set; } + + public string Description { get; set; } + } + + [DbConfigurationType(typeof(MySqlEFConfiguration))] + public class ShipContext : DbContext + { + public DbSet Harbors { get; set; } + public DbSet Ships { get; set; } + public DbSet CrewMembers { get; set; } + public DbSet Ranks { get; set; } + public DbSet Clearances { get; set; } + + public ShipContext() : base(CodeFirstFixture.GetEFConnectionString()) + { + Database.SetInitializer(new DropCreateDatabaseAlways()); + } + } +} diff --git a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SiteDB.cs b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SiteDB.cs index 7910e1153..8e30623d4 100644 --- a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SiteDB.cs +++ b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/SiteDB.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2014, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/TransactionTests.cs b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/TransactionTests.cs index 4a5e276b6..15be38e01 100644 --- a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/TransactionTests.cs +++ b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/TransactionTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2016, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/Vehicle.cs b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/Vehicle.cs index 3c579edb7..f95bbbfa1 100644 --- a/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/Vehicle.cs +++ b/EntityFramework/tests/MySql.EntityFramework.CodeFirst.Tests/Vehicle.cs @@ -1,362 +1,414 @@ -// Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Data.Entity; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; - - -namespace MySql.Data.EntityFramework.CodeFirst.Tests -{ - - [DbConfigurationType(typeof(MySqlEFConfiguration))] - public class VehicleDbContext : DbContext - { - public DbSet Vehicles { get; set; } - public DbSet Manufacturers { get; set; } - public DbSet Distributors { get; set; } - - public VehicleDbContext() : base(CodeFirstFixture.GetEFConnectionString()) - { - Database.SetInitializer(new VehicleDBInitializer()); - } - - protected override void OnModelCreating(DbModelBuilder modelBuilder) - { - //modelBuilder.Entity() - // .Map(o => o.ToTable("Cars")) - // .Map(o => o.ToTable("Bikes")); - modelBuilder.Entity().ToTable("Cars"); - modelBuilder.Entity().ToTable("Bikes"); - } - } - - public class VehicleDBInitializer : DropCreateDatabaseReallyAlways - { - } - - [DbConfigurationType(typeof(MySqlEFConfiguration))] - public class VehicleDbContext2 : DbContext - { - public DbSet Vehicles { get; set; } - - public VehicleDbContext2() : base(CodeFirstFixture.GetEFConnectionString()) - { - Database.SetInitializer(new VehicleDBInitializer2()); - } - } - - public class VehicleDBInitializer2 : DropCreateDatabaseReallyAlways - { - } - - /// - /// This initializer really drops the database, not just once per AppDomain (like the DropCreateDatabaseAlways). - /// - /// - public class DropCreateDatabaseReallyAlways : IDatabaseInitializer where TContext : DbContext - { - public void InitializeDatabase(TContext context) - { - context.Database.Delete(); - context.Database.CreateIfNotExists(); - this.Seed(context); - context.SaveChanges(); - } - - protected virtual void Seed(TContext context) - { - } - } - - public class Vehicle - { - public int Id { get; set; } - public int Year { get; set; } - - [MaxLength(1024)] - public string Name { get; set; } - } - - [DbConfigurationType(typeof(MySqlEFConfiguration))] - public class VehicleDbContext3 : DbContext - { - public DbSet Accessories { get; set; } - - public VehicleDbContext3() : base(CodeFirstFixture.GetEFConnectionString()) - { - - } - } - - public class Accessory - { - [Key] - [MaxLength(255)] - public string Name { get; set; } - - [Required] - [MaxLength(80000)] - public string Description { get; set; } - - [Required] - [MaxLength(16777216)] - public string LongDescription { get; set; } - - } - - public class Car : Vehicle - { - public string CarProperty { get; set; } - } - - public class Bike : Vehicle - { - public string BikeProperty { get; set; } - } - public class Vehicle2 - { - public int Id { get; set; } - public int Year { get; set; } - [MaxLength(1024)] - public string Name { get; set; } - } - - public class Car2 : Vehicle2 - { - public string CarProperty { get; set; } - } - - public class Bike2 : Vehicle2 - { - public string BikeProperty { get; set; } - } - - public class Manufacturer - { - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public Guid ManufacturerId { get; set; } - public string Name { get; set; } - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public Guid GroupIdentifier { get; set; } - } - - public class Distributor - { - public int DistributorId { get; set; } - public string Name { get; set; } - } - - - public class Product - { - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id { get; set; } - - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public DateTime DateCreated { get; set; } - - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - [Column(TypeName = "timestamp")] - public DateTime Timestamp { get; set; } - - public DateTime DateTimeWithPrecision { get; set; } - - [Column(TypeName = "TimeStamp")] - public DateTime TimeStampWithPrecision { get; set; } - - } - - [DbConfigurationType(typeof(MySqlEFConfiguration))] - public class ProductsDbContext : DbContext - { - public DbSet Products { get; set; } - - public ProductsDbContext() : base(CodeFirstFixture.GetEFConnectionString()) - { - - } - - protected override void OnModelCreating(DbModelBuilder modelBuilder) - { - base.OnModelCreating(modelBuilder); - - Database.SetInitializer(new ProductDBInitializer()); - - modelBuilder.Entity() - .Property(f => f.DateTimeWithPrecision) - .HasColumnType("DateTime") - .HasPrecision(3); - - modelBuilder.Entity() - .Property(f => f.TimeStampWithPrecision) - .HasColumnType("Timestamp") - .HasPrecision(3); - - Database.SetInitializer(new MigrateDatabaseToLatestVersion>()); - } - } - - public class ProductDBInitializer : DropCreateDatabaseReallyAlways - { - } - - public class Names - { - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id { get; set; } - - public DateTime DateCreated { get; set; } - } - - [DbConfigurationType(typeof(MySqlEFConfiguration))] - public class ShortDbContext : DbContext - { - public DbSet Names { get; set; } - - public ShortDbContext() : base(CodeFirstFixture.GetEFConnectionString()) - { - - } - - protected override void OnModelCreating(DbModelBuilder modelBuilder) - { - modelBuilder.Entity() - .Property(f => f.DateCreated) - .HasColumnType("DateTime") - .HasPrecision(9); - } - } - - [DbConfigurationType(typeof(MySqlEFConfiguration))] - public class AutoIncrementBugContext : DbContext - { - public DbSet AutoIncrementBug { get; set; } - - public AutoIncrementBugContext() : base(CodeFirstFixture.GetEFConnectionString()) - { - Database.SetInitializer(new AutoIncrementBugInitialize()); - Database.SetInitializer(new DropCreateDatabaseAlways()); - } - - protected override void OnModelCreating(DbModelBuilder modelBuilder) - { - base.OnModelCreating(modelBuilder); - } - } - - public class AutoIncrementBugInitialize : IDatabaseInitializer where TContext : DbContext - { - public void InitializeDatabase(TContext context) - { - context.Database.Delete(); - context.Database.CreateIfNotExists(); - this.Seed(context); - context.SaveChanges(); - } - - protected virtual void Seed(TContext context) - { - } - } - - public class AutoIncrementBug - { - [Key] - public short MyKey { get; set; } - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public long AutoIncrementBugId { get; set; } - public string Description { get; set; } - } - - public class AutoIncrementConfiguration : System.Data.Entity.Migrations.DbMigrationsConfiguration where TContext : DbContext - { - public AutoIncrementConfiguration() - { - AutomaticMigrationsEnabled = true; - //CodeGenerator = new MySqlMigrationCodeGenerator(); - SetSqlGenerator("MySql.Data.MySqlClient", new MySql.Data.EntityFramework.MySqlMigrationSqlGenerator()); - } - } - - - [Table("client")] - public class Client - { - [Key] - public int Id { get; set; } - public ICollection Orders { get; set; } - } - - [Table("order")] - public class Order - { - [Key] - public int Id { get; set; } - public ICollection Items { get; set; } - public ICollection Discounts { get; set; } - } - - [Table("item")] - public class Item - { - [Key] - public int Id { get; set; } - } - - [Table("discount")] - public class Discount - { - [Key] - public int Id { get; set; } - } - - - [DbConfigurationType(typeof(MySqlEFConfiguration))] - public class UsingUnionContext : DbContext - { - public DbSet Clients { get; set; } - public DbSet Items { get; set; } - - public DbSet Orders { get; set; } - - public DbSet Discounts { get; set; } - - public UsingUnionContext() : base(CodeFirstFixture.GetEFConnectionString()) - { - - } - } - - - -} +// Copyright © 2014, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Data.Entity; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + + +namespace MySql.Data.EntityFramework.CodeFirst.Tests +{ + + [DbConfigurationType(typeof(MySqlEFConfiguration))] + public class VehicleDbContext : DbContext + { + public DbSet Vehicles { get; set; } + public DbSet Manufacturers { get; set; } + public DbSet Distributors { get; set; } + + public VehicleDbContext() : base(CodeFirstFixture.GetEFConnectionString()) + { + Database.SetInitializer(new VehicleDBInitializer()); + } + + protected override void OnModelCreating(DbModelBuilder modelBuilder) + { + //modelBuilder.Entity() + // .Map(o => o.ToTable("Cars")) + // .Map(o => o.ToTable("Bikes")); + modelBuilder.Entity().ToTable("Cars"); + modelBuilder.Entity().ToTable("Bikes"); + } + } + + public class VehicleDBInitializer : DropCreateDatabaseReallyAlways + { + } + + [DbConfigurationType(typeof(MySqlEFConfiguration))] + public class VehicleDbContext2 : DbContext + { + public DbSet Vehicles { get; set; } + + public VehicleDbContext2() : base(CodeFirstFixture.GetEFConnectionString()) + { + Database.SetInitializer(new VehicleDBInitializer2()); + } + } + + public class VehicleDBInitializer2 : DropCreateDatabaseReallyAlways + { + } + + /// + /// This initializer really drops the database, not just once per AppDomain (like the DropCreateDatabaseAlways). + /// + /// + public class DropCreateDatabaseReallyAlways : IDatabaseInitializer where TContext : DbContext + { + public void InitializeDatabase(TContext context) + { + context.Database.Delete(); + context.Database.CreateIfNotExists(); + this.Seed(context); + context.SaveChanges(); + } + + protected virtual void Seed(TContext context) + { + } + } + + public class Vehicle + { + public int Id { get; set; } + public int Year { get; set; } + + [MaxLength(1024)] + public string Name { get; set; } + } + + [DbConfigurationType(typeof(MySqlEFConfiguration))] + public class VehicleDbContext3 : DbContext + { + public DbSet Accessories { get; set; } + + public VehicleDbContext3() : base(CodeFirstFixture.GetEFConnectionString()) + { + + } + } + + public class Car4 : Vehicle4 + { + public string CarProperty { get; set; } + } + + public class Bike4 : Vehicle4 + { + public string BikeProperty { get; set; } + } + public class Manufacturer4 + { + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public Guid ManufacturerId { get; set; } + public string Name { get; set; } + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public Guid GroupIdentifier { get; set; } + public virtual ICollection Vehicles { get; set; } + } + public class Vehicle4 + { + public int Id { get; set; } + public int Year { get; set; } + + [MaxLength(1024)] + public string Name { get; set; } + public Guid ManufacturerId { get; set; } + [ForeignKey(nameof(ManufacturerId))] + public virtual Manufacturer4 Manufacturer { get; set; } + } + [DbConfigurationType(typeof(MySqlEFConfiguration))] + public class VehicleDbContext4 : DbContext + { + public DbSet Vehicles { get; set; } + public DbSet Manufacturers { get; set; } + + public VehicleDbContext4() : base(CodeFirstFixture.GetEFConnectionString()) + { + Database.SetInitializer(new VehicleDBInitializer4()); + + } + protected override void OnModelCreating(DbModelBuilder modelBuilder) + { + modelBuilder.Entity().ToTable("Vehicles"); + modelBuilder.Entity().ToTable("Cars"); + modelBuilder.Entity().ToTable("Bikes"); + } + } + public class VehicleDBInitializer4 : DropCreateDatabaseReallyAlways + { + } + + public class Accessory + { + [Key] + [MaxLength(255)] + public string Name { get; set; } + + [Required] + [MaxLength(80000)] + public string Description { get; set; } + + [Required] + [MaxLength(16777216)] + public string LongDescription { get; set; } + + } + + public class Car : Vehicle + { + public string CarProperty { get; set; } + } + + public class Bike : Vehicle + { + public string BikeProperty { get; set; } + } + public class Vehicle2 + { + public int Id { get; set; } + public int Year { get; set; } + [MaxLength(1024)] + public string Name { get; set; } + } + + public class Car2 : Vehicle2 + { + public string CarProperty { get; set; } + } + + public class Bike2 : Vehicle2 + { + public string BikeProperty { get; set; } + } + + public class Manufacturer + { + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public Guid ManufacturerId { get; set; } + public string Name { get; set; } + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public Guid GroupIdentifier { get; set; } + } + + public class Distributor + { + public int DistributorId { get; set; } + public string Name { get; set; } + } + + + public class Product + { + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; set; } + + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public DateTime DateCreated { get; set; } + + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + [Column(TypeName = "timestamp")] + public DateTime Timestamp { get; set; } + + public DateTime DateTimeWithPrecision { get; set; } + + [Column(TypeName = "TimeStamp")] + public DateTime TimeStampWithPrecision { get; set; } + + } + + [DbConfigurationType(typeof(MySqlEFConfiguration))] + public class ProductsDbContext : DbContext + { + public DbSet Products { get; set; } + + public ProductsDbContext() : base(CodeFirstFixture.GetEFConnectionString()) + { + + } + + protected override void OnModelCreating(DbModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + + Database.SetInitializer(new ProductDBInitializer()); + + modelBuilder.Entity() + .Property(f => f.DateTimeWithPrecision) + .HasColumnType("DateTime") + .HasPrecision(3); + + modelBuilder.Entity() + .Property(f => f.TimeStampWithPrecision) + .HasColumnType("Timestamp") + .HasPrecision(3); + + Database.SetInitializer(new MigrateDatabaseToLatestVersion>()); + } + } + + public class ProductDBInitializer : DropCreateDatabaseReallyAlways + { + } + + public class Names + { + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; set; } + + public DateTime DateCreated { get; set; } + } + + [DbConfigurationType(typeof(MySqlEFConfiguration))] + public class ShortDbContext : DbContext + { + public DbSet Names { get; set; } + + public ShortDbContext() : base(CodeFirstFixture.GetEFConnectionString()) + { + + } + + protected override void OnModelCreating(DbModelBuilder modelBuilder) + { + modelBuilder.Entity() + .Property(f => f.DateCreated) + .HasColumnType("DateTime") + .HasPrecision(9); + } + } + + [DbConfigurationType(typeof(MySqlEFConfiguration))] + public class AutoIncrementBugContext : DbContext + { + public DbSet AutoIncrementBug { get; set; } + + public AutoIncrementBugContext() : base(CodeFirstFixture.GetEFConnectionString()) + { + Database.SetInitializer(new AutoIncrementBugInitialize()); + Database.SetInitializer(new DropCreateDatabaseAlways()); + } + + protected override void OnModelCreating(DbModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + } + } + + public class AutoIncrementBugInitialize : IDatabaseInitializer where TContext : DbContext + { + public void InitializeDatabase(TContext context) + { + context.Database.Delete(); + context.Database.CreateIfNotExists(); + this.Seed(context); + context.SaveChanges(); + } + + protected virtual void Seed(TContext context) + { + } + } + + public class AutoIncrementBug + { + [Key] + public short MyKey { get; set; } + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public long AutoIncrementBugId { get; set; } + public string Description { get; set; } + } + + public class AutoIncrementConfiguration : System.Data.Entity.Migrations.DbMigrationsConfiguration where TContext : DbContext + { + public AutoIncrementConfiguration() + { + AutomaticMigrationsEnabled = true; + //CodeGenerator = new MySqlMigrationCodeGenerator(); + SetSqlGenerator("MySql.Data.MySqlClient", new MySql.Data.EntityFramework.MySqlMigrationSqlGenerator()); + } + } + + + [Table("client")] + public class Client + { + [Key] + public int Id { get; set; } + public ICollection Orders { get; set; } + } + + [Table("order")] + public class Order + { + [Key] + public int Id { get; set; } + public ICollection Items { get; set; } + public ICollection Discounts { get; set; } + } + + [Table("item")] + public class Item + { + [Key] + public int Id { get; set; } + } + + [Table("discount")] + public class Discount + { + [Key] + public int Id { get; set; } + } + + + [DbConfigurationType(typeof(MySqlEFConfiguration))] + public class UsingUnionContext : DbContext + { + public DbSet Clients { get; set; } + public DbSet Items { get; set; } + + public DbSet Orders { get; set; } + + public DbSet Discounts { get; set; } + + public UsingUnionContext() : base(CodeFirstFixture.GetEFConnectionString()) + { + + } + } + + + +} diff --git a/EntityFramework/tests/MySql.EntityFramework.Migrations.Tests/BlogsModel.cs b/EntityFramework/tests/MySql.EntityFramework.Migrations.Tests/BlogsModel.cs index 9e0086c75..d2b4b4cf7 100644 --- a/EntityFramework/tests/MySql.EntityFramework.Migrations.Tests/BlogsModel.cs +++ b/EntityFramework/tests/MySql.EntityFramework.Migrations.Tests/BlogsModel.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2020 Oracle and/or its affiliates. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/tests/MySql.EntityFramework.Migrations.Tests/MyConfiguration.cs b/EntityFramework/tests/MySql.EntityFramework.Migrations.Tests/MyConfiguration.cs index 25cab30ef..b316b0781 100644 --- a/EntityFramework/tests/MySql.EntityFramework.Migrations.Tests/MyConfiguration.cs +++ b/EntityFramework/tests/MySql.EntityFramework.Migrations.Tests/MyConfiguration.cs @@ -1,16 +1,16 @@ -// Copyright © 2013, 2017, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/EntityFramework/tests/MySql.EntityFramework.Migrations.Tests/MySql.EntityFramework.Migrations.Tests.csproj b/EntityFramework/tests/MySql.EntityFramework.Migrations.Tests/MySql.EntityFramework.Migrations.Tests.csproj index 8be578e10..dacd09bc8 100644 --- a/EntityFramework/tests/MySql.EntityFramework.Migrations.Tests/MySql.EntityFramework.Migrations.Tests.csproj +++ b/EntityFramework/tests/MySql.EntityFramework.Migrations.Tests/MySql.EntityFramework.Migrations.Tests.csproj @@ -2,17 +2,17 @@ MySql.Data.EntityFramework.Migrations.Tests - Copyright (c) 2016, 2023, Oracle and/or its affiliates. + Copyright © 2016, 2025, Oracle and/or its affiliates. en-US - 8.2.0 + 9.4.0 Oracle - net7.0 + net462;net48;net9.0 MySql.EntityFramework.Migrations.Tests MySql.EntityFramework.Migrations.Tests MySql;.NET Connector;MySql Connector/NET http://www.mysql.com/common/logos/logo-mysql-170x115.png http://dev.mysql.com/downloads/ - GPL-2.0-only + GPL-2.0-only WITH Universal-FOSS-exception-1.0 true false false @@ -24,6 +24,7 @@ ..\..\..\ConnectorNetPublicKey.snk true CA2100 + latest @@ -33,10 +34,10 @@ - + - - + + diff --git a/EntityFramework/tests/MySql.EntityFramework.Migrations.Tests/MySqlMigrationsTests.cs b/EntityFramework/tests/MySql.EntityFramework.Migrations.Tests/MySqlMigrationsTests.cs index e0dd5f6c7..1fe29388d 100644 --- a/EntityFramework/tests/MySql.EntityFramework.Migrations.Tests/MySqlMigrationsTests.cs +++ b/EntityFramework/tests/MySql.EntityFramework.Migrations.Tests/MySqlMigrationsTests.cs @@ -1,460 +1,460 @@ -// Copyright (c) 2013, 2020 Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using System; -using System.Collections.Generic; -using System.Data.Entity; -using System.Data.Entity.Infrastructure; -using System.Data.Entity.Migrations.Model; -using System.Data.Entity.Migrations.Sql; -using System.Linq; -using NUnit.Framework; -using MySql.Data.MySqlClient; -using System.Data.Entity.Core.EntityClient; -using System.Data.Entity.Core.Metadata.Edm; - -namespace MySql.Data.EntityFramework.Migrations.Tests -{ - public class MySqlMigrationsTests : SetUpMigrationsTests - { - private MySqlProviderManifest ProviderManifest; - - public MySqlMigrationsTests() - { - Database.SetInitializer(new MigrateDatabaseToLatestVersion()); - } - - private MySqlConnection GetConnectionFromContext(DbContext ctx) - { - return (MySqlConnection)((EntityConnection)(((IObjectContextAdapter)ctx).ObjectContext.Connection)).StoreConnection; - } - - /// - /// Add int32 type column to existing table - /// - [Test] - public void AddColumnOperationMigration() - { - var migrationOperations = new List(); - - if (ProviderManifest == null) - ProviderManifest = new MySqlProviderManifest(Version.ToString()); - - TypeUsage tu = TypeUsage.CreateDefaultTypeUsage(PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Int32)); - TypeUsage result = ProviderManifest.GetStoreType(tu); - - var intColumn = new ColumnModel(PrimitiveTypeKind.Int32, result) - { - Name = "TotalPosts", - IsNullable = false - }; - - var addColumnMigratioOperation = new AddColumnOperation("Blogs", intColumn); - migrationOperations.Add(addColumnMigratioOperation); - - using (BlogContext context = new BlogContext()) - { - if (context.Database.Exists()) context.Database.Delete(); - context.Database.Create(); - - using (MySqlConnection conn = new MySqlConnection(context.Database.Connection.ConnectionString)) - { - if (conn.State == System.Data.ConnectionState.Closed) conn.Open(); - Assert.AreEqual(true, GenerateAndExecuteMySQLStatements(migrationOperations)); - - MySqlCommand query = new MySqlCommand("Select Column_name, Is_Nullable, Data_Type from information_schema.Columns where table_schema ='" + conn.Database + "' and table_name = 'Blogs' and column_name ='TotalPosts'", conn); - MySqlDataReader reader = query.ExecuteReader(); - while (reader.Read()) - { - Assert.AreEqual("TotalPosts", reader[0].ToString()); - Assert.AreEqual("NO", reader[1].ToString()); - Assert.AreEqual("int", reader[2].ToString()); - } - reader.Close(); - conn.Close(); - } - } - } - - /// - /// CreateTable operation - /// with the following columns int PostId string Title string Body - /// - [Test] - public void CreateTableOperationMigration() - { - - var migrationOperations = new List(); - var createTableOperation = CreateTableOperation(); - - migrationOperations.Add(createTableOperation); - - using (BlogContext context = new BlogContext()) - { - if (context.Database.Exists()) context.Database.Delete(); - context.Database.Create(); - - using (var conn = new MySqlConnection(context.Database.Connection.ConnectionString)) - { - if (conn.State == System.Data.ConnectionState.Closed) conn.Open(); - Assert.True(GenerateAndExecuteMySQLStatements(migrationOperations)); - using (MySqlCommand query = new MySqlCommand($"SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA ='{conn.Database}'" + - $" AND TABLE_NAME = 'Posts'", conn)) - { - using (MySqlDataReader reader = query.ExecuteReader()) - { - while (reader.Read()) - Assert.That(createTableOperation.Columns.Where(t => t.Name.Equals(reader[0].ToString())), Has.One.Items); - reader.Close(); - } - - - query.CommandText = $"SELECT COLUMN_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = '{conn.Database}' AND " + - $"TABLE_NAME = 'Posts' AND COLUMN_NAME = 'Password'"; - - StringAssert.AreEqualIgnoringCase("binary(10)", query.ExecuteScalar().ToString()); - } - } - } - } - - /// - /// CreateForeignKey operation - /// between Blogs and Posts table - /// - [Test] - public void CreateForeignKeyOperation() - { - var migrationOperations = new List(); - - // create dependant table Posts - var createTableOperation = CreateTableOperation(); - migrationOperations.Add(createTableOperation); - - // Add column BlogId to create the constraints - - if (ProviderManifest == null) - ProviderManifest = new MySqlProviderManifest(Version.ToString()); - - TypeUsage tu = TypeUsage.CreateDefaultTypeUsage(PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Int32)); - TypeUsage result = ProviderManifest.GetStoreType(tu); - - var intColumn = new ColumnModel(PrimitiveTypeKind.Int32, result) - { - Name = "BlogId", - IsNullable = false - }; - - var addColumnMigratioOperation = new AddColumnOperation("Posts", intColumn); - migrationOperations.Add(addColumnMigratioOperation); - - // create constrain object - var createForeignkeyOperation = new AddForeignKeyOperation(); - - createForeignkeyOperation.Name = "FKBlogs"; - createForeignkeyOperation.DependentTable = "Posts"; - createForeignkeyOperation.DependentColumns.Add("BlogId"); - createForeignkeyOperation.CascadeDelete = true; - createForeignkeyOperation.PrincipalTable = "Blogs"; - createForeignkeyOperation.PrincipalColumns.Add("BlogId"); - - //create index to use - migrationOperations.Add(createForeignkeyOperation.CreateCreateIndexOperation()); - - migrationOperations.Add(createForeignkeyOperation); - - - using (BlogContext context = new BlogContext()) - { - - if (context.Database.Exists()) context.Database.Delete(); - context.Database.Create(); - - Assert.AreEqual(true, GenerateAndExecuteMySQLStatements(migrationOperations)); - - using (var conn = new MySqlConnection(context.Database.Connection.ConnectionString)) - { - if (conn.State == System.Data.ConnectionState.Closed) conn.Open(); - // check for foreign key creation - MySqlCommand query = new MySqlCommand("select Count(*) from information_schema.table_constraints where LOWER(constraint_type) = 'foreign key' and constraint_schema = '" + conn.Database + "' and constraint_name = 'FKBlogs'", conn); - int rows = Convert.ToInt32(query.ExecuteScalar()); - Assert.AreEqual(1, rows); - // check for table creation - query = new MySqlCommand("select Count(*) from information_schema.Tables WHERE `table_name` = 'Posts' and `table_schema` = '" + conn.Database + "' ", conn); - rows = Convert.ToInt32(query.ExecuteScalar()); - Assert.AreEqual(1, rows); - conn.Close(); - } - - // Test fix for - MySqlConnection con = GetConnectionFromContext(context); - con.Open(); - try - { - MySqlCommand cmd = new MySqlCommand("show create table `Posts`", con); - using (MySqlDataReader r = cmd.ExecuteReader()) - { - r.Read(); - string sql = r.GetString(1); - Assert.True(sql.IndexOf( - " CONSTRAINT `FKBlogs` FOREIGN KEY (`BlogId`) REFERENCES `blogs` (`BlogId`) ON DELETE CASCADE ON UPDATE CASCADE", - StringComparison.OrdinalIgnoreCase) != -1); - } - } - finally - { - con.Close(); - } - } - } - - - /// - /// Remove PK and the autoincrement property for the column - /// - - [Test] - public void DropPrimaryKeyOperationWithAnonymousArguments() - { - - var migrationOperations = new List(); - - // create table where the PK exists - var createTableOperation = CreateTableOperation(); - migrationOperations.Add(createTableOperation); - - var createDropPKOperation = new DropPrimaryKeyOperation(anonymousArguments: new { DeleteAutoIncrement = true }); - createDropPKOperation.Table = "Posts"; - createDropPKOperation.Columns.Add("PostId"); - migrationOperations.Add(createDropPKOperation); - - using (BlogContext context = new BlogContext()) - { - if (context.Database.Exists()) context.Database.Delete(); - context.Database.Create(); - - - Assert.AreEqual(true, GenerateAndExecuteMySQLStatements(migrationOperations)); - - using (var conn = new MySqlConnection(context.Database.Connection.ConnectionString)) - { - if (conn.State == System.Data.ConnectionState.Closed) conn.Open(); - - // check for table creation - var query = new MySqlCommand("select Count(*) from information_schema.Tables WHERE `table_name` = 'Posts' and `table_schema` = '" + conn.Database + "' ", conn); - int rows = Convert.ToInt32(query.ExecuteScalar()); - Assert.AreEqual(1, rows); - - // check if PK exists - query = new MySqlCommand("select Count(*) from information_schema.table_constraints where `constraint_type` = 'primary key' and `constraint_schema` = '" + conn.Database + "' and table_name= 'Posts'", conn); - rows = Convert.ToInt32(query.ExecuteScalar()); - Assert.AreEqual(0, rows); - - //check the definition of the column that was PK - query = new MySqlCommand("Select Column_name, Is_Nullable, Data_Type from information_schema.Columns where table_schema ='" + conn.Database + "' and table_name = 'Posts' and column_name ='PostId'", conn); - MySqlDataReader reader = query.ExecuteReader(); - while (reader.Read()) - { - Assert.AreEqual("PostId", reader[0].ToString()); - Assert.AreEqual("NO", reader[1].ToString()); - Assert.AreEqual("int", reader[2].ToString()); - } - reader.Close(); - conn.Close(); - } - } - } - - - /// - /// Drop primary key. No anonymous arguments - /// - [Test] - public void DropPrimaryKeyOperation() - { - - var migrationOperations = new List(); - - // create table where the PK exists - var createTableOperation = CreateTableOperation(); - migrationOperations.Add(createTableOperation); - - var createDropPKOperation = new DropPrimaryKeyOperation(anonymousArguments: new { DeleteAutoIncrement = true }); - createDropPKOperation.Table = "Posts"; - createDropPKOperation.Columns.Add("PostId"); - migrationOperations.Add(createDropPKOperation); - - using (BlogContext context = new BlogContext()) - { - if (context.Database.Exists()) context.Database.Delete(); - context.Database.Create(); - - - Assert.AreEqual(true, GenerateAndExecuteMySQLStatements(migrationOperations)); - - using (var conn = new MySqlConnection(context.Database.Connection.ConnectionString)) - { - if (conn.State == System.Data.ConnectionState.Closed) conn.Open(); - - // check for table creation - var query = new MySqlCommand("select Count(*) from information_schema.Tables WHERE `table_name` = 'Posts' and `table_schema` = '" + conn.Database + "' ", conn); - int rows = Convert.ToInt32(query.ExecuteScalar()); - Assert.AreEqual(1, rows); - - // check if PK exists - query = new MySqlCommand("select Count(*) from information_schema.table_constraints where `constraint_type` = 'primary key' and `constraint_schema` = '" + conn.Database + "' and table_name= 'Posts'", conn); - rows = Convert.ToInt32(query.ExecuteScalar()); - Assert.AreEqual(0, rows); - - //check the definition of the column that was PK - query = new MySqlCommand("Select Column_name, Is_Nullable, Data_Type from information_schema.Columns where table_schema ='" + conn.Database + "' and table_name = 'Posts' and column_name ='PostId'", conn); - MySqlDataReader reader = query.ExecuteReader(); - while (reader.Read()) - { - Assert.AreEqual("PostId", reader[0].ToString()); - Assert.AreEqual("NO", reader[1].ToString()); - Assert.AreEqual("int", reader[2].ToString()); - } - reader.Close(); - conn.Close(); - } - } - } - - - /// - /// Creates a table named Posts - /// and columns int PostId, string Title, string Body - /// - /// - - private CreateTableOperation CreateTableOperation() - { - TypeUsage tu; - TypeUsage result; - - if (ProviderManifest == null) - ProviderManifest = new MySqlProviderManifest(Version.ToString()); - - var createTableOperation = new CreateTableOperation("Posts"); - - //Column model for int IdPost - tu = TypeUsage.CreateDefaultTypeUsage(PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Int32)); - result = ProviderManifest.GetStoreType(tu); - - var intColumn = new ColumnModel(PrimitiveTypeKind.Int32, result) - { - Name = "PostId", - IsNullable = false, - IsIdentity = true - }; - - createTableOperation.Columns.Add(intColumn); - - //Column model for string - tu = TypeUsage.CreateDefaultTypeUsage(PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.String)); - result = ProviderManifest.GetStoreType(tu); - - var stringColumnTitle = new ColumnModel(PrimitiveTypeKind.String, result) - { - Name = "Title", - IsNullable = false - }; - - var stringColumnBody = new ColumnModel(PrimitiveTypeKind.String, result) - { - Name = "Body", - IsNullable = true - }; - - createTableOperation.Columns.Add(stringColumnTitle); - createTableOperation.Columns.Add(stringColumnBody); - - //Column model for binary - tu = TypeUsage.CreateDefaultTypeUsage(PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Binary)); - result = ProviderManifest.GetStoreType(tu); - - var binaryColumn = new ColumnModel(PrimitiveTypeKind.Binary, result) - { - Name = "Password", - MaxLength = 10, - StoreType = "binary" - }; - - createTableOperation.Columns.Add(binaryColumn); - - var primaryKey = new AddPrimaryKeyOperation(); - - primaryKey.Columns.Add("PostId"); - - createTableOperation.PrimaryKey = primaryKey; - - return createTableOperation; - - } - - - /// - /// Generate and apply sql statemens from the - /// migration operations list - /// return false is case of fail or if database doesn't exist - /// - private bool GenerateAndExecuteMySQLStatements(List migrationOperations) - { - MySqlProviderServices ProviderServices; - - ProviderServices = new MySqlProviderServices(); - - using (BlogContext context = new BlogContext()) - { - if (!context.Database.Exists()) return false; - - using (MySqlConnection conn = new MySqlConnection(context.Database.Connection.ConnectionString)) - { - var migratorGenerator = new MySqlMigrationSqlGenerator(); - var Token = ProviderServices.GetProviderManifestToken(conn); - var sqlStmts = migratorGenerator.Generate(migrationOperations, providerManifestToken: Token); - if (conn.State == System.Data.ConnectionState.Closed) conn.Open(); - foreach (MigrationStatement stmt in sqlStmts) - { - try - { - MySqlCommand cmd = new MySqlCommand(stmt.Sql, conn); - cmd.ExecuteNonQuery(); - } - catch (Exception) - { - return false; - } - } - } - } - return true; - } - } -} \ No newline at end of file +// Copyright © 2013, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using System; +using System.Collections.Generic; +using System.Data.Entity; +using System.Data.Entity.Infrastructure; +using System.Data.Entity.Migrations.Model; +using System.Data.Entity.Migrations.Sql; +using System.Linq; +using NUnit.Framework; +using MySql.Data.MySqlClient; +using System.Data.Entity.Core.EntityClient; +using System.Data.Entity.Core.Metadata.Edm; + +namespace MySql.Data.EntityFramework.Migrations.Tests +{ + public class MySqlMigrationsTests : SetUpMigrationsTests + { + private MySqlProviderManifest ProviderManifest; + + public MySqlMigrationsTests() + { + Database.SetInitializer(new MigrateDatabaseToLatestVersion()); + } + + private MySqlConnection GetConnectionFromContext(DbContext ctx) + { + return (MySqlConnection)((EntityConnection)(((IObjectContextAdapter)ctx).ObjectContext.Connection)).StoreConnection; + } + + /// + /// Add int32 type column to existing table + /// + [Test] + public void AddColumnOperationMigration() + { + var migrationOperations = new List(); + + if (ProviderManifest == null) + ProviderManifest = new MySqlProviderManifest(Version.ToString()); + + TypeUsage tu = TypeUsage.CreateDefaultTypeUsage(PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Int32)); + TypeUsage result = ProviderManifest.GetStoreType(tu); + + var intColumn = new ColumnModel(PrimitiveTypeKind.Int32, result) + { + Name = "TotalPosts", + IsNullable = false + }; + + var addColumnMigratioOperation = new AddColumnOperation("Blogs", intColumn); + migrationOperations.Add(addColumnMigratioOperation); + + using (BlogContext context = new BlogContext()) + { + if (context.Database.Exists()) context.Database.Delete(); + context.Database.Create(); + + using (MySqlConnection conn = new MySqlConnection(context.Database.Connection.ConnectionString)) + { + if (conn.State == System.Data.ConnectionState.Closed) conn.Open(); + Assert.That(GenerateAndExecuteMySQLStatements(migrationOperations), Is.EqualTo(true)); + + MySqlCommand query = new MySqlCommand("Select Column_name, Is_Nullable, Data_Type from information_schema.Columns where table_schema ='" + conn.Database + "' and table_name = 'Blogs' and column_name ='TotalPosts'", conn); + MySqlDataReader reader = query.ExecuteReader(); + while (reader.Read()) + { + Assert.That(reader[0].ToString(), Is.EqualTo("TotalPosts")); + Assert.That(reader[1].ToString(), Is.EqualTo("NO")); + Assert.That(reader[2].ToString(), Is.EqualTo("int")); + } + reader.Close(); + conn.Close(); + } + } + } + + /// + /// CreateTable operation + /// with the following columns int PostId string Title string Body + /// + [Test] + public void CreateTableOperationMigration() + { + + var migrationOperations = new List(); + var createTableOperation = CreateTableOperation(); + + migrationOperations.Add(createTableOperation); + + using (BlogContext context = new BlogContext()) + { + if (context.Database.Exists()) context.Database.Delete(); + context.Database.Create(); + + using (var conn = new MySqlConnection(context.Database.Connection.ConnectionString)) + { + if (conn.State == System.Data.ConnectionState.Closed) conn.Open(); + Assert.That(GenerateAndExecuteMySQLStatements(migrationOperations)); + using (MySqlCommand query = new MySqlCommand($"SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA ='{conn.Database}'" + + $" AND TABLE_NAME = 'Posts'", conn)) + { + using (MySqlDataReader reader = query.ExecuteReader()) + { + while (reader.Read()) + Assert.That(createTableOperation.Columns.Where(t => t.Name.Equals(reader[0].ToString())), Has.One.Items); + reader.Close(); + } + + + query.CommandText = $"SELECT COLUMN_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = '{conn.Database}' AND " + + $"TABLE_NAME = 'Posts' AND COLUMN_NAME = 'Password'"; + + Assert.That(query.ExecuteScalar().ToString(), Is.EqualTo("binary(10)").IgnoreCase); + } + } + } + } + + /// + /// CreateForeignKey operation + /// between Blogs and Posts table + /// + [Test] + public void CreateForeignKeyOperation() + { + var migrationOperations = new List(); + + // create dependant table Posts + var createTableOperation = CreateTableOperation(); + migrationOperations.Add(createTableOperation); + + // Add column BlogId to create the constraints + + if (ProviderManifest == null) + ProviderManifest = new MySqlProviderManifest(Version.ToString()); + + TypeUsage tu = TypeUsage.CreateDefaultTypeUsage(PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Int32)); + TypeUsage result = ProviderManifest.GetStoreType(tu); + + var intColumn = new ColumnModel(PrimitiveTypeKind.Int32, result) + { + Name = "BlogId", + IsNullable = false + }; + + var addColumnMigratioOperation = new AddColumnOperation("Posts", intColumn); + migrationOperations.Add(addColumnMigratioOperation); + + // create constrain object + var createForeignkeyOperation = new AddForeignKeyOperation(); + + createForeignkeyOperation.Name = "FKBlogs"; + createForeignkeyOperation.DependentTable = "Posts"; + createForeignkeyOperation.DependentColumns.Add("BlogId"); + createForeignkeyOperation.CascadeDelete = true; + createForeignkeyOperation.PrincipalTable = "Blogs"; + createForeignkeyOperation.PrincipalColumns.Add("BlogId"); + + //create index to use + migrationOperations.Add(createForeignkeyOperation.CreateCreateIndexOperation()); + + migrationOperations.Add(createForeignkeyOperation); + + + using (BlogContext context = new BlogContext()) + { + + if (context.Database.Exists()) context.Database.Delete(); + context.Database.Create(); + + Assert.That(GenerateAndExecuteMySQLStatements(migrationOperations), Is.EqualTo(true)); + + using (var conn = new MySqlConnection(context.Database.Connection.ConnectionString)) + { + if (conn.State == System.Data.ConnectionState.Closed) conn.Open(); + // check for foreign key creation + MySqlCommand query = new MySqlCommand("select Count(*) from information_schema.table_constraints where LOWER(constraint_type) = 'foreign key' and constraint_schema = '" + conn.Database + "' and constraint_name = 'FKBlogs'", conn); + int rows = Convert.ToInt32(query.ExecuteScalar()); + Assert.That(rows, Is.EqualTo(1)); + // check for table creation + query = new MySqlCommand("select Count(*) from information_schema.Tables WHERE `table_name` = 'Posts' and `table_schema` = '" + conn.Database + "' ", conn); + rows = Convert.ToInt32(query.ExecuteScalar()); + Assert.That(rows, Is.EqualTo(1)); + conn.Close(); + } + + // Test fix for + MySqlConnection con = GetConnectionFromContext(context); + con.Open(); + try + { + MySqlCommand cmd = new MySqlCommand("show create table `Posts`", con); + using (MySqlDataReader r = cmd.ExecuteReader()) + { + r.Read(); + string sql = r.GetString(1); + Assert.That(sql.IndexOf( + " CONSTRAINT `FKBlogs` FOREIGN KEY (`BlogId`) REFERENCES `blogs` (`BlogId`) ON DELETE CASCADE ON UPDATE CASCADE", + StringComparison.OrdinalIgnoreCase) != -1); + } + } + finally + { + con.Close(); + } + } + } + + + /// + /// Remove PK and the autoincrement property for the column + /// + + [Test] + public void DropPrimaryKeyOperationWithAnonymousArguments() + { + + var migrationOperations = new List(); + + // create table where the PK exists + var createTableOperation = CreateTableOperation(); + migrationOperations.Add(createTableOperation); + + var createDropPKOperation = new DropPrimaryKeyOperation(anonymousArguments: new { DeleteAutoIncrement = true }); + createDropPKOperation.Table = "Posts"; + createDropPKOperation.Columns.Add("PostId"); + migrationOperations.Add(createDropPKOperation); + + using (BlogContext context = new BlogContext()) + { + if (context.Database.Exists()) context.Database.Delete(); + context.Database.Create(); + + + Assert.That(GenerateAndExecuteMySQLStatements(migrationOperations), Is.EqualTo(true)); + + using (var conn = new MySqlConnection(context.Database.Connection.ConnectionString)) + { + if (conn.State == System.Data.ConnectionState.Closed) conn.Open(); + + // check for table creation + var query = new MySqlCommand("select Count(*) from information_schema.Tables WHERE `table_name` = 'Posts' and `table_schema` = '" + conn.Database + "' ", conn); + int rows = Convert.ToInt32(query.ExecuteScalar()); + Assert.That(rows, Is.EqualTo(1)); + + // check if PK exists + query = new MySqlCommand("select Count(*) from information_schema.table_constraints where `constraint_type` = 'primary key' and `constraint_schema` = '" + conn.Database + "' and table_name= 'Posts'", conn); + rows = Convert.ToInt32(query.ExecuteScalar()); + Assert.That(rows, Is.EqualTo(0)); + + //check the definition of the column that was PK + query = new MySqlCommand("Select Column_name, Is_Nullable, Data_Type from information_schema.Columns where table_schema ='" + conn.Database + "' and table_name = 'Posts' and column_name ='PostId'", conn); + MySqlDataReader reader = query.ExecuteReader(); + while (reader.Read()) + { + Assert.That(reader[0].ToString(), Is.EqualTo("PostId")); + Assert.That(reader[1].ToString(), Is.EqualTo("NO")); + Assert.That(reader[2].ToString(), Is.EqualTo("int")); + } + reader.Close(); + conn.Close(); + } + } + } + + + /// + /// Drop primary key. No anonymous arguments + /// + [Test] + public void DropPrimaryKeyOperation() + { + + var migrationOperations = new List(); + + // create table where the PK exists + var createTableOperation = CreateTableOperation(); + migrationOperations.Add(createTableOperation); + + var createDropPKOperation = new DropPrimaryKeyOperation(anonymousArguments: new { DeleteAutoIncrement = true }); + createDropPKOperation.Table = "Posts"; + createDropPKOperation.Columns.Add("PostId"); + migrationOperations.Add(createDropPKOperation); + + using (BlogContext context = new BlogContext()) + { + if (context.Database.Exists()) context.Database.Delete(); + context.Database.Create(); + + + Assert.That(GenerateAndExecuteMySQLStatements(migrationOperations), Is.EqualTo(true)); + + using (var conn = new MySqlConnection(context.Database.Connection.ConnectionString)) + { + if (conn.State == System.Data.ConnectionState.Closed) conn.Open(); + + // check for table creation + var query = new MySqlCommand("select Count(*) from information_schema.Tables WHERE `table_name` = 'Posts' and `table_schema` = '" + conn.Database + "' ", conn); + int rows = Convert.ToInt32(query.ExecuteScalar()); + Assert.That(rows, Is.EqualTo(1)); + + // check if PK exists + query = new MySqlCommand("select Count(*) from information_schema.table_constraints where `constraint_type` = 'primary key' and `constraint_schema` = '" + conn.Database + "' and table_name= 'Posts'", conn); + rows = Convert.ToInt32(query.ExecuteScalar()); + Assert.That(rows, Is.EqualTo(0)); + + //check the definition of the column that was PK + query = new MySqlCommand("Select Column_name, Is_Nullable, Data_Type from information_schema.Columns where table_schema ='" + conn.Database + "' and table_name = 'Posts' and column_name ='PostId'", conn); + MySqlDataReader reader = query.ExecuteReader(); + while (reader.Read()) + { + Assert.That(reader[0].ToString(), Is.EqualTo("PostId")); + Assert.That(reader[1].ToString(), Is.EqualTo("NO")); + Assert.That(reader[2].ToString(), Is.EqualTo("int")); + } + reader.Close(); + conn.Close(); + } + } + } + + + /// + /// Creates a table named Posts + /// and columns int PostId, string Title, string Body + /// + /// + + private CreateTableOperation CreateTableOperation() + { + TypeUsage tu; + TypeUsage result; + + if (ProviderManifest == null) + ProviderManifest = new MySqlProviderManifest(Version.ToString()); + + var createTableOperation = new CreateTableOperation("Posts"); + + //Column model for int IdPost + tu = TypeUsage.CreateDefaultTypeUsage(PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Int32)); + result = ProviderManifest.GetStoreType(tu); + + var intColumn = new ColumnModel(PrimitiveTypeKind.Int32, result) + { + Name = "PostId", + IsNullable = false, + IsIdentity = true + }; + + createTableOperation.Columns.Add(intColumn); + + //Column model for string + tu = TypeUsage.CreateDefaultTypeUsage(PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.String)); + result = ProviderManifest.GetStoreType(tu); + + var stringColumnTitle = new ColumnModel(PrimitiveTypeKind.String, result) + { + Name = "Title", + IsNullable = false + }; + + var stringColumnBody = new ColumnModel(PrimitiveTypeKind.String, result) + { + Name = "Body", + IsNullable = true + }; + + createTableOperation.Columns.Add(stringColumnTitle); + createTableOperation.Columns.Add(stringColumnBody); + + //Column model for binary + tu = TypeUsage.CreateDefaultTypeUsage(PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Binary)); + result = ProviderManifest.GetStoreType(tu); + + var binaryColumn = new ColumnModel(PrimitiveTypeKind.Binary, result) + { + Name = "Password", + MaxLength = 10, + StoreType = "binary" + }; + + createTableOperation.Columns.Add(binaryColumn); + + var primaryKey = new AddPrimaryKeyOperation(); + + primaryKey.Columns.Add("PostId"); + + createTableOperation.PrimaryKey = primaryKey; + + return createTableOperation; + + } + + + /// + /// Generate and apply sql statemens from the + /// migration operations list + /// return false is case of fail or if database doesn't exist + /// + private bool GenerateAndExecuteMySQLStatements(List migrationOperations) + { + MySqlProviderServices ProviderServices; + + ProviderServices = new MySqlProviderServices(); + + using (BlogContext context = new BlogContext()) + { + if (!context.Database.Exists()) return false; + + using (MySqlConnection conn = new MySqlConnection(context.Database.Connection.ConnectionString)) + { + var migratorGenerator = new MySqlMigrationSqlGenerator(); + var Token = ProviderServices.GetProviderManifestToken(conn); + var sqlStmts = migratorGenerator.Generate(migrationOperations, providerManifestToken: Token); + if (conn.State == System.Data.ConnectionState.Closed) conn.Open(); + foreach (MigrationStatement stmt in sqlStmts) + { + try + { + MySqlCommand cmd = new MySqlCommand(stmt.Sql, conn); + cmd.ExecuteNonQuery(); + } + catch (Exception) + { + return false; + } + } + } + } + return true; + } + } +} diff --git a/EntityFramework/tests/MySql.EntityFramework.Migrations.Tests/Properties/AssemblyInfo.cs b/EntityFramework/tests/MySql.EntityFramework.Migrations.Tests/Properties/AssemblyInfo.cs index a28f3ab9c..c337fd60a 100644 --- a/EntityFramework/tests/MySql.EntityFramework.Migrations.Tests/Properties/AssemblyInfo.cs +++ b/EntityFramework/tests/MySql.EntityFramework.Migrations.Tests/Properties/AssemblyInfo.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -39,7 +39,7 @@ [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Oracle")] [assembly: AssemblyProduct("MySql.Data.EntityFramework.Migrations.Tests")] -[assembly: AssemblyCopyright("Copyright © 2013, 2019, Oracle and/or its affiliates. All rights reserved.")] +[assembly: AssemblyCopyright("Copyright © 2013, 2025, Oracle and/or its affiliates.")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] @@ -54,4 +54,4 @@ #if !DEBUG [assembly: AssemblyKeyName("ConnectorNet")] #endif -[assembly: NonParallelizable] \ No newline at end of file +[assembly: NonParallelizable] diff --git a/EntityFramework/tests/MySql.EntityFramework.Migrations.Tests/SetUpMigrationsTests.cs b/EntityFramework/tests/MySql.EntityFramework.Migrations.Tests/SetUpMigrationsTests.cs index 7bb327775..f39c7375e 100644 --- a/EntityFramework/tests/MySql.EntityFramework.Migrations.Tests/SetUpMigrationsTests.cs +++ b/EntityFramework/tests/MySql.EntityFramework.Migrations.Tests/SetUpMigrationsTests.cs @@ -1,115 +1,116 @@ -// Copyright (c) 2013, 2023 Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data.EntityFramework.Properties; -using MySql.Data.EntityFramework.Tests; -using NUnit.Framework; -using System; -using System.Configuration; -using System.Data; -using System.Data.Entity.Migrations; -using System.IO; -using System.Reflection; -using System.Runtime.InteropServices; - -namespace MySql.Data.EntityFramework.Migrations.Tests -{ - public class SetUpMigrationsTests : DefaultFixture - { - - private Configuration configuration; - public DbMigrator Migrator; - public static string ConnectionStringBlogContext { get; set; } - - [OneTimeSetUp] - public new void OneTimeSetup() - { - ConnectionStringBlogContext = RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? MySql.EntityFramework.Migrations.Tests.Properties.Resources.ConnStringMacOS : MySql.EntityFramework.Migrations.Tests.Properties.Resources.ConnString; - - configuration = new Configuration(); - DataSet dataSet = ConfigurationManager.GetSection("system.data") as System.Data.DataSet; - if (dataSet != null) - { - DataView vi = dataSet.Tables[0].DefaultView; - vi.Sort = "Name"; - int idx = -1; - if (((idx = vi.Find("MySql")) != -1) || ((idx = vi.Find("MySQL Data Provider")) != -1)) - { - DataRow row = vi[idx].Row; - dataSet.Tables[0].Rows.Remove(row); - } - dataSet.Tables[0].Rows.Add("MySql" - , "MySql.Data.MySqlClient" - , "MySql.Data.MySqlClient" - , - typeof(MySql.Data.MySqlClient.MySqlClientFactory).AssemblyQualifiedName); - } - Migrator = new DbMigrator(configuration); - } - - [OneTimeTearDown] - public new void OneTimeTearDown() - { - using (BlogContext context = new BlogContext()) - { - if (context.Database.Exists()) - { - context.Database.Delete(); - } - } - } - } - - internal sealed class Configuration : DbMigrationsConfiguration - { - public Configuration() - { - CodeGenerator = new MySqlMigrationCodeGenerator(); - AutomaticMigrationsEnabled = false; - SetSqlGenerator("MySql.Data.MySqlClient", new MySql.Data.EntityFramework.MySqlMigrationSqlGenerator()); - } - - protected override void Seed(BlogContext context) - { - } - } - - internal sealed class EF6Configuration : DbMigrationsConfiguration - { - public EF6Configuration() - { - CodeGenerator = new MySqlMigrationCodeGenerator(); - AutomaticMigrationsEnabled = true; - SetSqlGenerator("MySql.Data.MySqlClient", new MySql.Data.EntityFramework.MySqlMigrationSqlGenerator()); - } - - protected override void Seed(BlogContext context) - { - } - } -} \ No newline at end of file +// Copyright © 2013, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data.EntityFramework.Properties; +using MySql.Data.EntityFramework.Tests; +using NUnit.Framework; +using NUnit.Framework.Internal; +using System; +using System.Configuration; +using System.Data; +using System.Data.Entity.Migrations; +using System.IO; +using System.Reflection; +using System.Runtime.InteropServices; + +namespace MySql.Data.EntityFramework.Migrations.Tests +{ + public class SetUpMigrationsTests : DefaultFixture + { + + private Configuration configuration; + public DbMigrator Migrator; + public static string ConnectionStringBlogContext { get; set; } + + [OneTimeSetUp] + public new void OneTimeSetup() + { + ConnectionStringBlogContext = System.Environment.OSVersion.Platform == PlatformID.MacOSX ? MySql.EntityFramework.Migrations.Tests.Properties.Resources.ConnStringMacOS : MySql.EntityFramework.Migrations.Tests.Properties.Resources.ConnString; + + configuration = new Configuration(); + DataSet dataSet = ConfigurationManager.GetSection("system.data") as System.Data.DataSet; + if (dataSet != null) + { + DataView vi = dataSet.Tables[0].DefaultView; + vi.Sort = "Name"; + int idx = -1; + if (((idx = vi.Find("MySql")) != -1) || ((idx = vi.Find("MySQL Data Provider")) != -1)) + { + DataRow row = vi[idx].Row; + dataSet.Tables[0].Rows.Remove(row); + } + dataSet.Tables[0].Rows.Add("MySql" + , "MySql.Data.MySqlClient" + , "MySql.Data.MySqlClient" + , + typeof(MySql.Data.MySqlClient.MySqlClientFactory).AssemblyQualifiedName); + } + Migrator = new DbMigrator(configuration); + } + + [OneTimeTearDown] + public new void OneTimeTearDown() + { + using (BlogContext context = new BlogContext()) + { + if (context.Database.Exists()) + { + context.Database.Delete(); + } + } + } + } + + internal sealed class Configuration : DbMigrationsConfiguration + { + public Configuration() + { + CodeGenerator = new MySqlMigrationCodeGenerator(); + AutomaticMigrationsEnabled = false; + SetSqlGenerator("MySql.Data.MySqlClient", new MySql.Data.EntityFramework.MySqlMigrationSqlGenerator()); + } + + protected override void Seed(BlogContext context) + { + } + } + + internal sealed class EF6Configuration : DbMigrationsConfiguration + { + public EF6Configuration() + { + CodeGenerator = new MySqlMigrationCodeGenerator(); + AutomaticMigrationsEnabled = true; + SetSqlGenerator("MySql.Data.MySqlClient", new MySql.Data.EntityFramework.MySqlMigrationSqlGenerator()); + } + + protected override void Seed(BlogContext context) + { + } + } +} diff --git a/LICENSE b/LICENSE index f1204f0e0..5bd685ccc 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ Licensing Information User Manual -MySQL Connector/NET 8.2.0 Community +MySQL Connector/NET 9.4.0 Community __________________________________________________________________ Introduction @@ -8,24 +8,25 @@ Introduction This License Information User Manual contains Oracle's product license and other licensing information, including licensing information for third-party software which may be included in this distribution of - MySQL Connector/NET 8.2.0 Community. + MySQL Connector/NET 9.4.0 Community. - Last updated: September 2023 + Last updated: June 2025 Licensing Information - This release of MySQL Connector/NET 8.2.0 Community is brought to you + This release of MySQL Connector/NET 9.4.0 Community is brought to you by the MySQL team at Oracle. This software is released under version 2 of the GNU General Public License (GPLv2), as set forth below, with the following additional permissions: - This distribution of MySQL Connector/NET 8.2.0 Community is distributed - with certain software (including but not limited to OpenSSL) that is - licensed under separate terms, as designated in a particular file or + This distribution of MySQL Connector/NET 9.4.0 Community is designed to + work with certain software (including but not limited to OpenSSL) that + is licensed under separate terms, as designated in a particular file or component or in the license documentation. Without limiting your rights under the GPLv2, the authors of MySQL hereby grant you an additional permission to link the program and your derivative works with the - separately licensed software that they have included with the program. + separately licensed software that they have either included with the + program or referenced in the documentation. Without limiting the foregoing grant of rights under the GPLv2 and additional permission as to separately licensed software, this @@ -33,7 +34,7 @@ Licensing Information a copy of which is reproduced below and can also be found along with its FAQ at http://oss.oracle.com/licenses/universal-foss-exception. - Copyright (c) 2004, 2023, Oracle and/or its affiliates. + Copyright (c) 2004, 2025, Oracle and/or its affiliates. Election of GPLv2 @@ -518,58 +519,1333 @@ support library is itself covered by the above license. ====================================================================== ====================================================================== -K4os.Compression.LZ4.Streams +Kerberos5 -LICENSE file: -======== -MIT License +You may be receiving a copy of the kerberos documentation as part of this +product. The terms of the Oracle license do NOT apply to Kerberos documentation. -Copyright (c) 2017 Milosz Krajewski +Kerberos documentation is licensed under the CC-BY-SA 3.0 license, separate from -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +the Oracle product. +If you do not wish to install this library, you may remove it, but +the Oracle program might not operate properly or at all without it. -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. +Copyright (C) 1985-2019 by the Massachusetts Institute of Technology. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +All rights reserved. ------------------------------------------------------------------------------- -4th party dependency -(https://github.com/MiloszKrajewski/K4os.Hash.xxHash/archive/master.zip): -LICENSE File (same copyright): +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: -MIT License +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. -Copyright (c) 2017 Milosz Krajewski +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. +Downloading of this software may constitute an export of cryptographic +software from the United States of America that is subject to the +United States Export Administration Regulations (EAR), 15 CFR 730-774. +Additional laws or regulations may apply. It is the responsibility of +the person or entity contemplating export to comply with all +applicable export laws and regulations, including obtaining any +required license from the U.S. government. + +The U.S. government prohibits export of encryption source code to +certain countries and individuals, including, but not limited to, the +countries of Cuba, Iran, North Korea, Sudan, Syria, and residents and +nationals of those countries. + +Documentation components of this software distribution are licensed +under a Creative Commons Attribution-ShareAlike 3.0 Unported License. +(http://creativecommons.org/licenses/by-sa/3.0/) + +Individual source code files are copyright MIT, Cygnus Support, +Novell, OpenVision Technologies, Oracle, Red Hat, Sun Microsystems, +FundsXpress, and others. + +Project Athena, Athena, Athena MUSE, Discuss, Hesiod, Kerberos, Moira, +and Zephyr are trademarks of the Massachusetts Institute of Technology +(MIT). No commercial use of these trademarks may be made without +prior written permission of MIT. + +"Commercial use" means use of a name in a product or other for-profit +manner. It does NOT prevent a commercial firm from referring to the +MIT trademarks in order to convey information (although in doing so, +recognition of their trademark status should be given). + +====================================================================== + +The following copyright and permission notice applies to the +OpenVision Kerberos Administration system located in "kadmin/create", +"kadmin/dbutil", "kadmin/passwd", "kadmin/server", "lib/kadm5", and +portions of "lib/rpc": -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. + Copyright, OpenVision Technologies, Inc., 1993-1996, All Rights + Reserved + + WARNING: Retrieving the OpenVision Kerberos Administration system + source code, as described below, indicates your acceptance of the + following terms. If you do not agree to the following terms, do + not retrieve the OpenVision Kerberos administration system. + + You may freely use and distribute the Source Code and Object Code + compiled from it, with or without modification, but this Source + Code is provided to you "AS IS" EXCLUSIVE OF ANY WARRANTY, + INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY OR + FITNESS FOR A PARTICULAR PURPOSE, OR ANY OTHER WARRANTY, WHETHER + EXPRESS OR IMPLIED. IN NO EVENT WILL OPENVISION HAVE ANY LIABILITY + FOR ANY LOST PROFITS, LOSS OF DATA OR COSTS OF PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES, OR FOR ANY SPECIAL, INDIRECT, OR + CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, INCLUDING, + WITHOUT LIMITATION, THOSE RESULTING FROM THE USE OF THE SOURCE + CODE, OR THE FAILURE OF THE SOURCE CODE TO PERFORM, OR FOR ANY + OTHER REASON. + + OpenVision retains all copyrights in the donated Source Code. + OpenVision also retains copyright to derivative works of the Source + Code, whether created by OpenVision or by a third party. The + OpenVision copyright notice must be preserved if derivative works + are made based on the donated Source Code. + + OpenVision Technologies, Inc. has donated this Kerberos + Administration system to MIT for inclusion in the standard Kerberos + 5 distribution. This donation underscores our commitment to + continuing Kerberos technology development and our gratitude for + the valuable work which has been performed by MIT and the Kerberos + community. + +====================================================================== + + Portions contributed by Matt Crawford "crawdad@fnal.gov" were work +performed at Fermi National Accelerator Laboratory, which is + operated by Universities Research Association, Inc., under contract + DE-AC02-76CHO3000 with the U.S. Department of Energy. + +====================================================================== + +Portions of "src/lib/crypto" have the following copyright: + + Copyright (C) 1998 by the FundsXpress, INC. + + All rights reserved. + + Export of this software from the United States of America may + require a specific license from the United States Government. + It is the responsibility of any person or organization + contemplating export to obtain such a license before exporting. + + WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + distribute this software and its documentation for any purpose and + without fee is hereby granted, provided that the above copyright + notice appear in all copies and that both that copyright notice and + this permission notice appear in supporting documentation, and that + the name of FundsXpress. not be used in advertising or publicity + pertaining to distribution of the software without specific, + written prior permission. FundsXpress makes no representations + about the suitability of this software for any purpose. It is + provided "as is" without express or implied warranty. + + THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + +====================================================================== + +The implementation of the AES encryption algorithm in +"src/lib/crypto/builtin/aes" has the following copyright: + + Copyright (C) 2001, Dr Brian Gladman "brg@gladman.uk.net", Worcester, UK. + All rights reserved. + + LICENSE TERMS + + The free distribution and use of this software in both source and + binary form is allowed (with or without changes) provided that: + + 1. distributions of this source code include the above copyright + notice, this list of conditions and the following disclaimer; + + 2. distributions in binary form include the above copyright notice, + this list of conditions and the following disclaimer in the + documentation and/or other associated materials; + + 3. the copyright holder's name is not used to endorse products + built using this software without specific written permission. + + DISCLAIMER + + This software is provided 'as is' with no explcit or implied + warranties in respect of any properties, including, but not limited + to, correctness and fitness for purpose. + +====================================================================== + +Portions contributed by Red Hat, including the pre-authentication +plug-in framework and the NSS crypto implementation, contain the +following copyright: + + Copyright (C) 2006 Red Hat, Inc. + Portions copyright (C) 2006 Massachusetts Institute of Technology + All Rights Reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + * Neither the name of Red Hat, Inc., nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. + +====================================================================== + +The bundled verto source code is subject to the following license: + + Copyright 2011 Red Hat, Inc. + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, copy, + modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + +====================================================================== + +The MS-KKDCP client implementation has the following copyright: + + Copyright 2013,2014 Red Hat, Inc. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + 2. Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. + +====================================================================== + +The implementations of GSSAPI mechglue in GSSAPI-SPNEGO in +"src/lib/gssapi", including the following files: + + lib/gssapi/generic/gssapi_err_generic.et + lib/gssapi/mechglue/g_accept_sec_context.c + lib/gssapi/mechglue/g_acquire_cred.c + lib/gssapi/mechglue/g_canon_name.c + lib/gssapi/mechglue/g_compare_name.c + lib/gssapi/mechglue/g_context_time.c + lib/gssapi/mechglue/g_delete_sec_context.c + lib/gssapi/mechglue/g_dsp_name.c + lib/gssapi/mechglue/g_dsp_status.c + lib/gssapi/mechglue/g_dup_name.c + lib/gssapi/mechglue/g_exp_sec_context.c + lib/gssapi/mechglue/g_export_name.c + lib/gssapi/mechglue/g_glue.c + lib/gssapi/mechglue/g_imp_name.c + lib/gssapi/mechglue/g_imp_sec_context.c + lib/gssapi/mechglue/g_init_sec_context.c + lib/gssapi/mechglue/g_initialize.c + lib/gssapi/mechglue/g_inquire_context.c + lib/gssapi/mechglue/g_inquire_cred.c + lib/gssapi/mechglue/g_inquire_names.c + lib/gssapi/mechglue/g_process_context.c + lib/gssapi/mechglue/g_rel_buffer.c + lib/gssapi/mechglue/g_rel_cred.c + lib/gssapi/mechglue/g_rel_name.c + lib/gssapi/mechglue/g_rel_oid_set.c + lib/gssapi/mechglue/g_seal.c + lib/gssapi/mechglue/g_sign.c + lib/gssapi/mechglue/g_store_cred.c + lib/gssapi/mechglue/g_unseal.c + lib/gssapi/mechglue/g_userok.c + lib/gssapi/mechglue/g_utils.c + lib/gssapi/mechglue/g_verify.c + lib/gssapi/mechglue/gssd_pname_to_uid.c + lib/gssapi/mechglue/mglueP.h + lib/gssapi/mechglue/oid_ops.c + lib/gssapi/spnego/gssapiP_spnego.h + lib/gssapi/spnego/spnego_mech.c + +and the initial implementation of incremental propagation, including +the following new or changed files: + + include/iprop_hdr.h + kadmin/server/ipropd_svc.c + lib/kdb/iprop.x + lib/kdb/kdb_convert.c + lib/kdb/kdb_log.c + lib/kdb/kdb_log.h + lib/krb5/error_tables/kdb5_err.et + slave/kpropd_rpc.c + slave/kproplog.c + +are subject to the following license: + + Copyright (C) 2004 Sun Microsystems, Inc. + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, copy, + modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + +====================================================================== + +Kerberos V5 includes documentation and software developed at the +University of California at Berkeley, which includes this copyright +notice: + + Copyright (C) 1983 Regents of the University of California. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + 3. Neither the name of the University nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + +====================================================================== + +Portions contributed by Novell, Inc., including the LDAP database +backend, are subject to the following license: + + Copyright (C) 2004-2005, Novell, Inc. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + * The copyright holder's name is not used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. + +====================================================================== + +Portions funded by Sandia National Laboratory and developed by the +University of Michigan's Center for Information Technology +Integration, including the PKINIT implementation, are subject to the +following license: + + COPYRIGHT (C) 2006-2007 + THE REGENTS OF THE UNIVERSITY OF MICHIGAN + ALL RIGHTS RESERVED + + Permission is granted to use, copy, create derivative works and + redistribute this software and such derivative works for any + purpose, so long as the name of The University of Michigan is not + used in any advertising or publicity pertaining to the use of + distribution of this software without specific, written prior + authorization. If the above copyright notice or any other + identification of the University of Michigan is included in any + copy of any portion of this software, then the disclaimer below + must also be included. + + THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE + UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY PURPOSE, AND + WITHOUT WARRANTY BY THE UNIVERSITY OF MICHIGAN OF ANY KIND, EITHER + EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + THE REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE FOR + ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR + CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING OUT OF OR + IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN IF IT HAS BEEN OR + IS HEREAFTER ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +====================================================================== + +The pkcs11.h file included in the PKINIT code has the following +license: + + Copyright 2006 g10 Code GmbH + Copyright 2006 Andreas Jellinghaus + + This file is free software; as a special exception the author gives + unlimited permission to copy and/or distribute it, with or without + modifications, as long as this notice is preserved. + + This file is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY, to the extent permitted by law; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + +====================================================================== + +Portions contributed by Apple Inc. are subject to the following +license: + + Copyright 2004-2008 Apple Inc. All Rights Reserved. + + Export of this software from the United States of America may + require a specific license from the United States Government. + It is the responsibility of any person or organization + contemplating export to obtain such a license before exporting. + + WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + distribute this software and its documentation for any purpose and + without fee is hereby granted, provided that the above copyright + notice appear in all copies and that both that copyright notice and + this permission notice appear in supporting documentation, and that + the name of Apple Inc. not be used in advertising or publicity + pertaining to distribution of the software without specific, + written prior permission. Apple Inc. makes no representations + about the suitability of this software for any purpose. It is + provided "as is" without express or implied warranty. + + THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + +====================================================================== + +The implementations of UTF-8 string handling in src/util/support and +src/lib/krb5/unicode are subject to the following copyright and +permission notice: + + The OpenLDAP Public License + Version 2.8, 17 August 2003 + + Redistribution and use of this software and associated + documentation ("Software"), with or without modification, are + permitted provided that the following conditions are met: + + 1. Redistributions in source form must retain copyright statements + and notices, + + 2. Redistributions in binary form must reproduce applicable + copyright statements and notices, this list of conditions, and + the following disclaimer in the documentation and/or other + materials provided with the distribution, and + + 3. Redistributions must contain a verbatim copy of this document. + + The OpenLDAP Foundation may revise this license from time to time. + Each revision is distinguished by a version number. You may use + this Software under terms of this license revision or under the + terms of any subsequent revision of the license. + + THIS SOFTWARE IS PROVIDED BY THE OPENLDAP FOUNDATION AND ITS + CONTRIBUTORS "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE OPENLDAP FOUNDATION, ITS + CONTRIBUTORS, OR THE AUTHOR(S) OR OWNER(S) OF THE SOFTWARE BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + DAMAGE. + + The names of the authors and copyright holders must not be used in + advertising or otherwise to promote the sale, use or other dealing + in this Software without specific, written prior permission. Title + to copyright in this Software shall at all times remain with + copyright holders. + + OpenLDAP is a registered trademark of the OpenLDAP Foundation. + + Copyright 1999-2003 The OpenLDAP Foundation, Redwood City, + California, USA. All Rights Reserved. Permission to copy and + distribute verbatim copies of this document is granted. + +Marked test programs in src/lib/krb5/krb have the following copyright: + + + Copyright (C) 2006 Kungliga Tekniska Högskolan + (Royal Institute of Technology, Stockholm, Sweden). + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + 3. Neither the name of KTH nor the names of its contributors may be + used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + +====================================================================== + +The KCM Mach RPC definition file used on macOS has the following +copyright: + + Copyright (C) 2009 Kungliga Tekniska Högskolan + (Royal Institute of Technology, Stockholm, Sweden). + All rights reserved. + + Portions Copyright (C) 2009 Apple Inc. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + 2. Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + 3. Neither the name of the Institute nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + +====================================================================== + +Portions of the RPC implementation in src/lib/rpc and +src/include/gssrpc have the following copyright and permission notice: + + Copyright (C) 2010, Oracle America, Inc. + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + 3. Neither the name of the "Oracle America, Inc." nor the names of + its contributors may be used to endorse or promote products + derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. + +====================================================================== + + Copyright (C) 2006,2007,2009 NTT (Nippon Telegraph and Telephone + Corporation). All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer as + the first lines of this file unmodified. + + 2. Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + THIS SOFTWARE IS PROVIDED BY NTT "AS IS" AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL NTT BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. + +====================================================================== + + Copyright 2000 by Carnegie Mellon University + + All Rights Reserved + + Permission to use, copy, modify, and distribute this software and + its documentation for any purpose and without fee is hereby + granted, provided that the above copyright notice appear in all + copies and that both that copyright notice and this permission + notice appear in supporting documentation, and that the name of + Carnegie Mellon University not be used in advertising or publicity + pertaining to distribution of the software without specific, + written prior permission. + + CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO + THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE + FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + SOFTWARE. + +====================================================================== + + Copyright (C) 2002 Naval Research Laboratory (NRL/CCS) + + Permission to use, copy, modify and distribute this software and + its documentation is hereby granted, provided that both the + copyright notice and this permission notice appear in all copies of + the software, derivative works or modified versions, and any + portions thereof. + + NRL ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION AND + DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER + RESULTING FROM THE USE OF THIS SOFTWARE. + +====================================================================== + +Portions extracted from Internet RFCs have the following copyright +notice: + + Copyright (C) The Internet Society (2006). + + This document is subject to the rights, licenses and restrictions + contained in BCP 78, and except as set forth therein, the authors + retain all their rights. + + This document and the information contained herein are provided on + an "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE + REPRESENTS OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND + THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT + THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR + ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A + PARTICULAR PURPOSE. + +====================================================================== + + Copyright (C) 1991, 1992, 1994 by Cygnus Support. + + Permission to use, copy, modify, and distribute this software and + its documentation for any purpose and without fee is hereby + granted, provided that the above copyright notice appear in all + copies and that both that copyright notice and this permission + notice appear in supporting documentation. Cygnus Support makes no + representations about the suitability of this software for any + purpose. It is provided "as is" without express or implied + warranty. + +====================================================================== + + Copyright (C) 2006 Secure Endpoints Inc. + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, copy, + modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + +====================================================================== + +Portions of the implementation of the Fortuna-like PRNG are subject to +the following notice: + + + Copyright (C) 2005 Marko Kreen + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + + Copyright (C) 1994 by the University of Southern California + + EXPORT OF THIS SOFTWARE from the United States of America may + require a specific license from the United States Government. It + is the responsibility of any person or organization + contemplating export to obtain such a license before exporting. + + WITHIN THAT CONSTRAINT, permission to copy, modify, and distribute + this software and its documentation in source and binary forms is + hereby granted, provided that any documentation or other materials + related to such distribution or use acknowledge that the software + was developed by the University of Southern California. + + DISCLAIMER OF WARRANTY. THIS SOFTWARE IS PROVIDED "AS IS". The + University of Southern California MAKES NO REPRESENTATIONS OR + WARRANTIES, EXPRESS OR IMPLIED. By way of example, but not + limitation, the University of Southern California MAKES NO + REPRESENTATIONS OR WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY + PARTICULAR PURPOSE. The University of Southern California shall not + be held liable for any liability nor for any direct, indirect, or + consequential damages with respect to any claim by the user or + distributor of the ksu software. + +====================================================================== + + Copyright (C) 1995 + The President and Fellows of Harvard University + + This code is derived from software contributed to Harvard by Jeremy + Rassen. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + 3. All advertising materials mentioning features or use of this + software must display the following acknowledgement: + + This product includes software developed by the University of + California, Berkeley and its contributors. + + 4. Neither the name of the University nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + +====================================================================== + + Copyright (C) 2008 by the Massachusetts Institute of Technology. + Copyright 1995 by Richard P. Basch. All Rights Reserved. + Copyright 1995 by Lehman Brothers, Inc. All Rights Reserved. + + Export of this software from the United States of America may + require a specific license from the United States Government. It + is the responsibility of any person or organization + contemplating export to obtain such a license before exporting. + + WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + distribute this software and its documentation for any purpose and + without fee is hereby granted, provided that the above copyright + notice appear in all copies and that both that copyright notice and + this permission notice appear in supporting documentation, and that + the name of Richard P. Basch, Lehman Brothers and M.I.T. not be + used in advertising or publicity pertaining to distribution of the + software without specific, written prior permission. Richard P. + Basch, Lehman Brothers and M.I.T. make no representations about the + suitability of this software for any purpose. It is provided "as + is" without express or implied warranty. + +====================================================================== + +The following notice applies to "src/lib/krb5/krb/strptime.c" and +"src/include/k5-queue.h". + + Copyright (C) 1997, 1998 The NetBSD Foundation, Inc. + All rights reserved. + + This code was contributed to The NetBSD Foundation by Klaus Klein. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + 3. All advertising materials mentioning features or use of this + software must display the following acknowledgement: + + This product includes software developed by the NetBSD + Foundation, Inc. and its contributors. + + 4. Neither the name of The NetBSD Foundation nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND + CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + DAMAGE. + +====================================================================== + +The following notice applies to Unicode library files in +"src/lib/krb5/unicode": + + Copyright 1997, 1998, 1999 Computing Research Labs, + New Mexico State University + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, copy, + modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE COMPUTING RESEARCH LAB OR + NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +====================================================================== + +The following notice applies to "src/util/support/strlcpy.c": + + Copyright (C) 1998 Todd C. Miller "Todd.Miller@courtesan.com" + + Permission to use, copy, modify, and distribute this software for + any purpose with or without fee is hereby granted, provided that + the above copyright notice and this permission notice appear in all + copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR + CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +====================================================================== + +The following notice applies to "src/util/profile/argv_parse.c" and +"src/util/profile/argv_parse.h": + + Copyright 1999 by Theodore Ts'o. + + Permission to use, copy, modify, and distribute this software for + any purpose with or without fee is hereby granted, provided that + the above copyright notice and this permission notice appear in all + copies. THE SOFTWARE IS PROVIDED "AS IS" AND THEODORE TS'O (THE + AUTHOR) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN + NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. (Isn't + it sick that the U.S. culture of lawsuit-happy lawyers requires + this kind of disclaimer?) + +====================================================================== + +The following notice applies to SWIG-generated code in +"src/util/profile/profile_tcl.c": + + Copyright (C) 1999-2000, The University of Chicago + + This file may be freely redistributed without license or fee + provided this copyright message remains intact. + +====================================================================== + +The following notice applies to portiions of "src/lib/rpc" and +"src/include/gssrpc": + + Copyright (C) 2000 The Regents of the University of Michigan. All + rights reserved. + + Copyright (C) 2000 Dug Song "dugsong@UMICH.EDU". All rights + reserved, all wrongs reversed. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + 3. Neither the name of the University nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + DAMAGE. + +Implementations of the MD4 algorithm are subject to the following +notice: + + Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. + + License to copy and use this software is granted provided that it + is identified as the "RSA Data Security, Inc. MD4 Message Digest + Algorithm" in all material mentioning or referencing this software + or this function. + + License is also granted to make and use derivative works provided + that such works are identified as "derived from the RSA Data + Security, Inc. MD4 Message Digest Algorithm" in all material + mentioning or referencing the derived work. + + RSA Data Security, Inc. makes no representations concerning either + the merchantability of this software or the suitability of this + software for any particular purpose. It is provided "as is" + without express or implied warranty of any kind. + + These notices must be retained in any copies of any part of this + documentation and/or software. + +====================================================================== + +Implementations of the MD5 algorithm are subject to the following +notice: + + Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. + + License to copy and use this software is granted provided that it + is identified as the "RSA Data Security, Inc. MD5 Message- Digest + Algorithm" in all material mentioning or referencing this software + or this function. + + License is also granted to make and use derivative works provided + that such works are identified as "derived from the RSA Data + Security, Inc. MD5 Message-Digest Algorithm" in all material + mentioning or referencing the derived work. + + RSA Data Security, Inc. makes no representations concerning either + the merchantability of this software or the suitability of this + software for any particular purpose. It is provided "as is" + without express or implied warranty of any kind. + + These notices must be retained in any copies of any part of this + documentation and/or software. + +====================================================================== + +The following notice applies to +"src/lib/crypto/crypto_tests/t_mddriver.c": + + Copyright (C) 1990-2, RSA Data Security, Inc. Created 1990. All + rights reserved. + + RSA Data Security, Inc. makes no representations concerning either + the merchantability of this software or the suitability of this + software for any particular purpose. It is provided "as is" without + express or implied warranty of any kind. + + These notices must be retained in any copies of any part of this + documentation and/or software. + +====================================================================== + +Portions of "src/lib/krb5" are subject to the following notice: + + Copyright (C) 1994 CyberSAFE Corporation. + Copyright 1990,1991,2007,2008 by the Massachusetts Institute of +Technology. + All Rights Reserved. + + Export of this software from the United States of America may + require a specific license from the United States Government. It + is the responsibility of any person or organization + contemplating export to obtain such a license before exporting. + + WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + distribute this software and its documentation for any purpose and + without fee is hereby granted, provided that the above copyright + notice appear in all copies and that both that copyright notice and + this permission notice appear in supporting documentation, and that + the name of M.I.T. not be used in advertising or publicity + pertaining to distribution of the software without specific, + written prior permission. Furthermore if you modify this software + you must label your software as modified software and not + distribute it in such a fashion that it might be confused with the + original M.I.T. software. Neither M.I.T., the Open Computing + Security Group, nor CyberSAFE Corporation make any representations + about the suitability of this software for any purpose. It is + provided "as is" without express or implied warranty. + +====================================================================== + +Portions contributed by PADL Software are subject to the following +license: + + Copyright (c) 2011, PADL Software Pty Ltd. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + 3. Neither the name of PADL Software nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + +====================================================================== + +The bundled libev source code is subject to the following license: + + All files in libev are Copyright (C)2007,2008,2009 Marc Alexander + Lehmann. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. + + Alternatively, the contents of this package may be used under the + terms of the GNU General Public License ("GPL") version 2 or any + later version, in which case the provisions of the GPL are + applicable instead of the above. If you wish to allow the use of + your version of this package only under the terms of the GPL and + not to allow others to use your version of this file under the BSD + license, indicate your decision by deleting the provisions above + and replace them with the notice and other provisions required by + the GPL in this and the other files of this package. If you do not + delete the provisions above, a recipient may use your version of + this file under either the BSD or the GPL. + +====================================================================== + +Files copied from the Intel AESNI Sample Library are subject to the +following license: + + Copyright (C) 2010, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + + * Neither the name of Intel Corporation nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. + +====================================================================== + +The following notice applies to +"src/ccapi/common/win/OldCC/autolock.hxx": + + Copyright (C) 1998 by Danilo Almeida. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. ====================================================================== ====================================================================== @@ -727,34 +2003,6 @@ See Apache License v2.0, January 2004 in the 'Standard Licenses' section. ====================================================================== ====================================================================== -ZstdSharp.Port - -MIT License - -Copyright (c) 2021 Oleg Stepanischev - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - - ====================================================================== - ====================================================================== - Standard Licenses Apache License v2.0, January 2004 diff --git a/MySQL.Data.OpenTelemetry/src/MySQL.Data.OpenTelemetry.csproj b/MySQL.Data.OpenTelemetry/src/MySQL.Data.OpenTelemetry.csproj index 1d144fae4..589d41210 100644 --- a/MySQL.Data.OpenTelemetry/src/MySQL.Data.OpenTelemetry.csproj +++ b/MySQL.Data.OpenTelemetry/src/MySQL.Data.OpenTelemetry.csproj @@ -2,28 +2,42 @@ MySql.Data.OpenTelemetry - Copyright (c) 2023, Oracle and/or its affiliates. + Copyright © 2023, 2025, Oracle and/or its affiliates. en-US - 8.2.0 - Oracle + 9.4.0 + Oracle Corporation netstandard2.0 MySql.Data.OpenTelemetry MySql.Data.OpenTelemetry MySql;.NET Connector;MySql Connector/NET;ado;ado.net;database;sql;opentelemetry;tracing;diagnostics;instrumentation - http://www.mysql.com/common/logos/logo-mysql-170x115.png + logo-mysql-170x115.png + README.md https://dev.mysql.com/downloads/ - GPL-2.0-only + GPL-2.0-only WITH Universal-FOSS-exception-1.0 true True True ..\..\ConnectorNetPublicKey.snk True - MySql.Data.OpenTelemetry + MySql.Data.OpenTelemetry + false - - ..\..\Dependencies\OpenTelemetry.Api\OpenTelemetry.Api.dll - + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MySQL.Data.OpenTelemetry/src/Properties/AssemblyInfo.cs b/MySQL.Data.OpenTelemetry/src/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..50362f2a6 --- /dev/null +++ b/MySQL.Data.OpenTelemetry/src/Properties/AssemblyInfo.cs @@ -0,0 +1,55 @@ +// Copyright © 2024, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using System; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Security; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("MySql.Data.OpenTelemetry")] +[assembly: AssemblyDescription("MySql.Data.OpenTelemetry activates telemetry capabilities when the target MySQL server is configured to support telemetry.")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Oracle Corporation")] +[assembly: AssemblyProduct("MySQL Connector/NET")] +[assembly: AssemblyCopyright("Copyright © 2023, 2025, Oracle and/or its affiliates.")] +[assembly: AssemblyTrademark("Oracle®, Java, MySQL, and NetSuite are registered trademarks of Oracle and/or its affiliates.")] +[assembly: AssemblyCulture("")] +[assembly: SecurityRules(SecurityRuleSet.Level1)] +[assembly: CLSCompliant(false)] + +// Setting ComVisible to false makes the types in this assembly not visible to COM +// components. If you need to access a type in this assembly from COM, set the ComVisible +// attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM. + +[assembly: Guid("e33f787c-329b-410a-ab72-37126450cd7b")] diff --git a/MySQL.Data.OpenTelemetry/src/Properties/VersionInfo.cs b/MySQL.Data.OpenTelemetry/src/Properties/VersionInfo.cs new file mode 100644 index 000000000..05488fcf7 --- /dev/null +++ b/MySQL.Data.OpenTelemetry/src/Properties/VersionInfo.cs @@ -0,0 +1,47 @@ +// Copyright © 2024, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using System.Reflection; +using System.Resources; + +// +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: + +[assembly: AssemblyVersion("9.4.0")] +[assembly: AssemblyInformationalVersion("9.4.0.0")] +[assembly: AssemblyFileVersion("9.4.0.0")] +[assembly: NeutralResourcesLanguage("en-US")] + diff --git a/MySQL.Data.OpenTelemetry/src/TraceProviderBuilderExtension.cs b/MySQL.Data.OpenTelemetry/src/TraceProviderBuilderExtension.cs index 3722078d4..0844c66db 100644 --- a/MySQL.Data.OpenTelemetry/src/TraceProviderBuilderExtension.cs +++ b/MySQL.Data.OpenTelemetry/src/TraceProviderBuilderExtension.cs @@ -1,3 +1,31 @@ +// Copyright © 2023, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + using System; using OpenTelemetry.Trace; @@ -9,4 +37,4 @@ public static class TracerProviderBuilderExtensions public static TracerProviderBuilder AddConnectorNet( this TracerProviderBuilder builder) => builder.AddSource("connector-net"); -} \ No newline at end of file +} diff --git a/MySQL.Data/MySql.Data.sln b/MySQL.Data/MySql.Data.sln index 5bd527a5a..3d178e566 100644 --- a/MySQL.Data/MySql.Data.sln +++ b/MySQL.Data/MySql.Data.sln @@ -9,8 +9,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MySqlX.Data.Tests", "tests\ EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MySql.Data.Tests", "tests\MySql.Data.Tests\MySql.Data.Tests.csproj", "{951A6C18-E97C-4F6A-A52C-B6FC4DECABAE}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MySqlX.Data.Performance.Console.Tests", "tests\MySqlX.Data.Performance.Console.Tests\MySqlX.Data.Performance.Console.Tests.csproj", "{9D5EDC76-5A1C-46C9-A4F2-CF57F276E537}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU diff --git a/MySQL.Data/MySql.Replication.Tests/BaseTest.cs b/MySQL.Data/MySql.Replication.Tests/BaseTest.cs index 9e1310b9c..0857d727a 100644 --- a/MySQL.Data/MySql.Replication.Tests/BaseTest.cs +++ b/MySQL.Data/MySql.Replication.Tests/BaseTest.cs @@ -1,172 +1,172 @@ -// Copyright (c) 2013, 2020, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using NUnit.Framework; -using System.Reflection; -using MySql.Data.MySqlClient; -using System.Configuration; - -namespace MySql.LoadBalancing.Tests -{ - public class BaseTest - { - protected string databaseName; - protected int sourcePort; - protected int replicaPort; - protected string server; - private MySqlConnectionStringBuilder connStringRootSource; - private MySqlConnectionStringBuilder connStringReplica; - - protected string ConnectionString - { - get - { - return string.Format("{0}database={1};", ConnectionStringNoDb, databaseName); - } - } - - protected string ConnectionStringNoDb - { - get - { - return string.Format("server={0};", server); - } - } - - protected string ConnectionStringRootSource - { - get - { - return connStringRootSource.ConnectionString; - } - } - - protected string ConnectionStringReplica - { - get - { - return connStringReplica.ConnectionString; - } - } - - - - public BaseTest() - { - Initialize(); - LoadBaseConfiguration(); - } - - protected void LoadBaseConfiguration() - { - string sourcePortString = ValueIfEmpty(ConfigurationManager.AppSettings["sourcePort"], "3305"); - string replicaPortString = ValueIfEmpty(ConfigurationManager.AppSettings["replicaPort"], "3307"); - server = ValueIfEmpty(ConfigurationManager.AppSettings["server"], "Group1"); - - sourcePort = int.Parse(sourcePortString); - replicaPort = int.Parse(replicaPortString); - - connStringRootSource = new MySqlConnectionStringBuilder(); - connStringRootSource.UserID = ValueIfEmpty(ConfigurationManager.AppSettings["rootuser"], "root"); - connStringRootSource.Password = ValueIfEmpty(ConfigurationManager.AppSettings["rootpassword"], string.Empty); - connStringRootSource.Server = ValueIfEmpty(ConfigurationManager.AppSettings["host"], "localhost"); - connStringRootSource.Port = (uint)sourcePort; - - connStringReplica = new MySqlConnectionStringBuilder(); - connStringReplica.UserID = ValueIfEmpty(ConfigurationManager.AppSettings["replicaUser"], "lbuser"); - connStringReplica.Password = ValueIfEmpty(ConfigurationManager.AppSettings["replicaPassword"], "lbpass"); - connStringReplica.Server = ValueIfEmpty(ConfigurationManager.AppSettings["replicaHost"], "localhost"); - connStringReplica.Port = (uint)replicaPort; - connStringReplica.Database = databaseName; - } - - protected virtual void Initialize() - { - // we don't use FileVersion because it's not available - // on the compact framework - string fullname = Assembly.GetExecutingAssembly().FullName; - string[] parts = fullname.Split(new char[] { '=' }); - string[] versionParts = parts[1].Split(new char[] { '.' }); - databaseName = String.Format("dblb{0}{1}", versionParts[0], versionParts[1]); - } - - [SetUp] - public void Setup() - { - using (MySqlConnection connection = new MySqlConnection(ConnectionStringRootSource)) - { - connection.Open(); - MySqlScript script = new MySqlScript(connection); - - // Sets users - script.Query = Properties.Resources._01_Startup_root_script; - script.Execute(); - - // Sets database objects - script.Query = string.Format(Properties.Resources._02_Startup_script, databaseName); - script.Execute(); - } - } - - //[TearDown] - public void Teardown() - { - using (MySqlConnection connection = new MySqlConnection(ConnectionStringRootSource)) - { - connection.Open(); - MySqlCommand cmd = new MySqlCommand(string.Empty, connection); - - cmd.CommandText = "DROP USER lbuser@localhost;"; - cmd.CommandText += "DROP DATABASE IF EXISTS " + databaseName; - cmd.ExecuteNonQuery(); - } - } - - protected MySqlDataReader ExecuteQuery(MySqlConnection connection, string query) - { - MySqlCommand cmd = new MySqlCommand(query, connection); - return cmd.ExecuteReader(); - } - - protected int ExecuteNonQuery(MySqlConnection connection, string query) - { - MySqlCommand cmd = new MySqlCommand(query, connection); - return cmd.ExecuteNonQuery(); - } - - private string ValueIfEmpty(string value, string valueIfEmtpy) - { - if (string.IsNullOrEmpty(value)) return valueIfEmtpy; - return value; - } - } -} +// Copyright © 2013, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using NUnit.Framework; +using System.Reflection; +using MySql.Data.MySqlClient; +using System.Configuration; + +namespace MySql.LoadBalancing.Tests +{ + public class BaseTest + { + protected string databaseName; + protected int sourcePort; + protected int replicaPort; + protected string server; + private MySqlConnectionStringBuilder connStringRootSource; + private MySqlConnectionStringBuilder connStringReplica; + + protected string ConnectionString + { + get + { + return string.Format("{0}database={1};", ConnectionStringNoDb, databaseName); + } + } + + protected string ConnectionStringNoDb + { + get + { + return string.Format("server={0};", server); + } + } + + protected string ConnectionStringRootSource + { + get + { + return connStringRootSource.ConnectionString; + } + } + + protected string ConnectionStringReplica + { + get + { + return connStringReplica.ConnectionString; + } + } + + + + public BaseTest() + { + Initialize(); + LoadBaseConfiguration(); + } + + protected void LoadBaseConfiguration() + { + string sourcePortString = ValueIfEmpty(ConfigurationManager.AppSettings["sourcePort"], "3305"); + string replicaPortString = ValueIfEmpty(ConfigurationManager.AppSettings["replicaPort"], "3307"); + server = ValueIfEmpty(ConfigurationManager.AppSettings["server"], "Group1"); + + sourcePort = int.Parse(sourcePortString); + replicaPort = int.Parse(replicaPortString); + + connStringRootSource = new MySqlConnectionStringBuilder(); + connStringRootSource.UserID = ValueIfEmpty(ConfigurationManager.AppSettings["rootuser"], "root"); + connStringRootSource.Password = ValueIfEmpty(ConfigurationManager.AppSettings["rootpassword"], string.Empty); + connStringRootSource.Server = ValueIfEmpty(ConfigurationManager.AppSettings["host"], "localhost"); + connStringRootSource.Port = (uint)sourcePort; + + connStringReplica = new MySqlConnectionStringBuilder(); + connStringReplica.UserID = ValueIfEmpty(ConfigurationManager.AppSettings["replicaUser"], "lbuser"); + connStringReplica.Password = ValueIfEmpty(ConfigurationManager.AppSettings["replicaPassword"], "lbpass"); + connStringReplica.Server = ValueIfEmpty(ConfigurationManager.AppSettings["replicaHost"], "localhost"); + connStringReplica.Port = (uint)replicaPort; + connStringReplica.Database = databaseName; + } + + protected virtual void Initialize() + { + // we don't use FileVersion because it's not available + // on the compact framework + string fullname = Assembly.GetExecutingAssembly().FullName; + string[] parts = fullname.Split(new char[] { '=' }); + string[] versionParts = parts[1].Split(new char[] { '.' }); + databaseName = String.Format("dblb{0}{1}", versionParts[0], versionParts[1]); + } + + [SetUp] + public void Setup() + { + using (MySqlConnection connection = new MySqlConnection(ConnectionStringRootSource)) + { + connection.Open(); + MySqlScript script = new MySqlScript(connection); + + // Sets users + script.Query = Properties.Resources._01_Startup_root_script; + script.Execute(); + + // Sets database objects + script.Query = string.Format(Properties.Resources._02_Startup_script, databaseName); + script.Execute(); + } + } + + //[TearDown] + public void Teardown() + { + using (MySqlConnection connection = new MySqlConnection(ConnectionStringRootSource)) + { + connection.Open(); + MySqlCommand cmd = new MySqlCommand(string.Empty, connection); + + cmd.CommandText = "DROP USER lbuser@localhost;"; + cmd.CommandText += "DROP DATABASE IF EXISTS " + databaseName; + cmd.ExecuteNonQuery(); + } + } + + protected MySqlDataReader ExecuteQuery(MySqlConnection connection, string query) + { + MySqlCommand cmd = new MySqlCommand(query, connection); + return cmd.ExecuteReader(); + } + + protected int ExecuteNonQuery(MySqlConnection connection, string query) + { + MySqlCommand cmd = new MySqlCommand(query, connection); + return cmd.ExecuteNonQuery(); + } + + private string ValueIfEmpty(string value, string valueIfEmtpy) + { + if (string.IsNullOrEmpty(value)) return valueIfEmtpy; + return value; + } + } +} diff --git a/MySQL.Data/MySql.Replication.Tests/Properties/AssemblyInfo.cs b/MySQL.Data/MySql.Replication.Tests/Properties/AssemblyInfo.cs index b7762a94b..cc810761b 100644 --- a/MySQL.Data/MySql.Replication.Tests/Properties/AssemblyInfo.cs +++ b/MySQL.Data/MySql.Replication.Tests/Properties/AssemblyInfo.cs @@ -1,55 +1,55 @@ -// Copyright © 2013, 2019, Oracle and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - - -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("MySql.LoadBalancing.Tests")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Oracle Corporation")] -[assembly: AssemblyProduct("MySql.LoadBalancing.Tests")] -[assembly: AssemblyCopyright("Copyright © 2013, 2019, Oracle and/or its affiliates. All rights reserved.")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("02681727-f306-4923-8c16-717d6f1716ce")] - -[assembly: AssemblyDelaySign(true)] -[assembly: AssemblyKeyFileAttribute(@"..\..\ConnectorNetPublicKey.snk")] +// Copyright © 2013, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("MySql.LoadBalancing.Tests")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Oracle Corporation")] +[assembly: AssemblyProduct("MySql.LoadBalancing.Tests")] +[assembly: AssemblyCopyright("Copyright © 2013, 2025, Oracle and/or its affiliates.")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("02681727-f306-4923-8c16-717d6f1716ce")] + +[assembly: AssemblyDelaySign(true)] +[assembly: AssemblyKeyFileAttribute(@"..\..\ConnectorNetPublicKey.snk")] diff --git a/MySQL.Data/MySql.Replication.Tests/Properties/Resources.Designer.cs b/MySQL.Data/MySql.Replication.Tests/Properties/Resources.Designer.cs index ff6244c10..72af81f13 100644 --- a/MySQL.Data/MySql.Replication.Tests/Properties/Resources.Designer.cs +++ b/MySQL.Data/MySql.Replication.Tests/Properties/Resources.Designer.cs @@ -1,112 +1,112 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace MySql.Replication.Tests.Properties { - using System; - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Resources { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Resources() { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("MySql.Replication.Tests.Properties.Resources", typeof(Resources).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - /// - /// Looks up a localized string similar to -- Users - /// - ///GRANT ALL ON *.* TO lbuser@localhost IDENTIFIED BY 'lbpass'; - /// - ///REVOKE SUPER ON *.* FROM lbuser@localhost; - ///. - /// - internal static string _01_Startup_root_script { - get { - return ResourceManager.GetString("_01_Startup_root_script", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to DROP DATABASE IF EXISTS {0}; - /// - /// - ///CREATE DATABASE {0}; - ///USE {0}; - /// - ///CREATE TABLE items ( - /// item_id int primary key auto_increment, - /// description varchar(50) not null, - /// brand varchar(50), - /// price float not null, - /// quantity int not null - ///); - /// - ///CREATE TABLE stores( - /// store_id int primary key auto_increment, - /// name varchar(50) not null, - /// address varchar(100) - ///); - /// - ///CREATE TABLE employees( - /// employee_id int primary key auto_increment, - /// name varchar(50) not null, - /// store_id int, - /// active bool - ///); - /// [rest of string was truncated]";. - /// - internal static string _02_Startup_script { - get { - return ResourceManager.GetString("_02_Startup_script", resourceCulture); - } - } - } -} +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace MySql.Replication.Tests.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("MySql.Replication.Tests.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to -- Users + /// + ///GRANT ALL ON *.* TO lbuser@localhost IDENTIFIED BY 'lbpass'; + /// + ///REVOKE SUPER ON *.* FROM lbuser@localhost; + ///. + /// + internal static string _01_Startup_root_script { + get { + return ResourceManager.GetString("_01_Startup_root_script", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DROP DATABASE IF EXISTS {0}; + /// + /// + ///CREATE DATABASE {0}; + ///USE {0}; + /// + ///CREATE TABLE items ( + /// item_id int primary key auto_increment, + /// description varchar(50) not null, + /// brand varchar(50), + /// price float not null, + /// quantity int not null + ///); + /// + ///CREATE TABLE stores( + /// store_id int primary key auto_increment, + /// name varchar(50) not null, + /// address varchar(100) + ///); + /// + ///CREATE TABLE employees( + /// employee_id int primary key auto_increment, + /// name varchar(50) not null, + /// store_id int, + /// active bool + ///); + /// [rest of string was truncated]";. + /// + internal static string _02_Startup_script { + get { + return ResourceManager.GetString("_02_Startup_script", resourceCulture); + } + } + } +} diff --git a/MySQL.Data/MySql.Replication.Tests/ReplicationTest.cs b/MySQL.Data/MySql.Replication.Tests/ReplicationTest.cs index d3dea4de5..b6f53f857 100644 --- a/MySQL.Data/MySql.Replication.Tests/ReplicationTest.cs +++ b/MySQL.Data/MySql.Replication.Tests/ReplicationTest.cs @@ -1,246 +1,246 @@ -// Copyright (c) 2013, 2020, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using MySql.Data.MySqlClient; -using Xunit; -using System.Diagnostics; -using MySql.Data; - -namespace MySql.Replication.Tests -{ - public class ReplicationTest : IUseFixture, IDisposable - { - - private SetUp st; - - public void SetFixture(SetUp data) - { - st = data; - } - - public void Dispose() - { - MySqlConnectionStringBuilder connString = new MySqlConnectionStringBuilder(st.ConnectionStringRootSource); - connString.Database = st.databaseName; - using (MySqlConnection conn = new MySqlConnection(connString.ToString())) - { - conn.Open(); - st.ExecuteNonQuery(conn, "DELETE FROM orders"); - st.ExecuteNonQuery(conn, "DELETE FROM order_details"); - } - } - - /// - /// Validates that the replica is readonly - /// - [Fact] - public void _ReplicaAsReadOnly() - { - using (MySqlConnection conn = new MySqlConnection(st.ConnectionStringReplica)) - { - conn.Open(); - MySqlException ex = Assert.Throws(() => st.ExecuteNonQuery(conn, "INSERT INTO orders VALUES(null, 1, 'James')")); - // Error 1290: The MySQL server is running with the --read-only option so - // it cannot execute this statement - Assert.Equal(1290, ex.Number); - } - } - - /// - /// Validates that each request for a connection is switched between the - /// source and replica; also validates that all non-read statements are sent - /// to the source - /// - [Fact] - public void RoundRobinWritting() - { - using (MySqlConnection conn = new MySqlConnection(st.ConnectionString)) - { - conn.Open(); - - st.ExecuteNonQuery(conn, "INSERT INTO orders VALUES(null, 1, 'James')"); - st.ExecuteNonQuery(conn, "INSERT INTO order_details VALUES(1, 1, 1, 0, 0)"); - st.ExecuteNonQuery(conn, "INSERT INTO order_details VALUES(1, 2, 1, 0, 0)"); - - Assert.Equal(st.replicaPort, GetPort(conn)); - Assert.Equal(st.sourcePort, GetPort(conn)); - Assert.Equal(st.replicaPort, GetPort(conn)); - Assert.Equal(st.sourcePort, GetPort(conn)); - - st.ExecuteNonQuery(conn, "INSERT INTO order_details VALUES(1, 3, 1, 0, 0)"); - } - } - - /// - /// Test for a source connection failure - /// - [Fact] - public void RoundRobinReadOnly() - { - using (MySqlConnection conn = new MySqlConnection("server=Group2;")) - { - conn.Open(); - - - MySqlException ex = Assert.Throws(() => st.ExecuteNonQuery(conn, "INSERT INTO orders VALUES(null, 1, 'James')")); - - Assert.Equal(Resources.Replication_NoAvailableServer, ex.Message); - - int currentPort = GetPort(conn); - Assert.True(currentPort != (currentPort = GetPort(conn)), "1st try"); - Assert.True(currentPort != (currentPort = GetPort(conn)), "2nd try"); - Assert.True(currentPort != (currentPort = GetPort(conn)), "3rd try"); - Assert.True(currentPort != (currentPort = GetPort(conn)), "4th try"); - } - } - - /// - /// Validates that data inserted in source is replicated into replica - /// - [Fact] - public void RoundRobinValidateReplicaData() - { - using (MySqlConnection conn = new MySqlConnection(st.ConnectionString)) - { - conn.Open(); - - st.ExecuteNonQuery(conn, "INSERT INTO orders VALUES(null, 2, 'Bruce')"); - } - - // Waits for replication on replica - System.Threading.Thread.Sleep(3000); - - // validates data on replica - using (MySqlConnection replicaConn = new MySqlConnection(st.ConnectionStringReplica)) - { - replicaConn.Open(); - MySqlDataReader dr = st.ExecuteQuery(replicaConn, "SELECT * FROM orders"); - Assert.True(dr.Read()); - Assert.Equal(2, dr.GetValue(1)); - Assert.Equal("Bruce", dr.GetValue(2)); - } - } - - [Fact] - public void ValidateLogging() - { - MySqlTrace.Listeners.Clear(); - MySqlTrace.Switch.Level = SourceLevels.All; - MySql.Data.MySqlClient.Tests.GenericListener listener = new MySql.Data.MySqlClient.Tests.GenericListener(); - MySqlTrace.Listeners.Add(listener); - using (MySqlConnection conn = new MySqlConnection(st.ConnectionString )) - { - conn.Open(); - - st.ExecuteNonQuery(conn, "INSERT INTO orders VALUES(null, 2, 'Bruce')"); - st.ExecuteNonQuery(conn, "INSERT INTO orders VALUES(null, 1, 'James')"); - st.ExecuteNonQuery(conn, "INSERT INTO order_details VALUES(1, 1, 1, 0, 0)"); - st.ExecuteNonQuery(conn, "INSERT INTO order_details VALUES(1, 2, 1, 0, 0)"); - } - - // Waits for replication on replica - System.Threading.Thread.Sleep(3000); - - // validates data on replica - using (MySqlConnection replicaConn = new MySqlConnection(st.ConnectionStringReplica)) - { - replicaConn.Open(); - MySqlDataReader dr = st.ExecuteQuery(replicaConn, "SELECT * FROM orders"); - Assert.True(dr.Read()); - Assert.Equal(2, dr.GetValue(1)); - Assert.Equal("Bruce", dr.GetValue(2)); - } - Debug.WriteLine("Start of tracing"); - foreach (string s in listener.Strings) - { - Debug.WriteLine(s); - } - Debug.WriteLine("End of tracing"); - } - - /// - /// When using transactions, load balancing must lock on the current server. - /// - [Fact] - public void ValidateTransactions() - { - MySqlTrace.Listeners.Clear(); - MySqlTrace.Switch.Level = SourceLevels.All; - MySql.Data.MySqlClient.Tests.GenericListener listener = new MySql.Data.MySqlClient.Tests.GenericListener(); - MySqlTrace.Listeners.Add(listener); - using (MySqlConnection conn = new MySqlConnection(st.ConnectionString)) - { - conn.Open(); - MySqlTransaction tx = conn.BeginTransaction(); - st.ExecuteNonQuery(conn, "INSERT INTO orders VALUES(null, 2, 'Bruce')"); - st.ExecuteNonQuery(conn, "INSERT INTO orders VALUES(null, 1, 'James')"); - st.ExecuteNonQuery(conn, "INSERT INTO order_details VALUES(1, 1, 1, 0, 0)"); - st.ExecuteNonQuery(conn, "INSERT INTO order_details VALUES(1, 2, 1, 0, 0)"); - tx.Commit(); - } - - // Waits for replication on replica - System.Threading.Thread.Sleep(3000); - - // validates data on replica - using (MySqlConnection replicaConn = new MySqlConnection(st.ConnectionStringReplica)) - { - replicaConn.Open(); - MySqlDataReader dr = st.ExecuteQuery(replicaConn, "SELECT * FROM orders"); - Assert.True(dr.Read()); - Assert.Equal(2, dr.GetValue(1)); - Assert.Equal("Bruce", dr.GetValue(2)); - } - Debug.WriteLine("Start of tracing"); - foreach (string s in listener.Strings) - { - Debug.WriteLine(s); - } - Debug.WriteLine("End of tracing"); - } - - #region Private methods - - private int GetPort(MySqlConnection connection) - { - MySqlDataReader dr = st.ExecuteQuery(connection, "SHOW VARIABLES LIKE 'port';"); - - dr.Read(); - int port = dr.GetInt32(1); - dr.Close(); - - return port; - } - - #endregion - } -} +// Copyright © 2013, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using MySql.Data.MySqlClient; +using Xunit; +using System.Diagnostics; +using MySql.Data; + +namespace MySql.Replication.Tests +{ + public class ReplicationTest : IUseFixture, IDisposable + { + + private SetUp st; + + public void SetFixture(SetUp data) + { + st = data; + } + + public void Dispose() + { + MySqlConnectionStringBuilder connString = new MySqlConnectionStringBuilder(st.ConnectionStringRootSource); + connString.Database = st.databaseName; + using (MySqlConnection conn = new MySqlConnection(connString.ToString())) + { + conn.Open(); + st.ExecuteNonQuery(conn, "DELETE FROM orders"); + st.ExecuteNonQuery(conn, "DELETE FROM order_details"); + } + } + + /// + /// Validates that the replica is readonly + /// + [Fact] + public void _ReplicaAsReadOnly() + { + using (MySqlConnection conn = new MySqlConnection(st.ConnectionStringReplica)) + { + conn.Open(); + MySqlException ex = Assert.Throws(() => st.ExecuteNonQuery(conn, "INSERT INTO orders VALUES(null, 1, 'James')")); + // Error 1290: The MySQL server is running with the --read-only option so + // it cannot execute this statement + Assert.Equal(1290, ex.Number); + } + } + + /// + /// Validates that each request for a connection is switched between the + /// source and replica; also validates that all non-read statements are sent + /// to the source + /// + [Fact] + public void RoundRobinWritting() + { + using (MySqlConnection conn = new MySqlConnection(st.ConnectionString)) + { + conn.Open(); + + st.ExecuteNonQuery(conn, "INSERT INTO orders VALUES(null, 1, 'James')"); + st.ExecuteNonQuery(conn, "INSERT INTO order_details VALUES(1, 1, 1, 0, 0)"); + st.ExecuteNonQuery(conn, "INSERT INTO order_details VALUES(1, 2, 1, 0, 0)"); + + Assert.Equal(st.replicaPort, GetPort(conn)); + Assert.Equal(st.sourcePort, GetPort(conn)); + Assert.Equal(st.replicaPort, GetPort(conn)); + Assert.Equal(st.sourcePort, GetPort(conn)); + + st.ExecuteNonQuery(conn, "INSERT INTO order_details VALUES(1, 3, 1, 0, 0)"); + } + } + + /// + /// Test for a source connection failure + /// + [Fact] + public void RoundRobinReadOnly() + { + using (MySqlConnection conn = new MySqlConnection("server=Group2;")) + { + conn.Open(); + + + MySqlException ex = Assert.Throws(() => st.ExecuteNonQuery(conn, "INSERT INTO orders VALUES(null, 1, 'James')")); + + Assert.Equal(Resources.Replication_NoAvailableServer, ex.Message); + + int currentPort = GetPort(conn); + Assert.True(currentPort != (currentPort = GetPort(conn)), "1st try"); + Assert.True(currentPort != (currentPort = GetPort(conn)), "2nd try"); + Assert.True(currentPort != (currentPort = GetPort(conn)), "3rd try"); + Assert.True(currentPort != (currentPort = GetPort(conn)), "4th try"); + } + } + + /// + /// Validates that data inserted in source is replicated into replica + /// + [Fact] + public void RoundRobinValidateReplicaData() + { + using (MySqlConnection conn = new MySqlConnection(st.ConnectionString)) + { + conn.Open(); + + st.ExecuteNonQuery(conn, "INSERT INTO orders VALUES(null, 2, 'Bruce')"); + } + + // Waits for replication on replica + System.Threading.Thread.Sleep(3000); + + // validates data on replica + using (MySqlConnection replicaConn = new MySqlConnection(st.ConnectionStringReplica)) + { + replicaConn.Open(); + MySqlDataReader dr = st.ExecuteQuery(replicaConn, "SELECT * FROM orders"); + Assert.True(dr.Read()); + Assert.Equal(2, dr.GetValue(1)); + Assert.Equal("Bruce", dr.GetValue(2)); + } + } + + [Fact] + public void ValidateLogging() + { + MySqlTrace.Listeners.Clear(); + MySqlTrace.Switch.Level = SourceLevels.All; + MySql.Data.MySqlClient.Tests.GenericListener listener = new MySql.Data.MySqlClient.Tests.GenericListener(); + MySqlTrace.Listeners.Add(listener); + using (MySqlConnection conn = new MySqlConnection(st.ConnectionString )) + { + conn.Open(); + + st.ExecuteNonQuery(conn, "INSERT INTO orders VALUES(null, 2, 'Bruce')"); + st.ExecuteNonQuery(conn, "INSERT INTO orders VALUES(null, 1, 'James')"); + st.ExecuteNonQuery(conn, "INSERT INTO order_details VALUES(1, 1, 1, 0, 0)"); + st.ExecuteNonQuery(conn, "INSERT INTO order_details VALUES(1, 2, 1, 0, 0)"); + } + + // Waits for replication on replica + System.Threading.Thread.Sleep(3000); + + // validates data on replica + using (MySqlConnection replicaConn = new MySqlConnection(st.ConnectionStringReplica)) + { + replicaConn.Open(); + MySqlDataReader dr = st.ExecuteQuery(replicaConn, "SELECT * FROM orders"); + Assert.True(dr.Read()); + Assert.Equal(2, dr.GetValue(1)); + Assert.Equal("Bruce", dr.GetValue(2)); + } + Debug.WriteLine("Start of tracing"); + foreach (string s in listener.Strings) + { + Debug.WriteLine(s); + } + Debug.WriteLine("End of tracing"); + } + + /// + /// When using transactions, load balancing must lock on the current server. + /// + [Fact] + public void ValidateTransactions() + { + MySqlTrace.Listeners.Clear(); + MySqlTrace.Switch.Level = SourceLevels.All; + MySql.Data.MySqlClient.Tests.GenericListener listener = new MySql.Data.MySqlClient.Tests.GenericListener(); + MySqlTrace.Listeners.Add(listener); + using (MySqlConnection conn = new MySqlConnection(st.ConnectionString)) + { + conn.Open(); + MySqlTransaction tx = conn.BeginTransaction(); + st.ExecuteNonQuery(conn, "INSERT INTO orders VALUES(null, 2, 'Bruce')"); + st.ExecuteNonQuery(conn, "INSERT INTO orders VALUES(null, 1, 'James')"); + st.ExecuteNonQuery(conn, "INSERT INTO order_details VALUES(1, 1, 1, 0, 0)"); + st.ExecuteNonQuery(conn, "INSERT INTO order_details VALUES(1, 2, 1, 0, 0)"); + tx.Commit(); + } + + // Waits for replication on replica + System.Threading.Thread.Sleep(3000); + + // validates data on replica + using (MySqlConnection replicaConn = new MySqlConnection(st.ConnectionStringReplica)) + { + replicaConn.Open(); + MySqlDataReader dr = st.ExecuteQuery(replicaConn, "SELECT * FROM orders"); + Assert.True(dr.Read()); + Assert.Equal(2, dr.GetValue(1)); + Assert.Equal("Bruce", dr.GetValue(2)); + } + Debug.WriteLine("Start of tracing"); + foreach (string s in listener.Strings) + { + Debug.WriteLine(s); + } + Debug.WriteLine("End of tracing"); + } + + #region Private methods + + private int GetPort(MySqlConnection connection) + { + MySqlDataReader dr = st.ExecuteQuery(connection, "SHOW VARIABLES LIKE 'port';"); + + dr.Read(); + int port = dr.GetInt32(1); + dr.Close(); + + return port; + } + + #endregion + } +} diff --git a/MySQL.Data/MySql.Replication.Tests/SetUp.cs b/MySQL.Data/MySql.Replication.Tests/SetUp.cs index bef3bd551..88edd19b7 100644 --- a/MySQL.Data/MySql.Replication.Tests/SetUp.cs +++ b/MySQL.Data/MySql.Replication.Tests/SetUp.cs @@ -1,158 +1,158 @@ -// Copyright (c) 2013, 2020, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Reflection; -using MySql.Data.MySqlClient; -using System.Configuration; - -namespace MySql.Replication.Tests -{ - public class SetUp : IDisposable - { - protected internal string databaseName; - protected internal int sourcePort; - protected internal int replicaPort; - protected internal string groupName; - private MySqlConnectionStringBuilder connStringRootSource; - private MySqlConnectionStringBuilder connStringReplica; - - protected internal string ConnectionString - { - get - { - return string.Format("{0}database={1};", ConnectionStringNoDb, databaseName); - } - } - - protected internal string ConnectionStringNoDb - { - get - { - return string.Format("server={0};", groupName); - } - } - - protected internal string ConnectionStringRootSource - { - get - { - return connStringRootSource.ConnectionString; - } - } - - protected internal string ConnectionStringReplica - { - get - { - return connStringReplica.ConnectionString; - } - } - - public SetUp() - { - Initialize(); - LoadBaseConfiguration(); - - using (MySqlConnection connection = new MySqlConnection(ConnectionStringRootSource)) - { - connection.Open(); - MySqlScript script = new MySqlScript(connection); - - // Sets users - script.Query = Properties.Resources._01_Startup_root_script; - script.Execute(); - - // Sets database objects - script.Query = string.Format(Properties.Resources._02_Startup_script, databaseName); - script.Execute(); - } - } - - protected internal void LoadBaseConfiguration() - { - ReplicationServerGroupConfigurationElement group1 = (ConfigurationManager.GetSection("MySQL") as MySqlConfiguration).Replication.ServerGroups.ToArray()[0]; - ReplicationServerConfigurationElement sourceConfiguration = group1.Servers.ToArray()[0]; - ReplicationServerConfigurationElement replicaConfiguration = group1.Servers.ToArray()[1]; - - groupName = group1.Name; - - connStringRootSource = new MySqlConnectionStringBuilder(sourceConfiguration.ConnectionString); - sourcePort = (int)connStringRootSource.Port; - - connStringReplica = new MySqlConnectionStringBuilder(replicaConfiguration.ConnectionString); - replicaPort = (int)connStringReplica.Port; - connStringReplica.Database = databaseName; - } - - protected virtual void Initialize() - { - // we don't use FileVersion because it's not available - // on the compact framework - string fullname = Assembly.GetExecutingAssembly().FullName; - string[] parts = fullname.Split(new char[] { '=' }); - string[] versionParts = parts[1].Split(new char[] { '.' }); - databaseName = String.Format("dblb{0}{1}", versionParts[0], versionParts[1]); - } - - - public void Dispose() - { - using (MySqlConnection connection = new MySqlConnection(ConnectionStringRootSource)) - { - connection.Open(); - MySqlCommand cmd = new MySqlCommand(string.Empty, connection); - - cmd.CommandText = "DROP USER lbuser@localhost;"; - cmd.CommandText += "DROP DATABASE IF EXISTS " + databaseName; - cmd.ExecuteNonQuery(); - } - } - - protected internal MySqlDataReader ExecuteQuery(MySqlConnection connection, string query) - { - MySqlCommand cmd = new MySqlCommand(query, connection); - return cmd.ExecuteReader(); - } - - protected internal int ExecuteNonQuery(MySqlConnection connection, string query) - { - MySqlCommand cmd = new MySqlCommand(query, connection); - return cmd.ExecuteNonQuery(); - } - - private string ValueIfEmpty(string value, string valueIfEmtpy) - { - if (string.IsNullOrEmpty(value)) return valueIfEmtpy; - return value; - } - } -} +// Copyright © 2013, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Reflection; +using MySql.Data.MySqlClient; +using System.Configuration; + +namespace MySql.Replication.Tests +{ + public class SetUp : IDisposable + { + protected internal string databaseName; + protected internal int sourcePort; + protected internal int replicaPort; + protected internal string groupName; + private MySqlConnectionStringBuilder connStringRootSource; + private MySqlConnectionStringBuilder connStringReplica; + + protected internal string ConnectionString + { + get + { + return string.Format("{0}database={1};", ConnectionStringNoDb, databaseName); + } + } + + protected internal string ConnectionStringNoDb + { + get + { + return string.Format("server={0};", groupName); + } + } + + protected internal string ConnectionStringRootSource + { + get + { + return connStringRootSource.ConnectionString; + } + } + + protected internal string ConnectionStringReplica + { + get + { + return connStringReplica.ConnectionString; + } + } + + public SetUp() + { + Initialize(); + LoadBaseConfiguration(); + + using (MySqlConnection connection = new MySqlConnection(ConnectionStringRootSource)) + { + connection.Open(); + MySqlScript script = new MySqlScript(connection); + + // Sets users + script.Query = Properties.Resources._01_Startup_root_script; + script.Execute(); + + // Sets database objects + script.Query = string.Format(Properties.Resources._02_Startup_script, databaseName); + script.Execute(); + } + } + + protected internal void LoadBaseConfiguration() + { + ReplicationServerGroupConfigurationElement group1 = (ConfigurationManager.GetSection("MySQL") as MySqlConfiguration).Replication.ServerGroups.ToArray()[0]; + ReplicationServerConfigurationElement sourceConfiguration = group1.Servers.ToArray()[0]; + ReplicationServerConfigurationElement replicaConfiguration = group1.Servers.ToArray()[1]; + + groupName = group1.Name; + + connStringRootSource = new MySqlConnectionStringBuilder(sourceConfiguration.ConnectionString); + sourcePort = (int)connStringRootSource.Port; + + connStringReplica = new MySqlConnectionStringBuilder(replicaConfiguration.ConnectionString); + replicaPort = (int)connStringReplica.Port; + connStringReplica.Database = databaseName; + } + + protected virtual void Initialize() + { + // we don't use FileVersion because it's not available + // on the compact framework + string fullname = Assembly.GetExecutingAssembly().FullName; + string[] parts = fullname.Split(new char[] { '=' }); + string[] versionParts = parts[1].Split(new char[] { '.' }); + databaseName = String.Format("dblb{0}{1}", versionParts[0], versionParts[1]); + } + + + public void Dispose() + { + using (MySqlConnection connection = new MySqlConnection(ConnectionStringRootSource)) + { + connection.Open(); + MySqlCommand cmd = new MySqlCommand(string.Empty, connection); + + cmd.CommandText = "DROP USER lbuser@localhost;"; + cmd.CommandText += "DROP DATABASE IF EXISTS " + databaseName; + cmd.ExecuteNonQuery(); + } + } + + protected internal MySqlDataReader ExecuteQuery(MySqlConnection connection, string query) + { + MySqlCommand cmd = new MySqlCommand(query, connection); + return cmd.ExecuteReader(); + } + + protected internal int ExecuteNonQuery(MySqlConnection connection, string query) + { + MySqlCommand cmd = new MySqlCommand(query, connection); + return cmd.ExecuteNonQuery(); + } + + private string ValueIfEmpty(string value, string valueIfEmtpy) + { + if (string.IsNullOrEmpty(value)) return valueIfEmtpy; + return value; + } + } +} diff --git a/MySQL.Data/src/Authentication/AuthenticationManager.cs b/MySQL.Data/src/Authentication/AuthenticationManager.cs index 9d4099359..92435f652 100644 --- a/MySQL.Data/src/Authentication/AuthenticationManager.cs +++ b/MySQL.Data/src/Authentication/AuthenticationManager.cs @@ -1,97 +1,97 @@ -// Copyright (c) 2012, 2022, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using System; -using System.Collections.Generic; -using System.Reflection; - -namespace MySql.Data.MySqlClient.Authentication -{ - internal partial class AuthenticationPluginManager - { - private static readonly Dictionary Plugins = new Dictionary(); - - static partial void AuthenticationManagerCtorConfiguration(); - - static AuthenticationPluginManager() - { - Plugins["mysql_native_password"] = new PluginInfo("MySql.Data.MySqlClient.Authentication.MySqlNativePasswordPlugin"); - Plugins["sha256_password"] = new PluginInfo("MySql.Data.MySqlClient.Authentication.Sha256AuthenticationPlugin"); - Plugins["authentication_windows_client"] = new PluginInfo("MySql.Data.MySqlClient.Authentication.MySqlWindowsAuthenticationPlugin"); - Plugins["caching_sha2_password"] = new PluginInfo("MySql.Data.MySqlClient.Authentication.CachingSha2AuthenticationPlugin"); - Plugins["authentication_ldap_sasl_client"] = new PluginInfo("MySql.Data.MySqlClient.Authentication.MySqlSASLPlugin"); - Plugins["mysql_clear_password"] = new PluginInfo("MySql.Data.MySqlClient.Authentication.MySqlClearPasswordPlugin"); - Plugins["authentication_kerberos_client"] = new PluginInfo("MySql.Data.MySqlClient.Authentication.KerberosAuthenticationPlugin"); - Plugins["authentication_oci_client"] = new PluginInfo("MySql.Data.MySqlClient.Authentication.OciAuthenticationPlugin"); - Plugins["authentication_fido_client"] = new PluginInfo("MySql.Data.MySqlClient.Authentication.FidoAuthenticationPlugin"); - Plugins["authentication_webauthn_client"] = new PluginInfo("MySql.Data.MySqlClient.Authentication.WebAuthnAuthenticationPlugin"); - - AuthenticationManagerCtorConfiguration(); - } - - public static MySqlAuthenticationPlugin GetPlugin(string method) - { - ValidateAuthenticationPlugin(method); - return CreatePlugin(method); - } - - private static MySqlAuthenticationPlugin CreatePlugin(string method) - { - PluginInfo pi = Plugins[method]; - - try - { - Type t = Type.GetType(pi.Type); - MySqlAuthenticationPlugin o = (MySqlAuthenticationPlugin)Activator.CreateInstance(t); - return o; - } - catch (Exception e) - { - throw new MySqlException(String.Format(Resources.UnableToCreateAuthPlugin, method), e); - } - } - - public static void ValidateAuthenticationPlugin(string method) - { - if (!Plugins.ContainsKey(method)) - throw new MySqlException(String.Format(Resources.AuthenticationMethodNotSupported, method)); - } - } - - struct PluginInfo - { - public string Type; - public Assembly Assembly; - - public PluginInfo(string type) - { - Type = type; - Assembly = null; - } - } -} +// Copyright © 2012, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using System; +using System.Collections.Generic; +using System.Reflection; + +namespace MySql.Data.MySqlClient.Authentication +{ + internal partial class AuthenticationPluginManager + { + private static readonly Dictionary Plugins = new Dictionary(); + + static partial void AuthenticationManagerCtorConfiguration(); + + static AuthenticationPluginManager() + { + Plugins["mysql_native_password"] = new PluginInfo("MySql.Data.MySqlClient.Authentication.MySqlNativePasswordPlugin"); + Plugins["sha256_password"] = new PluginInfo("MySql.Data.MySqlClient.Authentication.Sha256AuthenticationPlugin"); + Plugins["authentication_windows_client"] = new PluginInfo("MySql.Data.MySqlClient.Authentication.MySqlWindowsAuthenticationPlugin"); + Plugins["caching_sha2_password"] = new PluginInfo("MySql.Data.MySqlClient.Authentication.CachingSha2AuthenticationPlugin"); + Plugins["authentication_ldap_sasl_client"] = new PluginInfo("MySql.Data.MySqlClient.Authentication.MySqlSASLPlugin"); + Plugins["mysql_clear_password"] = new PluginInfo("MySql.Data.MySqlClient.Authentication.MySqlClearPasswordPlugin"); + Plugins["authentication_kerberos_client"] = new PluginInfo("MySql.Data.MySqlClient.Authentication.KerberosAuthenticationPlugin"); + Plugins["authentication_oci_client"] = new PluginInfo("MySql.Data.MySqlClient.Authentication.OciAuthenticationPlugin"); + Plugins["authentication_webauthn_client"] = new PluginInfo("MySql.Data.MySqlClient.Authentication.WebAuthnAuthenticationPlugin"); + Plugins["authentication_openid_connect_client"] = new PluginInfo("MySql.Data.MySqlClient.Authentication.OpenIdConnectClientAuthentication"); + + AuthenticationManagerCtorConfiguration(); + } + + public static MySqlAuthenticationPlugin GetPlugin(string method) + { + ValidateAuthenticationPlugin(method); + return CreatePlugin(method); + } + + private static MySqlAuthenticationPlugin CreatePlugin(string method) + { + PluginInfo pi = Plugins[method]; + + try + { + Type t = Type.GetType(pi.Type); + MySqlAuthenticationPlugin o = (MySqlAuthenticationPlugin)Activator.CreateInstance(t); + return o; + } + catch (Exception e) + { + throw new MySqlException(String.Format(Resources.UnableToCreateAuthPlugin, method), e); + } + } + + public static void ValidateAuthenticationPlugin(string method) + { + if (!Plugins.ContainsKey(method)) + throw new MySqlException(String.Format(Resources.AuthenticationMethodNotSupported, method)); + } + } + + struct PluginInfo + { + public string Type; + public Assembly Assembly; + + public PluginInfo(string type) + { + Type = type; + Assembly = null; + } + } +} diff --git a/MySQL.Data/src/Authentication/CachingSha2AuthenticationPlugin.cs b/MySQL.Data/src/Authentication/CachingSha2AuthenticationPlugin.cs index bf6183e70..96295a57c 100644 --- a/MySQL.Data/src/Authentication/CachingSha2AuthenticationPlugin.cs +++ b/MySQL.Data/src/Authentication/CachingSha2AuthenticationPlugin.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2017, 2022, Oracle and/or its affiliates. +// Copyright © 2017, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -178,4 +178,4 @@ internal enum AuthStage FAST_AUTH = 2, FULL_AUTH = 3 } -} \ No newline at end of file +} diff --git a/MySQL.Data/src/Authentication/ClearPasswordPlugin.cs b/MySQL.Data/src/Authentication/ClearPasswordPlugin.cs index 135997166..b42ebda36 100644 --- a/MySQL.Data/src/Authentication/ClearPasswordPlugin.cs +++ b/MySQL.Data/src/Authentication/ClearPasswordPlugin.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2020, 2022, Oracle and/or its affiliates. +// Copyright © 2020, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/Authentication/FIDO/FidoAssertion.cs b/MySQL.Data/src/Authentication/FIDO/FidoAssertion.cs index 4d2bad412..4df6de4e4 100644 --- a/MySQL.Data/src/Authentication/FIDO/FidoAssertion.cs +++ b/MySQL.Data/src/Authentication/FIDO/FidoAssertion.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2022, 2023, Oracle and/or its affiliates. +// Copyright © 2022, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/Authentication/FIDO/FidoDevice.cs b/MySQL.Data/src/Authentication/FIDO/FidoDevice.cs index dd015fe17..71a20e1cb 100644 --- a/MySQL.Data/src/Authentication/FIDO/FidoDevice.cs +++ b/MySQL.Data/src/Authentication/FIDO/FidoDevice.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2022, 2023, Oracle and/or its affiliates. +// Copyright © 2022, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/Authentication/FIDO/FidoDeviceInfo.cs b/MySQL.Data/src/Authentication/FIDO/FidoDeviceInfo.cs index a34d03266..d38a265bb 100644 --- a/MySQL.Data/src/Authentication/FIDO/FidoDeviceInfo.cs +++ b/MySQL.Data/src/Authentication/FIDO/FidoDeviceInfo.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2022, Oracle and/or its affiliates. +// Copyright © 2022, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/Authentication/FIDO/Native/NativeMethods.cs b/MySQL.Data/src/Authentication/FIDO/Native/NativeMethods.cs index 47404be9b..2931a61b3 100644 --- a/MySQL.Data/src/Authentication/FIDO/Native/NativeMethods.cs +++ b/MySQL.Data/src/Authentication/FIDO/Native/NativeMethods.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2022, 2023, Oracle and/or its affiliates. +// Copyright © 2022, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General internal License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/Authentication/FIDO/Native/Structs.cs b/MySQL.Data/src/Authentication/FIDO/Native/Structs.cs index d798bf048..29a2a24a6 100644 --- a/MySQL.Data/src/Authentication/FIDO/Native/Structs.cs +++ b/MySQL.Data/src/Authentication/FIDO/Native/Structs.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2022, Oracle and/or its affiliates. +// Copyright © 2022, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/Authentication/FIDO/Utility/ConstStringMarshaler.cs b/MySQL.Data/src/Authentication/FIDO/Utility/ConstStringMarshaler.cs index 57cf867cc..0129ab241 100644 --- a/MySQL.Data/src/Authentication/FIDO/Utility/ConstStringMarshaler.cs +++ b/MySQL.Data/src/Authentication/FIDO/Utility/ConstStringMarshaler.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2022, Oracle and/or its affiliates. +// Copyright © 2022, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/Authentication/FIDO/Utility/Enums.cs b/MySQL.Data/src/Authentication/FIDO/Utility/Enums.cs index ccdec93c5..41503cb68 100644 --- a/MySQL.Data/src/Authentication/FIDO/Utility/Enums.cs +++ b/MySQL.Data/src/Authentication/FIDO/Utility/Enums.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2022, Oracle and/or its affiliates. +// Copyright © 2022, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/Authentication/FIDO/Utility/Extensions.cs b/MySQL.Data/src/Authentication/FIDO/Utility/Extensions.cs index e9be6c55a..b141dc1af 100644 --- a/MySQL.Data/src/Authentication/FIDO/Utility/Extensions.cs +++ b/MySQL.Data/src/Authentication/FIDO/Utility/Extensions.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2022, Oracle and/or its affiliates. +// Copyright © 2022, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/Authentication/FIDO/Utility/FidoExceptions.cs b/MySQL.Data/src/Authentication/FIDO/Utility/FidoExceptions.cs index 560bdd0d0..b0d5ce8dc 100644 --- a/MySQL.Data/src/Authentication/FIDO/Utility/FidoExceptions.cs +++ b/MySQL.Data/src/Authentication/FIDO/Utility/FidoExceptions.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2022, Oracle and/or its affiliates. +// Copyright © 2022, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/Authentication/FIDO/Utility/Init.cs b/MySQL.Data/src/Authentication/FIDO/Utility/Init.cs index 2e159a005..20d5584e5 100644 --- a/MySQL.Data/src/Authentication/FIDO/Utility/Init.cs +++ b/MySQL.Data/src/Authentication/FIDO/Utility/Init.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2022, Oracle and/or its affiliates. +// Copyright © 2022, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/Authentication/FidoAuthenticationPlugin.cs b/MySQL.Data/src/Authentication/FidoAuthenticationPlugin.cs deleted file mode 100644 index 5936c1e12..000000000 --- a/MySQL.Data/src/Authentication/FidoAuthenticationPlugin.cs +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright (c) 2022, 2023, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data.Authentication.FIDO; -using System; -using System.IO; -using System.Text; -using System.Threading.Tasks; - -namespace MySql.Data.MySqlClient.Authentication -{ - [Obsolete("FIDO authentication client-side plugin is now deprecated.")] - internal class FidoAuthenticationPlugin : MySqlAuthenticationPlugin - { - public override string PluginName => "authentication_fido_client"; - - // Constants - private const int CLIENT_DATA_LENGTH = 32; - private const int RELYING_PARTY_ID_MAX_LENGTH = 255; - - // Fields - private byte[] _clientDataHash; - private byte[] _credentialId; - private string _relyingPartyId; - - protected override void SetAuthData(byte[] data) - { - if (data.Length > 0) - ParseChallenge(data); - else - throw new MySqlException(Resources.FidoRegistrationMissing); - } - - protected override async Task MoreDataAsync(byte[] data, bool execAsync) - { - Tuple response = BuildFidoAssertionStatement(); - return await SignChallengeAsync(response, execAsync).ConfigureAwait(false); - } - - /// - /// Method that parse the challenge received from server during authentication process. - /// This method extracts salt, relying party name and set it in the object. - /// - /// Buffer holding the server challenge. - /// Thrown if an error occurs while parsing the challenge. - private void ParseChallenge(byte[] challenge) - { - // client_data_hash length should be 32 bytes - int clientDataLength = challenge[0]; - if (clientDataLength != CLIENT_DATA_LENGTH) throw new MySqlException(Resources.FidoChallengeCorrupt); - // client_data_hash - _clientDataHash = new byte[clientDataLength]; - Array.Copy(challenge, 1, _clientDataHash, 0, clientDataLength); - - // relyting_party_id length cannot be more than 255 - int relyingPartyIdLength = challenge[clientDataLength + 1]; - if (relyingPartyIdLength > RELYING_PARTY_ID_MAX_LENGTH) throw new MySqlException(Resources.FidoChallengeCorrupt); - // relying_party_id - _relyingPartyId = Encoding.GetString(challenge, clientDataLength + 2, relyingPartyIdLength); - - // credential_id length - int credentialIdLength = challenge[clientDataLength + relyingPartyIdLength + 2]; - // credential_id - _credentialId = new byte[credentialIdLength]; - Array.Copy(challenge, clientDataLength + relyingPartyIdLength + 3, _credentialId, 0, credentialIdLength); - } - - /// - /// Signs the challenge obtained from the FIDO device and returns it to the server. - /// - private async Task SignChallengeAsync(Tuple response, bool execAsync) - { - var challenge = new MySqlPacket(new MemoryStream(response.Item1)); - await challenge.WriteLengthAsync(response.Item2, execAsync).ConfigureAwait(false); - await challenge.WriteAsync(response.Item3, execAsync).ConfigureAwait(false); - await challenge.WriteLengthAsync(response.Item4, execAsync).ConfigureAwait(false); - await challenge.WriteAsync(response.Item5, execAsync).ConfigureAwait(false); - - return challenge.Buffer; - } - - /// - /// Method to obtain an assertion from a FIDO device. - /// - private Tuple BuildFidoAssertionStatement() - { - string devicePath; - - using (var fidoDeviceInfo = new FidoDeviceInfo()) - devicePath = fidoDeviceInfo.Path; - - using (var fidoAssertion = new FidoAssertion()) - { - using (var fidoDevice = new FidoDevice()) - { - fidoAssertion.ClientDataHash = _clientDataHash; - fidoAssertion.Rp = _relyingPartyId; - fidoAssertion.AllowCredential(_credentialId); - - fidoDevice.Open(devicePath); - - if (_driver.Settings.FidoActionRequested != null) - _driver.Settings.FidoActionRequested?.Invoke(); - else - throw new MySqlException(Resources.FidoMissingHandler); - - fidoDevice.GetAssert(fidoAssertion); - - var fidoAssertionStatement = fidoAssertion.GetFidoAssertionStatement(); - int responseLength = fidoAssertionStatement.SignatureLen + fidoAssertionStatement.AuthDataLen + - Utils.GetLengthSize((ulong)fidoAssertionStatement.SignatureLen) + Utils.GetLengthSize((ulong)fidoAssertionStatement.AuthDataLen); - - return new Tuple(responseLength, - fidoAssertionStatement.AuthDataLen, fidoAssertionStatement.AuthData.ToArray(), - fidoAssertionStatement.SignatureLen, fidoAssertionStatement.Signature.ToArray()); - } - } - } - } -} diff --git a/MySQL.Data/src/Authentication/GSSAPI/Const.cs b/MySQL.Data/src/Authentication/GSSAPI/Const.cs index e1e70f7c6..8f153be0c 100644 --- a/MySQL.Data/src/Authentication/GSSAPI/Const.cs +++ b/MySQL.Data/src/Authentication/GSSAPI/Const.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021 Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -107,4 +107,4 @@ internal static class Const }; #endregion } -} \ No newline at end of file +} diff --git a/MySQL.Data/src/Authentication/GSSAPI/GssContext.cs b/MySQL.Data/src/Authentication/GSSAPI/GssContext.cs index 0f2030035..877656696 100644 --- a/MySQL.Data/src/Authentication/GSSAPI/GssContext.cs +++ b/MySQL.Data/src/Authentication/GSSAPI/GssContext.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2020, Oracle and/or its affiliates. +// Copyright © 2020, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -231,4 +231,4 @@ public void Dispose() GC.SuppressFinalize(this); } } -} \ No newline at end of file +} diff --git a/MySQL.Data/src/Authentication/GSSAPI/GssContextFlags.cs b/MySQL.Data/src/Authentication/GSSAPI/GssContextFlags.cs index a56b71683..e0bb81172 100644 --- a/MySQL.Data/src/Authentication/GSSAPI/GssContextFlags.cs +++ b/MySQL.Data/src/Authentication/GSSAPI/GssContextFlags.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2020, Oracle and/or its affiliates. +// Copyright © 2020, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -77,4 +77,4 @@ internal enum GssContextFlags Trans = 256, DelegPolicy = 32768 } -} \ No newline at end of file +} diff --git a/MySQL.Data/src/Authentication/GSSAPI/GssCredentials.cs b/MySQL.Data/src/Authentication/GSSAPI/GssCredentials.cs index e30fa6f71..ce0908868 100644 --- a/MySQL.Data/src/Authentication/GSSAPI/GssCredentials.cs +++ b/MySQL.Data/src/Authentication/GSSAPI/GssCredentials.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2022, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -225,4 +225,4 @@ public void Dispose() majorStatus, minorStatus, Const.GssNtHostBasedService)); } } -} \ No newline at end of file +} diff --git a/MySQL.Data/src/Authentication/GSSAPI/GssapiMechanism.cs b/MySQL.Data/src/Authentication/GSSAPI/GssapiMechanism.cs index 0c232c7b7..d786785f8 100644 --- a/MySQL.Data/src/Authentication/GSSAPI/GssapiMechanism.cs +++ b/MySQL.Data/src/Authentication/GSSAPI/GssapiMechanism.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -124,4 +124,4 @@ internal byte[] DoFinalHandshake(byte[] data) return response; } } -} \ No newline at end of file +} diff --git a/MySQL.Data/src/Authentication/GSSAPI/Native/GssBufferDescStruct.cs b/MySQL.Data/src/Authentication/GSSAPI/Native/GssBufferDescStruct.cs index d62569322..36932ed2d 100644 --- a/MySQL.Data/src/Authentication/GSSAPI/Native/GssBufferDescStruct.cs +++ b/MySQL.Data/src/Authentication/GSSAPI/Native/GssBufferDescStruct.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2020, Oracle and/or its affiliates. +// Copyright © 2020, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -40,4 +40,4 @@ internal struct GssBufferDescStruct /// void* public IntPtr value; } -} \ No newline at end of file +} diff --git a/MySQL.Data/src/Authentication/GSSAPI/Native/GssOidStruct.cs b/MySQL.Data/src/Authentication/GSSAPI/Native/GssOidStruct.cs index cc5422c89..14165a5f9 100644 --- a/MySQL.Data/src/Authentication/GSSAPI/Native/GssOidStruct.cs +++ b/MySQL.Data/src/Authentication/GSSAPI/Native/GssOidStruct.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2020, Oracle and/or its affiliates. +// Copyright © 2020, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -50,4 +50,4 @@ internal struct GssOidSetStruct /// void* public IntPtr elements; } -} \ No newline at end of file +} diff --git a/MySQL.Data/src/Authentication/GSSAPI/Native/NativeMethods.cs b/MySQL.Data/src/Authentication/GSSAPI/Native/NativeMethods.cs index 0f1832dd4..7f4fe0c39 100644 --- a/MySQL.Data/src/Authentication/GSSAPI/Native/NativeMethods.cs +++ b/MySQL.Data/src/Authentication/GSSAPI/Native/NativeMethods.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -471,4 +471,4 @@ internal static uint gss_wrap( : NativeMethodsLinux.gss_wrap(out minorStatus, contextHandle, 0, Const.GSS_C_QOP_DEFAULT, ref inputMessage, 0, out outputMessage); } } -} \ No newline at end of file +} diff --git a/MySQL.Data/src/Authentication/GSSAPI/Native/NativeMethodsLinux.cs b/MySQL.Data/src/Authentication/GSSAPI/Native/NativeMethodsLinux.cs index f0447a86c..0d8c060e8 100644 --- a/MySQL.Data/src/Authentication/GSSAPI/Native/NativeMethodsLinux.cs +++ b/MySQL.Data/src/Authentication/GSSAPI/Native/NativeMethodsLinux.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2022, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -149,4 +149,4 @@ internal static extern uint gss_display_name( out GssBufferDescStruct NameBuffer, out GssOidDescStruct nameType); } -} \ No newline at end of file +} diff --git a/MySQL.Data/src/Authentication/GSSAPI/Native/NativeMethodsWin64.cs b/MySQL.Data/src/Authentication/GSSAPI/Native/NativeMethodsWin64.cs index 61b9c2b4e..0615eae73 100644 --- a/MySQL.Data/src/Authentication/GSSAPI/Native/NativeMethodsWin64.cs +++ b/MySQL.Data/src/Authentication/GSSAPI/Native/NativeMethodsWin64.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2022, Oracle and/or its affiliates. +// Copyright © 2022, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -149,4 +149,4 @@ internal static extern uint gss_display_name( out GssBufferDescStruct NameBuffer, out GssOidDescStruct nameType); } -} \ No newline at end of file +} diff --git a/MySQL.Data/src/Authentication/GSSAPI/Utility/Disposable.cs b/MySQL.Data/src/Authentication/GSSAPI/Utility/Disposable.cs index 325b15319..45274babe 100644 --- a/MySQL.Data/src/Authentication/GSSAPI/Utility/Disposable.cs +++ b/MySQL.Data/src/Authentication/GSSAPI/Utility/Disposable.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2020, 2023, Oracle and/or its affiliates. +// Copyright © 2020, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -117,4 +117,4 @@ public void Dispose() _disposeAction?.Invoke(); } } -} \ No newline at end of file +} diff --git a/MySQL.Data/src/Authentication/GSSAPI/Utility/ExceptionMessages.cs b/MySQL.Data/src/Authentication/GSSAPI/Utility/ExceptionMessages.cs index cf4f76260..c0947f76c 100644 --- a/MySQL.Data/src/Authentication/GSSAPI/Utility/ExceptionMessages.cs +++ b/MySQL.Data/src/Authentication/GSSAPI/Utility/ExceptionMessages.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2020, Oracle and/or its affiliates. +// Copyright © 2020, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -65,4 +65,4 @@ private static string TranslateMinorStatusCode(uint status, GssOidDescStruct oid return buffer.value == IntPtr.Zero ? string.Empty : Marshal.PtrToStringAnsi(buffer.value); } } -} \ No newline at end of file +} diff --git a/MySQL.Data/src/Authentication/GSSAPI/Utility/GssType.cs b/MySQL.Data/src/Authentication/GSSAPI/Utility/GssType.cs index cdad230e2..49943759f 100644 --- a/MySQL.Data/src/Authentication/GSSAPI/Utility/GssType.cs +++ b/MySQL.Data/src/Authentication/GSSAPI/Utility/GssType.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2020, Oracle and/or its affiliates. +// Copyright © 2020, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -53,4 +53,4 @@ public static Disposable GetBufferFromBytes(byte[] buffer) majorStatus, minorStatus, Const.GSS_C_NO_OID)); }); } -} \ No newline at end of file +} diff --git a/MySQL.Data/src/Authentication/GSSAPI/Utility/KerberosConfig.cs b/MySQL.Data/src/Authentication/GSSAPI/Utility/KerberosConfig.cs index 49102bd6b..6d86220e6 100644 --- a/MySQL.Data/src/Authentication/GSSAPI/Utility/KerberosConfig.cs +++ b/MySQL.Data/src/Authentication/GSSAPI/Utility/KerberosConfig.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -225,4 +225,4 @@ private static void ReadValues(string currentLine, StringReader reader, List - /// Defines the default behavior for an authentication plugin. - /// - public abstract class MySqlAuthenticationPlugin - { - internal NativeDriver _driver; - - /// - /// Handles the iteration of the multifactor authentication. - /// - private int _mfaIteration = 1; - - /// - /// Gets the AuthPlugin name of the AuthSwitchRequest. - /// - internal string SwitchedPlugin { get; private set; } - - /// - /// Gets or sets the authentication data returned by the server. - /// - protected byte[] AuthenticationData; - - /// - /// This is a factory method that is used only internally. It creates an auth plugin based on the method type - /// - /// Authentication method. - /// The driver. - /// The authentication data. - /// Boolean that indicates if the function will be executed asynchronously. - /// MultiFactorAuthentication iteration. - /// - internal static async Task GetPluginAsync(string method, NativeDriver driver, byte[] authData, bool execAsync, int mfaIteration = 1) - { - if (method == "mysql_old_password") - { - await driver.CloseAsync(true, execAsync).ConfigureAwait(false); - throw new MySqlException(Resources.OldPasswordsNotSupported); - } - MySqlAuthenticationPlugin plugin = AuthenticationPluginManager.GetPlugin(method); - if (plugin == null) - throw new MySqlException(String.Format(Resources.UnknownAuthenticationMethod, method)); - - plugin._driver = driver; - plugin._mfaIteration = mfaIteration; - plugin.SetAuthData(authData); - return plugin; - } - - /// - /// Gets the connection option settings. - /// - protected MySqlConnectionStringBuilder Settings => _driver.Settings; - - /// - /// Gets the server version associated with this authentication plugin. - /// - protected Version ServerVersion => new Version(_driver.Version.Major, _driver.Version.Minor, _driver.Version.Build); - - internal ClientFlags Flags => _driver.Flags; - - /// - /// Gets the encoding assigned to the native driver. - /// - protected Encoding Encoding => _driver.Encoding; - - /// - /// Sets the authentication data required to encode, encrypt, or convert the password of the user. - /// - /// A byte array containing the authentication data provided by the server. - /// This method may be overriden based on the requirements by the implementing authentication plugin. - protected virtual void SetAuthData(byte[] data) - { - AuthenticationData = data; - } - - /// - /// Defines the behavior when checking for constraints. - /// - /// This method is intended to be overriden. - protected virtual void CheckConstraints() - { - } - - /// - /// Throws a that encapsulates the original exception. - /// - /// The exception to encapsulate. - protected virtual void AuthenticationFailed(MySqlException ex) - { - string msg = String.Format(Resources.AuthenticationFailed, Settings.Server, GetUsername(), PluginName, ex.Message); - throw new MySqlException(msg, ex.Number, ex); - } - - /// - /// Defines the behavior when authentication is successful. - /// - /// This method is intended to be overriden. - protected virtual void AuthenticationSuccessful() - { - } - - /// - /// Defines the behavior when more data is required from the server. - /// - /// The data returned by the server. - /// Boolean that indicates if the function will be executed asynchronously. - /// The data to return to the server. - /// This method is intended to be overriden. - protected virtual Task MoreDataAsync(byte[] data, bool execAsync) - { - return Task.FromResult(null); - } - - internal async Task AuthenticateAsync(bool reset, bool execAsync) - { - CheckConstraints(); - - MySqlPacket packet = _driver.Packet; - - // send auth response - await packet.WriteStringAsync(GetUsername(), execAsync).ConfigureAwait(false); - - // now write the password - await WritePasswordAsync(packet, execAsync).ConfigureAwait(false); - - if ((Flags & ClientFlags.CONNECT_WITH_DB) != 0 || reset) - { - if (!String.IsNullOrEmpty(Settings.Database)) - await packet.WriteStringAsync(Settings.Database, execAsync).ConfigureAwait(false); - } - - if (reset) - await packet.WriteIntegerAsync(8, 2, execAsync).ConfigureAwait(false); - - if ((Flags & ClientFlags.PLUGIN_AUTH) != 0) - await packet.WriteStringAsync(PluginName, execAsync).ConfigureAwait(false); - - await _driver.SetConnectAttrsAsync(execAsync).ConfigureAwait(false); - await _driver.SendPacketAsync(packet, execAsync); - - // Read server response. - packet = await ReadPacketAsync(execAsync).ConfigureAwait(false); - byte[] b = packet.Buffer; - - if (PluginName == "caching_sha2_password" && b[0] == 0x01) - { - // React to the authentication type set by server: FAST, FULL. - await ContinueAuthenticationAsync(execAsync, new byte[] { b[1] }).ConfigureAwait(false); - } - - // Auth switch request Protocol::AuthSwitchRequest. - if (b[0] == 0xfe) - { - if (packet.IsLastPacket) - { - await _driver.CloseAsync(true, execAsync).ConfigureAwait(false); - throw new MySqlException(Resources.OldPasswordsNotSupported); - } - else - { - await HandleAuthChangeAsync(packet, execAsync).ConfigureAwait(false); - } - } - - // Auth request Protocol::AuthNextFactor. - while (packet.Buffer[0] == 0x02) - { - ++_mfaIteration; - await HandleMFAAsync(packet, execAsync).ConfigureAwait(false); - } - - await _driver.ReadOkAsync(false, execAsync).ConfigureAwait(false); - - AuthenticationSuccessful(); - } - - private async Task WritePasswordAsync(MySqlPacket packet, bool execAsync) - { - bool secure = (Flags & ClientFlags.SECURE_CONNECTION) != 0; - object password = GetPassword(); - if (password is string) - { - if (secure) - await packet.WriteLenStringAsync((string)password, execAsync).ConfigureAwait(false); - else - await packet.WriteStringAsync((string)password, execAsync).ConfigureAwait(false); - } - else if (password == null) - packet.WriteByte(0); - else if (password is byte[]) - await packet.WriteAsync(password as byte[], execAsync).ConfigureAwait(false); - else throw new MySqlException("Unexpected password format: " + password.GetType()); - } - - internal async Task ReadPacketAsync(bool execAsync) - { - try - { - MySqlPacket p = await _driver.ReadPacketAsync(execAsync).ConfigureAwait(false); - return p; - } - catch (MySqlException ex) - { - // Make sure this is an auth failed ex - AuthenticationFailed(ex); - return null; - } - } - - private async Task HandleMFAAsync(MySqlPacket packet, bool execAsync) - { - byte b = packet.ReadByte(); - Debug.Assert(b == 0x02); - - var nextPlugin = await NextPluginAsync(packet, execAsync).ConfigureAwait(false); - nextPlugin.CheckConstraints(); - await nextPlugin.ContinueAuthenticationAsync(execAsync).ConfigureAwait(false); - } - - private async Task HandleAuthChangeAsync(MySqlPacket packet, bool execAsync) - { - byte b = packet.ReadByte(); - Debug.Assert(b == 0xfe); - - var nextPlugin = await NextPluginAsync(packet, execAsync).ConfigureAwait(false); - nextPlugin.CheckConstraints(); - await nextPlugin.ContinueAuthenticationAsync(execAsync).ConfigureAwait(false); - } - - private async Task NextPluginAsync(MySqlPacket packet, bool execAsync) - { - string method = packet.ReadString(); - SwitchedPlugin = method; - byte[] authData = new byte[packet.Length - packet.Position]; - Array.Copy(packet.Buffer, packet.Position, authData, 0, authData.Length); - - MySqlAuthenticationPlugin plugin = await GetPluginAsync(method, _driver, authData, execAsync, _mfaIteration).ConfigureAwait(false); - return plugin; - } - - private async Task ContinueAuthenticationAsync(bool execAsync, byte[] data = null) - { - MySqlPacket packet = _driver.Packet; - packet.Clear(); - - byte[] moreData = await MoreDataAsync(data, execAsync).ConfigureAwait(false); - - while (moreData != null) - { - packet.Clear(); - await packet.WriteAsync(moreData, execAsync).ConfigureAwait(false); - await _driver.SendPacketAsync(packet, execAsync).ConfigureAwait(false); - - packet = await ReadPacketAsync(execAsync).ConfigureAwait(false); - byte prefixByte = packet.Buffer[0]; - if (prefixByte != 1) return; - - // A prefix of 0x01 means need more auth data. - byte[] responseData = new byte[packet.Length - 1]; - Array.Copy(packet.Buffer, 1, responseData, 0, responseData.Length); - moreData = await MoreDataAsync(responseData, execAsync).ConfigureAwait(false); - } - // We get here if MoreData returned null but the last packet read was a more data packet. - await ReadPacketAsync(execAsync).ConfigureAwait(false); - } - - /// - /// Gets the password for the iteration of the multifactor authentication - /// - /// A password - protected string GetMFAPassword() - { - switch (_mfaIteration) - { - case 2: - return Settings.Password2; - case 3: - return Settings.Password3; - default: - return Settings.Password; - } - } - - /// - /// Gets the plugin name based on the authentication plugin type defined during the creation of this object. - /// - public abstract string PluginName { get; } - - /// - /// Gets the user name associated to the connection settings. - /// - /// The user name associated to the connection settings. - public virtual string GetUsername() - { - return !string.IsNullOrWhiteSpace(Settings.UserID) ? Settings.UserID : Environment.UserName; - } - - /// - /// Gets the encoded, encrypted, or converted password based on the authentication plugin type defined during the creation of this object. - /// This method is intended to be overriden. - /// - /// An object containing the encoded, encrypted, or converted password. - public virtual object GetPassword() - { - return null; - } - } -} +// Copyright © 2012, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using System; +using System.Diagnostics; +using System.Text; +using System.Threading.Tasks; + +namespace MySql.Data.MySqlClient.Authentication +{ + /// + /// Defines the default behavior for an authentication plugin. + /// + public abstract class MySqlAuthenticationPlugin + { + internal NativeDriver _driver; + + /// + /// Handles the iteration of the multifactor authentication. + /// + private int _mfaIteration = 1; + + /// + /// Gets the AuthPlugin name of the AuthSwitchRequest. + /// + internal string SwitchedPlugin { get; private set; } + + /// + /// Gets or sets the authentication data returned by the server. + /// + protected byte[] AuthenticationData; + + /// + /// This is a factory method that is used only internally. It creates an auth plugin based on the method type + /// + /// Authentication method. + /// The driver. + /// The authentication data. + /// Boolean that indicates if the function will be executed asynchronously. + /// MultiFactorAuthentication iteration. + /// + internal static async Task GetPluginAsync(string method, NativeDriver driver, byte[] authData, bool execAsync, int mfaIteration = 1) + { + if (method == "mysql_old_password") + { + await driver.CloseAsync(true, execAsync).ConfigureAwait(false); + throw new MySqlException(Resources.OldPasswordsNotSupported); + } + MySqlAuthenticationPlugin plugin = AuthenticationPluginManager.GetPlugin(method); + if (plugin == null) + throw new MySqlException(String.Format(Resources.UnknownAuthenticationMethod, method)); + + plugin._driver = driver; + plugin._mfaIteration = mfaIteration; + plugin.SetAuthData(authData); + return plugin; + } + + /// + /// Gets the connection option settings. + /// + protected MySqlConnectionStringBuilder Settings => _driver.Settings; + + /// + /// Gets the server version associated with this authentication plugin. + /// + protected Version ServerVersion => new Version(_driver.Version.Major, _driver.Version.Minor, _driver.Version.Build); + + internal ClientFlags Flags => _driver.Flags; + + /// + /// Gets the encoding assigned to the native driver. + /// + protected Encoding Encoding => _driver.Encoding; + + /// + /// Sets the authentication data required to encode, encrypt, or convert the password of the user. + /// + /// A byte array containing the authentication data provided by the server. + /// This method may be overriden based on the requirements by the implementing authentication plugin. + protected virtual void SetAuthData(byte[] data) + { + AuthenticationData = data; + } + + /// + /// Defines the behavior when checking for constraints. + /// + /// This method is intended to be overriden. + protected virtual void CheckConstraints() + { + } + + /// + /// Throws a that encapsulates the original exception. + /// + /// The exception to encapsulate. + protected virtual void AuthenticationFailed(MySqlException ex) + { + string msg = String.Format(Resources.AuthenticationFailed, Settings.Server, GetUsername(), PluginName, ex.Message); + throw new MySqlException(msg, ex.Number, ex); + } + + /// + /// Defines the behavior when authentication is successful. + /// + /// This method is intended to be overriden. + protected virtual void AuthenticationSuccessful() + { + } + + /// + /// Defines the behavior when more data is required from the server. + /// + /// The data returned by the server. + /// Boolean that indicates if the function will be executed asynchronously. + /// The data to return to the server. + /// This method is intended to be overriden. + protected virtual Task MoreDataAsync(byte[] data, bool execAsync) + { + return Task.FromResult(null); + } + + internal async Task AuthenticateAsync(bool reset, bool execAsync) + { + CheckConstraints(); + + MySqlPacket packet = _driver.Packet; + + // send auth response + await packet.WriteStringAsync(GetUsername(), execAsync).ConfigureAwait(false); + + // now write the password + await WritePasswordAsync(packet, execAsync).ConfigureAwait(false); + + if ((Flags & ClientFlags.CONNECT_WITH_DB) != 0 || reset) + { + if (!String.IsNullOrEmpty(Settings.Database)) + await packet.WriteStringAsync(Settings.Database, execAsync).ConfigureAwait(false); + } + + if (reset) + await packet.WriteIntegerAsync(8, 2, execAsync).ConfigureAwait(false); + + if ((Flags & ClientFlags.PLUGIN_AUTH) != 0) + await packet.WriteStringAsync(PluginName, execAsync).ConfigureAwait(false); + + await _driver.SetConnectAttrsAsync(execAsync).ConfigureAwait(false); + await _driver.SendPacketAsync(packet, execAsync).ConfigureAwait(false); + + // Read server response. + packet = await ReadPacketAsync(execAsync).ConfigureAwait(false); + byte[] b = packet.Buffer; + + if (PluginName == "caching_sha2_password" && b[0] == 0x01) + { + // React to the authentication type set by server: FAST, FULL. + await ContinueAuthenticationAsync(execAsync, new byte[] { b[1] }).ConfigureAwait(false); + } + + // Auth switch request Protocol::AuthSwitchRequest. + if (b[0] == 0xfe) + { + if (packet.IsLastPacket) + { + await _driver.CloseAsync(true, execAsync).ConfigureAwait(false); + throw new MySqlException(Resources.OldPasswordsNotSupported); + } + else + { + await HandleAuthChangeAsync(packet, execAsync).ConfigureAwait(false); + } + } + + // Auth request Protocol::AuthNextFactor. + while (packet.Buffer[0] == 0x02) + { + ++_mfaIteration; + await HandleMFAAsync(packet, execAsync).ConfigureAwait(false); + } + + await _driver.ReadOkAsync(false, execAsync).ConfigureAwait(false); + + AuthenticationSuccessful(); + } + + private async Task WritePasswordAsync(MySqlPacket packet, bool execAsync) + { + bool secure = (Flags & ClientFlags.SECURE_CONNECTION) != 0; + object password = GetPassword(); + if (password is string) + { + if (secure) + await packet.WriteLenStringAsync((string)password, execAsync).ConfigureAwait(false); + else + await packet.WriteStringAsync((string)password, execAsync).ConfigureAwait(false); + } + else if (password == null) + packet.WriteByte(0); + else if (password is byte[]) + await packet.WriteAsync(password as byte[], execAsync).ConfigureAwait(false); + else throw new MySqlException("Unexpected password format: " + password.GetType()); + } + + internal async Task ReadPacketAsync(bool execAsync) + { + try + { + MySqlPacket p = await _driver.ReadPacketAsync(execAsync).ConfigureAwait(false); + return p; + } + catch (MySqlException ex) + { + // Make sure this is an auth failed ex + AuthenticationFailed(ex); + return null; + } + } + + private async Task HandleMFAAsync(MySqlPacket packet, bool execAsync) + { + byte b = packet.ReadByte(); + Debug.Assert(b == 0x02); + + var nextPlugin = await NextPluginAsync(packet, execAsync).ConfigureAwait(false); + nextPlugin.CheckConstraints(); + await nextPlugin.ContinueAuthenticationAsync(execAsync).ConfigureAwait(false); + } + + private async Task HandleAuthChangeAsync(MySqlPacket packet, bool execAsync) + { + byte b = packet.ReadByte(); + Debug.Assert(b == 0xfe); + + var nextPlugin = await NextPluginAsync(packet, execAsync).ConfigureAwait(false); + nextPlugin.CheckConstraints(); + await nextPlugin.ContinueAuthenticationAsync(execAsync).ConfigureAwait(false); + } + + private async Task NextPluginAsync(MySqlPacket packet, bool execAsync) + { + string method = packet.ReadString(); + SwitchedPlugin = method; + byte[] authData = new byte[packet.Length - packet.Position]; + Array.Copy(packet.Buffer, packet.Position, authData, 0, authData.Length); + + MySqlAuthenticationPlugin plugin = await GetPluginAsync(method, _driver, authData, execAsync, _mfaIteration).ConfigureAwait(false); + return plugin; + } + + private async Task ContinueAuthenticationAsync(bool execAsync, byte[] data = null) + { + MySqlPacket packet = _driver.Packet; + packet.Clear(); + + byte[] moreData = await MoreDataAsync(data, execAsync).ConfigureAwait(false); + + while (moreData != null) + { + packet.Clear(); + await packet.WriteAsync(moreData, execAsync).ConfigureAwait(false); + await _driver.SendPacketAsync(packet, execAsync).ConfigureAwait(false); + + packet = await ReadPacketAsync(execAsync).ConfigureAwait(false); + byte prefixByte = packet.Buffer[0]; + if (prefixByte != 1) return; + + // A prefix of 0x01 means need more auth data. + byte[] responseData = new byte[packet.Length - 1]; + Array.Copy(packet.Buffer, 1, responseData, 0, responseData.Length); + moreData = await MoreDataAsync(responseData, execAsync).ConfigureAwait(false); + } + // We get here if MoreData returned null but the last packet read was a more data packet. + await ReadPacketAsync(execAsync).ConfigureAwait(false); + } + + /// + /// Gets the password for the iteration of the multifactor authentication + /// + /// A password + protected string GetMFAPassword() + { + switch (_mfaIteration) + { + case 2: + return Settings.Password2; + case 3: + return Settings.Password3; + default: + return Settings.Password; + } + } + + /// + /// Gets the plugin name based on the authentication plugin type defined during the creation of this object. + /// + public abstract string PluginName { get; } + + /// + /// Gets the user name associated to the connection settings. + /// + /// The user name associated to the connection settings. + public virtual string GetUsername() + { + return !string.IsNullOrWhiteSpace(Settings.UserID) ? Settings.UserID : Environment.UserName; + } + + /// + /// Gets the encoded, encrypted, or converted password based on the authentication plugin type defined during the creation of this object. + /// This method is intended to be overriden. + /// + /// An object containing the encoded, encrypted, or converted password. + public virtual object GetPassword() + { + return null; + } + } +} diff --git a/MySQL.Data/src/Authentication/MySqlPemReader.cs b/MySQL.Data/src/Authentication/MySqlPemReader.cs index 9de5044ac..e89272f0e 100644 --- a/MySQL.Data/src/Authentication/MySqlPemReader.cs +++ b/MySQL.Data/src/Authentication/MySqlPemReader.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2017, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -113,7 +113,7 @@ static RSACryptoServiceProvider DecodeX509Key(byte[] key) } else return null; - int modulusSize = BitConverter.ToInt32(new byte[] { lowByte, highByte, 0x00, 0x00 }, 0); + int modulusSize = highByte << 8 | lowByte; byte firstByte = reader.ReadByte(); reader.BaseStream.Seek(-1, SeekOrigin.Current); @@ -231,4 +231,4 @@ private static bool EndsWith(byte[] array, byte[] containedArray) return true; } } -} \ No newline at end of file +} diff --git a/MySQL.Data/src/Authentication/MySqlSASLPlugin.cs b/MySQL.Data/src/Authentication/MySqlSASLPlugin.cs index 81a7424ab..db8532905 100644 --- a/MySQL.Data/src/Authentication/MySqlSASLPlugin.cs +++ b/MySQL.Data/src/Authentication/MySqlSASLPlugin.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2020, 2022, Oracle and/or its affiliates. +// Copyright © 2020, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -49,7 +49,6 @@ internal class MySqlSASLPlugin : MySqlAuthenticationPlugin protected override void SetAuthData(byte[] data) { _mechanismName = Encoding.UTF8.GetString(data); - switch (_mechanismName) { case "SCRAM-SHA-1": @@ -59,8 +58,6 @@ protected override void SetAuthData(byte[] data) scramMechanism = new ScramSha256Mechanism(GetUsername(), GetMFAPassword(), Settings.Server); break; case "GSSAPI": - if (Platform.IsWindows()) - throw new PlatformNotSupportedException(string.Format(Resources.AuthenticationPluginNotSupported, "GSSAPI/Kerberos")); gssapiMechanism = new GssapiMechanism(GetUsername(), GetMFAPassword()); break; } @@ -256,4 +253,4 @@ internal static string GetRandomBytes(int n) return Convert.ToBase64String(bytes); } } -} \ No newline at end of file +} diff --git a/MySQL.Data/src/Authentication/NativePasswordPlugins.cs b/MySQL.Data/src/Authentication/NativePasswordPlugins.cs index 47eab4890..248a93d02 100644 --- a/MySQL.Data/src/Authentication/NativePasswordPlugins.cs +++ b/MySQL.Data/src/Authentication/NativePasswordPlugins.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2012, 2022, Oracle and/or its affiliates. +// Copyright © 2012, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/Authentication/OciAuthenticationPlugin.cs b/MySQL.Data/src/Authentication/OciAuthenticationPlugin.cs index 6d060352c..dc3ade5f0 100644 --- a/MySQL.Data/src/Authentication/OciAuthenticationPlugin.cs +++ b/MySQL.Data/src/Authentication/OciAuthenticationPlugin.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/Authentication/OpenIdConnectClientAuthentication.cs b/MySQL.Data/src/Authentication/OpenIdConnectClientAuthentication.cs new file mode 100644 index 000000000..b4ad5b251 --- /dev/null +++ b/MySQL.Data/src/Authentication/OpenIdConnectClientAuthentication.cs @@ -0,0 +1,69 @@ +// Copyright © 2024, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data.MySqlClient; +using MySql.Data.MySqlClient.Authentication; +using Org.BouncyCastle.Utilities.Encoders; +using System; +using System.Collections.Generic; +using System.Configuration; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MySql.Data.MySqlClient.Authentication +{ + internal class OpenIdConnectClientAuthentication : MySqlAuthenticationPlugin + { + public override string PluginName => "authentication_openid_connect_client"; + + private static int IdentityToken_sizelimit = 10 * 1024; + + protected override Task MoreDataAsync(byte[] data, bool execAsync) + { + byte[] IdToken = Encoding.GetBytes(Settings.OpenIdIdentityToken); + int responseLength = 10;//1 Byte for capability flag. the rest is for Bytes lenenc. + responseLength += IdToken.Length; + + if (IdToken == null || IdToken.Length == 0) + throw new ArgumentException(Resources.OpenIdIdentityTokenIsEmpty); + + if (IdToken.Length > IdentityToken_sizelimit) + throw new ArgumentException(Resources.OpenIdIdentityTokenTooBig); + + var response = new MySqlPacket(new MemoryStream(responseLength)); + response.Write(new byte[] { 0x01 }); //capability flag. + response.WriteLength(IdToken.Length); + response.Write(IdToken); + + response.Position = 0; + return Task.FromResult(response.Buffer); + } + } +} diff --git a/MySQL.Data/src/Authentication/SSPI/Const.cs b/MySQL.Data/src/Authentication/SSPI/Const.cs index f4c96688b..de84e35ca 100644 --- a/MySQL.Data/src/Authentication/SSPI/Const.cs +++ b/MySQL.Data/src/Authentication/SSPI/Const.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/Authentication/SSPI/NativeMethods.cs b/MySQL.Data/src/Authentication/SSPI/NativeMethods.cs index d081ac083..3cc1277ca 100644 --- a/MySQL.Data/src/Authentication/SSPI/NativeMethods.cs +++ b/MySQL.Data/src/Authentication/SSPI/NativeMethods.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/Authentication/SSPI/SspiCredentials.cs b/MySQL.Data/src/Authentication/SSPI/SspiCredentials.cs index 5084a2296..682401d24 100644 --- a/MySQL.Data/src/Authentication/SSPI/SspiCredentials.cs +++ b/MySQL.Data/src/Authentication/SSPI/SspiCredentials.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/Authentication/SSPI/SspiSecurityContext.cs b/MySQL.Data/src/Authentication/SSPI/SspiSecurityContext.cs index 061e71d46..0f04fd1b0 100644 --- a/MySQL.Data/src/Authentication/SSPI/SspiSecurityContext.cs +++ b/MySQL.Data/src/Authentication/SSPI/SspiSecurityContext.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/Authentication/SSPI/Structs.cs b/MySQL.Data/src/Authentication/SSPI/Structs.cs index da1a80d31..15d329fb4 100644 --- a/MySQL.Data/src/Authentication/SSPI/Structs.cs +++ b/MySQL.Data/src/Authentication/SSPI/Structs.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/Authentication/ScramBase.cs b/MySQL.Data/src/Authentication/ScramBase.cs index c5ebdf68a..1a6a36192 100644 --- a/MySQL.Data/src/Authentication/ScramBase.cs +++ b/MySQL.Data/src/Authentication/ScramBase.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2020, Oracle and/or its affiliates. +// Copyright © 2020, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -279,4 +279,4 @@ static Dictionary ParseServerChallenge(string challenge) return results; } } -} \ No newline at end of file +} diff --git a/MySQL.Data/src/Authentication/ScramSha1Mechanism.cs b/MySQL.Data/src/Authentication/ScramSha1Mechanism.cs index f4d9ab8bb..d3e8ca6f8 100644 --- a/MySQL.Data/src/Authentication/ScramSha1Mechanism.cs +++ b/MySQL.Data/src/Authentication/ScramSha1Mechanism.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2020, Oracle and/or its affiliates. +// Copyright © 2020, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -69,4 +69,4 @@ protected override byte[] Hash(byte[] str) return sha1.ComputeHash(str); } } -} \ No newline at end of file +} diff --git a/MySQL.Data/src/Authentication/ScramSha256Mechanism.cs b/MySQL.Data/src/Authentication/ScramSha256Mechanism.cs index 3fed845d3..807d81853 100644 --- a/MySQL.Data/src/Authentication/ScramSha256Mechanism.cs +++ b/MySQL.Data/src/Authentication/ScramSha256Mechanism.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2020, Oracle and/or its affiliates. +// Copyright © 2020, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -69,4 +69,4 @@ protected override byte[] Hash(byte[] str) return sha256.ComputeHash(str); } } -} \ No newline at end of file +} diff --git a/MySQL.Data/src/Authentication/Sha256AuthenticationPlugin.cs b/MySQL.Data/src/Authentication/Sha256AuthenticationPlugin.cs index ec0e2f94b..b6882ea70 100644 --- a/MySQL.Data/src/Authentication/Sha256AuthenticationPlugin.cs +++ b/MySQL.Data/src/Authentication/Sha256AuthenticationPlugin.cs @@ -1,126 +1,126 @@ -// Copyright (c) 2013, 2022, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using System; -using System.Security.Cryptography; -using System.Text; -using System.Threading.Tasks; - -namespace MySql.Data.MySqlClient.Authentication -{ - /// - /// The implementation of the sha256_password authentication plugin. - /// - internal class Sha256AuthenticationPlugin : MySqlAuthenticationPlugin - { - /// - /// The byte array representation of the public key provided by the server. - /// - protected byte[] rawPubkey; - - public override string PluginName => "sha256_password"; - - protected override Task MoreDataAsync(byte[] data, bool execAsync) - { - rawPubkey = data; - byte[] buffer = GetNonLengthEncodedPassword(); - return Task.FromResult(buffer); - } - - public override object GetPassword() - { - if (Settings.SslMode != MySqlSslMode.Disabled) - { - // send as clear text, since the channel is already encrypted - byte[] passBytes = Encoding.GetBytes(GetMFAPassword()); - byte[] buffer = new byte[passBytes.Length + 2]; - Array.Copy(passBytes, 0, buffer, 1, passBytes.Length); - buffer[0] = (byte)(passBytes.Length + 1); - buffer[buffer.Length - 1] = 0x00; - return buffer; - } - else - { - if (GetMFAPassword().Length == 0) return new byte[1]; - // send RSA encrypted, since the channel is not protected - else if (rawPubkey == null) return new byte[] { 0x01 }; - else if (!Settings.AllowPublicKeyRetrieval) - throw new MySqlException(Resources.RSAPublicKeyRetrievalNotEnabled); - else - { - byte[] bytes = GetRsaPassword(GetMFAPassword(), AuthenticationData, rawPubkey); - if (bytes != null && bytes.Length == 1 && bytes[0] == 0) return null; - return bytes; - } - } - } - - private byte[] GetNonLengthEncodedPassword() - { - // Required for AuthChange requests. - if (Settings.SslMode != MySqlSslMode.Disabled) - { - // Send as clear text, since the channel is already encrypted. - byte[] passBytes = Encoding.GetBytes(GetMFAPassword()); - byte[] buffer = new byte[passBytes.Length + 1]; - Array.Copy(passBytes, 0, buffer, 0, passBytes.Length); - buffer[passBytes.Length] = 0; - return buffer; - } - else return GetPassword() as byte[]; - } - - private byte[] GetRsaPassword(string password, byte[] seedBytes, byte[] rawPublicKey) - { - if (password.Length == 0) return new byte[1]; - // Obfuscate the plain text password with the session scramble - byte[] obfuscated = GetXor(Encoding.Default.GetBytes(password), seedBytes); - // Encrypt the password and send it to the server - RSACryptoServiceProvider rsa = MySqlPemReader.ConvertPemToRSAProvider(rawPublicKey); - if (rsa == null) throw new MySqlException(Resources.UnableToReadRSAKey); - return rsa.Encrypt(obfuscated, true); - } - - /// - /// Applies XOR to the byte arrays provided as input. - /// - /// A byte array that contains the results of the XOR operation. - protected byte[] GetXor(byte[] src, byte[] pattern) - { - byte[] src2 = new byte[src.Length + 1]; - Array.Copy(src, 0, src2, 0, src.Length); - src2[src.Length] = 0; - byte[] result = new byte[src2.Length]; - for (int i = 0; i < src2.Length; i++) - { - result[i] = (byte)(src2[i] ^ (pattern[i % pattern.Length])); - } - return result; - } - } -} +// Copyright © 2013, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using System; +using System.Security.Cryptography; +using System.Text; +using System.Threading.Tasks; + +namespace MySql.Data.MySqlClient.Authentication +{ + /// + /// The implementation of the sha256_password authentication plugin. + /// + internal class Sha256AuthenticationPlugin : MySqlAuthenticationPlugin + { + /// + /// The byte array representation of the public key provided by the server. + /// + protected byte[] rawPubkey; + + public override string PluginName => "sha256_password"; + + protected override Task MoreDataAsync(byte[] data, bool execAsync) + { + rawPubkey = data; + byte[] buffer = GetNonLengthEncodedPassword(); + return Task.FromResult(buffer); + } + + public override object GetPassword() + { + if (Settings.SslMode != MySqlSslMode.Disabled) + { + // send as clear text, since the channel is already encrypted + byte[] passBytes = Encoding.GetBytes(GetMFAPassword()); + byte[] buffer = new byte[passBytes.Length + 2]; + Array.Copy(passBytes, 0, buffer, 1, passBytes.Length); + buffer[0] = (byte)(passBytes.Length + 1); + buffer[buffer.Length - 1] = 0x00; + return buffer; + } + else + { + if (GetMFAPassword().Length == 0) return new byte[1]; + // send RSA encrypted, since the channel is not protected + else if (rawPubkey == null) return new byte[] { 0x01 }; + else if (!Settings.AllowPublicKeyRetrieval) + throw new MySqlException(Resources.RSAPublicKeyRetrievalNotEnabled); + else + { + byte[] bytes = GetRsaPassword(GetMFAPassword(), AuthenticationData, rawPubkey); + if (bytes != null && bytes.Length == 1 && bytes[0] == 0) return null; + return bytes; + } + } + } + + private byte[] GetNonLengthEncodedPassword() + { + // Required for AuthChange requests. + if (Settings.SslMode != MySqlSslMode.Disabled) + { + // Send as clear text, since the channel is already encrypted. + byte[] passBytes = Encoding.GetBytes(GetMFAPassword()); + byte[] buffer = new byte[passBytes.Length + 1]; + Array.Copy(passBytes, 0, buffer, 0, passBytes.Length); + buffer[passBytes.Length] = 0; + return buffer; + } + else return GetPassword() as byte[]; + } + + private byte[] GetRsaPassword(string password, byte[] seedBytes, byte[] rawPublicKey) + { + if (password.Length == 0) return new byte[1]; + // Obfuscate the plain text password with the session scramble + byte[] obfuscated = GetXor(Encoding.Default.GetBytes(password), seedBytes); + // Encrypt the password and send it to the server + RSACryptoServiceProvider rsa = MySqlPemReader.ConvertPemToRSAProvider(rawPublicKey); + if (rsa == null) throw new MySqlException(Resources.UnableToReadRSAKey); + return rsa.Encrypt(obfuscated, true); + } + + /// + /// Applies XOR to the byte arrays provided as input. + /// + /// A byte array that contains the results of the XOR operation. + protected byte[] GetXor(byte[] src, byte[] pattern) + { + byte[] src2 = new byte[src.Length + 1]; + Array.Copy(src, 0, src2, 0, src.Length); + src2[src.Length] = 0; + byte[] result = new byte[src2.Length]; + for (int i = 0; i < src2.Length; i++) + { + result[i] = (byte)(src2[i] ^ (pattern[i % pattern.Length])); + } + return result; + } + } +} diff --git a/MySQL.Data/src/Authentication/Sha256MemoryAuthenticationPlugin.cs b/MySQL.Data/src/Authentication/Sha256MemoryAuthenticationPlugin.cs index 8a079b919..8c6a6161c 100644 --- a/MySQL.Data/src/Authentication/Sha256MemoryAuthenticationPlugin.cs +++ b/MySQL.Data/src/Authentication/Sha256MemoryAuthenticationPlugin.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2018, 2021, Oracle and/or its affiliates. +// Copyright © 2018, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/Authentication/WebAuthnAuthenticationPlugin.cs b/MySQL.Data/src/Authentication/WebAuthnAuthenticationPlugin.cs index 51b790d0b..08375cae9 100644 --- a/MySQL.Data/src/Authentication/WebAuthnAuthenticationPlugin.cs +++ b/MySQL.Data/src/Authentication/WebAuthnAuthenticationPlugin.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2023, Oracle and/or its affiliates. +// Copyright © 2023, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/Authentication/WindowsAuthenticationPlugin.cs b/MySQL.Data/src/Authentication/WindowsAuthenticationPlugin.cs index a9ff97542..393c52967 100644 --- a/MySQL.Data/src/Authentication/WindowsAuthenticationPlugin.cs +++ b/MySQL.Data/src/Authentication/WindowsAuthenticationPlugin.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2012, 2022, Oracle and/or its affiliates. +// Copyright © 2012, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/BulkLoader.cs b/MySQL.Data/src/BulkLoader.cs index 97dd6d869..3d9d80359 100644 --- a/MySQL.Data/src/BulkLoader.cs +++ b/MySQL.Data/src/BulkLoader.cs @@ -1,365 +1,365 @@ -// Copyright (c) 2006, 2023, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using System; -using System.Collections.Generic; -using System.Data; -using System.IO; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace MySql.Data.MySqlClient -{ - /// - /// Allows importing large amounts of data into a database with bulk loading. - /// - public class MySqlBulkLoader - { - // constant values - private const string defaultFieldTerminator = "\t"; - private const string defaultLineTerminator = "\n"; - private const char defaultEscapeCharacter = '\\'; - - /// - /// Initializes a new instance of the class using the specified instance of . - /// - /// The that will be used to perform the bulk operation. - public MySqlBulkLoader(MySqlConnection connection) - { - Connection = connection; - Local = false; - FieldTerminator = defaultFieldTerminator; - LineTerminator = defaultLineTerminator; - FieldQuotationCharacter = Char.MinValue; - ConflictOption = MySqlBulkLoaderConflictOption.None; - Columns = new List(); - Expressions = new List(); - } - - #region Properties - - /// - /// Gets or sets the connection. - /// - /// The connection. - public MySqlConnection Connection { get; set; } - - /// - /// Gets or sets the field terminator. - /// - /// The field terminator. - public string FieldTerminator { get; set; } - - /// - /// Gets or sets the line terminator. - /// - /// The line terminator. - public string LineTerminator { get; set; } - - /// - /// Gets or sets the name of the table. - /// - /// The name of the table. - public string TableName { get; set; } - - /// - /// Gets or sets the character set. - /// - /// The character set. - public string CharacterSet { get; set; } - - /// - /// Gets or sets the name of the file. - /// - /// The name of the file. - public string FileName { get; set; } - - /// - /// Gets or sets the timeout. - /// - /// The timeout. - public int Timeout { get; set; } - - /// - /// Gets or sets a value indicating whether the file name that is to be loaded - /// is local to the client or not. The default value is false. - /// - /// true if local; otherwise, false. - public bool Local { get; set; } - - /// - /// Gets or sets the number of lines to skip. - /// - /// The number of lines to skip. - public int NumberOfLinesToSkip { get; set; } - - /// - /// Gets or sets the line prefix. - /// - /// The line prefix. - public string LinePrefix { get; set; } - - /// - /// Gets or sets the field quotation character. - /// - /// The field quotation character. - public char FieldQuotationCharacter { get; set; } - - /// - /// Gets or sets a value indicating whether [field quotation optional]. - /// - /// - /// true if [field quotation optional]; otherwise, false. - /// - public bool FieldQuotationOptional { get; set; } - - /// - /// Gets or sets the escape character. - /// - /// The escape character. - public char EscapeCharacter { get; set; } - - /// - /// Gets or sets the conflict option. - /// - /// The conflict option. - public MySqlBulkLoaderConflictOption ConflictOption { get; set; } - - /// - /// Gets or sets the priority. - /// - /// The priority. - public MySqlBulkLoaderPriority Priority { get; set; } - - /// - /// Gets the columns. - /// - /// The columns. - public List Columns { get; } - - /// - /// Gets the expressions. - /// - /// The expressions. - public List Expressions { get; } - - #endregion - - /// - /// Executes the load operation. - /// - /// The number of rows inserted. - public int Load() - { - if (string.IsNullOrWhiteSpace(FileName)) - throw new MySqlException("FileName property of MySqlBulkLoader cannot be null or an empty string."); - - return LoadAsync(null, false).GetAwaiter().GetResult(); - } - - /// - /// Executes the load operation. - /// - /// A object containing the data to be loaded. - /// The number of rows inserted. - public int Load(Stream stream) => LoadAsync(stream, false).GetAwaiter().GetResult(); - - /// - /// Asynchronous version of the load operation. - /// - /// The number of rows inserted. - public Task LoadAsync() => LoadAsync(null, true); - - /// - /// Asynchronous version of the load operation that accepts a data stream. - /// - /// A containing the data to be loaded. - /// The number of rows inserted. - public Task LoadAsync(Stream stream) => LoadAsync(stream, true); - - /// - /// Executes the load operation asynchronously while the cancellation isn't requested. - /// - /// The cancellation token. - /// A containing the data to be loaded. - /// The number of rows inserted. - public Task LoadAsync(Stream stream, CancellationToken cancellationToken) => LoadAsync(stream, true, cancellationToken); - - private async Task LoadAsync(Stream stream, bool execAsync, CancellationToken cancellationToken = default) - { - bool openedConnection = false; - - if (Connection == null) - throw new InvalidOperationException(Resources.ConnectionNotSet); - - // next we open up the connetion if it is not already open - if (Connection.State != ConnectionState.Open) - { - await Connection.OpenAsync(execAsync, cancellationToken).ConfigureAwait(false); - openedConnection = true; - } - - try - { - string sql = BuildSqlCommand(stream is not null); - Connection.driver.BulkLoaderStream = stream; - using MySqlCommand cmd = new MySqlCommand(sql, Connection) { CommandTimeout = Timeout }; - return await cmd.ExecuteNonQueryAsync(execAsync, cancellationToken).ConfigureAwait(false); - } - finally - { - if (stream is not null) - Connection.driver.BulkLoaderStream.Dispose(); - - if (openedConnection) - await Connection.CloseAsync(execAsync).ConfigureAwait(false); - } - } - - private string BuildSqlCommand(bool useStream) - { - StringBuilder sql = new StringBuilder("LOAD DATA "); - if (Priority == MySqlBulkLoaderPriority.Low) - sql.Append("LOW_PRIORITY "); - else if (Priority == MySqlBulkLoaderPriority.Concurrent) - sql.Append("CONCURRENT "); - - if (useStream) - sql.Append("LOCAL INFILE 'MySQLTempFile' "); - else - { - if (Local) - sql.Append("LOCAL "); - - sql.Append("INFILE "); - - if (Path.DirectorySeparatorChar == '\\') - sql.AppendFormat("'{0}' ", FileName.Replace(@"\", @"\\")); - else - sql.AppendFormat("'{0}' ", FileName); - } - - if (ConflictOption == MySqlBulkLoaderConflictOption.Ignore) - sql.Append("IGNORE "); - else if (ConflictOption == MySqlBulkLoaderConflictOption.Replace) - sql.Append("REPLACE "); - - sql.AppendFormat("INTO TABLE {0} ", TableName); - - if (CharacterSet != null) - sql.AppendFormat("CHARACTER SET {0} ", CharacterSet); - - StringBuilder optionSql = new StringBuilder(String.Empty); - if (FieldTerminator != defaultFieldTerminator) - optionSql.AppendFormat("TERMINATED BY '{0}' ", FieldTerminator); - if (FieldQuotationCharacter != Char.MinValue) - optionSql.AppendFormat("{0} ENCLOSED BY '{1}' ", - FieldQuotationOptional ? "OPTIONALLY" : "", FieldQuotationCharacter); - if (EscapeCharacter != defaultEscapeCharacter && - EscapeCharacter != Char.MinValue) - optionSql.AppendFormat("ESCAPED BY '{0}' ", EscapeCharacter); - if (optionSql.Length > 0) - sql.AppendFormat("FIELDS {0}", optionSql.ToString()); - - optionSql = new StringBuilder(String.Empty); - if (!string.IsNullOrEmpty(LinePrefix)) - optionSql.AppendFormat("STARTING BY '{0}' ", LinePrefix); - if (LineTerminator != defaultLineTerminator) - optionSql.AppendFormat("TERMINATED BY '{0}' ", LineTerminator); - if (optionSql.Length > 0) - sql.AppendFormat("LINES {0}", optionSql.ToString()); - - if (NumberOfLinesToSkip > 0) - sql.AppendFormat("IGNORE {0} LINES ", NumberOfLinesToSkip); - - if (Columns.Count > 0) - { - sql.Append("("); - sql.Append(Columns[0]); - for (int i = 1; i < Columns.Count; i++) - sql.AppendFormat(",{0}", Columns[i]); - sql.Append(") "); - } - - if (Expressions.Count > 0) - { - sql.Append("SET "); - sql.Append(Expressions[0]); - for (int i = 1; i < Expressions.Count; i++) - sql.AppendFormat(",{0}", Expressions[i]); - } - - return sql.ToString(); - } - } - - /// - /// Represents the priority set for bulk loading operations. - /// - public enum MySqlBulkLoaderPriority - { - /// - /// This is the default and indicates normal priority - /// - None, - /// - /// Low priority will cause the load operation to wait until all readers of the table - /// have finished. This only affects storage engines that use only table-level locking - /// such as MyISAM, Memory, and Merge. - /// - Low, - /// - /// Concurrent priority is only relevant for MyISAM tables and signals that if the table - /// has no free blocks in the middle that other readers can retrieve data from the table - /// while the load operation is happening. - /// - Concurrent - } - - /// - /// Represents the behavior when conflicts arise during bulk loading operations. - /// - public enum MySqlBulkLoaderConflictOption - { - /// - /// This is the default and indicates normal operation. In the event of a LOCAL load, this - /// is the same as ignore. When the data file is on the server, then a key conflict will - /// cause an error to be thrown and the rest of the data file ignored. - /// - None, - /// - /// Replace column values when a key conflict occurs. - /// - Replace, - /// - /// Ignore any rows where the primary key conflicts. - /// - Ignore - } -} +// Copyright © 2006, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using System; +using System.Collections.Generic; +using System.Data; +using System.IO; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace MySql.Data.MySqlClient +{ + /// + /// Allows importing large amounts of data into a database with bulk loading. + /// + public class MySqlBulkLoader + { + // constant values + private const string defaultFieldTerminator = "\t"; + private const string defaultLineTerminator = "\n"; + private const char defaultEscapeCharacter = '\\'; + + /// + /// Initializes a new instance of the class using the specified instance of . + /// + /// The that will be used to perform the bulk operation. + public MySqlBulkLoader(MySqlConnection connection) + { + Connection = connection; + Local = false; + FieldTerminator = defaultFieldTerminator; + LineTerminator = defaultLineTerminator; + FieldQuotationCharacter = Char.MinValue; + ConflictOption = MySqlBulkLoaderConflictOption.None; + Columns = new List(); + Expressions = new List(); + } + + #region Properties + + /// + /// Gets or sets the connection. + /// + /// The connection. + public MySqlConnection Connection { get; set; } + + /// + /// Gets or sets the field terminator. + /// + /// The field terminator. + public string FieldTerminator { get; set; } + + /// + /// Gets or sets the line terminator. + /// + /// The line terminator. + public string LineTerminator { get; set; } + + /// + /// Gets or sets the name of the table. + /// + /// The name of the table. + public string TableName { get; set; } + + /// + /// Gets or sets the character set. + /// + /// The character set. + public string CharacterSet { get; set; } + + /// + /// Gets or sets the name of the file. + /// + /// The name of the file. + public string FileName { get; set; } + + /// + /// Gets or sets the timeout. + /// + /// The timeout. + public int Timeout { get; set; } + + /// + /// Gets or sets a value indicating whether the file name that is to be loaded + /// is local to the client or not. The default value is false. + /// + /// true if local; otherwise, false. + public bool Local { get; set; } + + /// + /// Gets or sets the number of lines to skip. + /// + /// The number of lines to skip. + public int NumberOfLinesToSkip { get; set; } + + /// + /// Gets or sets the line prefix. + /// + /// The line prefix. + public string LinePrefix { get; set; } + + /// + /// Gets or sets the field quotation character. + /// + /// The field quotation character. + public char FieldQuotationCharacter { get; set; } + + /// + /// Gets or sets a value indicating whether [field quotation optional]. + /// + /// + /// true if [field quotation optional]; otherwise, false. + /// + public bool FieldQuotationOptional { get; set; } + + /// + /// Gets or sets the escape character. + /// + /// The escape character. + public char EscapeCharacter { get; set; } + + /// + /// Gets or sets the conflict option. + /// + /// The conflict option. + public MySqlBulkLoaderConflictOption ConflictOption { get; set; } + + /// + /// Gets or sets the priority. + /// + /// The priority. + public MySqlBulkLoaderPriority Priority { get; set; } + + /// + /// Gets the columns. + /// + /// The columns. + public List Columns { get; } + + /// + /// Gets the expressions. + /// + /// The expressions. + public List Expressions { get; } + + #endregion + + /// + /// Executes the load operation. + /// + /// The number of rows inserted. + public int Load() + { + if (string.IsNullOrWhiteSpace(FileName)) + throw new MySqlException("FileName property of MySqlBulkLoader cannot be null or an empty string."); + + return LoadAsync(null, false).GetAwaiter().GetResult(); + } + + /// + /// Executes the load operation. + /// + /// A object containing the data to be loaded. + /// The number of rows inserted. + public int Load(Stream stream) => LoadAsync(stream, false).GetAwaiter().GetResult(); + + /// + /// Asynchronous version of the load operation. + /// + /// The number of rows inserted. + public Task LoadAsync() => LoadAsync(null, true); + + /// + /// Asynchronous version of the load operation that accepts a data stream. + /// + /// A containing the data to be loaded. + /// The number of rows inserted. + public Task LoadAsync(Stream stream) => LoadAsync(stream, true); + + /// + /// Executes the load operation asynchronously while the cancellation isn't requested. + /// + /// The cancellation token. + /// A containing the data to be loaded. + /// The number of rows inserted. + public Task LoadAsync(Stream stream, CancellationToken cancellationToken) => LoadAsync(stream, true, cancellationToken); + + private async Task LoadAsync(Stream stream, bool execAsync, CancellationToken cancellationToken = default) + { + bool openedConnection = false; + + if (Connection == null) + throw new InvalidOperationException(Resources.ConnectionNotSet); + + // next we open up the connetion if it is not already open + if (Connection.State != ConnectionState.Open) + { + await Connection.OpenAsync(execAsync, cancellationToken).ConfigureAwait(false); + openedConnection = true; + } + + try + { + string sql = BuildSqlCommand(stream is not null); + Connection.driver.BulkLoaderStream = stream; + using MySqlCommand cmd = new MySqlCommand(sql, Connection) { CommandTimeout = Timeout }; + return await cmd.ExecuteNonQueryAsync(execAsync, cancellationToken).ConfigureAwait(false); + } + finally + { + if (stream is not null) + Connection.driver.BulkLoaderStream.Dispose(); + + if (openedConnection) + await Connection.CloseAsync(execAsync).ConfigureAwait(false); + } + } + + private string BuildSqlCommand(bool useStream) + { + StringBuilder sql = new StringBuilder("LOAD DATA "); + if (Priority == MySqlBulkLoaderPriority.Low) + sql.Append("LOW_PRIORITY "); + else if (Priority == MySqlBulkLoaderPriority.Concurrent) + sql.Append("CONCURRENT "); + + if (useStream) + sql.Append("LOCAL INFILE 'MySQLTempFile' "); + else + { + if (Local) + sql.Append("LOCAL "); + + sql.Append("INFILE "); + + if (Path.DirectorySeparatorChar == '\\') + sql.AppendFormat("'{0}' ", FileName.Replace(@"\", @"\\")); + else + sql.AppendFormat("'{0}' ", FileName); + } + + if (ConflictOption == MySqlBulkLoaderConflictOption.Ignore) + sql.Append("IGNORE "); + else if (ConflictOption == MySqlBulkLoaderConflictOption.Replace) + sql.Append("REPLACE "); + + sql.AppendFormat("INTO TABLE {0} ", TableName); + + if (CharacterSet != null) + sql.AppendFormat("CHARACTER SET {0} ", CharacterSet); + + StringBuilder optionSql = new StringBuilder(String.Empty); + if (FieldTerminator != defaultFieldTerminator) + optionSql.AppendFormat("TERMINATED BY '{0}' ", FieldTerminator); + if (FieldQuotationCharacter != Char.MinValue) + optionSql.AppendFormat("{0} ENCLOSED BY '{1}' ", + FieldQuotationOptional ? "OPTIONALLY" : "", FieldQuotationCharacter); + if (EscapeCharacter != defaultEscapeCharacter && + EscapeCharacter != Char.MinValue) + optionSql.AppendFormat("ESCAPED BY '{0}' ", EscapeCharacter); + if (optionSql.Length > 0) + sql.AppendFormat("FIELDS {0}", optionSql.ToString()); + + optionSql = new StringBuilder(String.Empty); + if (!string.IsNullOrEmpty(LinePrefix)) + optionSql.AppendFormat("STARTING BY '{0}' ", LinePrefix); + if (LineTerminator != defaultLineTerminator) + optionSql.AppendFormat("TERMINATED BY '{0}' ", LineTerminator); + if (optionSql.Length > 0) + sql.AppendFormat("LINES {0}", optionSql.ToString()); + + if (NumberOfLinesToSkip > 0) + sql.AppendFormat("IGNORE {0} LINES ", NumberOfLinesToSkip); + + if (Columns.Count > 0) + { + sql.Append("("); + sql.Append(Columns[0]); + for (int i = 1; i < Columns.Count; i++) + sql.AppendFormat(",{0}", Columns[i]); + sql.Append(") "); + } + + if (Expressions.Count > 0) + { + sql.Append("SET "); + sql.Append(Expressions[0]); + for (int i = 1; i < Expressions.Count; i++) + sql.AppendFormat(",{0}", Expressions[i]); + } + + return sql.ToString(); + } + } + + /// + /// Represents the priority set for bulk loading operations. + /// + public enum MySqlBulkLoaderPriority + { + /// + /// This is the default and indicates normal priority + /// + None, + /// + /// Low priority will cause the load operation to wait until all readers of the table + /// have finished. This only affects storage engines that use only table-level locking + /// such as MyISAM, Memory, and Merge. + /// + Low, + /// + /// Concurrent priority is only relevant for MyISAM tables and signals that if the table + /// has no free blocks in the middle that other readers can retrieve data from the table + /// while the load operation is happening. + /// + Concurrent + } + + /// + /// Represents the behavior when conflicts arise during bulk loading operations. + /// + public enum MySqlBulkLoaderConflictOption + { + /// + /// This is the default and indicates normal operation. In the event of a LOCAL load, this + /// is the same as ignore. When the data file is on the server, then a key conflict will + /// cause an error to be thrown and the rest of the data file ignored. + /// + None, + /// + /// Replace column values when a key conflict occurs. + /// + Replace, + /// + /// Ignore any rows where the primary key conflicts. + /// + Ignore + } +} diff --git a/MySQL.Data/src/CharSetMap.cs b/MySQL.Data/src/CharSetMap.cs index 553ca4160..2d4f18e7d 100644 --- a/MySQL.Data/src/CharSetMap.cs +++ b/MySQL.Data/src/CharSetMap.cs @@ -1,230 +1,244 @@ -// Copyright (c) 2004, 2022, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace MySql.Data.MySqlClient -{ - /// - /// Summary description for CharSetMap. - /// - internal class CharSetMap - { - private static Dictionary _defaultCollations; - private static Dictionary _maxLengths; - private static Dictionary _mapping; - private static readonly object LockObject; - - // we use a static constructor here since we only want to init - // the mapping once - static CharSetMap() - { - LockObject = new Object(); - InitializeMapping(); - } - - public static CharacterSet GetCharacterSet(string charSetName) - { - if (charSetName == null) - throw new ArgumentNullException("CharSetName is null"); - CharacterSet cs = null; - if (_mapping.ContainsKey(charSetName)) - cs = _mapping[charSetName]; - - if (cs == null) - throw new NotSupportedException("Character set '" + charSetName + "' is not supported by .Net Framework."); - return cs; - } - - /// - /// Returns the text encoding for a given MySQL character set name - /// - /// Name of the character set to get the encoding for - /// Encoding object for the given character set name - public static Encoding GetEncoding(string charSetName) - { - try - { - CharacterSet cs = GetCharacterSet(charSetName); - - return Encoding.GetEncoding(cs.name); - } - catch (ArgumentException) - { - return Encoding.GetEncoding("utf-8"); - } - catch (NotSupportedException) - { - return Encoding.GetEncoding("utf-8"); - } - } - - /// - /// Initializes the mapping. - /// - private static void InitializeMapping() - { - LoadCharsetMap(); - } - - private static void LoadCharsetMap() - { - _mapping = new Dictionary(); - - _mapping.Add("latin1", new CharacterSet("windows-1252", 1)); - _mapping.Add("big5", new CharacterSet("big5", 2)); - _mapping.Add("dec8", _mapping["latin1"]); - _mapping.Add("cp850", new CharacterSet("ibm850", 1)); - _mapping.Add("hp8", _mapping["latin1"]); - _mapping.Add("koi8r", new CharacterSet("koi8-u", 1)); - _mapping.Add("latin2", new CharacterSet("latin2", 1)); - _mapping.Add("swe7", _mapping["latin1"]); - _mapping.Add("ujis", new CharacterSet("EUC-JP", 3)); - _mapping.Add("eucjpms", _mapping["ujis"]); - _mapping.Add("sjis", new CharacterSet("sjis", 2)); - _mapping.Add("cp932", _mapping["sjis"]); - _mapping.Add("hebrew", new CharacterSet("hebrew", 1)); - _mapping.Add("tis620", new CharacterSet("windows-874", 1)); - _mapping.Add("euckr", new CharacterSet("euc-kr", 2)); - _mapping.Add("euc_kr", _mapping["euckr"]); - _mapping.Add("koi8u", new CharacterSet("koi8-u", 1)); - _mapping.Add("koi8_ru", _mapping["koi8u"]); - _mapping.Add("gb2312", new CharacterSet("gb2312", 2)); - _mapping.Add("gbk", _mapping["gb2312"]); - _mapping.Add("greek", new CharacterSet("greek", 1)); - _mapping.Add("cp1250", new CharacterSet("windows-1250", 1)); - _mapping.Add("win1250", _mapping["cp1250"]); - _mapping.Add("latin5", new CharacterSet("latin5", 1)); - _mapping.Add("armscii8", _mapping["latin1"]); - _mapping.Add("utf8", new CharacterSet("utf-8", 3)); - _mapping.Add("ucs2", new CharacterSet("UTF-16BE", 2)); - _mapping.Add("cp866", new CharacterSet("cp866", 1)); - _mapping.Add("keybcs2", _mapping["latin1"]); - _mapping.Add("macce", new CharacterSet("x-mac-ce", 1)); - _mapping.Add("macroman", new CharacterSet("x-mac-romanian", 1)); - _mapping.Add("cp852", new CharacterSet("ibm852", 2)); - _mapping.Add("latin7", new CharacterSet("iso-8859-7", 1)); - _mapping.Add("cp1251", new CharacterSet("windows-1251", 1)); - _mapping.Add("win1251ukr", _mapping["cp1251"]); - _mapping.Add("cp1251csas", _mapping["cp1251"]); - _mapping.Add("cp1251cias", _mapping["cp1251"]); - _mapping.Add("win1251", _mapping["cp1251"]); - _mapping.Add("cp1256", new CharacterSet("cp1256", 1)); - _mapping.Add("cp1257", new CharacterSet("windows-1257", 1)); - _mapping.Add("ascii", new CharacterSet("us-ascii", 1)); - _mapping.Add("usa7", _mapping["ascii"]); - _mapping.Add("binary", _mapping["ascii"]); - _mapping.Add("latin3", new CharacterSet("latin3", 1)); - _mapping.Add("latin4", new CharacterSet("latin4", 1)); - _mapping.Add("latin1_de", new CharacterSet("iso-8859-1", 1)); - _mapping.Add("german1", new CharacterSet("iso-8859-1", 1)); - _mapping.Add("danish", new CharacterSet("iso-8859-1", 1)); - _mapping.Add("czech", new CharacterSet("iso-8859-2", 1)); - _mapping.Add("hungarian", new CharacterSet("iso-8859-2", 1)); - _mapping.Add("croat", new CharacterSet("iso-8859-2", 1)); - _mapping.Add("latvian", new CharacterSet("iso-8859-13", 1)); - _mapping.Add("latvian1", new CharacterSet("iso-8859-13", 1)); - _mapping.Add("estonia", new CharacterSet("iso-8859-13", 1)); - _mapping.Add("dos", new CharacterSet("ibm437", 1)); - _mapping.Add("utf8mb3", _mapping["utf8"]); - _mapping.Add("utf8mb4", new CharacterSet("utf-8", 4)); - _mapping.Add("utf16", new CharacterSet("utf-16BE", 2)); - _mapping.Add("utf16le", new CharacterSet("utf-16", 2)); - _mapping.Add("utf32", new CharacterSet("utf-32BE", 4)); - _mapping.Add("gb18030", new CharacterSet("gb18030", 4)); - } - - internal static async Task InitCollectionsAsync(MySqlConnection connection, bool execAsync, CancellationToken cancellationToken = default) - { - _defaultCollations = new Dictionary(); - _maxLengths = new Dictionary(); - - MySqlCommand cmd = new MySqlCommand("SHOW CHARSET", connection); - using (MySqlDataReader reader = await cmd.ExecuteReaderAsync(default, execAsync, cancellationToken).ConfigureAwait(false)) - { - while (await reader.ReadAsync(execAsync, cancellationToken).ConfigureAwait(false)) - { - _defaultCollations.Add(reader.GetString(0), reader.GetString(2)); - _maxLengths.Add(reader.GetString(0), Convert.ToInt32(reader.GetValue(3))); - } - } - } - - internal static async Task GetDefaultCollationAsync(string charset, MySqlConnection connection, bool execAsync, CancellationToken cancellationToken = default) - { - SemaphoreSlim semaphoreSlim = new SemaphoreSlim(1); - semaphoreSlim.Wait(); - - if (_defaultCollations == null) - await InitCollectionsAsync(connection, execAsync, cancellationToken).ConfigureAwait(false); - - semaphoreSlim.Release(); - return !_defaultCollations.ContainsKey(charset) ? null : _defaultCollations[charset]; - } - - internal static async Task GetMaxLengthAsync(string charset, MySqlConnection connection, bool execAsync, CancellationToken cancellationToken = default) - { - SemaphoreSlim semaphoreSlim = new SemaphoreSlim(1); - semaphoreSlim.Wait(); - - if (_maxLengths == null) - await InitCollectionsAsync(connection, execAsync, cancellationToken).ConfigureAwait(false); - - semaphoreSlim.Release(); - - return !_maxLengths.ContainsKey(charset) ? 1 : _maxLengths[charset]; - } - } - - /// - /// Represents a character set object. - /// - public class CharacterSet - { - public string name; - public int byteCount; - - public CharacterSet(string name, int byteCount) - { - this.name = name; - this.byteCount = byteCount; - } - - public override int GetHashCode() - { - unchecked - { - return ((name != null ? name.GetHashCode() : 0) * 397) ^ byteCount; - } - } - } -} \ No newline at end of file +// Copyright © 2004, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace MySql.Data.MySqlClient +{ + /// + /// Summary description for CharSetMap. + /// + internal class CharSetMap + { + private static Dictionary _defaultCollations; + private static Dictionary _maxLengths; + private static Dictionary _mapping; + private static SemaphoreSlim semaphoreSlim = new SemaphoreSlim(1, 1); + + // we use a static constructor here since we only want to init + // the mapping once + static CharSetMap() + { + InitializeMapping(); + } + + public static CharacterSet GetCharacterSet(string charSetName) + { + if (charSetName == null) + throw new ArgumentNullException("CharSetName is null"); + CharacterSet cs = null; + if (_mapping.TryGetValue(charSetName, out var charset)) + cs = charset; + + if (cs == null) + throw new NotSupportedException("Character set '" + charSetName + "' is not supported by .Net Framework."); + return cs; + } + + /// + /// Returns the text encoding for a given MySQL character set name + /// + /// Name of the character set to get the encoding for + /// Encoding object for the given character set name + public static Encoding GetEncoding(string charSetName) + { + try + { + CharacterSet cs = GetCharacterSet(charSetName); + + return Encoding.GetEncoding(cs.name); + } + catch (ArgumentException) + { + return Encoding.GetEncoding("utf-8"); + } + catch (NotSupportedException) + { + return Encoding.GetEncoding("utf-8"); + } + } + + /// + /// Initializes the mapping. + /// + private static void InitializeMapping() + { + LoadCharsetMap(); + } + + private static void LoadCharsetMap() + { + _mapping = new Dictionary(); + + _mapping.Add("latin1", new CharacterSet("windows-1252", 1)); + _mapping.Add("big5", new CharacterSet("big5", 2)); + _mapping.Add("dec8", _mapping["latin1"]); + _mapping.Add("cp850", new CharacterSet("ibm850", 1)); + _mapping.Add("hp8", _mapping["latin1"]); + _mapping.Add("koi8r", new CharacterSet("koi8-u", 1)); + _mapping.Add("latin2", new CharacterSet("latin2", 1)); + _mapping.Add("swe7", _mapping["latin1"]); + _mapping.Add("ujis", new CharacterSet("EUC-JP", 3)); + _mapping.Add("eucjpms", _mapping["ujis"]); + _mapping.Add("sjis", new CharacterSet("sjis", 2)); + _mapping.Add("cp932", _mapping["sjis"]); + _mapping.Add("hebrew", new CharacterSet("hebrew", 1)); + _mapping.Add("tis620", new CharacterSet("windows-874", 1)); + _mapping.Add("euckr", new CharacterSet("euc-kr", 2)); + _mapping.Add("euc_kr", _mapping["euckr"]); + _mapping.Add("koi8u", new CharacterSet("koi8-u", 1)); + _mapping.Add("koi8_ru", _mapping["koi8u"]); + _mapping.Add("gb2312", new CharacterSet("gb2312", 2)); + _mapping.Add("gbk", _mapping["gb2312"]); + _mapping.Add("greek", new CharacterSet("greek", 1)); + _mapping.Add("cp1250", new CharacterSet("windows-1250", 1)); + _mapping.Add("win1250", _mapping["cp1250"]); + _mapping.Add("latin5", new CharacterSet("latin5", 1)); + _mapping.Add("armscii8", _mapping["latin1"]); + _mapping.Add("utf8", new CharacterSet("utf-8", 3)); + _mapping.Add("ucs2", new CharacterSet("UTF-16BE", 2)); + _mapping.Add("cp866", new CharacterSet("cp866", 1)); + _mapping.Add("keybcs2", _mapping["latin1"]); + _mapping.Add("macce", new CharacterSet("x-mac-ce", 1)); + _mapping.Add("macroman", new CharacterSet("x-mac-romanian", 1)); + _mapping.Add("cp852", new CharacterSet("ibm852", 2)); + _mapping.Add("latin7", new CharacterSet("iso-8859-7", 1)); + _mapping.Add("cp1251", new CharacterSet("windows-1251", 1)); + _mapping.Add("win1251ukr", _mapping["cp1251"]); + _mapping.Add("cp1251csas", _mapping["cp1251"]); + _mapping.Add("cp1251cias", _mapping["cp1251"]); + _mapping.Add("win1251", _mapping["cp1251"]); + _mapping.Add("cp1256", new CharacterSet("cp1256", 1)); + _mapping.Add("cp1257", new CharacterSet("windows-1257", 1)); + _mapping.Add("ascii", new CharacterSet("us-ascii", 1)); + _mapping.Add("usa7", _mapping["ascii"]); + _mapping.Add("binary", _mapping["ascii"]); + _mapping.Add("latin3", new CharacterSet("latin3", 1)); + _mapping.Add("latin4", new CharacterSet("latin4", 1)); + _mapping.Add("latin1_de", new CharacterSet("iso-8859-1", 1)); + _mapping.Add("german1", new CharacterSet("iso-8859-1", 1)); + _mapping.Add("danish", new CharacterSet("iso-8859-1", 1)); + _mapping.Add("czech", new CharacterSet("iso-8859-2", 1)); + _mapping.Add("hungarian", new CharacterSet("iso-8859-2", 1)); + _mapping.Add("croat", new CharacterSet("iso-8859-2", 1)); + _mapping.Add("latvian", new CharacterSet("iso-8859-13", 1)); + _mapping.Add("latvian1", new CharacterSet("iso-8859-13", 1)); + _mapping.Add("estonia", new CharacterSet("iso-8859-13", 1)); + _mapping.Add("dos", new CharacterSet("ibm437", 1)); + _mapping.Add("utf8mb3", _mapping["utf8"]); + _mapping.Add("utf8mb4", new CharacterSet("utf-8", 4)); + _mapping.Add("utf16", new CharacterSet("utf-16BE", 2)); + _mapping.Add("utf16le", new CharacterSet("utf-16", 2)); + _mapping.Add("utf32", new CharacterSet("utf-32BE", 4)); + _mapping.Add("gb18030", new CharacterSet("gb18030", 4)); + } + + internal static async Task InitCollectionsAsync(MySqlConnection connection, bool execAsync, CancellationToken cancellationToken = default) + { + _defaultCollations = new Dictionary(); + _maxLengths = new Dictionary(); + + MySqlCommand cmd = new MySqlCommand("SHOW CHARSET", connection); + using (MySqlDataReader reader = await cmd.ExecuteReaderAsync(default, execAsync, cancellationToken).ConfigureAwait(false)) + { + while (await reader.ReadAsync(execAsync, cancellationToken).ConfigureAwait(false)) + { + _defaultCollations.Add(reader.GetString(0), reader.GetString(2)); + _maxLengths.Add(reader.GetString(0), Convert.ToInt32(reader.GetValue(3))); + } + } + } + + internal static async Task GetDefaultCollationAsync(string charset, MySqlConnection connection, bool execAsync, CancellationToken cancellationToken = default) + { + if (execAsync) + await semaphoreSlim.WaitAsync(cancellationToken); + else + semaphoreSlim.Wait(cancellationToken); + + try + { + if (_defaultCollations == null) + await InitCollectionsAsync(connection, execAsync, cancellationToken).ConfigureAwait(false); + } + finally + { + semaphoreSlim.Release(); + } + + return !_defaultCollations.TryGetValue(charset, out string collation) ? null : collation; + } + + internal static async Task GetMaxLengthAsync(string charset, MySqlConnection connection, bool execAsync, CancellationToken cancellationToken = default) + { + if (execAsync) + await semaphoreSlim.WaitAsync(cancellationToken); + else + semaphoreSlim.Wait(cancellationToken); + + try + { + if (_maxLengths == null) + await InitCollectionsAsync(connection, execAsync, cancellationToken).ConfigureAwait(false); + } + finally + { + semaphoreSlim.Release(); + } + + return !_maxLengths.TryGetValue(charset, out int maxLength) ? 1 : maxLength; + } + } + + /// + /// Represents a character set object. + /// + public class CharacterSet + { + public string name; + public int byteCount; + + public CharacterSet(string name, int byteCount) + { + this.name = name; + this.byteCount = byteCount; + } + + public override int GetHashCode() + { + unchecked + { + return ((name != null ? name.GetHashCode() : 0) * 397) ^ byteCount; + } + } + } +} diff --git a/MySQL.Data/src/CompressedStream.cs b/MySQL.Data/src/CompressedStream.cs index b48c5c156..631cbe975 100644 --- a/MySQL.Data/src/CompressedStream.cs +++ b/MySQL.Data/src/CompressedStream.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2004, 2022, Oracle and/or its affiliates. +// Copyright © 2004, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/Crypt.cs b/MySQL.Data/src/Crypt.cs index d93f0396c..3f897479e 100644 --- a/MySQL.Data/src/Crypt.cs +++ b/MySQL.Data/src/Crypt.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2004, 2019, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2004, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -184,4 +184,4 @@ private static long[] Hash(String P) return hash; } } -} \ No newline at end of file +} diff --git a/MySQL.Data/src/Driver.cs b/MySQL.Data/src/Driver.cs index 6e96c9f23..3ae102d32 100644 --- a/MySQL.Data/src/Driver.cs +++ b/MySQL.Data/src/Driver.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2004, 2023, Oracle and/or its affiliates. +// Copyright © 2004, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/Exception.cs b/MySQL.Data/src/Exception.cs index d3be7037d..701ca4bd0 100644 --- a/MySQL.Data/src/Exception.cs +++ b/MySQL.Data/src/Exception.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2004, 2022, Oracle and/or its affiliates. +// Copyright © 2004, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/Failover/FailoverGroup.cs b/MySQL.Data/src/Failover/FailoverGroup.cs index c9198d8ab..34d8765f8 100644 --- a/MySQL.Data/src/Failover/FailoverGroup.cs +++ b/MySQL.Data/src/Failover/FailoverGroup.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2017, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/Failover/FailoverManager.cs b/MySQL.Data/src/Failover/FailoverManager.cs index 1c2711b3e..faba5ad35 100644 --- a/MySQL.Data/src/Failover/FailoverManager.cs +++ b/MySQL.Data/src/Failover/FailoverManager.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2017, 2022, Oracle and/or its affiliates. +// Copyright © 2017, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/Failover/FailoverServer.cs b/MySQL.Data/src/Failover/FailoverServer.cs index 3f23ef604..b0e7a7fb2 100644 --- a/MySQL.Data/src/Failover/FailoverServer.cs +++ b/MySQL.Data/src/Failover/FailoverServer.cs @@ -1,16 +1,16 @@ -// Copyright © 2017, 2019, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2017, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/Failover/RandomFailoverGroup.cs b/MySQL.Data/src/Failover/RandomFailoverGroup.cs index 137c5475e..66db9d1ef 100644 --- a/MySQL.Data/src/Failover/RandomFailoverGroup.cs +++ b/MySQL.Data/src/Failover/RandomFailoverGroup.cs @@ -1,16 +1,16 @@ -// Copyright © 2019, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2019, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -96,4 +96,4 @@ protected internal override FailoverServer GetNextHost() return _activeHost; } } -} \ No newline at end of file +} diff --git a/MySQL.Data/src/Failover/SequentialFailoverGroup.cs b/MySQL.Data/src/Failover/SequentialFailoverGroup.cs index af64c3800..998b077c5 100644 --- a/MySQL.Data/src/Failover/SequentialFailoverGroup.cs +++ b/MySQL.Data/src/Failover/SequentialFailoverGroup.cs @@ -1,16 +1,16 @@ -// Copyright © 2017, 2019, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2017, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -94,4 +94,4 @@ protected internal override FailoverServer GetNextHost() return _activeHost; } } -} \ No newline at end of file +} diff --git a/MySQL.Data/src/Field.cs b/MySQL.Data/src/Field.cs index 2202b07e3..29966d31b 100644 --- a/MySQL.Data/src/Field.cs +++ b/MySQL.Data/src/Field.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2004, 2022, Oracle and/or its affiliates. +// Copyright © 2004, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -345,6 +345,7 @@ public static IMySqlValue GetIMySqlValue(MySqlDbType type) case MySqlDbType.TinyBlob: case MySqlDbType.Binary: case MySqlDbType.VarBinary: + case MySqlDbType.Vector: return new MySqlBinary(type, true); case MySqlDbType.Guid: return new MySqlGuid(); diff --git a/MySQL.Data/src/Framework/net462/SystemPerformanceMonitor.cs b/MySQL.Data/src/Framework/net462/SystemPerformanceMonitor.cs index f92324d66..736383f6d 100644 --- a/MySQL.Data/src/Framework/net462/SystemPerformanceMonitor.cs +++ b/MySQL.Data/src/Framework/net462/SystemPerformanceMonitor.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2004, 2023, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2004, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -89,4 +89,4 @@ public override void AddSoftProcedureQuery() } } #endif -} \ No newline at end of file +} diff --git a/MySQL.Data/src/Framework/netstandard2_0/AuthenticationManager.cs b/MySQL.Data/src/Framework/netstandard2_0/AuthenticationManager.cs index eb3a6a54e..75d6356e9 100644 --- a/MySQL.Data/src/Framework/netstandard2_0/AuthenticationManager.cs +++ b/MySQL.Data/src/Framework/netstandard2_0/AuthenticationManager.cs @@ -1,16 +1,16 @@ -// Copyright © 2012, 2016, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2012, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -47,4 +47,4 @@ static partial void AuthenticationManagerCtorConfiguration() } } } -} \ No newline at end of file +} diff --git a/MySQL.Data/src/Framework/netstandard2_0/CommandBuilder.cs b/MySQL.Data/src/Framework/netstandard2_0/CommandBuilder.cs index 4b01bfb8a..64a00b0df 100644 --- a/MySQL.Data/src/Framework/netstandard2_0/CommandBuilder.cs +++ b/MySQL.Data/src/Framework/netstandard2_0/CommandBuilder.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2004, 2022, Oracle and/or its affiliates. +// Copyright © 2004, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/Framework/netstandard2_0/MySqlClientPermission.cs b/MySQL.Data/src/Framework/netstandard2_0/MySqlClientPermission.cs index 42edca767..8284cc347 100644 --- a/MySQL.Data/src/Framework/netstandard2_0/MySqlClientPermission.cs +++ b/MySQL.Data/src/Framework/netstandard2_0/MySqlClientPermission.cs @@ -1,102 +1,102 @@ -// Copyright � 2004, 2018, Oracle and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using System; -using System.Collections.Generic; -using System.Data; -using System.Data.Common; -using System.Security; -using System.Security.Permissions; - -namespace MySql.Data.MySqlClient -{ - /// - /// Enables the provider to help ensure that a user has a security level adequate for accessing data. - /// - [Serializable] - public sealed class MySqlClientPermission : DBDataPermission - { - - #region Contructors - - public MySqlClientPermission(PermissionState permissionState) - : base(permissionState) - { - } - - private MySqlClientPermission(MySqlClientPermission permission):base(permission) - { - } - - internal MySqlClientPermission(MySqlClientPermissionAttribute permissionAttribute):base(permissionAttribute) - { - } - - internal MySqlClientPermission (DBDataPermission permission) - : base (permission) - { - } - - internal MySqlClientPermission(string connectionString) - : base(PermissionState.None) - { - if ((connectionString == null) || connectionString.Length == 0) - base.Add(string.Empty, string.Empty, KeyRestrictionBehavior.AllowOnly); - else - base.Add(connectionString, string.Empty, KeyRestrictionBehavior.AllowOnly); - } - - - #endregion - - #region Methods - - /// - /// Adds a new connection string with set of restricted keywords to the MySqlClientPermission object - /// - ///Settings to be used for the connection - ///Keywords to define the restrictions - ///KeyRestrictionBehavior to be used - public override void Add(string connectionString, string restrictions, KeyRestrictionBehavior behavior) - { - base.Add(connectionString, restrictions, behavior); - } - - /// - /// Returns MySqlClientPermission as an IPermission - /// - /// - public override IPermission Copy() - { - return new MySqlClientPermission(this); - } - - #endregion - - } -} +// Copyright © 2004, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using System; +using System.Collections.Generic; +using System.Data; +using System.Data.Common; +using System.Security; +using System.Security.Permissions; + +namespace MySql.Data.MySqlClient +{ + /// + /// Enables the provider to help ensure that a user has a security level adequate for accessing data. + /// + [Serializable] + public sealed class MySqlClientPermission : DBDataPermission + { + + #region Contructors + + public MySqlClientPermission(PermissionState permissionState) + : base(permissionState) + { + } + + private MySqlClientPermission(MySqlClientPermission permission):base(permission) + { + } + + internal MySqlClientPermission(MySqlClientPermissionAttribute permissionAttribute):base(permissionAttribute) + { + } + + internal MySqlClientPermission (DBDataPermission permission) + : base (permission) + { + } + + internal MySqlClientPermission(string connectionString) + : base(PermissionState.None) + { + if ((connectionString == null) || connectionString.Length == 0) + base.Add(string.Empty, string.Empty, KeyRestrictionBehavior.AllowOnly); + else + base.Add(connectionString, string.Empty, KeyRestrictionBehavior.AllowOnly); + } + + + #endregion + + #region Methods + + /// + /// Adds a new connection string with set of restricted keywords to the MySqlClientPermission object + /// + ///Settings to be used for the connection + ///Keywords to define the restrictions + ///KeyRestrictionBehavior to be used + public override void Add(string connectionString, string restrictions, KeyRestrictionBehavior behavior) + { + base.Add(connectionString, restrictions, behavior); + } + + /// + /// Returns MySqlClientPermission as an IPermission + /// + /// + public override IPermission Copy() + { + return new MySqlClientPermission(this); + } + + #endregion + + } +} diff --git a/MySQL.Data/src/Framework/netstandard2_0/MySqlClientPermissionAttribute.cs b/MySQL.Data/src/Framework/netstandard2_0/MySqlClientPermissionAttribute.cs index b5ac3263a..e2ee73a4a 100644 --- a/MySQL.Data/src/Framework/netstandard2_0/MySqlClientPermissionAttribute.cs +++ b/MySQL.Data/src/Framework/netstandard2_0/MySqlClientPermissionAttribute.cs @@ -1,53 +1,53 @@ -// Copyright � 2004, 2018, Oracle and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using System; -using System.Collections.Generic; -using System.Data.Common; -using System.Security; -using System.Security.Permissions; - -namespace MySql.Data.MySqlClient -{ - /// - /// Associates a security action with a custom security attribute. - /// - [Serializable, AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Struct | AttributeTargets.Class | AttributeTargets.Assembly, AllowMultiple = true, Inherited = false)] - public sealed class MySqlClientPermissionAttribute : DBDataPermissionAttribute - { - // Methods - public MySqlClientPermissionAttribute(SecurityAction action) : base(action) - { - } - - public override IPermission CreatePermission() - { - return new MySqlClientPermission(this); - } - } -} +// Copyright © 2004, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using System; +using System.Collections.Generic; +using System.Data.Common; +using System.Security; +using System.Security.Permissions; + +namespace MySql.Data.MySqlClient +{ + /// + /// Associates a security action with a custom security attribute. + /// + [Serializable, AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Struct | AttributeTargets.Class | AttributeTargets.Assembly, AllowMultiple = true, Inherited = false)] + public sealed class MySqlClientPermissionAttribute : DBDataPermissionAttribute + { + // Methods + public MySqlClientPermissionAttribute(SecurityAction action) : base(action) + { + } + + public override IPermission CreatePermission() + { + return new MySqlClientPermission(this); + } + } +} diff --git a/MySQL.Data/src/Framework/netstandard2_0/MySqlConfiguration.cs b/MySQL.Data/src/Framework/netstandard2_0/MySqlConfiguration.cs index 1dddfc35e..af38bb5f9 100644 --- a/MySQL.Data/src/Framework/netstandard2_0/MySqlConfiguration.cs +++ b/MySQL.Data/src/Framework/netstandard2_0/MySqlConfiguration.cs @@ -1,205 +1,205 @@ -// Copyright � 2013, 2018, Oracle and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using System; -using System.Collections.Generic; -using System.Text; -using System.Configuration; - -namespace MySql.Data.MySqlClient -{ - /// - /// Represents a section within a configuration file. - /// - public sealed class MySqlConfiguration : ConfigurationSection - { - private static MySqlConfiguration settings - = ConfigurationManager.GetSection("MySQL") as MySqlConfiguration; - - /// - /// Gets the MySQL configuations associated to the current configuration. - /// - public static MySqlConfiguration Settings - { - get { return settings; } - } - - /// - /// Gets a collection of the exception interceptors available in the current configuration. - /// - [ConfigurationProperty("ExceptionInterceptors", IsRequired = false)] - [ConfigurationCollection(typeof(InterceptorConfigurationElement), AddItemName = "add", ClearItemsName = "clear", RemoveItemName = "remove")] - public GenericConfigurationElementCollection ExceptionInterceptors - { - get { return (GenericConfigurationElementCollection)this["ExceptionInterceptors"]; } - } - - /// - /// Gets a collection of the command interceptors available in the current configuration. - /// - [ConfigurationProperty("CommandInterceptors", IsRequired = false)] - [ConfigurationCollection(typeof(InterceptorConfigurationElement), AddItemName = "add", ClearItemsName = "clear", RemoveItemName = "remove")] - public GenericConfigurationElementCollection CommandInterceptors - { - get { return (GenericConfigurationElementCollection)this["CommandInterceptors"]; } - } - - /// - /// Gets a collection of the authentication plugins available in the current configuration. - /// - [ConfigurationProperty("AuthenticationPlugins", IsRequired = false)] - [ConfigurationCollection(typeof(AuthenticationPluginConfigurationElement), AddItemName = "add", ClearItemsName = "clear", RemoveItemName = "remove")] - public GenericConfigurationElementCollection AuthenticationPlugins - { - get { return (GenericConfigurationElementCollection)this["AuthenticationPlugins"]; } - } - - /// - /// Gets or sets the replication configurations. - /// - [ConfigurationProperty("Replication", IsRequired = true)] - public ReplicationConfigurationElement Replication - { - get - { - return (ReplicationConfigurationElement)this["Replication"]; - } - set - { - this["Replication"] = value; - } - } - - } - - /// - /// Defines the configurations allowed for an authentication plugin. - /// - public sealed class AuthenticationPluginConfigurationElement : ConfigurationElement - { - /// - /// Gets or sets the name of the authentication plugin. - /// - [ConfigurationProperty("name", IsRequired = true)] - public string Name - { - get - { - return (string)this["name"]; - } - set - { - this["name"] = value; - } - } - - /// - /// Gets or sets the type of the authentication plugin. - /// - [ConfigurationProperty("type", IsRequired = true)] - public string Type - { - get - { - return (string)this["type"]; - } - set - { - this["type"] = value; - } - } - } - - /// - /// Defines the configurations allowed for an interceptor. - /// - public sealed class InterceptorConfigurationElement : ConfigurationElement - { - /// - /// Gets or sets the name of the interceptor. - /// - [ConfigurationProperty("name", IsRequired = true)] - public string Name - { - get - { - return (string)this["name"]; - } - set - { - this["name"] = value; - } - } - - /// - /// Gets or sets the type of the interceptor. - /// - [ConfigurationProperty("type", IsRequired = true)] - public string Type - { - get - { - return (string)this["type"]; - } - set - { - this["type"] = value; - } - } - } - - /// - /// Represents a generic configuration element. - /// - /// - public sealed class GenericConfigurationElementCollection : ConfigurationElementCollection, IEnumerable where T : ConfigurationElement, new() - { - List _elements = new List(); - - protected override ConfigurationElement CreateNewElement() - { - T newElement = new T(); - _elements.Add(newElement); - return newElement; - } - - protected override object GetElementKey(ConfigurationElement element) - { - return _elements.Find(e => e.Equals(element)); - } - - /// - /// Gets an enumerator that iterates through the returned list. - /// - /// An enumerator that iterates through the returned list. - public new IEnumerator GetEnumerator() - { - return _elements.GetEnumerator(); - } - } -} +// Copyright © 2013, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using System; +using System.Collections.Generic; +using System.Text; +using System.Configuration; + +namespace MySql.Data.MySqlClient +{ + /// + /// Represents a section within a configuration file. + /// + public sealed class MySqlConfiguration : ConfigurationSection + { + private static MySqlConfiguration settings + = ConfigurationManager.GetSection("MySQL") as MySqlConfiguration; + + /// + /// Gets the MySQL configuations associated to the current configuration. + /// + public static MySqlConfiguration Settings + { + get { return settings; } + } + + /// + /// Gets a collection of the exception interceptors available in the current configuration. + /// + [ConfigurationProperty("ExceptionInterceptors", IsRequired = false)] + [ConfigurationCollection(typeof(InterceptorConfigurationElement), AddItemName = "add", ClearItemsName = "clear", RemoveItemName = "remove")] + public GenericConfigurationElementCollection ExceptionInterceptors + { + get { return (GenericConfigurationElementCollection)this["ExceptionInterceptors"]; } + } + + /// + /// Gets a collection of the command interceptors available in the current configuration. + /// + [ConfigurationProperty("CommandInterceptors", IsRequired = false)] + [ConfigurationCollection(typeof(InterceptorConfigurationElement), AddItemName = "add", ClearItemsName = "clear", RemoveItemName = "remove")] + public GenericConfigurationElementCollection CommandInterceptors + { + get { return (GenericConfigurationElementCollection)this["CommandInterceptors"]; } + } + + /// + /// Gets a collection of the authentication plugins available in the current configuration. + /// + [ConfigurationProperty("AuthenticationPlugins", IsRequired = false)] + [ConfigurationCollection(typeof(AuthenticationPluginConfigurationElement), AddItemName = "add", ClearItemsName = "clear", RemoveItemName = "remove")] + public GenericConfigurationElementCollection AuthenticationPlugins + { + get { return (GenericConfigurationElementCollection)this["AuthenticationPlugins"]; } + } + + /// + /// Gets or sets the replication configurations. + /// + [ConfigurationProperty("Replication", IsRequired = true)] + public ReplicationConfigurationElement Replication + { + get + { + return (ReplicationConfigurationElement)this["Replication"]; + } + set + { + this["Replication"] = value; + } + } + + } + + /// + /// Defines the configurations allowed for an authentication plugin. + /// + public sealed class AuthenticationPluginConfigurationElement : ConfigurationElement + { + /// + /// Gets or sets the name of the authentication plugin. + /// + [ConfigurationProperty("name", IsRequired = true)] + public string Name + { + get + { + return (string)this["name"]; + } + set + { + this["name"] = value; + } + } + + /// + /// Gets or sets the type of the authentication plugin. + /// + [ConfigurationProperty("type", IsRequired = true)] + public string Type + { + get + { + return (string)this["type"]; + } + set + { + this["type"] = value; + } + } + } + + /// + /// Defines the configurations allowed for an interceptor. + /// + public sealed class InterceptorConfigurationElement : ConfigurationElement + { + /// + /// Gets or sets the name of the interceptor. + /// + [ConfigurationProperty("name", IsRequired = true)] + public string Name + { + get + { + return (string)this["name"]; + } + set + { + this["name"] = value; + } + } + + /// + /// Gets or sets the type of the interceptor. + /// + [ConfigurationProperty("type", IsRequired = true)] + public string Type + { + get + { + return (string)this["type"]; + } + set + { + this["type"] = value; + } + } + } + + /// + /// Represents a generic configuration element. + /// + /// + public sealed class GenericConfigurationElementCollection : ConfigurationElementCollection, IEnumerable where T : ConfigurationElement, new() + { + List _elements = new List(); + + protected override ConfigurationElement CreateNewElement() + { + T newElement = new T(); + _elements.Add(newElement); + return newElement; + } + + protected override object GetElementKey(ConfigurationElement element) + { + return _elements.Find(e => e.Equals(element)); + } + + /// + /// Gets an enumerator that iterates through the returned list. + /// + /// An enumerator that iterates through the returned list. + public new IEnumerator GetEnumerator() + { + return _elements.GetEnumerator(); + } + } +} diff --git a/MySQL.Data/src/Framework/netstandard2_0/MySqlHelper.cs b/MySQL.Data/src/Framework/netstandard2_0/MySqlHelper.cs index 7bd6f07de..4b88132c7 100644 --- a/MySQL.Data/src/Framework/netstandard2_0/MySqlHelper.cs +++ b/MySQL.Data/src/Framework/netstandard2_0/MySqlHelper.cs @@ -1,16 +1,16 @@ -// Copyright © 2004, 2018, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2004, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/Framework/netstandard2_0/MySqlPromotableTransaction.cs b/MySQL.Data/src/Framework/netstandard2_0/MySqlPromotableTransaction.cs index cbafb651b..c5e304829 100644 --- a/MySQL.Data/src/Framework/netstandard2_0/MySqlPromotableTransaction.cs +++ b/MySQL.Data/src/Framework/netstandard2_0/MySqlPromotableTransaction.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2004, 2022, Oracle and/or its affiliates. +// Copyright © 2004, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/Framework/netstandard2_0/MySqlSecurityPermission.cs b/MySQL.Data/src/Framework/netstandard2_0/MySqlSecurityPermission.cs index 329f1e4d7..3319eb2cd 100644 --- a/MySQL.Data/src/Framework/netstandard2_0/MySqlSecurityPermission.cs +++ b/MySQL.Data/src/Framework/netstandard2_0/MySqlSecurityPermission.cs @@ -1,65 +1,65 @@ -// Copyright (c) 2011, 2022, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using System; -using System.Net; -using System.Security; -using System.Security.Permissions; - -namespace MySql.Data.MySqlClient -{ - /// - /// Defines security permissions assigned to a MySQL object. - /// - public sealed class MySqlSecurityPermission : MarshalByRefObject - { - private MySqlSecurityPermission() - { - } - - /// - /// Creates a set of permissions. - /// - /// A flag indicating if the reflection permission should be included. - /// A object representing a collection of permissions. - public static PermissionSet CreatePermissionSet(bool includeReflectionPermission) - { - PermissionSet permissionsSet = new PermissionSet(null); - permissionsSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution)); - permissionsSet.AddPermission(new SocketPermission(PermissionState.Unrestricted)); - permissionsSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.UnmanagedCode)); - permissionsSet.AddPermission(new DnsPermission(PermissionState.Unrestricted)); - permissionsSet.AddPermission(new FileIOPermission(PermissionState.Unrestricted)); - permissionsSet.AddPermission(new EnvironmentPermission(PermissionState.Unrestricted)); - - if (includeReflectionPermission) permissionsSet.AddPermission(new ReflectionPermission(PermissionState.Unrestricted)); - - return permissionsSet; - } - } -} +// Copyright © 2011, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using System; +using System.Net; +using System.Security; +using System.Security.Permissions; + +namespace MySql.Data.MySqlClient +{ + /// + /// Defines security permissions assigned to a MySQL object. + /// + public sealed class MySqlSecurityPermission : MarshalByRefObject + { + private MySqlSecurityPermission() + { + } + + /// + /// Creates a set of permissions. + /// + /// A flag indicating if the reflection permission should be included. + /// A object representing a collection of permissions. + public static PermissionSet CreatePermissionSet(bool includeReflectionPermission) + { + PermissionSet permissionsSet = new PermissionSet(null); + permissionsSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution)); + permissionsSet.AddPermission(new SocketPermission(PermissionState.Unrestricted)); + permissionsSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.UnmanagedCode)); + permissionsSet.AddPermission(new DnsPermission(PermissionState.Unrestricted)); + permissionsSet.AddPermission(new FileIOPermission(PermissionState.Unrestricted)); + permissionsSet.AddPermission(new EnvironmentPermission(PermissionState.Unrestricted)); + + if (includeReflectionPermission) permissionsSet.AddPermission(new ReflectionPermission(PermissionState.Unrestricted)); + + return permissionsSet; + } + } +} diff --git a/MySQL.Data/src/Framework/netstandard2_0/dataadapter.cs b/MySQL.Data/src/Framework/netstandard2_0/dataadapter.cs index f2f2f9073..402fcb3a9 100644 --- a/MySQL.Data/src/Framework/netstandard2_0/dataadapter.cs +++ b/MySQL.Data/src/Framework/netstandard2_0/dataadapter.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2004, 2023, Oracle and/or its affiliates. +// Copyright © 2004, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/ISSchemaProvider.cs b/MySQL.Data/src/ISSchemaProvider.cs index 4a4bb5d77..545466a28 100644 --- a/MySQL.Data/src/ISSchemaProvider.cs +++ b/MySQL.Data/src/ISSchemaProvider.cs @@ -1,397 +1,397 @@ -// Copyright (c) 2004, 2023, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data.Common; -using MySql.Data.Types; -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace MySql.Data.MySqlClient -{ - internal class ISSchemaProvider : SchemaProvider - { - public ISSchemaProvider(MySqlConnection connection) - : base(connection) - { - } - - protected override MySqlSchemaCollection GetCollections() - { - MySqlSchemaCollection dt = base.GetCollections(); - - object[][] collections = { - new object[] {"Views", 2, 3}, - new object[] {"ViewColumns", 3, 4}, - new object[] {"Procedure Parameters", 5, 1}, - new object[] {"Procedures", 4, 3}, - new object[] {"Triggers", 2, 4} - }; - - FillTable(dt, collections); - return dt; - } - - protected override MySqlSchemaCollection GetRestrictions() - { - MySqlSchemaCollection dt = base.GetRestrictions(); - - object[][] restrictions = new object[][] - { - new object[] {"Procedure Parameters", "Database", "", 0}, - new object[] {"Procedure Parameters", "Schema", "", 1}, - new object[] {"Procedure Parameters", "Name", "", 2}, - new object[] {"Procedure Parameters", "Type", "", 3}, - new object[] {"Procedure Parameters", "Parameter", "", 4}, - new object[] {"Procedures", "Database", "", 0}, - new object[] {"Procedures", "Schema", "", 1}, - new object[] {"Procedures", "Name", "", 2}, - new object[] {"Procedures", "Type", "", 3}, - new object[] {"Views", "Database", "", 0}, - new object[] {"Views", "Schema", "", 1}, - new object[] {"Views", "Table", "", 2}, - new object[] {"ViewColumns", "Database", "", 0}, - new object[] {"ViewColumns", "Schema", "", 1}, - new object[] {"ViewColumns", "Table", "", 2}, - new object[] {"ViewColumns", "Column", "", 3}, - new object[] {"Triggers", "Database", "", 0}, - new object[] {"Triggers", "Schema", "", 1}, - new object[] {"Triggers", "Name", "", 2}, - new object[] {"Triggers", "EventObjectTable", "", 3}, - }; - FillTable(dt, restrictions); - return dt; - } - - public override async Task GetDatabasesAsync(string[] restrictions, bool execAsync, CancellationToken cancellationToken = default) - { - string[] keys = new string[1]; - keys[0] = "SCHEMA_NAME"; - MySqlSchemaCollection dt = await QueryAsync("SCHEMATA", "", keys, restrictions, execAsync, cancellationToken).ConfigureAwait(false); - dt.Columns[1].Name = "database_name"; - dt.Name = "Databases"; - return dt; - } - - public override async Task GetTablesAsync(string[] restrictions, bool execAsync, CancellationToken cancellationToken = default) - { - string[] keys = new string[4]; - keys[0] = "TABLE_CATALOG"; - keys[1] = "TABLE_SCHEMA"; - keys[2] = "TABLE_NAME"; - keys[3] = "TABLE_TYPE"; - MySqlSchemaCollection dt = await QueryAsync("TABLES", "TABLE_TYPE != 'VIEW'", keys, restrictions, execAsync, cancellationToken).ConfigureAwait(false); - dt.Name = "Tables"; - return dt; - } - - public override async Task GetColumnsAsync(string[] restrictions, bool execAsync, CancellationToken cancellationToken = default) - { - string[] keys = new string[4]; - keys[0] = "TABLE_CATALOG"; - keys[1] = "TABLE_SCHEMA"; - keys[2] = "TABLE_NAME"; - keys[3] = "COLUMN_NAME"; - MySqlSchemaCollection dt = await QueryAsync("COLUMNS", null, keys, restrictions, execAsync, cancellationToken).ConfigureAwait(false); - dt.RemoveColumn("CHARACTER_OCTET_LENGTH"); - dt.Name = "Columns"; - QuoteDefaultValues(dt); - return dt; - } - - private async Task GetViewsAsync(string[] restrictions, bool execAsync, CancellationToken cancellationToken = default) - { - string[] keys = new string[3]; - keys[0] = "TABLE_CATALOG"; - keys[1] = "TABLE_SCHEMA"; - keys[2] = "TABLE_NAME"; - MySqlSchemaCollection dt = await QueryAsync("VIEWS", null, keys, restrictions, execAsync, cancellationToken).ConfigureAwait(false); - dt.Name = "Views"; - return dt; - } - - private async Task GetViewColumnsAsync(string[] restrictions, bool execAsync, CancellationToken cancellationToken = default) - { - StringBuilder where = new StringBuilder(); - StringBuilder sql = new StringBuilder( - "SELECT C.* FROM information_schema.columns C"); - sql.Append(" JOIN information_schema.views V "); - sql.Append("ON C.table_schema=V.table_schema AND C.table_name=V.table_name "); - if (restrictions != null && restrictions.Length >= 2 && - restrictions[1] != null) - where.AppendFormat(CultureInfo.InvariantCulture, "C.table_schema='{0}' ", restrictions[1]); - if (restrictions != null && restrictions.Length >= 3 && - restrictions[2] != null) - { - if (where.Length > 0) - where.Append("AND "); - where.AppendFormat(CultureInfo.InvariantCulture, "C.table_name='{0}' ", restrictions[2]); - } - if (restrictions != null && restrictions.Length == 4 && - restrictions[3] != null) - { - if (where.Length > 0) - where.Append("AND "); - where.AppendFormat(CultureInfo.InvariantCulture, "C.column_name='{0}' ", restrictions[3]); - } - if (where.Length > 0) - sql.AppendFormat(CultureInfo.InvariantCulture, " WHERE {0}", where); - MySqlSchemaCollection dt = await GetTableAsync(sql.ToString(), execAsync, cancellationToken).ConfigureAwait(false); - dt.Name = "ViewColumns"; - dt.Columns[0].Name = "VIEW_CATALOG"; - dt.Columns[1].Name = "VIEW_SCHEMA"; - dt.Columns[2].Name = "VIEW_NAME"; - QuoteDefaultValues(dt); - return dt; - } - - private async Task GetTriggersAsync(string[] restrictions, bool execAsync, CancellationToken cancellationToken = default) - { - string[] keys = new string[4]; - keys[0] = "TRIGGER_CATALOG"; - keys[1] = "TRIGGER_SCHEMA"; - keys[2] = "EVENT_OBJECT_TABLE"; - keys[3] = "TRIGGER_NAME"; - MySqlSchemaCollection dt = await QueryAsync("TRIGGERS", null, keys, restrictions, execAsync, cancellationToken).ConfigureAwait(false); - dt.Name = "Triggers"; - return dt; - } - - /// - /// Return schema information about procedures and functions - /// Restrictions supported are: - /// schema, name, type - /// - /// - /// Boolean that indicates if the function will be executed asynchronously. - /// The cancellation token. - public async Task GetProceduresAsync(string[] restrictions, bool execAsync, CancellationToken cancellationToken = default) - { - string[] keys = new string[4]; - keys[0] = "ROUTINE_CATALOG"; - keys[1] = "ROUTINE_SCHEMA"; - keys[2] = "ROUTINE_NAME"; - keys[3] = "ROUTINE_TYPE"; - - MySqlSchemaCollection dt = await QueryAsync("ROUTINES", null, keys, restrictions, execAsync, cancellationToken).ConfigureAwait(false); - dt.Name = "Procedures"; - return dt; - } - - private async Task GetParametersForRoutineFromexecAsync(string[] restrictions, bool execAsync, CancellationToken cancellationToken = default) - { - string[] keys = new string[5]; - keys[0] = "SPECIFIC_CATALOG"; - keys[1] = "SPECIFIC_SCHEMA"; - keys[2] = "SPECIFIC_NAME"; - keys[3] = "ROUTINE_TYPE"; - keys[4] = "PARAMETER_NAME"; - - StringBuilder sql = new StringBuilder(@"SELECT * FROM INFORMATION_SCHEMA.PARAMETERS"); - // now get our where clause and append it if there is one - string where = GetWhereClause(null, keys, restrictions); - if (!String.IsNullOrEmpty(where)) - sql.AppendFormat(CultureInfo.InvariantCulture, " WHERE {0}", where); - - MySqlSchemaCollection coll = await QueryCollectionAsync("parameters", sql.ToString(), execAsync, cancellationToken).ConfigureAwait(false); - - if ((coll.Rows.Count != 0) && ((string)coll.Rows[0]["routine_type"] == "FUNCTION")) - { - // update missing data for the first row (function return value). - // (using sames valus than GetParametersFromShowCreate). - coll.Rows[0]["parameter_mode"] = "IN"; - coll.Rows[0]["parameter_name"] = "return_value"; // "FUNCTION"; - } - return coll; - } - - /// - /// Return schema information about parameters for procedures and functions - /// Restrictions supported are: - /// schema, name, type, parameter name - /// - public virtual async Task GetProcedureParametersAsync(string[] restrictions, - MySqlSchemaCollection routines, bool execAsync, CancellationToken cancellationToken = default) - { - MySqlSchemaCollection parms = null; - - if (routines == null || routines.Rows.Count == 0) - { - parms = await GetParametersForRoutineFromexecAsync(restrictions, execAsync, cancellationToken).ConfigureAwait(false); - } - else foreach (MySqlSchemaRow routine in routines.Rows) - { - if (restrictions != null && restrictions.Length >= 3) - restrictions[2] = routine["ROUTINE_NAME"].ToString(); - - parms = await GetParametersForRoutineFromexecAsync(restrictions, execAsync, cancellationToken).ConfigureAwait(false); - } - parms.Name = "Procedure Parameters"; - return parms; - } - - protected override async Task GetSchemaInternalAsync(string collection, string[] restrictions, bool execAsync, CancellationToken cancellationToken = default) - { - MySqlSchemaCollection dt = await base.GetSchemaInternalAsync(collection, restrictions, execAsync, cancellationToken).ConfigureAwait(false); - if (dt != null) - return dt; - - switch (collection) - { - case "VIEWS": - return await GetViewsAsync(restrictions, execAsync, cancellationToken).ConfigureAwait(false); - case "PROCEDURES": - return await GetProceduresAsync(restrictions, execAsync, cancellationToken).ConfigureAwait(false); - case "PROCEDURE PARAMETERS": - return await GetProcedureParametersAsync(restrictions, null, execAsync, cancellationToken).ConfigureAwait(false); - case "TRIGGERS": - return await GetTriggersAsync(restrictions, execAsync, cancellationToken).ConfigureAwait(false); - case "VIEWCOLUMNS": - return await GetViewColumnsAsync(restrictions, execAsync, cancellationToken).ConfigureAwait(false); - } - return null; - } - - private static string GetWhereClause(string initial_where, string[] keys, string[] values) - { - StringBuilder where = new StringBuilder(initial_where); - if (values != null) - { - for (int i = 0; i < keys.Length; i++) - { - if (i >= values.Length) break; - if (values[i] == null || values[i] == String.Empty) continue; - if (where.Length > 0) - where.Append(" AND "); - where.AppendFormat(CultureInfo.InvariantCulture, - "{0} LIKE '{1}'", keys[i], values[i]); - } - } - return where.ToString(); - } - - private async Task QueryAsync(string tableName, string initialWhere, string[] keys, string[] values, bool execAsync, CancellationToken cancellationToken = default) - { - StringBuilder query = new StringBuilder("SELECT * FROM INFORMATION_SCHEMA."); - query.Append(tableName); - - string where = GetWhereClause(initialWhere, keys, values); - - if (where.Length > 0) - query.AppendFormat(CultureInfo.InvariantCulture, " WHERE {0}", where); - - if (tableName.Equals("COLUMNS", StringComparison.OrdinalIgnoreCase)) - query.Append(" ORDER BY ORDINAL_POSITION"); - - return await GetTableAsync(query.ToString(), execAsync, cancellationToken).ConfigureAwait(false); - } - - private async Task GetTableAsync(string sql, bool execAsync, CancellationToken cancellationToken = default) - { - MySqlSchemaCollection c = new MySqlSchemaCollection(); - using MySqlCommand cmd = new MySqlCommand(sql, connection); - MySqlDataReader reader = await cmd.ExecuteReaderAsync(default, execAsync, cancellationToken).ConfigureAwait(false); - - // add columns - for (int i = 0; i < reader.FieldCount; i++) - c.AddColumn(reader.GetName(i), reader.GetFieldType(i)); - - using (reader) - { - while (await reader.ReadAsync(execAsync, cancellationToken).ConfigureAwait(false)) - { - MySqlSchemaRow row = c.AddRow(); - for (int i = 0; i < reader.FieldCount; i++) - row[i] = reader.GetValue(i); - } - } - - return c; - } - - public override async Task GetForeignKeysAsync(string[] restrictions, bool execAsync, CancellationToken cancellationToken = default) - { - if (!connection.driver.Version.isAtLeast(5, 1, 16)) - return await base.GetForeignKeysAsync(restrictions, execAsync, cancellationToken).ConfigureAwait(false); - - string sql = @"SELECT rc.constraint_catalog, rc.constraint_schema, - rc.constraint_name, kcu.table_catalog, kcu.table_schema, rc.table_name, - rc.match_option, rc.update_rule, rc.delete_rule, - NULL as referenced_table_catalog, - kcu.referenced_table_schema, rc.referenced_table_name - FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS rc - LEFT JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu ON - kcu.constraint_catalog <=> rc.constraint_catalog AND - kcu.constraint_schema <=> rc.constraint_schema AND - kcu.constraint_name <=> rc.constraint_name - WHERE 1=1 AND kcu.ORDINAL_POSITION=1"; - - StringBuilder where = new StringBuilder(); - if (restrictions.Length >= 2 && !String.IsNullOrEmpty(restrictions[1])) - where.AppendFormat(CultureInfo.InvariantCulture, - " AND rc.constraint_schema LIKE '{0}'", restrictions[1]); - if (restrictions.Length >= 3 && !String.IsNullOrEmpty(restrictions[2])) - where.AppendFormat(CultureInfo.InvariantCulture, - " AND rc.table_name LIKE '{0}'", restrictions[2]); - if (restrictions.Length >= 4 && !String.IsNullOrEmpty(restrictions[3])) - where.AppendFormat(CultureInfo.InvariantCulture, - " AND rc.constraint_name LIKE '{0}'", restrictions[2]); - - sql += where.ToString(); - - return await GetTableAsync(sql, execAsync, cancellationToken).ConfigureAwait(false); - } - - public override async Task GetForeignKeyColumnsAsync(string[] restrictions, bool execAsync, CancellationToken cancellationToken = default) - { - if (!connection.driver.Version.isAtLeast(5, 0, 6)) - return await base.GetForeignKeyColumnsAsync(restrictions, execAsync, cancellationToken).ConfigureAwait(false); - - string sql = @"SELECT kcu.* FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu - WHERE kcu.referenced_table_name IS NOT NULL"; - - StringBuilder where = new StringBuilder(); - if (restrictions.Length >= 2 && !String.IsNullOrEmpty(restrictions[1])) - where.AppendFormat(CultureInfo.InvariantCulture, - " AND kcu.constraint_schema LIKE '{0}'", restrictions[1]); - if (restrictions.Length >= 3 && !String.IsNullOrEmpty(restrictions[2])) - where.AppendFormat(CultureInfo.InvariantCulture, - " AND kcu.table_name LIKE '{0}'", restrictions[2]); - if (restrictions.Length >= 4 && !String.IsNullOrEmpty(restrictions[3])) - where.AppendFormat(CultureInfo.InvariantCulture, - " AND kcu.constraint_name LIKE '{0}'", restrictions[3]); - - sql += where.ToString(); - - return await GetTableAsync(sql, execAsync, cancellationToken).ConfigureAwait(false); - } - } -} +// Copyright © 2004, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data.Common; +using MySql.Data.Types; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace MySql.Data.MySqlClient +{ + internal class ISSchemaProvider : SchemaProvider + { + public ISSchemaProvider(MySqlConnection connection) + : base(connection) + { + } + + protected override MySqlSchemaCollection GetCollections() + { + MySqlSchemaCollection dt = base.GetCollections(); + + object[][] collections = { + new object[] {"Views", 2, 3}, + new object[] {"ViewColumns", 3, 4}, + new object[] {"Procedure Parameters", 5, 1}, + new object[] {"Procedures", 4, 3}, + new object[] {"Triggers", 2, 4} + }; + + FillTable(dt, collections); + return dt; + } + + protected override MySqlSchemaCollection GetRestrictions() + { + MySqlSchemaCollection dt = base.GetRestrictions(); + + object[][] restrictions = new object[][] + { + new object[] {"Procedure Parameters", "Database", "", 0}, + new object[] {"Procedure Parameters", "Schema", "", 1}, + new object[] {"Procedure Parameters", "Name", "", 2}, + new object[] {"Procedure Parameters", "Type", "", 3}, + new object[] {"Procedure Parameters", "Parameter", "", 4}, + new object[] {"Procedures", "Database", "", 0}, + new object[] {"Procedures", "Schema", "", 1}, + new object[] {"Procedures", "Name", "", 2}, + new object[] {"Procedures", "Type", "", 3}, + new object[] {"Views", "Database", "", 0}, + new object[] {"Views", "Schema", "", 1}, + new object[] {"Views", "Table", "", 2}, + new object[] {"ViewColumns", "Database", "", 0}, + new object[] {"ViewColumns", "Schema", "", 1}, + new object[] {"ViewColumns", "Table", "", 2}, + new object[] {"ViewColumns", "Column", "", 3}, + new object[] {"Triggers", "Database", "", 0}, + new object[] {"Triggers", "Schema", "", 1}, + new object[] {"Triggers", "Name", "", 2}, + new object[] {"Triggers", "EventObjectTable", "", 3}, + }; + FillTable(dt, restrictions); + return dt; + } + + public override async Task GetDatabasesAsync(string[] restrictions, bool execAsync, CancellationToken cancellationToken = default) + { + string[] keys = new string[1]; + keys[0] = "SCHEMA_NAME"; + MySqlSchemaCollection dt = await QueryAsync("SCHEMATA", "", keys, restrictions, execAsync, cancellationToken).ConfigureAwait(false); + dt.Columns[1].Name = "database_name"; + dt.Name = "Databases"; + return dt; + } + + public override async Task GetTablesAsync(string[] restrictions, bool execAsync, CancellationToken cancellationToken = default) + { + string[] keys = new string[4]; + keys[0] = "TABLE_CATALOG"; + keys[1] = "TABLE_SCHEMA"; + keys[2] = "TABLE_NAME"; + keys[3] = "TABLE_TYPE"; + MySqlSchemaCollection dt = await QueryAsync("TABLES", "TABLE_TYPE != 'VIEW'", keys, restrictions, execAsync, cancellationToken).ConfigureAwait(false); + dt.Name = "Tables"; + return dt; + } + + public override async Task GetColumnsAsync(string[] restrictions, bool execAsync, CancellationToken cancellationToken = default) + { + string[] keys = new string[4]; + keys[0] = "TABLE_CATALOG"; + keys[1] = "TABLE_SCHEMA"; + keys[2] = "TABLE_NAME"; + keys[3] = "COLUMN_NAME"; + MySqlSchemaCollection dt = await QueryAsync("COLUMNS", null, keys, restrictions, execAsync, cancellationToken).ConfigureAwait(false); + dt.RemoveColumn("CHARACTER_OCTET_LENGTH"); + dt.Name = "Columns"; + QuoteDefaultValues(dt); + return dt; + } + + private async Task GetViewsAsync(string[] restrictions, bool execAsync, CancellationToken cancellationToken = default) + { + string[] keys = new string[3]; + keys[0] = "TABLE_CATALOG"; + keys[1] = "TABLE_SCHEMA"; + keys[2] = "TABLE_NAME"; + MySqlSchemaCollection dt = await QueryAsync("VIEWS", null, keys, restrictions, execAsync, cancellationToken).ConfigureAwait(false); + dt.Name = "Views"; + return dt; + } + + private async Task GetViewColumnsAsync(string[] restrictions, bool execAsync, CancellationToken cancellationToken = default) + { + StringBuilder where = new StringBuilder(); + StringBuilder sql = new StringBuilder( + "SELECT C.* FROM information_schema.columns C"); + sql.Append(" JOIN information_schema.views V "); + sql.Append("ON C.table_schema=V.table_schema AND C.table_name=V.table_name "); + if (restrictions != null && restrictions.Length >= 2 && + restrictions[1] != null) + where.AppendFormat(CultureInfo.InvariantCulture, "C.table_schema='{0}' ", restrictions[1]); + if (restrictions != null && restrictions.Length >= 3 && + restrictions[2] != null) + { + if (where.Length > 0) + where.Append("AND "); + where.AppendFormat(CultureInfo.InvariantCulture, "C.table_name='{0}' ", restrictions[2]); + } + if (restrictions != null && restrictions.Length == 4 && + restrictions[3] != null) + { + if (where.Length > 0) + where.Append("AND "); + where.AppendFormat(CultureInfo.InvariantCulture, "C.column_name='{0}' ", restrictions[3]); + } + if (where.Length > 0) + sql.AppendFormat(CultureInfo.InvariantCulture, " WHERE {0}", where); + MySqlSchemaCollection dt = await GetTableAsync(sql.ToString(), execAsync, cancellationToken).ConfigureAwait(false); + dt.Name = "ViewColumns"; + dt.Columns[0].Name = "VIEW_CATALOG"; + dt.Columns[1].Name = "VIEW_SCHEMA"; + dt.Columns[2].Name = "VIEW_NAME"; + QuoteDefaultValues(dt); + return dt; + } + + private async Task GetTriggersAsync(string[] restrictions, bool execAsync, CancellationToken cancellationToken = default) + { + string[] keys = new string[4]; + keys[0] = "TRIGGER_CATALOG"; + keys[1] = "TRIGGER_SCHEMA"; + keys[2] = "EVENT_OBJECT_TABLE"; + keys[3] = "TRIGGER_NAME"; + MySqlSchemaCollection dt = await QueryAsync("TRIGGERS", null, keys, restrictions, execAsync, cancellationToken).ConfigureAwait(false); + dt.Name = "Triggers"; + return dt; + } + + /// + /// Return schema information about procedures and functions + /// Restrictions supported are: + /// schema, name, type + /// + /// + /// Boolean that indicates if the function will be executed asynchronously. + /// The cancellation token. + public async Task GetProceduresAsync(string[] restrictions, bool execAsync, CancellationToken cancellationToken = default) + { + string[] keys = new string[4]; + keys[0] = "ROUTINE_CATALOG"; + keys[1] = "ROUTINE_SCHEMA"; + keys[2] = "ROUTINE_NAME"; + keys[3] = "ROUTINE_TYPE"; + + MySqlSchemaCollection dt = await QueryAsync("ROUTINES", null, keys, restrictions, execAsync, cancellationToken).ConfigureAwait(false); + dt.Name = "Procedures"; + return dt; + } + + private async Task GetParametersForRoutineFromexecAsync(string[] restrictions, bool execAsync, CancellationToken cancellationToken = default) + { + string[] keys = new string[5]; + keys[0] = "SPECIFIC_CATALOG"; + keys[1] = "SPECIFIC_SCHEMA"; + keys[2] = "SPECIFIC_NAME"; + keys[3] = "ROUTINE_TYPE"; + keys[4] = "PARAMETER_NAME"; + + StringBuilder sql = new StringBuilder(@"SELECT * FROM INFORMATION_SCHEMA.PARAMETERS"); + // now get our where clause and append it if there is one + string where = GetWhereClause(null, keys, restrictions); + if (!String.IsNullOrEmpty(where)) + sql.AppendFormat(CultureInfo.InvariantCulture, " WHERE {0}", where); + + MySqlSchemaCollection coll = await QueryCollectionAsync("parameters", sql.ToString(), execAsync, cancellationToken).ConfigureAwait(false); + + if ((coll.Rows.Count != 0) && ((string)coll.Rows[0]["routine_type"] == "FUNCTION")) + { + // update missing data for the first row (function return value). + // (using sames valus than GetParametersFromShowCreate). + coll.Rows[0]["parameter_mode"] = "IN"; + coll.Rows[0]["parameter_name"] = "return_value"; // "FUNCTION"; + } + return coll; + } + + /// + /// Return schema information about parameters for procedures and functions + /// Restrictions supported are: + /// schema, name, type, parameter name + /// + public virtual async Task GetProcedureParametersAsync(string[] restrictions, + MySqlSchemaCollection routines, bool execAsync, CancellationToken cancellationToken = default) + { + MySqlSchemaCollection parms = null; + + if (routines == null || routines.Rows.Count == 0) + { + parms = await GetParametersForRoutineFromexecAsync(restrictions, execAsync, cancellationToken).ConfigureAwait(false); + } + else foreach (MySqlSchemaRow routine in routines.Rows) + { + if (restrictions != null && restrictions.Length >= 3) + restrictions[2] = routine["ROUTINE_NAME"].ToString(); + + parms = await GetParametersForRoutineFromexecAsync(restrictions, execAsync, cancellationToken).ConfigureAwait(false); + } + parms.Name = "Procedure Parameters"; + return parms; + } + + protected override async Task GetSchemaInternalAsync(string collection, string[] restrictions, bool execAsync, CancellationToken cancellationToken = default) + { + MySqlSchemaCollection dt = await base.GetSchemaInternalAsync(collection, restrictions, execAsync, cancellationToken).ConfigureAwait(false); + if (dt != null) + return dt; + + switch (collection) + { + case "VIEWS": + return await GetViewsAsync(restrictions, execAsync, cancellationToken).ConfigureAwait(false); + case "PROCEDURES": + return await GetProceduresAsync(restrictions, execAsync, cancellationToken).ConfigureAwait(false); + case "PROCEDURE PARAMETERS": + return await GetProcedureParametersAsync(restrictions, null, execAsync, cancellationToken).ConfigureAwait(false); + case "TRIGGERS": + return await GetTriggersAsync(restrictions, execAsync, cancellationToken).ConfigureAwait(false); + case "VIEWCOLUMNS": + return await GetViewColumnsAsync(restrictions, execAsync, cancellationToken).ConfigureAwait(false); + } + return null; + } + + private static string GetWhereClause(string initial_where, string[] keys, string[] values) + { + StringBuilder where = new StringBuilder(initial_where); + if (values != null) + { + for (int i = 0; i < keys.Length; i++) + { + if (i >= values.Length) break; + if (values[i] == null || values[i] == String.Empty) continue; + if (where.Length > 0) + where.Append(" AND "); + where.AppendFormat(CultureInfo.InvariantCulture, + "{0} LIKE '{1}'", keys[i], values[i]); + } + } + return where.ToString(); + } + + private async Task QueryAsync(string tableName, string initialWhere, string[] keys, string[] values, bool execAsync, CancellationToken cancellationToken = default) + { + StringBuilder query = new StringBuilder("SELECT * FROM INFORMATION_SCHEMA."); + query.Append(tableName); + + string where = GetWhereClause(initialWhere, keys, values); + + if (where.Length > 0) + query.AppendFormat(CultureInfo.InvariantCulture, " WHERE {0}", where); + + if (tableName.Equals("COLUMNS", StringComparison.OrdinalIgnoreCase)) + query.Append(" ORDER BY ORDINAL_POSITION"); + + return await GetTableAsync(query.ToString(), execAsync, cancellationToken).ConfigureAwait(false); + } + + private async Task GetTableAsync(string sql, bool execAsync, CancellationToken cancellationToken = default) + { + MySqlSchemaCollection c = new MySqlSchemaCollection(); + using MySqlCommand cmd = new MySqlCommand(sql, connection); + MySqlDataReader reader = await cmd.ExecuteReaderAsync(default, execAsync, cancellationToken).ConfigureAwait(false); + + // add columns + for (int i = 0; i < reader.FieldCount; i++) + c.AddColumn(reader.GetName(i), reader.GetFieldType(i)); + + using (reader) + { + while (await reader.ReadAsync(execAsync, cancellationToken).ConfigureAwait(false)) + { + MySqlSchemaRow row = c.AddRow(); + for (int i = 0; i < reader.FieldCount; i++) + row[i] = reader.GetValue(i); + } + } + + return c; + } + + public override async Task GetForeignKeysAsync(string[] restrictions, bool execAsync, CancellationToken cancellationToken = default) + { + if (!connection.driver.Version.isAtLeast(5, 1, 16)) + return await base.GetForeignKeysAsync(restrictions, execAsync, cancellationToken).ConfigureAwait(false); + + string sql = @"SELECT rc.constraint_catalog, rc.constraint_schema, + rc.constraint_name, kcu.table_catalog, kcu.table_schema, rc.table_name, + rc.match_option, rc.update_rule, rc.delete_rule, + NULL as referenced_table_catalog, + kcu.referenced_table_schema, rc.referenced_table_name + FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS rc + LEFT JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu ON + kcu.constraint_catalog <=> rc.constraint_catalog AND + kcu.constraint_schema <=> rc.constraint_schema AND + kcu.constraint_name <=> rc.constraint_name + WHERE 1=1 AND kcu.ORDINAL_POSITION=1"; + + StringBuilder where = new StringBuilder(); + if (restrictions.Length >= 2 && !String.IsNullOrEmpty(restrictions[1])) + where.AppendFormat(CultureInfo.InvariantCulture, + " AND rc.constraint_schema LIKE '{0}'", restrictions[1]); + if (restrictions.Length >= 3 && !String.IsNullOrEmpty(restrictions[2])) + where.AppendFormat(CultureInfo.InvariantCulture, + " AND rc.table_name LIKE '{0}'", restrictions[2]); + if (restrictions.Length >= 4 && !String.IsNullOrEmpty(restrictions[3])) + where.AppendFormat(CultureInfo.InvariantCulture, + " AND rc.constraint_name LIKE '{0}'", restrictions[2]); + + sql += where.ToString(); + + return await GetTableAsync(sql, execAsync, cancellationToken).ConfigureAwait(false); + } + + public override async Task GetForeignKeyColumnsAsync(string[] restrictions, bool execAsync, CancellationToken cancellationToken = default) + { + if (!connection.driver.Version.isAtLeast(5, 0, 6)) + return await base.GetForeignKeyColumnsAsync(restrictions, execAsync, cancellationToken).ConfigureAwait(false); + + string sql = @"SELECT kcu.* FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu + WHERE kcu.referenced_table_name IS NOT NULL"; + + StringBuilder where = new StringBuilder(); + if (restrictions.Length >= 2 && !String.IsNullOrEmpty(restrictions[1])) + where.AppendFormat(CultureInfo.InvariantCulture, + " AND kcu.constraint_schema LIKE '{0}'", restrictions[1]); + if (restrictions.Length >= 3 && !String.IsNullOrEmpty(restrictions[2])) + where.AppendFormat(CultureInfo.InvariantCulture, + " AND kcu.table_name LIKE '{0}'", restrictions[2]); + if (restrictions.Length >= 4 && !String.IsNullOrEmpty(restrictions[3])) + where.AppendFormat(CultureInfo.InvariantCulture, + " AND kcu.constraint_name LIKE '{0}'", restrictions[3]); + + sql += where.ToString(); + + return await GetTableAsync(sql, execAsync, cancellationToken).ConfigureAwait(false); + } + } +} diff --git a/MySQL.Data/src/Interceptors/CommandInterceptor.cs b/MySQL.Data/src/Interceptors/CommandInterceptor.cs index f705c1d23..34e0ebb32 100644 --- a/MySQL.Data/src/Interceptors/CommandInterceptor.cs +++ b/MySQL.Data/src/Interceptors/CommandInterceptor.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2004, 2019, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2004, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/Interceptors/ExceptionInterceptor.cs b/MySQL.Data/src/Interceptors/ExceptionInterceptor.cs index 2ffca486e..475c6dc30 100644 --- a/MySQL.Data/src/Interceptors/ExceptionInterceptor.cs +++ b/MySQL.Data/src/Interceptors/ExceptionInterceptor.cs @@ -1,16 +1,16 @@ -// Copyright � 2004, 2018, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2004, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/Interceptors/Interceptor.cs b/MySQL.Data/src/Interceptors/Interceptor.cs index c5ee4b76d..87dd0c572 100644 --- a/MySQL.Data/src/Interceptors/Interceptor.cs +++ b/MySQL.Data/src/Interceptors/Interceptor.cs @@ -1,64 +1,64 @@ -// Copyright (c) 2004, 2019, Oracle and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using System; - -namespace MySql.Data.MySqlClient -{ - /// - /// Interceptor is the base class for the "manager" classes such as ExceptionInterceptor, - /// CommandInterceptor, etc - /// - internal abstract class Interceptor - { - protected MySqlConnection Connection; - - protected void LoadInterceptors(string interceptorList) - { - if (String.IsNullOrEmpty(interceptorList)) return; - - string[] interceptors = interceptorList.Split('|'); - foreach (string interceptorType in interceptors) - { - if (String.IsNullOrEmpty(interceptorType)) continue; - - string type = ResolveType(interceptorType); - Type t = Type.GetType(type); - object interceptorObject = Activator.CreateInstance(t); - AddInterceptor(interceptorObject); - } - } - - protected abstract void AddInterceptor(object o); - - protected virtual string ResolveType(string nameOrType) - { - return nameOrType; - } - } -} +// Copyright © 2004, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using System; + +namespace MySql.Data.MySqlClient +{ + /// + /// Interceptor is the base class for the "manager" classes such as ExceptionInterceptor, + /// CommandInterceptor, etc + /// + internal abstract class Interceptor + { + protected MySqlConnection Connection; + + protected void LoadInterceptors(string interceptorList) + { + if (String.IsNullOrEmpty(interceptorList)) return; + + string[] interceptors = interceptorList.Split('|'); + foreach (string interceptorType in interceptors) + { + if (String.IsNullOrEmpty(interceptorType)) continue; + + string type = ResolveType(interceptorType); + Type t = Type.GetType(type); + object interceptorObject = Activator.CreateInstance(t); + AddInterceptor(interceptorObject); + } + } + + protected abstract void AddInterceptor(object o); + + protected virtual string ResolveType(string nameOrType) + { + return nameOrType; + } + } +} diff --git a/MySQL.Data/src/MySQLActivitySource.cs b/MySQL.Data/src/MySQLActivitySource.cs index 069a3bc3d..739bcee09 100644 --- a/MySQL.Data/src/MySQLActivitySource.cs +++ b/MySQL.Data/src/MySQLActivitySource.cs @@ -1,4 +1,32 @@ -using System; +// Copyright © 2023, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using System; using System.Data; using System.Diagnostics; using System.Reflection; @@ -74,9 +102,12 @@ internal static Activity CommandStart(MySqlCommand command) var settings = command.Connection.Settings; var activity = Activity.Current != null ? Source.StartActivity("SQL Statement", ActivityKind.Client, Activity.Current.Context) : Source.StartActivity("SQL Statement", ActivityKind.Client); - // passing through this attribute will propagate the context into the server - string query_attr = $"00-{Activity.Current.Context.TraceId}-{Activity.Current.Context.SpanId}-00"; - command.Attributes.SetAttribute("traceparent", query_attr); + if (Activity.Current != null) + { + // passing through this attribute will propagate the context into the server + string query_attr = $"00-{Activity.Current.Context.TraceId}-{Activity.Current.Context.SpanId}-00"; + command.Attributes.SetAttribute("traceparent", query_attr); + } activity?.SetTag("db.system", "mysql"); activity?.SetTag("db.name", command.Connection.Database); diff --git a/MySQL.Data/src/MySql.Data.csproj b/MySQL.Data/src/MySql.Data.csproj index 26d1d1652..e8d4a0b3c 100644 --- a/MySQL.Data/src/MySql.Data.csproj +++ b/MySQL.Data/src/MySql.Data.csproj @@ -1,30 +1,23 @@ - + MySql.Data.MySqlClient .Net Core Class Library - Copyright (c) 2016, 2023, Oracle and/or its affiliates. + Copyright © 2004, 2025, Oracle and/or its affiliates. en-US - 8.2.0 - Oracle + 9.4.0 + Oracle Corporation MySql.Data - net462;net48;netstandard2.0;netstandard2.1;net6.0;net7.0;net8.0; + netstandard2.0;netstandard2.1;net9.0;net8.0; MySql.Data MySql;.NET Connector;MySql Connector/NET;netcore;.Net Core;MySql Conector/Net Core;coreclr;C/NET;C/Net Core Review ReleaseNotes.txt for details. logo-mysql-170x115.png + README.md https://dev.mysql.com/downloads/ - GPL-2.0-only + GPL-2.0-only WITH Universal-FOSS-exception-1.0 true - false - false - false - false - false - false - false - false - false + false True True ..\..\ConnectorNetPublicKey.snk @@ -33,33 +26,41 @@ true + + $(TargetFrameworks);net10.0 + + + + net462;net48;$(TargetFrameworks) + + + + + + + + + + - + + - + - - - + + + - - - - - - - - true - - - true - + + + @@ -71,14 +72,14 @@ - + - - + + - + - + diff --git a/MySQL.Data/src/MySqlAttribute.cs b/MySQL.Data/src/MySqlAttribute.cs index 298724f9c..370b7c16a 100644 --- a/MySQL.Data/src/MySqlAttribute.cs +++ b/MySQL.Data/src/MySqlAttribute.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2022, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/MySqlAttributeCollection.cs b/MySQL.Data/src/MySqlAttributeCollection.cs index fb6c518c4..4c66ca4b9 100644 --- a/MySQL.Data/src/MySqlAttributeCollection.cs +++ b/MySQL.Data/src/MySqlAttributeCollection.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2022, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/MySqlBaseConnectionStringBuilder.cs b/MySQL.Data/src/MySqlBaseConnectionStringBuilder.cs index b23f80b8c..278cbcf16 100644 --- a/MySQL.Data/src/MySqlBaseConnectionStringBuilder.cs +++ b/MySQL.Data/src/MySqlBaseConnectionStringBuilder.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2018, 2023, Oracle and/or its affiliates. +// Copyright © 2018, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -524,4 +524,4 @@ internal void SetValue(string keyword, object value, [CallerMemberName] string c public abstract override bool TryGetValue(string keyword, out object value); } -} \ No newline at end of file +} diff --git a/MySQL.Data/src/MySqlClientFactory.cs b/MySQL.Data/src/MySqlClientFactory.cs index d361c44ce..29006a5b9 100644 --- a/MySQL.Data/src/MySqlClientFactory.cs +++ b/MySQL.Data/src/MySqlClientFactory.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2004, 2019, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2004, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/MySqlCommand.cs b/MySQL.Data/src/MySqlCommand.cs index c3b5a241b..f6f93f415 100644 --- a/MySQL.Data/src/MySqlCommand.cs +++ b/MySQL.Data/src/MySqlCommand.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2004, 2023, Oracle and/or its affiliates. +// Copyright © 2004, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/MySqlConnection.cs b/MySQL.Data/src/MySqlConnection.cs index f5cbee54e..e68debbf1 100644 --- a/MySQL.Data/src/MySqlConnection.cs +++ b/MySQL.Data/src/MySqlConnection.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2004, 2023, Oracle and/or its affiliates. +// Copyright © 2004, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -73,6 +73,7 @@ public sealed class MySqlConnection : DbConnection, ICloneable internal ConnectionState connectionState; internal Driver driver; internal bool hasBeenOpen; + internal bool hasBeenDisposed; private SchemaProvider _schemaProvider; private ExceptionInterceptor _exceptionInterceptor; internal CommandInterceptor commandInterceptor; @@ -85,12 +86,6 @@ public sealed class MySqlConnection : DbConnection, ICloneable #nullable disable #endif - /// - /// Occurs when FIDO authentication requests to perform gesture action on a device. - /// - [Obsolete("FIDO authentication client-side plugin is now deprecated. Use WebAuthn authentication client-side plugin instead.")] - public event FidoActionCallback FidoActionRequested; - /// /// Occurs when WebAuthn authentication makes a request to perform the gesture action on a device. /// @@ -115,6 +110,7 @@ public MySqlConnection() //TODO: add event data to StateChange docs Settings = new MySqlConnectionStringBuilder(); _database = String.Empty; + hasBeenDisposed = false; } /// @@ -249,6 +245,12 @@ internal bool SoftClosed [Browsable(false)] public override ConnectionState State => connectionState; + [Browsable(true)] + /// + /// Gets a boolean indicating if the current connection had been disposed. + /// + public bool IsDisposed { get { return hasBeenDisposed; } } + /// Gets a string containing the version of the MySQL server to which the client is connected. /// The version of the instance of MySQL. /// The connection is closed. @@ -355,6 +357,7 @@ protected override void Dispose(bool disposing) { if (State == ConnectionState.Open) Close(); + hasBeenDisposed = true; base.Dispose(disposing); } @@ -599,6 +602,9 @@ internal async Task OpenAsync(bool execAsync, CancellationToken cancellationToke if (State != ConnectionState.Closed) Throw(new InvalidOperationException(Resources.ConnectionAlreadyOpen)); + if (hasBeenDisposed) + Throw(new InvalidOperationException("The connection had been disposed.")); + // start up our interceptors _exceptionInterceptor = new ExceptionInterceptor(this); commandInterceptor = new CommandInterceptor(this); @@ -606,7 +612,6 @@ internal async Task OpenAsync(bool execAsync, CancellationToken cancellationToke SetState(ConnectionState.Connecting, true); AssertPermissions(); - Settings.FidoActionRequested = FidoActionRequested; Settings.WebAuthnActionRequested = WebAuthnActionRequested; //TODO: SUPPORT FOR 452 AND 46X @@ -743,8 +748,6 @@ internal async Task AbortAsync(bool execAsync, CancellationToken cancellationTok driver.currentTransaction.Connection = newConn; } } - - await driver.CloseAsync(execAsync).ConfigureAwait(false); } catch (Exception ex) { @@ -752,6 +755,7 @@ internal async Task AbortAsync(bool execAsync, CancellationToken cancellationTok } finally { + await driver.CloseAsync(execAsync).ConfigureAwait(false); this.IsInUse = false; } SetState(ConnectionState.Closed, true); @@ -1260,13 +1264,6 @@ private static async Task ClearAllPoolsAsync(bool execAsync) #endregion } - /// - /// Represents the method to handle the event of a - /// - /// - [Obsolete("FIDO authentication client-side plugin is now deprecated. Use WebAuthn authentication client-side plugin instead.")] - public delegate void FidoActionCallback(); - /// /// Represents the method to handle the event of a /// . diff --git a/MySQL.Data/src/MySqlConnectionStringBuilder.cs b/MySQL.Data/src/MySqlConnectionStringBuilder.cs index f790cfb45..c61949777 100644 --- a/MySQL.Data/src/MySqlConnectionStringBuilder.cs +++ b/MySQL.Data/src/MySqlConnectionStringBuilder.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2023, Oracle and/or its affiliates. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -144,7 +144,7 @@ static MySqlConnectionStringBuilder() msb.SetValue("kerberosauthmode", value); }, (msb, sender) => msb.KerberosAuthMode)); - + Options.Add(new MySqlConnectionStringOption("openididentitytoken", null, typeof(string), string.Empty, false)); #endregion #region OtherProperties @@ -211,6 +211,7 @@ static MySqlConnectionStringBuilder() (msb, sender, value) => { msb.SetValue("exceptioninterceptors", value); }, (msb, sender) => msb.ExceptionInterceptors)); Options.Add(new MySqlConnectionStringOption("commandinterceptors", "command interceptors", typeof(string), null, false, (msb, sender, value) => { msb.SetValue("commandinterceptors", value); }, (msb, sender) => msb.CommandInterceptors)); + Options.Add(new MySqlConnectionStringOption("rewritebatchedstatements", null, typeof(bool), false, false)); #endregion @@ -536,6 +537,21 @@ public KerberosAuthMode KerberosAuthMode set { SetValue("kerberosauthmode", value); } } + /// + /// Gets or sets the Identity Token to be used in OpenID Connect authentication. + /// + /// + /// If is set the value will be used to try to log in using OpenID Connect authentication. + /// + [Category("Authentication")] + [DisplayName("OpenIdIdentityToken")] + [Description("Specifies the Identity Token to use during OpenID Connect authentication.")] + public string OpenIdIdentityToken + { + get { return (string)values["openididentitytoken"]; } + set { SetValue("openididentitytoken", value); } + } + #endregion #region Other Properties @@ -850,9 +866,16 @@ public string CommandInterceptors } /// - /// Gets or sets the event for the Fido callback. + /// Gets or sets a boolean indicating if this connection should rewrite batched statements as one block. /// - internal FidoActionCallback FidoActionRequested { get; set; } + [Category("Advanced")] + [DisplayName("Rewrite Batched Statements")] + [Description("Indicates if this connection should rewrite batched statements as one block.")] + public bool RewriteBatchedStatements + { + get { return (bool)values["rewritebatchedstatements"]; } + set { SetValue("rewritebatchedstatements", value); } + } /// /// Gets or sets the event for the WebauthN callback. diff --git a/MySQL.Data/src/MySqlDataReader.cs b/MySQL.Data/src/MySqlDataReader.cs index 37198d7da..380dd648a 100644 --- a/MySQL.Data/src/MySqlDataReader.cs +++ b/MySQL.Data/src/MySqlDataReader.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2004, 2023, Oracle and/or its affiliates. +// Copyright © 2004, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -336,7 +336,11 @@ public sbyte GetSByte(int i) if (v is MySqlByte) return (sbyte)ChangeType(v, i, typeof(sbyte)); else +#if !NET8_0_OR_GREATER return checked(((MySqlByte)v).Value); +#else + return checked((sbyte)((MySqlUByte)v).Value); +#endif } /// @@ -915,13 +919,7 @@ public override String GetString(int i) { IMySqlValue val = GetFieldValue(i, true); - if (val is MySqlBinary) - { - byte[] v = ((MySqlBinary)val).Value; - return ResultSet.Fields[i].Encoding.GetString(v, 0, v.Length); - } - - return val.Value.ToString(); + return (string)val.Value; } /// diff --git a/MySQL.Data/src/MySqlError.cs b/MySQL.Data/src/MySqlError.cs index b98cfc1bd..518aa70b0 100644 --- a/MySQL.Data/src/MySqlError.cs +++ b/MySQL.Data/src/MySqlError.cs @@ -1,2010 +1,2010 @@ -// Copyright (c) 2004, 2021, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -namespace MySql.Data.MySqlClient -{ - /// - /// Collection of error codes that can be returned by the server - /// - public class MySqlError - { - /// - /// - /// - /// - public MySqlError(string level, int code, string message) - { - this.Level = level; - this.Code = code; - this.Message = message; - } - - /// - /// Error level - /// - public string Level { get; } - - /// - /// Error code - /// - public int Code { get; } - - /// - /// Error message - /// - public string Message { get; } - }; - - /// - /// Provides a reference to error codes returned by MySQL. - /// - public enum MySqlErrorCode - { - None = 0, - /// - ///ER_HASHCHK - HashCheck = 1000, - /// - ///ER_NISAMCHK - ISAMCheck = 1001, - /// - ///ER_NO - No = 1002, - /// - ///ER_YES - Yes = 1003, - ///The file couldn't be created. - ///ER_CANT_CREATE_FILE - CannotCreateFile = 1004, - ///The table couldn't be created. - ///ER_CANT_CREATE_TABLE - CannotCreateTable = 1005, - ///The database couldn't be created. - ///ER_CANT_CREATE_DB - CannotCreateDatabase = 1006, - ///The database couldn't be created, it already exists. - ///ER_DB_CREATE_EXISTS - DatabaseCreateExists = 1007, - ///The database couldn't be dropped, it doesn't exist. - ///ER_DB_DROP_EXISTS - DatabaseDropExists = 1008, - ///The database couldn't be dropped, the file can't be deleted. - ///ER_DB_DROP_DELETE - DatabaseDropDelete = 1009, - ///The database couldn't be dropped, the directory can't be deleted. - ///ER_DB_DROP_RMDIR - DatabaseDropRemoveDir = 1010, - ///The file couldn't be deleted. - ///ER_CANT_DELETE_FILE - CannotDeleteFile = 1011, - ///The record couldn't be read from the system table. - ///ER_CANT_FIND_SYSTEM_REC - CannotFindSystemRecord = 1012, - ///The status couldn't be retrieved. - ///ER_CANT_GET_STAT - CannotGetStatus = 1013, - ///The working directory couldn't be retrieved. - ///ER_CANT_GET_WD - CannotGetWorkingDirectory = 1014, - ///The file couldn't be locked. - ///ER_CANT_LOCK - CannotLock = 1015, - ///The file couldn't be opened. - ///ER_CANT_OPEN_FILE - CannotOpenFile = 1016, - ///The file couldn't be found. - ///ER_FILE_NOT_FOUND - FileNotFound = 1017, - ///The directory couldn't be read. - ///ER_CANT_READ_DIR - CannotReadDirectory = 1018, - ///The working directory couldn't be entered. - ///ER_CANT_SET_WD - CannotSetWorkingDirectory = 1019, - ///The record changed since it was last read. - ///ER_CHECKREAD - CheckRead = 1020, - ///The disk is full. - ///ER_DISK_FULL - DiskFull = 1021, - /// - /// There is already a key with the given values. - /// - DuplicateKey = 1022, - ///An error occurred when closing the file. - ///ER_ERROR_ON_CLOSE - ErrorOnClose = 1023, - ///An error occurred when reading from the file. - ///ER_ERROR_ON_READ - ErrorOnRead = 1024, - ///An error occurred when renaming then file. - ///ER_ERROR_ON_RENAME - ErrorOnRename = 1025, - ///An error occurred when writing to the file. - ///ER_ERROR_ON_WRITE - ErrorOnWrite = 1026, - ///The file is in use. - ///ER_FILE_USED - FileUsed = 1027, - ///Sorting has been aborted. - ///ER_FILSORT_ABORT - FileSortAborted = 1028, - ///The view doesn't exist. - ///ER_FORM_NOT_FOUND - FormNotFound = 1029, - ///Got the specified error from the table storage engine. - ///ER_GET_ERRNO - GetErrorNumber = 1030, - ///The table storage engine doesn't support the specified option. - ///ER_ILLEGAL_HA - IllegalHA = 1031, - /// - /// The specified key was not found. - /// - KeyNotFound = 1032, - ///The file contains incorrect information. - ///ER_NOT_FORM_FILE - NotFormFile = 1033, - ///The key file is incorrect for the table, it should be repaired. - ///ER_NOT_KEYFILE - NotKeyFile = 1034, - ///The key file is old for the table, it should be repaired. - ///ER_OLD_KEYFILE - OldKeyFile = 1035, - ///The table is read-only - ///ER_OPEN_AS_READONLY - OpenAsReadOnly = 1036, - ///The server is out of memory, it should be restarted. - ///ER_OUTOFMEMORY - OutOfMemory = 1037, - ///The server is out of sort-memory, the sort buffer size should be increased. - ///ER_OUT_OF_SORTMEMORY - OutOfSortMemory = 1038, - ///An unexpected EOF was found when reading from the file. - ///ER_UNEXPECTED_EOF - UnexepectedEOF = 1039, - ///Too many connections are open. - ///ER_CON_COUNT_ERROR - ConnectionCountError = 1040, - ///The server is out of resources, check if MySql or some other process is using all available memory. - ///ER_OUT_OF_RESOURCES - OutOfResources = 1041, - /// - /// Given when the connection is unable to successfully connect to host. - /// - UnableToConnectToHost = 1042, - ///The handshake was invalid. - ///ER_HANDSHAKE_ERROR - HandshakeError = 1043, - ///Access was denied for the specified user using the specified database. - ///ER_DBACCESS_DENIED_ERROR - DatabaseAccessDenied = 1044, - /// - /// Normally returned when an incorrect password is given - /// - AccessDenied = 1045, - ///No database has been selected. - ///ER_NO_DB_ERROR - NoDatabaseSelected = 1046, - ///The command is unknown. - ///ER_UNKNOWN_COM_ERROR - UnknownCommand = 1047, - ///The specified column cannot be NULL. - ///ER_BAD_NULL_ERROR - ColumnCannotBeNull = 1048, - /// The specified database is not known. - UnknownDatabase = 1049, - ///The specified table already exists. - ///ER_TABLE_EXISTS_ERROR - TableExists = 1050, - ///The specified table is unknown. - ///ER_BAD_TABLE_ERROR - BadTable = 1051, - ///The specified column is ambiguous. - ///ER_NON_UNIQ_ERROR - NonUnique = 1052, - ///The server is currently being shutdown. - ///ER_SERVER_SHUTDOWN - ServerShutdown = 1053, - ///The specified columns is unknown. - ///ER_BAD_FIELD_ERROR - BadFieldError = 1054, - ///The specified column isn't in GROUP BY. - ///ER_WRONG_FIELD_WITH_GROUP - WrongFieldWithGroup = 1055, - ///The specified columns cannot be grouped on. - ///ER_WRONG_GROUP_FIELD - WrongGroupField = 1056, - ///There are sum functions and columns in the same statement. - ///ER_WRONG_SUM_SELECT - WrongSumSelected = 1057, - ///The column count doesn't match the value count. - ///ER_WRONG_VALUE_COUNT - WrongValueCount = 1058, - ///The identifier name is too long. - ///ER_TOO_LONG_IDENT - TooLongIdentifier = 1059, - ///The column name is duplicated. - ///ER_DUP_FIELDNAME - DuplicateFieldName = 1060, - /// - /// Duplicate Key Name - /// - DuplicateKeyName = 1061, - /// - /// Duplicate Key Entry - /// - DuplicateKeyEntry = 1062, - ///The column specifier is incorrect. - ///ER_WRONG_FIELD_SPEC - WrongFieldSpecifier = 1063, - ///An error occurred when parsing the statement. - ///ER_PARSE_ERROR - ParseError = 1064, - ///The statement is empty. - ///ER_EMPTY_QUERY - EmptyQuery = 1065, - ///The table alias isn't unique. - ///ER_NONUNIQ_TABLE - NonUniqueTable = 1066, - ///The default value is invalid for the specified field. - ///ER_INVALID_DEFAULT - InvalidDefault = 1067, - ///The table has multiple primary keys defined. - ///ER_MULTIPLE_PRI_KEY - MultiplePrimaryKey = 1068, - ///Too many keys were defined for the table. - ///ER_TOO_MANY_KEYS - TooManyKeys = 1069, - ///Too many parts to the keys were defined for the table. - ///ER_TOO_MANY_KEY_PARTS - TooManyKeysParts = 1070, - ///The specified key is too long - ///ER_TOO_LONG_KEY - TooLongKey = 1071, - ///The specified key column doesn't exist in the table. - ///ER_KEY_COLUMN_DOES_NOT_EXITS - KeyColumnDoesNotExist = 1072, - ///The BLOB column was used as a key, this can't be done. - ///ER_BLOB_USED_AS_KEY - BlobUsedAsKey = 1073, - ///The column length is too big for the specified column type. - ///ER_TOO_BIG_FIELDLENGTH - TooBigFieldLength = 1074, - ///There can only be one auto-column, and it must be defined as a PK. - ///ER_WRONG_AUTO_KEY - WrongAutoKey = 1075, - ///The server is ready to accept connections. - ///ER_READY - Ready = 1076, - /// - ///ER_NORMAL_SHUTDOWN - NormalShutdown = 1077, - ///The server received the specified signal and is aborting. - ///ER_GOT_SIGNAL - GotSignal = 1078, - ///The server shutdown is complete. - ///ER_SHUTDOWN_COMPLETE - ShutdownComplete = 1079, - ///The server is forcing close of the specified thread. - ///ER_FORCING_CLOSE - ForcingClose = 1080, - ///An error occurred when creating the IP socket. - ///ER_IPSOCK_ERROR - IPSocketError = 1081, - ///The table has no index like the one used in CREATE INDEX. - ///ER_NO_SUCH_INDEX - NoSuchIndex = 1082, - ///The field separator argument is not what is expected, check the manual. - ///ER_WRONG_FIELD_TERMINATORS - WrongFieldTerminators = 1083, - ///The BLOB columns must terminated, fixed row lengths cannot be used. - ///ER_BLOBS_AND_NO_TERMINATED - BlobsAndNoTerminated = 1084, - ///The text file cannot be read. - ///ER_TEXTFILE_NOT_READABLE - TextFileNotReadable = 1085, - ///The specified file already exists. - ///ER_FILE_EXISTS_ERROR - FileExists = 1086, - ///Information returned by the LOAD statement. - ///ER_LOAD_INFO - LoadInfo = 1087, - ///Information returned by an UPDATE statement. - ///ER_ALTER_INFO - AlterInfo = 1088, - ///The prefix key is incorrect. - ///ER_WRONG_SUB_KEY - WrongSubKey = 1089, - ///All columns cannot be removed from a table, use DROP TABLE instead. - ///ER_CANT_REMOVE_ALL_FIELDS - CannotRemoveAllFields = 1090, - ///Cannot DROP, check that the column or key exists. - ///ER_CANT_DROP_FIELD_OR_KEY - CannotDropFieldOrKey = 1091, - ///Information returned by an INSERT statement. - ///ER_INSERT_INFO - InsertInfo = 1092, - ///The target table cannot be specified for update in FROM clause. - ///ER_UPDATE_TABLE_USED - UpdateTableUsed = 1093, - ///The specified thread ID is unknown. - ///ER_NO_SUCH_THREAD - NoSuchThread = 1094, - ///The thread cannot be killed, the current user is not the owner. - ///ER_KILL_DENIED_ERROR - KillDenied = 1095, - ///No tables used in the statement. - ///ER_NO_TABLES_USED - NoTablesUsed = 1096, - ///Too many string have been used for the specified column and SET. - ///ER_TOO_BIG_SET - TooBigSet = 1097, - ///A unique filename couldn't be generated. - ///ER_NO_UNIQUE_LOGFILE - NoUniqueLogFile = 1098, - ///The specified table was locked with a READ lock, and can't be updated. - ///ER_TABLE_NOT_LOCKED_FOR_WRITE - TableNotLockedForWrite = 1099, - ///The specified table was not locked with LOCK TABLES. - ///ER_TABLE_NOT_LOCKED - TableNotLocked = 1100, - ///BLOB and Text columns cannot have a default value. - ///ER_BLOB_CANT_HAVE_DEFAULT - BlobCannotHaveDefault = 1101, - ///The specified database name is incorrect. - ///ER_WRONG_DB_NAME - WrongDatabaseName = 1102, - ///The specified table name is incorrect. - ///ER_WRONG_TABLE_NAME - WrongTableName = 1103, - ///The SELECT command would examine more than MAX_JOIN_SIZE rows, check the WHERE clause and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is ok. - ///ER_TOO_BIG_SELECT - TooBigSelect = 1104, - ///An unknown error occurred. - ///ER_UNKNOWN_ERROR - UnknownError = 1105, - ///The specified procedure is unknown. - ///ER_UNKNOWN_PROCEDURE - UnknownProcedure = 1106, - ///The number of parameters provided for the specified procedure is incorrect. - ///ER_WRONG_PARAMCOUNT_TO_PROCEDURE - WrongParameterCountToProcedure = 1107, - ///The parameters provided for the specified procedure are incorrect. - ///ER_WRONG_PARAMETERS_TO_PROCEDURE - WrongParametersToProcedure = 1108, - ///The specified table is unknown. - ///ER_UNKNOWN_TABLE - UnknownTable = 1109, - ///The specified column has been specified twice. - ///ER_FIELD_SPECIFIED_TWICE - FieldSpecifiedTwice = 1110, - ///The group function has been incorrectly used. - ///ER_INVALID_GROUP_FUNC_USE - InvalidGroupFunctionUse = 1111, - ///The specified table uses an extension that doesn't exist in this MySQL version. - ///ER_UNSUPPORTED_EXTENSION - UnsupportedExtenstion = 1112, - ///The table must have at least one column. - ///ER_TABLE_MUST_HAVE_COLUMNS - TableMustHaveColumns = 1113, - ///The specified table is full. - ///ER_RECORD_FILE_FULL - RecordFileFull = 1114, - ///The specified character set is unknown. - ///ER_UNKNOWN_CHARACTER_SET - UnknownCharacterSet = 1115, - ///Too many tables, MySQL can only use the specified number of tables in a JOIN. - ///ER_TOO_MANY_TABLES - TooManyTables = 1116, - ///Too many columns - ///ER_TOO_MANY_FIELDS - TooManyFields = 1117, - ///The row size is too large, the maximum row size for the used tables (not counting BLOBS) is specified, change some columns or BLOBS. - ///ER_TOO_BIG_ROWSIZE - TooBigRowSize = 1118, - ///A thread stack overrun occurred. Stack statistics are specified. - ///ER_STACK_OVERRUN - StackOverrun = 1119, - ///A cross dependency was found in the OUTER JOIN, examine the ON conditions. - ///ER_WRONG_OUTER_JOIN - WrongOuterJoin = 1120, - ///The table handler doesn't support NULL in the given index, change specified column to be NOT NULL or use another handler. - ///ER_NULL_COLUMN_IN_INDEX - NullColumnInIndex = 1121, - ///The specified user defined function cannot be loaded. - ///ER_CANT_FIND_UDF - CannotFindUDF = 1122, - ///The specified user defined function cannot be initialised. - ///ER_CANT_INITIALIZE_UDF - CannotInitializeUDF = 1123, - ///No paths are allowed for the shared library. - ///ER_UDF_NO_PATHS - UDFNoPaths = 1124, - ///The specified user defined function already exists. - ///ER_UDF_EXISTS - UDFExists = 1125, - ///The specified shared library cannot be opened. - ///ER_CANT_OPEN_LIBRARY - CannotOpenLibrary = 1126, - ///The specified symbol cannot be found in the library. - ///ER_CANT_FIND_DL_ENTRY - CannotFindDLEntry = 1127, - ///The specified function is not defined. - ///ER_FUNCTION_NOT_DEFINED - FunctionNotDefined = 1128, - ///The specified host is blocked because of too many connection errors, unblock with 'mysqladmin flush-hosts'. - ///ER_HOST_IS_BLOCKED - HostIsBlocked = 1129, - /// - /// The given host is not allowed to connect - /// - HostNotPrivileged = 1130, - /// - /// The anonymous user is not allowed to connect - /// - AnonymousUser = 1131, - /// - /// The given password is not allowed - /// - PasswordNotAllowed = 1132, - /// - /// The given password does not match - /// - PasswordNoMatch = 1133, - ///Information returned by an UPDATE statement. - ///ER_UPDATE_INFO - UpdateInfo = 1134, - ///A new thread couldn't be created. - ///ER_CANT_CREATE_THREAD - CannotCreateThread = 1135, - ///The column count doesn't match the value count. - ///ER_WRONG_VALUE_COUNT_ON_ROW - WrongValueCountOnRow = 1136, - ///The specified table can't be re-opened. - ///ER_CANT_REOPEN_TABLE - CannotReopenTable = 1137, - ///The NULL value has been used incorrectly. - ///ER_INVALID_USE_OF_NULL - InvalidUseOfNull = 1138, - ///The regular expression contains an error. - ///ER_REGEXP_ERROR - RegExpError = 1139, - ///GROUP columns (MIN(), MAX(), COUNT(), ...) cannot be mixes with no GROUP columns if there is not GROUP BY clause. - ///ER_MIX_OF_GROUP_FUNC_AND_FIELDS - MixOfGroupFunctionAndFields = 1140, - /// - ///ER_NONEXISTING_GRANT - NonExistingGrant = 1141, - /// - ///ER_TABLEACCESS_DENIED_ERROR - TableAccessDenied = 1142, - /// - ///ER_COLUMNACCESS_DENIED_ERROR - ColumnAccessDenied = 1143, - /// - ///ER_ILLEGAL_GRANT_FOR_TABLE - IllegalGrantForTable = 1144, - /// - ///ER_GRANT_WRONG_HOST_OR_USER - GrantWrongHostOrUser = 1145, - /// - ///ER_NO_SUCH_TABLE - NoSuchTable = 1146, - /// - ///ER_NONEXISTING_TABLE_GRANT - NonExistingTableGrant = 1147, - /// - ///ER_NOT_ALLOWED_COMMAND - NotAllowedCommand = 1148, - /// - ///ER_SYNTAX_ERROR - SyntaxError = 1149, - /// - ///ER_DELAYED_CANT_CHANGE_LOCK - DelayedCannotChangeLock = 1150, - /// - ///ER_TOO_MANY_DELAYED_THREADS - TooManyDelayedThreads = 1151, - /// - ///ER_ABORTING_CONNECTION - AbortingConnection = 1152, - /// - /// An attempt was made to send or receive a packet larger than - /// max_allowed_packet_size - /// - PacketTooLarge = 1153, - /// - ///ER_NET_READ_ERROR_FROM_PIPE - NetReadErrorFromPipe = 1154, - /// - ///ER_NET_FCNTL_ERROR - NetFCntlError = 1155, - /// - ///ER_NET_PACKETS_OUT_OF_ORDER - NetPacketsOutOfOrder = 1156, - /// - ///ER_NET_UNCOMPRESS_ERROR - NetUncompressError = 1157, - /// - ///ER_NET_READ_ERROR - NetReadError = 1158, - /// - ///ER_NET_READ_INTERRUPTED - NetReadInterrupted = 1159, - /// - ///ER_NET_ERROR_ON_WRITE - NetErrorOnWrite = 1160, - /// - ///ER_NET_WRITE_INTERRUPTED - NetWriteInterrupted = 1161, - /// - ///ER_TOO_LONG_STRING - TooLongString = 1162, - /// - ///ER_TABLE_CANT_HANDLE_BLOB - TableCannotHandleBlob = 1163, - /// - ///ER_TABLE_CANT_HANDLE_AUTO_INCREMENT - TableCannotHandleAutoIncrement = 1164, - /// - ///ER_DELAYED_INSERT_TABLE_LOCKED - DelayedInsertTableLocked = 1165, - /// - ///ER_WRONG_COLUMN_NAME - WrongColumnName = 1166, - /// - ///ER_WRONG_KEY_COLUMN - WrongKeyColumn = 1167, - /// - ///ER_WRONG_MRG_TABLE - WrongMergeTable = 1168, - /// - ///ER_DUP_UNIQUE - DuplicateUnique = 1169, - /// - ///ER_BLOB_KEY_WITHOUT_LENGTH - BlobKeyWithoutLength = 1170, - /// - ///ER_PRIMARY_CANT_HAVE_NULL - PrimaryCannotHaveNull = 1171, - /// - ///ER_TOO_MANY_ROWS - TooManyRows = 1172, - /// - ///ER_REQUIRES_PRIMARY_KEY - RequiresPrimaryKey = 1173, - /// - ///ER_NO_RAID_COMPILED - NoRAIDCompiled = 1174, - /// - ///ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE - UpdateWithoutKeysInSafeMode = 1175, - /// - ///ER_KEY_DOES_NOT_EXITS - KeyDoesNotExist = 1176, - /// - ///ER_CHECK_NO_SUCH_TABLE - CheckNoSuchTable = 1177, - /// - ///ER_CHECK_NOT_IMPLEMENTED - CheckNotImplemented = 1178, - /// - ///ER_CANT_DO_THIS_DURING_AN_TRANSACTION - CannotDoThisDuringATransaction = 1179, - /// - ///ER_ERROR_DURING_COMMIT - ErrorDuringCommit = 1180, - /// - ///ER_ERROR_DURING_ROLLBACK - ErrorDuringRollback = 1181, - /// - ///ER_ERROR_DURING_FLUSH_LOGS - ErrorDuringFlushLogs = 1182, - /// - ///ER_ERROR_DURING_CHECKPOINT - ErrorDuringCheckpoint = 1183, - /// - ///ER_NEW_ABORTING_CONNECTION - NewAbortingConnection = 1184, - /// - ///ER_DUMP_NOT_IMPLEMENTED - DumpNotImplemented = 1185, - /// - ///ER_FLUSH_SOURCE_BINLOG_CLOSED - FlushSourceBinLogClosed = 1186, - /// - ///ER_INDEX_REBUILD - IndexRebuild = 1187, - /// - ///ER_SOURCE - SourceError = 1188, - /// - ///ER_SOURCE_NET_READ - SourceNetRead = 1189, - /// - ///ER_SOURCE_NET_WRITE - SourceNetWrite = 1190, - /// - ///ER_FT_MATCHING_KEY_NOT_FOUND - FullTextMatchingKeyNotFound = 1191, - /// - ///ER_LOCK_OR_ACTIVE_TRANSACTION - LockOrActiveTransaction = 1192, - /// - ///ER_UNKNOWN_SYSTEM_VARIABLE - UnknownSystemVariable = 1193, - /// - ///ER_CRASHED_ON_USAGE - CrashedOnUsage = 1194, - /// - ///ER_CRASHED_ON_REPAIR - CrashedOnRepair = 1195, - /// - ///ER_WARNING_NOT_COMPLETE_ROLLBACK - WarningNotCompleteRollback = 1196, - /// - ///ER_TRANS_CACHE_FULL - TransactionCacheFull = 1197, - /// - ///ER_REPLICA_MUST_STOP - ReplicaMustStop = 1198, - /// - ///ER_REPLICA_NOT_RUNNING - ReplicaNotRunning = 1199, - /// - ///ER_BAD_REPLICA - BadReplica = 1200, - /// - ///ER_SOURCE_INFO - SourceInfo = 1201, - /// - ///ER_REPLICA_THREAD - ReplicaThread = 1202, - /// - ///ER_TOO_MANY_USER_CONNECTIONS - TooManyUserConnections = 1203, - /// - ///ER_SET_CONSTANTS_ONLY - SetConstantsOnly = 1204, - /// - ///ER_LOCK_WAIT_TIMEOUT - LockWaitTimeout = 1205, - /// - ///ER_LOCK_TABLE_FULL - LockTableFull = 1206, - /// - ///ER_READ_ONLY_TRANSACTION - ReadOnlyTransaction = 1207, - /// - ///ER_DROP_DB_WITH_READ_LOCK - DropDatabaseWithReadLock = 1208, - /// - ///ER_CREATE_DB_WITH_READ_LOCK - CreateDatabaseWithReadLock = 1209, - /// - ///ER_WRONG_ARGUMENTS - WrongArguments = 1210, - /// - ///ER_NO_PERMISSION_TO_CREATE_USER - NoPermissionToCreateUser = 1211, - /// - ///ER_UNION_TABLES_IN_DIFFERENT_DIR - UnionTablesInDifferentDirectory = 1212, - /// - ///ER_LOCK_DEADLOCK - LockDeadlock = 1213, - /// - ///ER_TABLE_CANT_HANDLE_FT - TableCannotHandleFullText = 1214, - /// - ///ER_CANNOT_ADD_FOREIGN - CannotAddForeignConstraint = 1215, - /// - ///ER_NO_REFERENCED_ROW - NoReferencedRow = 1216, - /// - ///ER_ROW_IS_REFERENCED - RowIsReferenced = 1217, - /// - ///ER_CONNECT_TO_SOURCE - ConnectToSource = 1218, - /// - ///ER_QUERY_ON_SOURCE - QueryOnSource = 1219, - /// - ///ER_ERROR_WHEN_EXECUTING_COMMAND - ErrorWhenExecutingCommand = 1220, - /// - ///ER_WRONG_USAGE - WrongUsage = 1221, - /// - ///ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT - WrongNumberOfColumnsInSelect = 1222, - /// - ///ER_CANT_UPDATE_WITH_READLOCK - CannotUpdateWithReadLock = 1223, - /// - ///ER_MIXING_NOT_ALLOWED - MixingNotAllowed = 1224, - /// - ///ER_DUP_ARGUMENT - DuplicateArgument = 1225, - /// - ///ER_USER_LIMIT_REACHED - UserLimitReached = 1226, - /// - ///ER_SPECIFIC_ACCESS_DENIED_ERROR - SpecifiedAccessDeniedError = 1227, - /// - ///ER_LOCAL_VARIABLE - LocalVariableError = 1228, - /// - ///ER_GLOBAL_VARIABLE - GlobalVariableError = 1229, - /// - ///ER_NO_DEFAULT - NotDefaultError = 1230, - /// - ///ER_WRONG_VALUE_FOR_VAR - WrongValueForVariable = 1231, - /// - ///ER_WRONG_TYPE_FOR_VAR - WrongTypeForVariable = 1232, - /// - ///ER_VAR_CANT_BE_READ - VariableCannotBeRead = 1233, - /// - ///ER_CANT_USE_OPTION_HERE - CannotUseOptionHere = 1234, - /// - ///ER_NOT_SUPPORTED_YET - NotSupportedYet = 1235, - /// - ///ER_SOURCE_FATAL_ERROR_READING_BINLOG - SourceFatalErrorReadingBinLog = 1236, - /// - ///ER_REPLICA_IGNORED_TABLE - ReplicaIgnoredTable = 1237, - /// - ///ER_INCORRECT_GLOBAL_LOCAL_VAR - IncorrectGlobalLocalVariable = 1238, - /// - ///ER_WRONG_FK_DEF - WrongForeignKeyDefinition = 1239, - /// - ///ER_KEY_REF_DO_NOT_MATCH_TABLE_REF - KeyReferenceDoesNotMatchTableReference = 1240, - /// - ///ER_OPERAND_COLUMNS - OpearnColumnsError = 1241, - /// - ///ER_SUBQUERY_NO_1_ROW - SubQueryNoOneRow = 1242, - /// - ///ER_UNKNOWN_STMT_HANDLER - UnknownStatementHandler = 1243, - /// - ///ER_CORRUPT_HELP_DB - CorruptHelpDatabase = 1244, - /// - ///ER_CYCLIC_REFERENCE - CyclicReference = 1245, - /// - ///ER_AUTO_CONVERT - AutoConvert = 1246, - /// - ///ER_ILLEGAL_REFERENCE - IllegalReference = 1247, - /// - ///ER_DERIVED_MUST_HAVE_ALIAS - DerivedMustHaveAlias = 1248, - /// - ///ER_SELECT_REDUCED - SelectReduced = 1249, - /// - ///ER_TABLENAME_NOT_ALLOWED_HERE - TableNameNotAllowedHere = 1250, - /// - ///ER_NOT_SUPPORTED_AUTH_MODE - NotSupportedAuthMode = 1251, - /// - ///ER_SPATIAL_CANT_HAVE_NULL - SpatialCannotHaveNull = 1252, - /// - ///ER_COLLATION_CHARSET_MISMATCH - CollationCharsetMismatch = 1253, - /// - ///ER_REPLICA_WAS_RUNNING - ReplicaWasRunning = 1254, - /// - ///ER_REPLICA_WAS_NOT_RUNNING - ReplicaWasNotRunning = 1255, - /// - ///ER_TOO_BIG_FOR_UNCOMPRESS - TooBigForUncompress = 1256, - /// - ///ER_ZLIB_Z_MEM_ERROR - ZipLibMemoryError = 1257, - /// - ///ER_ZLIB_Z_BUF_ERROR - ZipLibBufferError = 1258, - /// - ///ER_ZLIB_Z_DATA_ERROR - ZipLibDataError = 1259, - /// - ///ER_CUT_VALUE_GROUP_CONCAT - CutValueGroupConcat = 1260, - /// - ///ER_WARN_TOO_FEW_RECORDS - WarningTooFewRecords = 1261, - /// - ///ER_WARN_TOO_MANY_RECORDS - WarningTooManyRecords = 1262, - /// - ///ER_WARN_NULL_TO_NOTNULL - WarningNullToNotNull = 1263, - /// - ///ER_WARN_DATA_OUT_OF_RANGE - WarningDataOutOfRange = 1264, - /// - ///WARN_DATA_TRUNCATED - WaningDataTruncated = 1265, - /// - ///ER_WARN_USING_OTHER_HANDLER - WaningUsingOtherHandler = 1266, - /// - ///ER_CANT_AGGREGATE_2COLLATIONS - CannotAggregateTwoCollations = 1267, - /// - ///ER_DROP_USER - DropUserError = 1268, - /// - ///ER_REVOKE_GRANTS - RevokeGrantsError = 1269, - /// - ///ER_CANT_AGGREGATE_3COLLATIONS - CannotAggregateThreeCollations = 1270, - /// - ///ER_CANT_AGGREGATE_NCOLLATIONS - CannotAggregateNCollations = 1271, - /// - ///ER_VARIABLE_IS_NOT_STRUCT - VariableIsNotStructure = 1272, - /// - ///ER_UNKNOWN_COLLATION - UnknownCollation = 1273, - /// - ///ER_REPLICA_IGNORED_SSL_PARAMS - ReplicaIgnoreSSLParameters = 1274, - /// - ///ER_SERVER_IS_IN_SECURE_AUTH_MODE - ServerIsInSecureAuthMode = 1275, - /// - ///ER_WARN_FIELD_RESOLVED - WaningFieldResolved = 1276, - /// - ///ER_BAD_REPLICA_UNTIL_COND - BadReplicaUntilCondition = 1277, - /// - ///ER_MISSING_SKIP_REPLICA - MissingSkipReplica = 1278, - /// - ///ER_UNTIL_COND_IGNORED - ErrorUntilConditionIgnored = 1279, - /// - ///ER_WRONG_NAME_FOR_INDEX - WrongNameForIndex = 1280, - /// - ///ER_WRONG_NAME_FOR_CATALOG - WrongNameForCatalog = 1281, - /// - ///ER_WARN_QC_RESIZE - WarningQueryCacheResize = 1282, - /// - ///ER_BAD_FT_COLUMN - BadFullTextColumn = 1283, - /// - ///ER_UNKNOWN_KEY_CACHE - UnknownKeyCache = 1284, - /// - ///ER_WARN_HOSTNAME_WONT_WORK - WarningHostnameWillNotWork = 1285, - /// - ///ER_UNKNOWN_STORAGE_ENGINE - UnknownStorageEngine = 1286, - /// - ///ER_WARN_DEPRECATED_SYNTAX - WaningDeprecatedSyntax = 1287, - /// - ///ER_NON_UPDATABLE_TABLE - NonUpdateableTable = 1288, - /// - ///ER_FEATURE_DISABLED - FeatureDisabled = 1289, - /// - ///ER_OPTION_PREVENTS_STATEMENT - OptionPreventsStatement = 1290, - /// - ///ER_DUPLICATED_VALUE_IN_TYPE - DuplicatedValueInType = 1291, - /// - ///ER_TRUNCATED_WRONG_VALUE - TruncatedWrongValue = 1292, - /// - ///ER_TOO_MUCH_AUTO_TIMESTAMP_COLS - TooMuchAutoTimestampColumns = 1293, - /// - ///ER_INVALID_ON_UPDATE - InvalidOnUpdate = 1294, - /// - ///ER_UNSUPPORTED_PS - UnsupportedPreparedStatement = 1295, - /// - ///ER_GET_ERRMSG - GetErroMessage = 1296, - /// - ///ER_GET_TEMPORARY_ERRMSG - GetTemporaryErrorMessage = 1297, - /// - ///ER_UNKNOWN_TIME_ZONE - UnknownTimeZone = 1298, - /// - ///ER_WARN_INVALID_TIMESTAMP - WarningInvalidTimestamp = 1299, - /// - ///ER_INVALID_CHARACTER_STRING - InvalidCharacterString = 1300, - /// - ///ER_WARN_ALLOWED_PACKET_OVERFLOWED - WarningAllowedPacketOverflowed = 1301, - /// - ///ER_CONFLICTING_DECLARATIONS - ConflictingDeclarations = 1302, - /// - ///ER_SP_NO_RECURSIVE_CREATE - StoredProcedureNoRecursiveCreate = 1303, - /// - ///ER_SP_ALREADY_EXISTS - StoredProcedureAlreadyExists = 1304, - /// - ///ER_SP_DOES_NOT_EXIST - StoredProcedureDoesNotExist = 1305, - /// - ///ER_SP_DROP_FAILED - StoredProcedureDropFailed = 1306, - /// - ///ER_SP_STORE_FAILED - StoredProcedureStoreFailed = 1307, - /// - ///ER_SP_LILABEL_MISMATCH - StoredProcedureLiLabelMismatch = 1308, - /// - ///ER_SP_LABEL_REDEFINE - StoredProcedureLabelRedefine = 1309, - /// - ///ER_SP_LABEL_MISMATCH - StoredProcedureLabelMismatch = 1310, - /// - ///ER_SP_UNINIT_VAR - StoredProcedureUninitializedVariable = 1311, - /// - ///ER_SP_BADSELECT - StoredProcedureBadSelect = 1312, - /// - ///ER_SP_BADRETURN - StoredProcedureBadReturn = 1313, - /// - ///ER_SP_BADSTATEMENT - StoredProcedureBadStatement = 1314, - /// - ///ER_UPDATE_LOG_DEPRECATED_IGNORED - UpdateLogDeprecatedIgnored = 1315, - /// - ///ER_UPDATE_LOG_DEPRECATED_TRANSLATED - UpdateLogDeprecatedTranslated = 1316, - /// - ///ER_QUERY_INTERRUPTED - QueryInterrupted = 1317, - /// - ///ER_SP_WRONG_NO_OF_ARGS - StoredProcedureNumberOfArguments = 1318, - /// - ///ER_SP_COND_MISMATCH - StoredProcedureConditionMismatch = 1319, - /// - ///ER_SP_NORETURN - StoredProcedureNoReturn = 1320, - /// - ///ER_SP_NORETURNEND - StoredProcedureNoReturnEnd = 1321, - /// - ///ER_SP_BAD_CURSOR_QUERY - StoredProcedureBadCursorQuery = 1322, - /// - ///ER_SP_BAD_CURSOR_SELECT - StoredProcedureBadCursorSelect = 1323, - /// - ///ER_SP_CURSOR_MISMATCH - StoredProcedureCursorMismatch = 1324, - /// - ///ER_SP_CURSOR_ALREADY_OPEN - StoredProcedureAlreadyOpen = 1325, - /// - ///ER_SP_CURSOR_NOT_OPEN - StoredProcedureCursorNotOpen = 1326, - /// - ///ER_SP_UNDECLARED_VAR - StoredProcedureUndeclaredVariabel = 1327, - /// - ///ER_SP_WRONG_NO_OF_FETCH_ARGS - StoredProcedureWrongNumberOfFetchArguments = 1328, - /// - ///ER_SP_FETCH_NO_DATA - StoredProcedureFetchNoData = 1329, - /// - ///ER_SP_DUP_PARAM - StoredProcedureDuplicateParameter = 1330, - /// - ///ER_SP_DUP_VAR - StoredProcedureDuplicateVariable = 1331, - /// - ///ER_SP_DUP_COND - StoredProcedureDuplicateCondition = 1332, - /// - ///ER_SP_DUP_CURS - StoredProcedureDuplicateCursor = 1333, - /// - ///ER_SP_CANT_ALTER - StoredProcedureCannotAlter = 1334, - /// - ///ER_SP_SUBSELECT_NYI - StoredProcedureSubSelectNYI = 1335, - /// - ///ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG - StatementNotAllowedInStoredFunctionOrTrigger = 1336, - /// - ///ER_SP_VARCOND_AFTER_CURSHNDLR - StoredProcedureVariableConditionAfterCursorHandler = 1337, - /// - ///ER_SP_CURSOR_AFTER_HANDLER - StoredProcedureCursorAfterHandler = 1338, - /// - ///ER_SP_CASE_NOT_FOUND - StoredProcedureCaseNotFound = 1339, - /// - ///ER_FPARSER_TOO_BIG_FILE - FileParserTooBigFile = 1340, - /// - ///ER_FPARSER_BAD_HEADER - FileParserBadHeader = 1341, - /// - ///ER_FPARSER_EOF_IN_COMMENT - FileParserEOFInComment = 1342, - /// - ///ER_FPARSER_ERROR_IN_PARAMETER - FileParserErrorInParameter = 1343, - /// - ///ER_FPARSER_EOF_IN_UNKNOWN_PARAMETER - FileParserEOFInUnknownParameter = 1344, - /// - ///ER_VIEW_NO_EXPLAIN - ViewNoExplain = 1345, - /// - ///ER_FRM_UNKNOWN_TYPE - FrmUnknownType = 1346, - /// - ///ER_WRONG_OBJECT - WrongObject = 1347, - /// - ///ER_NONUPDATEABLE_COLUMN - NonUpdateableColumn = 1348, - /// - ///ER_VIEW_SELECT_DERIVED - ViewSelectDerived = 1349, - /// - ///ER_VIEW_SELECT_CLAUSE - ViewSelectClause = 1350, - /// - ///ER_VIEW_SELECT_VARIABLE - ViewSelectVariable = 1351, - /// - ///ER_VIEW_SELECT_TMPTABLE - ViewSelectTempTable = 1352, - /// - ///ER_VIEW_WRONG_LIST - ViewWrongList = 1353, - /// - ///ER_WARN_VIEW_MERGE - WarningViewMerge = 1354, - /// - ///ER_WARN_VIEW_WITHOUT_KEY - WarningViewWithoutKey = 1355, - /// - ///ER_VIEW_INVALID - ViewInvalid = 1356, - /// - ///ER_SP_NO_DROP_SP - StoredProcedureNoDropStoredProcedure = 1357, - /// - ///ER_SP_GOTO_IN_HNDLR - StoredProcedureGotoInHandler = 1358, - /// - ///ER_TRG_ALREADY_EXISTS - TriggerAlreadyExists = 1359, - /// - ///ER_TRG_DOES_NOT_EXIST - TriggerDoesNotExist = 1360, - /// - ///ER_TRG_ON_VIEW_OR_TEMP_TABLE - TriggerOnViewOrTempTable = 1361, - /// - ///ER_TRG_CANT_CHANGE_ROW - TriggerCannotChangeRow = 1362, - /// - ///ER_TRG_NO_SUCH_ROW_IN_TRG - TriggerNoSuchRowInTrigger = 1363, - /// - ///ER_NO_DEFAULT_FOR_FIELD - NoDefaultForField = 1364, - /// - ///ER_DIVISION_BY_ZERO - DivisionByZero = 1365, - /// - ///ER_TRUNCATED_WRONG_VALUE_FOR_FIELD - TruncatedWrongValueForField = 1366, - /// - ///ER_ILLEGAL_VALUE_FOR_TYPE - IllegalValueForType = 1367, - /// - ///ER_VIEW_NONUPD_CHECK - ViewNonUpdatableCheck = 1368, - /// - ///ER_VIEW_CHECK_FAILED - ViewCheckFailed = 1369, - /// - ///ER_PROCACCESS_DENIED_ERROR - PrecedureAccessDenied = 1370, - /// - ///ER_RELAY_LOG_FAIL - RelayLogFail = 1371, - /// - ///ER_PASSWD_LENGTH - PasswordLength = 1372, - /// - ///ER_UNKNOWN_TARGET_BINLOG - UnknownTargetBinLog = 1373, - /// - ///ER_IO_ERR_LOG_INDEX_READ - IOErrorLogIndexRead = 1374, - /// - ///ER_BINLOG_PURGE_PROHIBITED - BinLogPurgeProhibited = 1375, - /// - ///ER_FSEEK_FAIL - FSeekFail = 1376, - /// - ///ER_BINLOG_PURGE_FATAL_ERR - BinLogPurgeFatalError = 1377, - /// - ///ER_LOG_IN_USE - LogInUse = 1378, - /// - ///ER_LOG_PURGE_UNKNOWN_ERR - LogPurgeUnknownError = 1379, - /// - ///ER_RELAY_LOG_INIT - RelayLogInit = 1380, - /// - ///ER_NO_BINARY_LOGGING - NoBinaryLogging = 1381, - /// - ///ER_RESERVED_SYNTAX - ReservedSyntax = 1382, - /// - ///ER_WSAS_FAILED - WSAStartupFailed = 1383, - /// - ///ER_DIFF_GROUPS_PROC - DifferentGroupsProcedure = 1384, - /// - ///ER_NO_GROUP_FOR_PROC - NoGroupForProcedure = 1385, - /// - ///ER_ORDER_WITH_PROC - OrderWithProcedure = 1386, - /// - ///ER_LOGGING_PROHIBIT_CHANGING_OF - LoggingProhibitsChangingOf = 1387, - /// - ///ER_NO_FILE_MAPPING - NoFileMapping = 1388, - /// - ///ER_WRONG_MAGIC - WrongMagic = 1389, - /// - ///ER_PS_MANY_PARAM - PreparedStatementManyParameters = 1390, - /// - ///ER_KEY_PART_0 - KeyPartZero = 1391, - /// - ///ER_VIEW_CHECKSUM - ViewChecksum = 1392, - /// - ///ER_VIEW_MULTIUPDATE - ViewMultiUpdate = 1393, - /// - ///ER_VIEW_NO_INSERT_FIELD_LIST - ViewNoInsertFieldList = 1394, - /// - ///ER_VIEW_DELETE_MERGE_VIEW - ViewDeleteMergeView = 1395, - /// - ///ER_CANNOT_USER - CannotUser = 1396, - /// - ///ER_XAER_NOTA - XAERNotA = 1397, - /// - ///ER_XAER_INVAL - XAERInvalid = 1398, - /// - ///ER_XAER_RMFAIL - XAERRemoveFail = 1399, - /// - ///ER_XAER_OUTSIDE - XAEROutside = 1400, - /// - ///ER_XAER_RMERR - XAERRemoveError = 1401, - /// - ///ER_XA_RBROLLBACK - XARBRollback = 1402, - /// - ///ER_NONEXISTING_PROC_GRANT - NonExistingProcedureGrant = 1403, - /// - ///ER_PROC_AUTO_GRANT_FAIL - ProcedureAutoGrantFail = 1404, - /// - ///ER_PROC_AUTO_REVOKE_FAIL - ProcedureAutoRevokeFail = 1405, - /// - ///ER_DATA_TOO_LONG - DataTooLong = 1406, - /// - ///ER_SP_BAD_SQLSTATE - StoredProcedureSQLState = 1407, - /// - ///ER_STARTUP - StartupError = 1408, - /// - ///ER_LOAD_FROM_FIXED_SIZE_ROWS_TO_VAR - LoadFromFixedSizeRowsToVariable = 1409, - /// - ///ER_CANT_CREATE_USER_WITH_GRANT - CannotCreateUserWithGrant = 1410, - /// - ///ER_WRONG_VALUE_FOR_TYPE - WrongValueForType = 1411, - /// - ///ER_TABLE_DEF_CHANGED - TableDefinitionChanged = 1412, - /// - ///ER_SP_DUP_HANDLER - StoredProcedureDuplicateHandler = 1413, - /// - ///ER_SP_NOT_VAR_ARG - StoredProcedureNotVariableArgument = 1414, - /// - ///ER_SP_NO_RETSET - StoredProcedureNoReturnSet = 1415, - /// - ///ER_CANT_CREATE_GEOMETRY_OBJECT - CannotCreateGeometryObject = 1416, - /// - ///ER_FAILED_ROUTINE_BREAK_BINLOG - FailedRoutineBreaksBinLog = 1417, - /// - ///ER_BINLOG_UNSAFE_ROUTINE - BinLogUnsafeRoutine = 1418, - /// - ///ER_BINLOG_CREATE_ROUTINE_NEED_SUPER - BinLogCreateRoutineNeedSuper = 1419, - /// - ///ER_EXEC_STMT_WITH_OPEN_CURSOR - ExecuteStatementWithOpenCursor = 1420, - /// - ///ER_STMT_HAS_NO_OPEN_CURSOR - StatementHasNoOpenCursor = 1421, - /// - ///ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG - CommitNotAllowedIfStoredFunctionOrTrigger = 1422, - /// - ///ER_NO_DEFAULT_FOR_VIEW_FIELD - NoDefaultForViewField = 1423, - /// - ///ER_SP_NO_RECURSION - StoredProcedureNoRecursion = 1424, - /// - ///ER_TOO_BIG_SCALE - TooBigScale = 1425, - /// - ///ER_TOO_BIG_PRECISION - TooBigPrecision = 1426, - /// - ///ER_M_BIGGER_THAN_D - MBiggerThanD = 1427, - /// - ///ER_WRONG_LOCK_OF_SYSTEM_TABLE - WrongLockOfSystemTable = 1428, - /// - ///ER_CONNECT_TO_FOREIGN_DATA_SOURCE - ConnectToForeignDataSource = 1429, - /// - ///ER_QUERY_ON_FOREIGN_DATA_SOURCE - QueryOnForeignDataSource = 1430, - /// - ///ER_FOREIGN_DATA_SOURCE_DOESNT_EXIST - ForeignDataSourceDoesNotExist = 1431, - /// - ///ER_FOREIGN_DATA_STRING_INVALID_CANT_CREATE - ForeignDataStringInvalidCannotCreate = 1432, - /// - ///ER_FOREIGN_DATA_STRING_INVALID - ForeignDataStringInvalid = 1433, - /// - ///ER_CANT_CREATE_FEDERATED_TABLE - CannotCreateFederatedTable = 1434, - /// - ///ER_TRG_IN_WRONG_SCHEMA - TriggerInWrongSchema = 1435, - /// - ///ER_STACK_OVERRUN_NEED_MORE - StackOverrunNeedMore = 1436, - /// - ///ER_TOO_LONG_BODY - TooLongBody = 1437, - /// - ///ER_WARN_CANT_DROP_DEFAULT_KEYCACHE - WarningCannotDropDefaultKeyCache = 1438, - /// - ///ER_TOO_BIG_DISPLAYWIDTH - TooBigDisplayWidth = 1439, - /// - ///ER_XAER_DUPID - XAERDuplicateID = 1440, - /// - ///ER_DATETIME_FUNCTION_OVERFLOW - DateTimeFunctionOverflow = 1441, - /// - ///ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG - CannotUpdateUsedTableInStoredFunctionOrTrigger = 1442, - /// - ///ER_VIEW_PREVENT_UPDATE - ViewPreventUpdate = 1443, - /// - ///ER_PS_NO_RECURSION - PreparedStatementNoRecursion = 1444, - /// - ///ER_SP_CANT_SET_AUTOCOMMIT - StoredProcedureCannotSetAutoCommit = 1445, - /// - ///ER_MALFORMED_DEFINER - MalformedDefiner = 1446, - /// - ///ER_VIEW_FRM_NO_USER - ViewFrmNoUser = 1447, - /// - ///ER_VIEW_OTHER_USER - ViewOtherUser = 1448, - /// - ///ER_NO_SUCH_USER - NoSuchUser = 1449, - /// - ///ER_FORBID_SCHEMA_CHANGE - ForbidSchemaChange = 1450, - /// - ///ER_ROW_IS_REFERENCED_2 - RowIsReferenced2 = 1451, - /// - ///ER_NO_REFERENCED_ROW_2 - NoReferencedRow2 = 1452, - /// - ///ER_SP_BAD_VAR_SHADOW - StoredProcedureBadVariableShadow = 1453, - /// - ///ER_TRG_NO_DEFINER - TriggerNoDefiner = 1454, - /// - ///ER_OLD_FILE_FORMAT - OldFileFormat = 1455, - /// - ///ER_SP_RECURSION_LIMIT - StoredProcedureRecursionLimit = 1456, - /// - ///ER_SP_PROC_TABLE_CORRUPT - StoredProcedureTableCorrupt = 1457, - /// - ///ER_SP_WRONG_NAME - StoredProcedureWrongName = 1458, - /// - ///ER_TABLE_NEEDS_UPGRADE - TableNeedsUpgrade = 1459, - /// - ///ER_SP_NO_AGGREGATE - StoredProcedureNoAggregate = 1460, - /// - ///ER_MAX_PREPARED_STMT_COUNT_REACHED - MaxPreparedStatementCountReached = 1461, - /// - ///ER_VIEW_RECURSIVE - ViewRecursive = 1462, - /// - ///ER_NON_GROUPING_FIELD_USED - NonGroupingFieldUsed = 1463, - /// - ///ER_TABLE_CANT_HANDLE_SPKEYS - TableCannotHandleSpatialKeys = 1464, - /// - ///ER_NO_TRIGGERS_ON_SYSTEM_SCHEMA - NoTriggersOnSystemSchema = 1465, - /// - ///ER_REMOVED_SPACES - RemovedSpaces = 1466, - /// - ///ER_AUTOINC_READ_FAILED - AutoIncrementReadFailed = 1467, - /// - ///ER_USERNAME - UserNameError = 1468, - /// - ///ER_HOSTNAME - HostNameError = 1469, - /// - ///ER_WRONG_STRING_LENGTH - WrongStringLength = 1470, - /// - ///ER_NON_INSERTABLE_TABLE - NonInsertableTable = 1471, - /// - ///ER_ADMIN_WRONG_MRG_TABLE - AdminWrongMergeTable = 1472, - /// - ///ER_TOO_HIGH_LEVEL_OF_NESTING_FOR_SELECT - TooHighLevelOfNestingForSelect = 1473, - /// - ///ER_NAME_BECOMES_EMPTY - NameBecomesEmpty = 1474, - /// - ///ER_AMBIGUOUS_FIELD_TERM - AmbiguousFieldTerm = 1475, - /// - ///ER_FOREIGN_SERVER_EXISTS - ForeignServerExists = 1476, - /// - ///ER_FOREIGN_SERVER_DOESNT_EXIST - ForeignServerDoesNotExist = 1477, - /// - ///ER_ILLEGAL_HA_CREATE_OPTION - IllegalHACreateOption = 1478, - /// - ///ER_PARTITION_REQUIRES_VALUES_ERROR - PartitionRequiresValues = 1479, - /// - ///ER_PARTITION_WRONG_VALUES_ERROR - PartitionWrongValues = 1480, - /// - ///ER_PARTITION_MAXVALUE_ERROR - PartitionMaxValue = 1481, - /// - ///ER_PARTITION_SUBPARTITION_ERROR - PartitionSubPartition = 1482, - /// - ///ER_PARTITION_SUBPART_MIX_ERROR - PartitionSubPartMix = 1483, - /// - ///ER_PARTITION_WRONG_NO_PART_ERROR - PartitionWrongNoPart = 1484, - /// - ///ER_PARTITION_WRONG_NO_SUBPART_ERROR - PartitionWrongNoSubPart = 1485, - /// - ///ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR - WrongExpressionInParitionFunction = 1486, - /// - ///ER_NO_CONST_EXPR_IN_RANGE_OR_LIST_ERROR - NoConstantExpressionInRangeOrListError = 1487, - /// - ///ER_FIELD_NOT_FOUND_PART_ERROR - FieldNotFoundPartitionErrror = 1488, - /// - ///ER_LIST_OF_FIELDS_ONLY_IN_HASH_ERROR - ListOfFieldsOnlyInHash = 1489, - /// - ///ER_INCONSISTENT_PARTITION_INFO_ERROR - InconsistentPartitionInfo = 1490, - /// - ///ER_PARTITION_FUNC_NOT_ALLOWED_ERROR - PartitionFunctionNotAllowed = 1491, - /// - ///ER_PARTITIONS_MUST_BE_DEFINED_ERROR - PartitionsMustBeDefined = 1492, - /// - ///ER_RANGE_NOT_INCREASING_ERROR - RangeNotIncreasing = 1493, - /// - ///ER_INCONSISTENT_TYPE_OF_FUNCTIONS_ERROR - InconsistentTypeOfFunctions = 1494, - /// - ///ER_MULTIPLE_DEF_CONST_IN_LIST_PART_ERROR - MultipleDefinitionsConstantInListPartition = 1495, - /// - ///ER_PARTITION_ENTRY_ERROR - PartitionEntryError = 1496, - /// - ///ER_MIX_HANDLER_ERROR - MixHandlerError = 1497, - /// - ///ER_PARTITION_NOT_DEFINED_ERROR - PartitionNotDefined = 1498, - /// - ///ER_TOO_MANY_PARTITIONS_ERROR - TooManyPartitions = 1499, - /// - ///ER_SUBPARTITION_ERROR - SubPartitionError = 1500, - /// - ///ER_CANT_CREATE_HANDLER_FILE - CannotCreateHandlerFile = 1501, - /// - ///ER_BLOB_FIELD_IN_PART_FUNC_ERROR - BlobFieldInPartitionFunction = 1502, - /// - ///ER_UNIQUE_KEY_NEED_ALL_FIELDS_IN_PF - UniqueKeyNeedAllFieldsInPartitioningFunction = 1503, - /// - ///ER_NO_PARTS_ERROR - NoPartitions = 1504, - /// - ///ER_PARTITION_MGMT_ON_NONPARTITIONED - PartitionManagementOnNoPartitioned = 1505, - /// - ///ER_FOREIGN_KEY_ON_PARTITIONED - ForeignKeyOnPartitioned = 1506, - /// - ///ER_DROP_PARTITION_NON_EXISTENT - DropPartitionNonExistent = 1507, - /// - ///ER_DROP_LAST_PARTITION - DropLastPartition = 1508, - /// - ///ER_COALESCE_ONLY_ON_HASH_PARTITION - CoalesceOnlyOnHashPartition = 1509, - /// - ///ER_REORG_HASH_ONLY_ON_SAME_NO - ReorganizeHashOnlyOnSameNumber = 1510, - /// - ///ER_REORG_NO_PARAM_ERROR - ReorganizeNoParameter = 1511, - /// - ///ER_ONLY_ON_RANGE_LIST_PARTITION - OnlyOnRangeListPartition = 1512, - /// - ///ER_ADD_PARTITION_SUBPART_ERROR - AddPartitionSubPartition = 1513, - /// - ///ER_ADD_PARTITION_NO_NEW_PARTITION - AddPartitionNoNewPartition = 1514, - /// - ///ER_COALESCE_PARTITION_NO_PARTITION - CoalescePartitionNoPartition = 1515, - /// - ///ER_REORG_PARTITION_NOT_EXIST - ReorganizePartitionNotExist = 1516, - /// - ///ER_SAME_NAME_PARTITION - SameNamePartition = 1517, - /// - ///ER_NO_BINLOG_ERROR - NoBinLog = 1518, - /// - ///ER_CONSECUTIVE_REORG_PARTITIONS - ConsecutiveReorganizePartitions = 1519, - /// - ///ER_REORG_OUTSIDE_RANGE - ReorganizeOutsideRange = 1520, - /// - ///ER_PARTITION_FUNCTION_FAILURE - PartitionFunctionFailure = 1521, - /// - ///ER_PART_STATE_ERROR - PartitionStateError = 1522, - /// - ///ER_LIMITED_PART_RANGE - LimitedPartitionRange = 1523, - /// - ///ER_PLUGIN_IS_NOT_LOADED - PluginIsNotLoaded = 1524, - /// - ///ER_WRONG_VALUE - WrongValue = 1525, - /// - ///ER_NO_PARTITION_FOR_GIVEN_VALUE - NoPartitionForGivenValue = 1526, - /// - ///ER_FILEGROUP_OPTION_ONLY_ONCE - FileGroupOptionOnlyOnce = 1527, - /// - ///ER_CREATE_FILEGROUP_FAILED - CreateFileGroupFailed = 1528, - /// - ///ER_DROP_FILEGROUP_FAILED - DropFileGroupFailed = 1529, - /// - ///ER_TABLESPACE_AUTO_EXTEND_ERROR - TableSpaceAutoExtend = 1530, - /// - ///ER_WRONG_SIZE_NUMBER - WrongSizeNumber = 1531, - /// - ///ER_SIZE_OVERFLOW_ERROR - SizeOverflow = 1532, - /// - ///ER_ALTER_FILEGROUP_FAILED - AlterFileGroupFailed = 1533, - /// - ///ER_BINLOG_ROW_LOGGING_FAILED - BinLogRowLogginFailed = 1534, - /// - ///ER_BINLOG_ROW_WRONG_TABLE_DEF - BinLogRowWrongTableDefinition = 1535, - /// - ///ER_BINLOG_ROW_RBR_TO_SBR - BinLogRowRBRToSBR = 1536, - /// - ///ER_EVENT_ALREADY_EXISTS - EventAlreadyExists = 1537, - /// - ///ER_EVENT_STORE_FAILED - EventStoreFailed = 1538, - /// - ///ER_EVENT_DOES_NOT_EXIST - EventDoesNotExist = 1539, - /// - ///ER_EVENT_CANT_ALTER - EventCannotAlter = 1540, - /// - ///ER_EVENT_DROP_FAILED - EventDropFailed = 1541, - /// - ///ER_EVENT_INTERVAL_NOT_POSITIVE_OR_TOO_BIG - EventIntervalNotPositiveOrTooBig = 1542, - /// - ///ER_EVENT_ENDS_BEFORE_STARTS - EventEndsBeforeStarts = 1543, - /// - ///ER_EVENT_EXEC_TIME_IN_THE_PAST - EventExecTimeInThePast = 1544, - /// - ///ER_EVENT_OPEN_TABLE_FAILED - EventOpenTableFailed = 1545, - /// - ///ER_EVENT_NEITHER_M_EXPR_NOR_M_AT - EventNeitherMExpresssionNorMAt = 1546, - /// - ///ER_COL_COUNT_DOESNT_MATCH_CORRUPTED - ColumnCountDoesNotMatchCorrupted = 1547, - /// - ///ER_CANNOT_LOAD_FROM_TABLE - CannotLoadFromTable = 1548, - /// - ///ER_EVENT_CANNOT_DELETE - EventCannotDelete = 1549, - /// - ///ER_EVENT_COMPILE_ERROR - EventCompileError = 1550, - /// - ///ER_EVENT_SAME_NAME - EventSameName = 1551, - /// - ///ER_EVENT_DATA_TOO_LONG - EventDataTooLong = 1552, - /// - ///ER_DROP_INDEX_FK - DropIndexForeignKey = 1553, - /// - ///ER_WARN_DEPRECATED_SYNTAX_WITH_VER - WarningDeprecatedSyntaxWithVersion = 1554, - /// - ///ER_CANT_WRITE_LOCK_LOG_TABLE - CannotWriteLockLogTable = 1555, - /// - ///ER_CANT_LOCK_LOG_TABLE - CannotLockLogTable = 1556, - /// - ///ER_FOREIGN_DUPLICATE_KEY - ForeignDuplicateKey = 1557, - /// - ///ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE - ColumnCountDoesNotMatchPleaseUpdate = 1558, - /// - ///ER_TEMP_TABLE_PREVENTS_SWITCH_OUT_OF_RBR - TemoraryTablePreventSwitchOutOfRBR = 1559, - /// - ///ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_FORMAT - StoredFunctionPreventsSwitchBinLogFormat = 1560, - /// - ///ER_NDB_CANT_SWITCH_BINLOG_FORMAT - NDBCannotSwitchBinLogFormat = 1561, - /// - ///ER_PARTITION_NO_TEMPORARY - PartitionNoTemporary = 1562, - /// - ///ER_PARTITION_CONST_DOMAIN_ERROR - PartitionConstantDomain = 1563, - /// - ///ER_PARTITION_FUNCTION_IS_NOT_ALLOWED - PartitionFunctionIsNotAllowed = 1564, - /// - ///ER_DDL_LOG_ERROR - DDLLogError = 1565, - /// - ///ER_NULL_IN_VALUES_LESS_THAN - NullInValuesLessThan = 1566, - /// - ///ER_WRONG_PARTITION_NAME - WrongPartitionName = 1567, - /// - ///ER_CANT_CHANGE_TRANSACTION_ISOLATION - CannotChangeTransactionIsolation = 1568, - /// - ///ER_DUP_ENTRY_AUTOINCREMENT_CASE - DuplicateEntryAutoIncrementCase = 1569, - /// - ///ER_EVENT_MODIFY_QUEUE_ERROR - EventModifyQueueError = 1570, - /// - ///ER_EVENT_SET_VAR_ERROR - EventSetVariableError = 1571, - /// - ///ER_PARTITION_MERGE_ERROR - PartitionMergeError = 1572, - /// - ///ER_CANT_ACTIVATE_LOG - CannotActivateLog = 1573, - /// - ///ER_RBR_NOT_AVAILABLE - RBRNotAvailable = 1574, - /// - ///ER_BASE64_DECODE_ERROR - Base64DecodeError = 1575, - /// - ///ER_EVENT_RECURSION_FORBIDDEN - EventRecursionForbidden = 1576, - /// - ///ER_EVENTS_DB_ERROR - EventsDatabaseError = 1577, - /// - ///ER_ONLY_INTEGERS_ALLOWED - OnlyIntegersAllowed = 1578, - /// - ///ER_UNSUPORTED_LOG_ENGINE - UnsupportedLogEngine = 1579, - /// - ///ER_BAD_LOG_STATEMENT - BadLogStatement = 1580, - /// - ///ER_CANT_RENAME_LOG_TABLE - CannotRenameLogTable = 1581, - /// - ///ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT - WrongParameterCountToNativeFCT = 1582, - /// - ///ER_WRONG_PARAMETERS_TO_NATIVE_FCT - WrongParametersToNativeFCT = 1583, - /// - ///ER_WRONG_PARAMETERS_TO_STORED_FCT - WrongParametersToStoredFCT = 1584, - /// - ///ER_NATIVE_FCT_NAME_COLLISION - NativeFCTNameCollision = 1585, - /// - ///ER_DUP_ENTRY_WITH_KEY_NAME - DuplicateEntryWithKeyName = 1586, - /// - ///ER_BINLOG_PURGE_EMFILE - BinLogPurgeEMFile = 1587, - /// - ///ER_EVENT_CANNOT_CREATE_IN_THE_PAST - EventCannotCreateInThePast = 1588, - /// - ///ER_EVENT_CANNOT_ALTER_IN_THE_PAST - EventCannotAlterInThePast = 1589, - /// - ///ER_REPLICA_INCIDENT - ReplicaIncident = 1590, - /// - ///ER_NO_PARTITION_FOR_GIVEN_VALUE_SILENT - NoPartitionForGivenValueSilent = 1591, - /// - ///ER_BINLOG_UNSAFE_STATEMENT - BinLogUnsafeStatement = 1592, - /// - ///ER_REPLICA_FATAL_ERROR - ReplicaFatalError = 1593, - /// - ///ER_REPLICA_RELAY_LOG_READ_FAILURE - ReplicaRelayLogReadFailure = 1594, - /// - ///ER_REPLICA_RELAY_LOG_WRITE_FAILURE - ReplicaRelayLogWriteFailure = 1595, - /// - ///ER_REPLICA_CREATE_EVENT_FAILURE - ReplicaCreateEventFailure = 1596, - /// - ///ER_REPLICA_SOURCE_COM_FAILURE - ReplicaSourceComFailure = 1597, - /// - ///ER_BINLOG_LOGGING_IMPOSSIBLE - BinLogLoggingImpossible = 1598, - /// - ///ER_VIEW_NO_CREATION_CTX - ViewNoCreationContext = 1599, - /// - ///ER_VIEW_INVALID_CREATION_CTX - ViewInvalidCreationContext = 1600, - /// - ///ER_SR_INVALID_CREATION_CTX - StoredRoutineInvalidCreateionContext = 1601, - /// - ///ER_TRG_CORRUPTED_FILE - TiggerCorruptedFile = 1602, - /// - ///ER_TRG_NO_CREATION_CTX - TriggerNoCreationContext = 1603, - /// - ///ER_TRG_INVALID_CREATION_CTX - TriggerInvalidCreationContext = 1604, - /// - ///ER_EVENT_INVALID_CREATION_CTX - EventInvalidCreationContext = 1605, - /// - ///ER_TRG_CANT_OPEN_TABLE - TriggerCannotOpenTable = 1606, - /// - ///ER_CANT_CREATE_SROUTINE - CannoCreateSubRoutine = 1607, - /// - ///ER_REPLICA_AMBIGOUS_EXEC_MODE - ReplicaAmbiguousExecMode = 1608, - /// - ///ER_NO_FORMAT_DESCRIPTION_EVENT_BEFORE_BINLOG_STATEMENT - NoFormatDescriptionEventBeforeBinLogStatement = 1609, - /// - ///ER_REPLICA_CORRUPT_EVENT - ReplicaCorruptEvent = 1610, - /// - ///ER_LOAD_DATA_INVALID_COLUMN - LoadDataInvalidColumn = 1611, - /// - ///ER_LOG_PURGE_NO_FILE - LogPurgeNoFile = 1612, - /// - ///ER_XA_RBTIMEOUT - XARBTimeout = 1613, - /// - ///ER_XA_RBDEADLOCK - XARBDeadlock = 1614, - /// - ///ER_NEED_REPREPARE - NeedRePrepare = 1615, - /// - ///ER_DELAYED_NOT_SUPPORTED - DelayedNotSupported = 1616, - /// - ///WARN_NO_SOURCE_INFO - WarningNoSourceInfo = 1617, - /// - ///WARN_OPTION_IGNORED - WarningOptionIgnored = 1618, - /// - ///WARN_PLUGIN_DELETE_BUILTIN - WarningPluginDeleteBuiltIn = 1619, - /// - ///WARN_PLUGIN_BUSY - WarningPluginBusy = 1620, - /// - ///ER_VARIABLE_IS_READONLY - VariableIsReadonly = 1621, - /// - ///ER_WARN_ENGINE_TRANSACTION_ROLLBACK - WarningEngineTransactionRollback = 1622, - /// - ///ER_REPLICA_HEARTBEAT_FAILURE - ReplicaHeartbeatFailure = 1623, - /// - ///ER_REPLICA_HEARTBEAT_VALUE_OUT_OF_RANGE - ReplicaHeartbeatValueOutOfRange = 1624, - /// - ///ER_NDB_REPLICATION_SCHEMA_ERROR - NDBReplicationSchemaError = 1625, - /// - ///ER_CONFLICT_FN_PARSE_ERROR - ConflictFunctionParseError = 1626, - /// - ///ER_EXCEPTIONS_WRITE_ERROR - ExcepionsWriteError = 1627, - /// - ///ER_TOO_LONG_TABLE_COMMENT - TooLongTableComment = 1628, - /// - ///ER_TOO_LONG_FIELD_COMMENT - TooLongFieldComment = 1629, - /// - ///ER_FUNC_INEXISTENT_NAME_COLLISION - FunctionInExistentNameCollision = 1630, - /// - ///ER_DATABASE_NAME - DatabaseNameError = 1631, - /// - ///ER_TABLE_NAME - TableNameErrror = 1632, - /// - ///ER_PARTITION_NAME - PartitionNameError = 1633, - /// - ///ER_SUBPARTITION_NAME - SubPartitionNameError = 1634, - /// - ///ER_TEMPORARY_NAME - TemporaryNameError = 1635, - /// - ///ER_RENAMED_NAME - RenamedNameError = 1636, - /// - ///ER_TOO_MANY_CONCURRENT_TRXS - TooManyConcurrentTransactions = 1637, - /// - ///WARN_NON_ASCII_SEPARATOR_NOT_IMPLEMENTED - WarningNonASCIISeparatorNotImplemented = 1638, - /// - ///ER_DEBUG_SYNC_TIMEOUT - DebugSyncTimeout = 1639, - /// - ///ER_DEBUG_SYNC_HIT_LIMIT - DebugSyncHitLimit = 1640, - /// - ///ER_ERROR_LAST - ErrorLast = 1640, - /// - ///ER_CLIENT_INTERACTION_TIMEOUT - ErrorClientInteractionTimeout = 4031 - } -} +// Copyright © 2004, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +namespace MySql.Data.MySqlClient +{ + /// + /// Collection of error codes that can be returned by the server + /// + public class MySqlError + { + /// + /// + /// + /// + public MySqlError(string level, int code, string message) + { + this.Level = level; + this.Code = code; + this.Message = message; + } + + /// + /// Error level + /// + public string Level { get; } + + /// + /// Error code + /// + public int Code { get; } + + /// + /// Error message + /// + public string Message { get; } + }; + + /// + /// Provides a reference to error codes returned by MySQL. + /// + public enum MySqlErrorCode + { + None = 0, + /// + ///ER_HASHCHK + HashCheck = 1000, + /// + ///ER_NISAMCHK + ISAMCheck = 1001, + /// + ///ER_NO + No = 1002, + /// + ///ER_YES + Yes = 1003, + ///The file couldn't be created. + ///ER_CANT_CREATE_FILE + CannotCreateFile = 1004, + ///The table couldn't be created. + ///ER_CANT_CREATE_TABLE + CannotCreateTable = 1005, + ///The database couldn't be created. + ///ER_CANT_CREATE_DB + CannotCreateDatabase = 1006, + ///The database couldn't be created, it already exists. + ///ER_DB_CREATE_EXISTS + DatabaseCreateExists = 1007, + ///The database couldn't be dropped, it doesn't exist. + ///ER_DB_DROP_EXISTS + DatabaseDropExists = 1008, + ///The database couldn't be dropped, the file can't be deleted. + ///ER_DB_DROP_DELETE + DatabaseDropDelete = 1009, + ///The database couldn't be dropped, the directory can't be deleted. + ///ER_DB_DROP_RMDIR + DatabaseDropRemoveDir = 1010, + ///The file couldn't be deleted. + ///ER_CANT_DELETE_FILE + CannotDeleteFile = 1011, + ///The record couldn't be read from the system table. + ///ER_CANT_FIND_SYSTEM_REC + CannotFindSystemRecord = 1012, + ///The status couldn't be retrieved. + ///ER_CANT_GET_STAT + CannotGetStatus = 1013, + ///The working directory couldn't be retrieved. + ///ER_CANT_GET_WD + CannotGetWorkingDirectory = 1014, + ///The file couldn't be locked. + ///ER_CANT_LOCK + CannotLock = 1015, + ///The file couldn't be opened. + ///ER_CANT_OPEN_FILE + CannotOpenFile = 1016, + ///The file couldn't be found. + ///ER_FILE_NOT_FOUND + FileNotFound = 1017, + ///The directory couldn't be read. + ///ER_CANT_READ_DIR + CannotReadDirectory = 1018, + ///The working directory couldn't be entered. + ///ER_CANT_SET_WD + CannotSetWorkingDirectory = 1019, + ///The record changed since it was last read. + ///ER_CHECKREAD + CheckRead = 1020, + ///The disk is full. + ///ER_DISK_FULL + DiskFull = 1021, + /// + /// There is already a key with the given values. + /// + DuplicateKey = 1022, + ///An error occurred when closing the file. + ///ER_ERROR_ON_CLOSE + ErrorOnClose = 1023, + ///An error occurred when reading from the file. + ///ER_ERROR_ON_READ + ErrorOnRead = 1024, + ///An error occurred when renaming then file. + ///ER_ERROR_ON_RENAME + ErrorOnRename = 1025, + ///An error occurred when writing to the file. + ///ER_ERROR_ON_WRITE + ErrorOnWrite = 1026, + ///The file is in use. + ///ER_FILE_USED + FileUsed = 1027, + ///Sorting has been aborted. + ///ER_FILSORT_ABORT + FileSortAborted = 1028, + ///The view doesn't exist. + ///ER_FORM_NOT_FOUND + FormNotFound = 1029, + ///Got the specified error from the table storage engine. + ///ER_GET_ERRNO + GetErrorNumber = 1030, + ///The table storage engine doesn't support the specified option. + ///ER_ILLEGAL_HA + IllegalHA = 1031, + /// + /// The specified key was not found. + /// + KeyNotFound = 1032, + ///The file contains incorrect information. + ///ER_NOT_FORM_FILE + NotFormFile = 1033, + ///The key file is incorrect for the table, it should be repaired. + ///ER_NOT_KEYFILE + NotKeyFile = 1034, + ///The key file is old for the table, it should be repaired. + ///ER_OLD_KEYFILE + OldKeyFile = 1035, + ///The table is read-only + ///ER_OPEN_AS_READONLY + OpenAsReadOnly = 1036, + ///The server is out of memory, it should be restarted. + ///ER_OUTOFMEMORY + OutOfMemory = 1037, + ///The server is out of sort-memory, the sort buffer size should be increased. + ///ER_OUT_OF_SORTMEMORY + OutOfSortMemory = 1038, + ///An unexpected EOF was found when reading from the file. + ///ER_UNEXPECTED_EOF + UnexepectedEOF = 1039, + ///Too many connections are open. + ///ER_CON_COUNT_ERROR + ConnectionCountError = 1040, + ///The server is out of resources, check if MySql or some other process is using all available memory. + ///ER_OUT_OF_RESOURCES + OutOfResources = 1041, + /// + /// Given when the connection is unable to successfully connect to host. + /// + UnableToConnectToHost = 1042, + ///The handshake was invalid. + ///ER_HANDSHAKE_ERROR + HandshakeError = 1043, + ///Access was denied for the specified user using the specified database. + ///ER_DBACCESS_DENIED_ERROR + DatabaseAccessDenied = 1044, + /// + /// Normally returned when an incorrect password is given + /// + AccessDenied = 1045, + ///No database has been selected. + ///ER_NO_DB_ERROR + NoDatabaseSelected = 1046, + ///The command is unknown. + ///ER_UNKNOWN_COM_ERROR + UnknownCommand = 1047, + ///The specified column cannot be NULL. + ///ER_BAD_NULL_ERROR + ColumnCannotBeNull = 1048, + /// The specified database is not known. + UnknownDatabase = 1049, + ///The specified table already exists. + ///ER_TABLE_EXISTS_ERROR + TableExists = 1050, + ///The specified table is unknown. + ///ER_BAD_TABLE_ERROR + BadTable = 1051, + ///The specified column is ambiguous. + ///ER_NON_UNIQ_ERROR + NonUnique = 1052, + ///The server is currently being shutdown. + ///ER_SERVER_SHUTDOWN + ServerShutdown = 1053, + ///The specified columns is unknown. + ///ER_BAD_FIELD_ERROR + BadFieldError = 1054, + ///The specified column isn't in GROUP BY. + ///ER_WRONG_FIELD_WITH_GROUP + WrongFieldWithGroup = 1055, + ///The specified columns cannot be grouped on. + ///ER_WRONG_GROUP_FIELD + WrongGroupField = 1056, + ///There are sum functions and columns in the same statement. + ///ER_WRONG_SUM_SELECT + WrongSumSelected = 1057, + ///The column count doesn't match the value count. + ///ER_WRONG_VALUE_COUNT + WrongValueCount = 1058, + ///The identifier name is too long. + ///ER_TOO_LONG_IDENT + TooLongIdentifier = 1059, + ///The column name is duplicated. + ///ER_DUP_FIELDNAME + DuplicateFieldName = 1060, + /// + /// Duplicate Key Name + /// + DuplicateKeyName = 1061, + /// + /// Duplicate Key Entry + /// + DuplicateKeyEntry = 1062, + ///The column specifier is incorrect. + ///ER_WRONG_FIELD_SPEC + WrongFieldSpecifier = 1063, + ///An error occurred when parsing the statement. + ///ER_PARSE_ERROR + ParseError = 1064, + ///The statement is empty. + ///ER_EMPTY_QUERY + EmptyQuery = 1065, + ///The table alias isn't unique. + ///ER_NONUNIQ_TABLE + NonUniqueTable = 1066, + ///The default value is invalid for the specified field. + ///ER_INVALID_DEFAULT + InvalidDefault = 1067, + ///The table has multiple primary keys defined. + ///ER_MULTIPLE_PRI_KEY + MultiplePrimaryKey = 1068, + ///Too many keys were defined for the table. + ///ER_TOO_MANY_KEYS + TooManyKeys = 1069, + ///Too many parts to the keys were defined for the table. + ///ER_TOO_MANY_KEY_PARTS + TooManyKeysParts = 1070, + ///The specified key is too long + ///ER_TOO_LONG_KEY + TooLongKey = 1071, + ///The specified key column doesn't exist in the table. + ///ER_KEY_COLUMN_DOES_NOT_EXITS + KeyColumnDoesNotExist = 1072, + ///The BLOB column was used as a key, this can't be done. + ///ER_BLOB_USED_AS_KEY + BlobUsedAsKey = 1073, + ///The column length is too big for the specified column type. + ///ER_TOO_BIG_FIELDLENGTH + TooBigFieldLength = 1074, + ///There can only be one auto-column, and it must be defined as a PK. + ///ER_WRONG_AUTO_KEY + WrongAutoKey = 1075, + ///The server is ready to accept connections. + ///ER_READY + Ready = 1076, + /// + ///ER_NORMAL_SHUTDOWN + NormalShutdown = 1077, + ///The server received the specified signal and is aborting. + ///ER_GOT_SIGNAL + GotSignal = 1078, + ///The server shutdown is complete. + ///ER_SHUTDOWN_COMPLETE + ShutdownComplete = 1079, + ///The server is forcing close of the specified thread. + ///ER_FORCING_CLOSE + ForcingClose = 1080, + ///An error occurred when creating the IP socket. + ///ER_IPSOCK_ERROR + IPSocketError = 1081, + ///The table has no index like the one used in CREATE INDEX. + ///ER_NO_SUCH_INDEX + NoSuchIndex = 1082, + ///The field separator argument is not what is expected, check the manual. + ///ER_WRONG_FIELD_TERMINATORS + WrongFieldTerminators = 1083, + ///The BLOB columns must terminated, fixed row lengths cannot be used. + ///ER_BLOBS_AND_NO_TERMINATED + BlobsAndNoTerminated = 1084, + ///The text file cannot be read. + ///ER_TEXTFILE_NOT_READABLE + TextFileNotReadable = 1085, + ///The specified file already exists. + ///ER_FILE_EXISTS_ERROR + FileExists = 1086, + ///Information returned by the LOAD statement. + ///ER_LOAD_INFO + LoadInfo = 1087, + ///Information returned by an UPDATE statement. + ///ER_ALTER_INFO + AlterInfo = 1088, + ///The prefix key is incorrect. + ///ER_WRONG_SUB_KEY + WrongSubKey = 1089, + ///All columns cannot be removed from a table, use DROP TABLE instead. + ///ER_CANT_REMOVE_ALL_FIELDS + CannotRemoveAllFields = 1090, + ///Cannot DROP, check that the column or key exists. + ///ER_CANT_DROP_FIELD_OR_KEY + CannotDropFieldOrKey = 1091, + ///Information returned by an INSERT statement. + ///ER_INSERT_INFO + InsertInfo = 1092, + ///The target table cannot be specified for update in FROM clause. + ///ER_UPDATE_TABLE_USED + UpdateTableUsed = 1093, + ///The specified thread ID is unknown. + ///ER_NO_SUCH_THREAD + NoSuchThread = 1094, + ///The thread cannot be killed, the current user is not the owner. + ///ER_KILL_DENIED_ERROR + KillDenied = 1095, + ///No tables used in the statement. + ///ER_NO_TABLES_USED + NoTablesUsed = 1096, + ///Too many string have been used for the specified column and SET. + ///ER_TOO_BIG_SET + TooBigSet = 1097, + ///A unique filename couldn't be generated. + ///ER_NO_UNIQUE_LOGFILE + NoUniqueLogFile = 1098, + ///The specified table was locked with a READ lock, and can't be updated. + ///ER_TABLE_NOT_LOCKED_FOR_WRITE + TableNotLockedForWrite = 1099, + ///The specified table was not locked with LOCK TABLES. + ///ER_TABLE_NOT_LOCKED + TableNotLocked = 1100, + ///BLOB and Text columns cannot have a default value. + ///ER_BLOB_CANT_HAVE_DEFAULT + BlobCannotHaveDefault = 1101, + ///The specified database name is incorrect. + ///ER_WRONG_DB_NAME + WrongDatabaseName = 1102, + ///The specified table name is incorrect. + ///ER_WRONG_TABLE_NAME + WrongTableName = 1103, + ///The SELECT command would examine more than MAX_JOIN_SIZE rows, check the WHERE clause and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is ok. + ///ER_TOO_BIG_SELECT + TooBigSelect = 1104, + ///An unknown error occurred. + ///ER_UNKNOWN_ERROR + UnknownError = 1105, + ///The specified procedure is unknown. + ///ER_UNKNOWN_PROCEDURE + UnknownProcedure = 1106, + ///The number of parameters provided for the specified procedure is incorrect. + ///ER_WRONG_PARAMCOUNT_TO_PROCEDURE + WrongParameterCountToProcedure = 1107, + ///The parameters provided for the specified procedure are incorrect. + ///ER_WRONG_PARAMETERS_TO_PROCEDURE + WrongParametersToProcedure = 1108, + ///The specified table is unknown. + ///ER_UNKNOWN_TABLE + UnknownTable = 1109, + ///The specified column has been specified twice. + ///ER_FIELD_SPECIFIED_TWICE + FieldSpecifiedTwice = 1110, + ///The group function has been incorrectly used. + ///ER_INVALID_GROUP_FUNC_USE + InvalidGroupFunctionUse = 1111, + ///The specified table uses an extension that doesn't exist in this MySQL version. + ///ER_UNSUPPORTED_EXTENSION + UnsupportedExtenstion = 1112, + ///The table must have at least one column. + ///ER_TABLE_MUST_HAVE_COLUMNS + TableMustHaveColumns = 1113, + ///The specified table is full. + ///ER_RECORD_FILE_FULL + RecordFileFull = 1114, + ///The specified character set is unknown. + ///ER_UNKNOWN_CHARACTER_SET + UnknownCharacterSet = 1115, + ///Too many tables, MySQL can only use the specified number of tables in a JOIN. + ///ER_TOO_MANY_TABLES + TooManyTables = 1116, + ///Too many columns + ///ER_TOO_MANY_FIELDS + TooManyFields = 1117, + ///The row size is too large, the maximum row size for the used tables (not counting BLOBS) is specified, change some columns or BLOBS. + ///ER_TOO_BIG_ROWSIZE + TooBigRowSize = 1118, + ///A thread stack overrun occurred. Stack statistics are specified. + ///ER_STACK_OVERRUN + StackOverrun = 1119, + ///A cross dependency was found in the OUTER JOIN, examine the ON conditions. + ///ER_WRONG_OUTER_JOIN + WrongOuterJoin = 1120, + ///The table handler doesn't support NULL in the given index, change specified column to be NOT NULL or use another handler. + ///ER_NULL_COLUMN_IN_INDEX + NullColumnInIndex = 1121, + ///The specified user defined function cannot be loaded. + ///ER_CANT_FIND_UDF + CannotFindUDF = 1122, + ///The specified user defined function cannot be initialised. + ///ER_CANT_INITIALIZE_UDF + CannotInitializeUDF = 1123, + ///No paths are allowed for the shared library. + ///ER_UDF_NO_PATHS + UDFNoPaths = 1124, + ///The specified user defined function already exists. + ///ER_UDF_EXISTS + UDFExists = 1125, + ///The specified shared library cannot be opened. + ///ER_CANT_OPEN_LIBRARY + CannotOpenLibrary = 1126, + ///The specified symbol cannot be found in the library. + ///ER_CANT_FIND_DL_ENTRY + CannotFindDLEntry = 1127, + ///The specified function is not defined. + ///ER_FUNCTION_NOT_DEFINED + FunctionNotDefined = 1128, + ///The specified host is blocked because of too many connection errors, unblock with 'mysqladmin flush-hosts'. + ///ER_HOST_IS_BLOCKED + HostIsBlocked = 1129, + /// + /// The given host is not allowed to connect + /// + HostNotPrivileged = 1130, + /// + /// The anonymous user is not allowed to connect + /// + AnonymousUser = 1131, + /// + /// The given password is not allowed + /// + PasswordNotAllowed = 1132, + /// + /// The given password does not match + /// + PasswordNoMatch = 1133, + ///Information returned by an UPDATE statement. + ///ER_UPDATE_INFO + UpdateInfo = 1134, + ///A new thread couldn't be created. + ///ER_CANT_CREATE_THREAD + CannotCreateThread = 1135, + ///The column count doesn't match the value count. + ///ER_WRONG_VALUE_COUNT_ON_ROW + WrongValueCountOnRow = 1136, + ///The specified table can't be re-opened. + ///ER_CANT_REOPEN_TABLE + CannotReopenTable = 1137, + ///The NULL value has been used incorrectly. + ///ER_INVALID_USE_OF_NULL + InvalidUseOfNull = 1138, + ///The regular expression contains an error. + ///ER_REGEXP_ERROR + RegExpError = 1139, + ///GROUP columns (MIN(), MAX(), COUNT(), ...) cannot be mixes with no GROUP columns if there is not GROUP BY clause. + ///ER_MIX_OF_GROUP_FUNC_AND_FIELDS + MixOfGroupFunctionAndFields = 1140, + /// + ///ER_NONEXISTING_GRANT + NonExistingGrant = 1141, + /// + ///ER_TABLEACCESS_DENIED_ERROR + TableAccessDenied = 1142, + /// + ///ER_COLUMNACCESS_DENIED_ERROR + ColumnAccessDenied = 1143, + /// + ///ER_ILLEGAL_GRANT_FOR_TABLE + IllegalGrantForTable = 1144, + /// + ///ER_GRANT_WRONG_HOST_OR_USER + GrantWrongHostOrUser = 1145, + /// + ///ER_NO_SUCH_TABLE + NoSuchTable = 1146, + /// + ///ER_NONEXISTING_TABLE_GRANT + NonExistingTableGrant = 1147, + /// + ///ER_NOT_ALLOWED_COMMAND + NotAllowedCommand = 1148, + /// + ///ER_SYNTAX_ERROR + SyntaxError = 1149, + /// + ///ER_DELAYED_CANT_CHANGE_LOCK + DelayedCannotChangeLock = 1150, + /// + ///ER_TOO_MANY_DELAYED_THREADS + TooManyDelayedThreads = 1151, + /// + ///ER_ABORTING_CONNECTION + AbortingConnection = 1152, + /// + /// An attempt was made to send or receive a packet larger than + /// max_allowed_packet_size + /// + PacketTooLarge = 1153, + /// + ///ER_NET_READ_ERROR_FROM_PIPE + NetReadErrorFromPipe = 1154, + /// + ///ER_NET_FCNTL_ERROR + NetFCntlError = 1155, + /// + ///ER_NET_PACKETS_OUT_OF_ORDER + NetPacketsOutOfOrder = 1156, + /// + ///ER_NET_UNCOMPRESS_ERROR + NetUncompressError = 1157, + /// + ///ER_NET_READ_ERROR + NetReadError = 1158, + /// + ///ER_NET_READ_INTERRUPTED + NetReadInterrupted = 1159, + /// + ///ER_NET_ERROR_ON_WRITE + NetErrorOnWrite = 1160, + /// + ///ER_NET_WRITE_INTERRUPTED + NetWriteInterrupted = 1161, + /// + ///ER_TOO_LONG_STRING + TooLongString = 1162, + /// + ///ER_TABLE_CANT_HANDLE_BLOB + TableCannotHandleBlob = 1163, + /// + ///ER_TABLE_CANT_HANDLE_AUTO_INCREMENT + TableCannotHandleAutoIncrement = 1164, + /// + ///ER_DELAYED_INSERT_TABLE_LOCKED + DelayedInsertTableLocked = 1165, + /// + ///ER_WRONG_COLUMN_NAME + WrongColumnName = 1166, + /// + ///ER_WRONG_KEY_COLUMN + WrongKeyColumn = 1167, + /// + ///ER_WRONG_MRG_TABLE + WrongMergeTable = 1168, + /// + ///ER_DUP_UNIQUE + DuplicateUnique = 1169, + /// + ///ER_BLOB_KEY_WITHOUT_LENGTH + BlobKeyWithoutLength = 1170, + /// + ///ER_PRIMARY_CANT_HAVE_NULL + PrimaryCannotHaveNull = 1171, + /// + ///ER_TOO_MANY_ROWS + TooManyRows = 1172, + /// + ///ER_REQUIRES_PRIMARY_KEY + RequiresPrimaryKey = 1173, + /// + ///ER_NO_RAID_COMPILED + NoRAIDCompiled = 1174, + /// + ///ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE + UpdateWithoutKeysInSafeMode = 1175, + /// + ///ER_KEY_DOES_NOT_EXITS + KeyDoesNotExist = 1176, + /// + ///ER_CHECK_NO_SUCH_TABLE + CheckNoSuchTable = 1177, + /// + ///ER_CHECK_NOT_IMPLEMENTED + CheckNotImplemented = 1178, + /// + ///ER_CANT_DO_THIS_DURING_AN_TRANSACTION + CannotDoThisDuringATransaction = 1179, + /// + ///ER_ERROR_DURING_COMMIT + ErrorDuringCommit = 1180, + /// + ///ER_ERROR_DURING_ROLLBACK + ErrorDuringRollback = 1181, + /// + ///ER_ERROR_DURING_FLUSH_LOGS + ErrorDuringFlushLogs = 1182, + /// + ///ER_ERROR_DURING_CHECKPOINT + ErrorDuringCheckpoint = 1183, + /// + ///ER_NEW_ABORTING_CONNECTION + NewAbortingConnection = 1184, + /// + ///ER_DUMP_NOT_IMPLEMENTED + DumpNotImplemented = 1185, + /// + ///ER_FLUSH_SOURCE_BINLOG_CLOSED + FlushSourceBinLogClosed = 1186, + /// + ///ER_INDEX_REBUILD + IndexRebuild = 1187, + /// + ///ER_SOURCE + SourceError = 1188, + /// + ///ER_SOURCE_NET_READ + SourceNetRead = 1189, + /// + ///ER_SOURCE_NET_WRITE + SourceNetWrite = 1190, + /// + ///ER_FT_MATCHING_KEY_NOT_FOUND + FullTextMatchingKeyNotFound = 1191, + /// + ///ER_LOCK_OR_ACTIVE_TRANSACTION + LockOrActiveTransaction = 1192, + /// + ///ER_UNKNOWN_SYSTEM_VARIABLE + UnknownSystemVariable = 1193, + /// + ///ER_CRASHED_ON_USAGE + CrashedOnUsage = 1194, + /// + ///ER_CRASHED_ON_REPAIR + CrashedOnRepair = 1195, + /// + ///ER_WARNING_NOT_COMPLETE_ROLLBACK + WarningNotCompleteRollback = 1196, + /// + ///ER_TRANS_CACHE_FULL + TransactionCacheFull = 1197, + /// + ///ER_REPLICA_MUST_STOP + ReplicaMustStop = 1198, + /// + ///ER_REPLICA_NOT_RUNNING + ReplicaNotRunning = 1199, + /// + ///ER_BAD_REPLICA + BadReplica = 1200, + /// + ///ER_SOURCE_INFO + SourceInfo = 1201, + /// + ///ER_REPLICA_THREAD + ReplicaThread = 1202, + /// + ///ER_TOO_MANY_USER_CONNECTIONS + TooManyUserConnections = 1203, + /// + ///ER_SET_CONSTANTS_ONLY + SetConstantsOnly = 1204, + /// + ///ER_LOCK_WAIT_TIMEOUT + LockWaitTimeout = 1205, + /// + ///ER_LOCK_TABLE_FULL + LockTableFull = 1206, + /// + ///ER_READ_ONLY_TRANSACTION + ReadOnlyTransaction = 1207, + /// + ///ER_DROP_DB_WITH_READ_LOCK + DropDatabaseWithReadLock = 1208, + /// + ///ER_CREATE_DB_WITH_READ_LOCK + CreateDatabaseWithReadLock = 1209, + /// + ///ER_WRONG_ARGUMENTS + WrongArguments = 1210, + /// + ///ER_NO_PERMISSION_TO_CREATE_USER + NoPermissionToCreateUser = 1211, + /// + ///ER_UNION_TABLES_IN_DIFFERENT_DIR + UnionTablesInDifferentDirectory = 1212, + /// + ///ER_LOCK_DEADLOCK + LockDeadlock = 1213, + /// + ///ER_TABLE_CANT_HANDLE_FT + TableCannotHandleFullText = 1214, + /// + ///ER_CANNOT_ADD_FOREIGN + CannotAddForeignConstraint = 1215, + /// + ///ER_NO_REFERENCED_ROW + NoReferencedRow = 1216, + /// + ///ER_ROW_IS_REFERENCED + RowIsReferenced = 1217, + /// + ///ER_CONNECT_TO_SOURCE + ConnectToSource = 1218, + /// + ///ER_QUERY_ON_SOURCE + QueryOnSource = 1219, + /// + ///ER_ERROR_WHEN_EXECUTING_COMMAND + ErrorWhenExecutingCommand = 1220, + /// + ///ER_WRONG_USAGE + WrongUsage = 1221, + /// + ///ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT + WrongNumberOfColumnsInSelect = 1222, + /// + ///ER_CANT_UPDATE_WITH_READLOCK + CannotUpdateWithReadLock = 1223, + /// + ///ER_MIXING_NOT_ALLOWED + MixingNotAllowed = 1224, + /// + ///ER_DUP_ARGUMENT + DuplicateArgument = 1225, + /// + ///ER_USER_LIMIT_REACHED + UserLimitReached = 1226, + /// + ///ER_SPECIFIC_ACCESS_DENIED_ERROR + SpecifiedAccessDeniedError = 1227, + /// + ///ER_LOCAL_VARIABLE + LocalVariableError = 1228, + /// + ///ER_GLOBAL_VARIABLE + GlobalVariableError = 1229, + /// + ///ER_NO_DEFAULT + NotDefaultError = 1230, + /// + ///ER_WRONG_VALUE_FOR_VAR + WrongValueForVariable = 1231, + /// + ///ER_WRONG_TYPE_FOR_VAR + WrongTypeForVariable = 1232, + /// + ///ER_VAR_CANT_BE_READ + VariableCannotBeRead = 1233, + /// + ///ER_CANT_USE_OPTION_HERE + CannotUseOptionHere = 1234, + /// + ///ER_NOT_SUPPORTED_YET + NotSupportedYet = 1235, + /// + ///ER_SOURCE_FATAL_ERROR_READING_BINLOG + SourceFatalErrorReadingBinLog = 1236, + /// + ///ER_REPLICA_IGNORED_TABLE + ReplicaIgnoredTable = 1237, + /// + ///ER_INCORRECT_GLOBAL_LOCAL_VAR + IncorrectGlobalLocalVariable = 1238, + /// + ///ER_WRONG_FK_DEF + WrongForeignKeyDefinition = 1239, + /// + ///ER_KEY_REF_DO_NOT_MATCH_TABLE_REF + KeyReferenceDoesNotMatchTableReference = 1240, + /// + ///ER_OPERAND_COLUMNS + OpearnColumnsError = 1241, + /// + ///ER_SUBQUERY_NO_1_ROW + SubQueryNoOneRow = 1242, + /// + ///ER_UNKNOWN_STMT_HANDLER + UnknownStatementHandler = 1243, + /// + ///ER_CORRUPT_HELP_DB + CorruptHelpDatabase = 1244, + /// + ///ER_CYCLIC_REFERENCE + CyclicReference = 1245, + /// + ///ER_AUTO_CONVERT + AutoConvert = 1246, + /// + ///ER_ILLEGAL_REFERENCE + IllegalReference = 1247, + /// + ///ER_DERIVED_MUST_HAVE_ALIAS + DerivedMustHaveAlias = 1248, + /// + ///ER_SELECT_REDUCED + SelectReduced = 1249, + /// + ///ER_TABLENAME_NOT_ALLOWED_HERE + TableNameNotAllowedHere = 1250, + /// + ///ER_NOT_SUPPORTED_AUTH_MODE + NotSupportedAuthMode = 1251, + /// + ///ER_SPATIAL_CANT_HAVE_NULL + SpatialCannotHaveNull = 1252, + /// + ///ER_COLLATION_CHARSET_MISMATCH + CollationCharsetMismatch = 1253, + /// + ///ER_REPLICA_WAS_RUNNING + ReplicaWasRunning = 1254, + /// + ///ER_REPLICA_WAS_NOT_RUNNING + ReplicaWasNotRunning = 1255, + /// + ///ER_TOO_BIG_FOR_UNCOMPRESS + TooBigForUncompress = 1256, + /// + ///ER_ZLIB_Z_MEM_ERROR + ZipLibMemoryError = 1257, + /// + ///ER_ZLIB_Z_BUF_ERROR + ZipLibBufferError = 1258, + /// + ///ER_ZLIB_Z_DATA_ERROR + ZipLibDataError = 1259, + /// + ///ER_CUT_VALUE_GROUP_CONCAT + CutValueGroupConcat = 1260, + /// + ///ER_WARN_TOO_FEW_RECORDS + WarningTooFewRecords = 1261, + /// + ///ER_WARN_TOO_MANY_RECORDS + WarningTooManyRecords = 1262, + /// + ///ER_WARN_NULL_TO_NOTNULL + WarningNullToNotNull = 1263, + /// + ///ER_WARN_DATA_OUT_OF_RANGE + WarningDataOutOfRange = 1264, + /// + ///WARN_DATA_TRUNCATED + WaningDataTruncated = 1265, + /// + ///ER_WARN_USING_OTHER_HANDLER + WaningUsingOtherHandler = 1266, + /// + ///ER_CANT_AGGREGATE_2COLLATIONS + CannotAggregateTwoCollations = 1267, + /// + ///ER_DROP_USER + DropUserError = 1268, + /// + ///ER_REVOKE_GRANTS + RevokeGrantsError = 1269, + /// + ///ER_CANT_AGGREGATE_3COLLATIONS + CannotAggregateThreeCollations = 1270, + /// + ///ER_CANT_AGGREGATE_NCOLLATIONS + CannotAggregateNCollations = 1271, + /// + ///ER_VARIABLE_IS_NOT_STRUCT + VariableIsNotStructure = 1272, + /// + ///ER_UNKNOWN_COLLATION + UnknownCollation = 1273, + /// + ///ER_REPLICA_IGNORED_SSL_PARAMS + ReplicaIgnoreSSLParameters = 1274, + /// + ///ER_SERVER_IS_IN_SECURE_AUTH_MODE + ServerIsInSecureAuthMode = 1275, + /// + ///ER_WARN_FIELD_RESOLVED + WaningFieldResolved = 1276, + /// + ///ER_BAD_REPLICA_UNTIL_COND + BadReplicaUntilCondition = 1277, + /// + ///ER_MISSING_SKIP_REPLICA + MissingSkipReplica = 1278, + /// + ///ER_UNTIL_COND_IGNORED + ErrorUntilConditionIgnored = 1279, + /// + ///ER_WRONG_NAME_FOR_INDEX + WrongNameForIndex = 1280, + /// + ///ER_WRONG_NAME_FOR_CATALOG + WrongNameForCatalog = 1281, + /// + ///ER_WARN_QC_RESIZE + WarningQueryCacheResize = 1282, + /// + ///ER_BAD_FT_COLUMN + BadFullTextColumn = 1283, + /// + ///ER_UNKNOWN_KEY_CACHE + UnknownKeyCache = 1284, + /// + ///ER_WARN_HOSTNAME_WONT_WORK + WarningHostnameWillNotWork = 1285, + /// + ///ER_UNKNOWN_STORAGE_ENGINE + UnknownStorageEngine = 1286, + /// + ///ER_WARN_DEPRECATED_SYNTAX + WaningDeprecatedSyntax = 1287, + /// + ///ER_NON_UPDATABLE_TABLE + NonUpdateableTable = 1288, + /// + ///ER_FEATURE_DISABLED + FeatureDisabled = 1289, + /// + ///ER_OPTION_PREVENTS_STATEMENT + OptionPreventsStatement = 1290, + /// + ///ER_DUPLICATED_VALUE_IN_TYPE + DuplicatedValueInType = 1291, + /// + ///ER_TRUNCATED_WRONG_VALUE + TruncatedWrongValue = 1292, + /// + ///ER_TOO_MUCH_AUTO_TIMESTAMP_COLS + TooMuchAutoTimestampColumns = 1293, + /// + ///ER_INVALID_ON_UPDATE + InvalidOnUpdate = 1294, + /// + ///ER_UNSUPPORTED_PS + UnsupportedPreparedStatement = 1295, + /// + ///ER_GET_ERRMSG + GetErroMessage = 1296, + /// + ///ER_GET_TEMPORARY_ERRMSG + GetTemporaryErrorMessage = 1297, + /// + ///ER_UNKNOWN_TIME_ZONE + UnknownTimeZone = 1298, + /// + ///ER_WARN_INVALID_TIMESTAMP + WarningInvalidTimestamp = 1299, + /// + ///ER_INVALID_CHARACTER_STRING + InvalidCharacterString = 1300, + /// + ///ER_WARN_ALLOWED_PACKET_OVERFLOWED + WarningAllowedPacketOverflowed = 1301, + /// + ///ER_CONFLICTING_DECLARATIONS + ConflictingDeclarations = 1302, + /// + ///ER_SP_NO_RECURSIVE_CREATE + StoredProcedureNoRecursiveCreate = 1303, + /// + ///ER_SP_ALREADY_EXISTS + StoredProcedureAlreadyExists = 1304, + /// + ///ER_SP_DOES_NOT_EXIST + StoredProcedureDoesNotExist = 1305, + /// + ///ER_SP_DROP_FAILED + StoredProcedureDropFailed = 1306, + /// + ///ER_SP_STORE_FAILED + StoredProcedureStoreFailed = 1307, + /// + ///ER_SP_LILABEL_MISMATCH + StoredProcedureLiLabelMismatch = 1308, + /// + ///ER_SP_LABEL_REDEFINE + StoredProcedureLabelRedefine = 1309, + /// + ///ER_SP_LABEL_MISMATCH + StoredProcedureLabelMismatch = 1310, + /// + ///ER_SP_UNINIT_VAR + StoredProcedureUninitializedVariable = 1311, + /// + ///ER_SP_BADSELECT + StoredProcedureBadSelect = 1312, + /// + ///ER_SP_BADRETURN + StoredProcedureBadReturn = 1313, + /// + ///ER_SP_BADSTATEMENT + StoredProcedureBadStatement = 1314, + /// + ///ER_UPDATE_LOG_DEPRECATED_IGNORED + UpdateLogDeprecatedIgnored = 1315, + /// + ///ER_UPDATE_LOG_DEPRECATED_TRANSLATED + UpdateLogDeprecatedTranslated = 1316, + /// + ///ER_QUERY_INTERRUPTED + QueryInterrupted = 1317, + /// + ///ER_SP_WRONG_NO_OF_ARGS + StoredProcedureNumberOfArguments = 1318, + /// + ///ER_SP_COND_MISMATCH + StoredProcedureConditionMismatch = 1319, + /// + ///ER_SP_NORETURN + StoredProcedureNoReturn = 1320, + /// + ///ER_SP_NORETURNEND + StoredProcedureNoReturnEnd = 1321, + /// + ///ER_SP_BAD_CURSOR_QUERY + StoredProcedureBadCursorQuery = 1322, + /// + ///ER_SP_BAD_CURSOR_SELECT + StoredProcedureBadCursorSelect = 1323, + /// + ///ER_SP_CURSOR_MISMATCH + StoredProcedureCursorMismatch = 1324, + /// + ///ER_SP_CURSOR_ALREADY_OPEN + StoredProcedureAlreadyOpen = 1325, + /// + ///ER_SP_CURSOR_NOT_OPEN + StoredProcedureCursorNotOpen = 1326, + /// + ///ER_SP_UNDECLARED_VAR + StoredProcedureUndeclaredVariabel = 1327, + /// + ///ER_SP_WRONG_NO_OF_FETCH_ARGS + StoredProcedureWrongNumberOfFetchArguments = 1328, + /// + ///ER_SP_FETCH_NO_DATA + StoredProcedureFetchNoData = 1329, + /// + ///ER_SP_DUP_PARAM + StoredProcedureDuplicateParameter = 1330, + /// + ///ER_SP_DUP_VAR + StoredProcedureDuplicateVariable = 1331, + /// + ///ER_SP_DUP_COND + StoredProcedureDuplicateCondition = 1332, + /// + ///ER_SP_DUP_CURS + StoredProcedureDuplicateCursor = 1333, + /// + ///ER_SP_CANT_ALTER + StoredProcedureCannotAlter = 1334, + /// + ///ER_SP_SUBSELECT_NYI + StoredProcedureSubSelectNYI = 1335, + /// + ///ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG + StatementNotAllowedInStoredFunctionOrTrigger = 1336, + /// + ///ER_SP_VARCOND_AFTER_CURSHNDLR + StoredProcedureVariableConditionAfterCursorHandler = 1337, + /// + ///ER_SP_CURSOR_AFTER_HANDLER + StoredProcedureCursorAfterHandler = 1338, + /// + ///ER_SP_CASE_NOT_FOUND + StoredProcedureCaseNotFound = 1339, + /// + ///ER_FPARSER_TOO_BIG_FILE + FileParserTooBigFile = 1340, + /// + ///ER_FPARSER_BAD_HEADER + FileParserBadHeader = 1341, + /// + ///ER_FPARSER_EOF_IN_COMMENT + FileParserEOFInComment = 1342, + /// + ///ER_FPARSER_ERROR_IN_PARAMETER + FileParserErrorInParameter = 1343, + /// + ///ER_FPARSER_EOF_IN_UNKNOWN_PARAMETER + FileParserEOFInUnknownParameter = 1344, + /// + ///ER_VIEW_NO_EXPLAIN + ViewNoExplain = 1345, + /// + ///ER_FRM_UNKNOWN_TYPE + FrmUnknownType = 1346, + /// + ///ER_WRONG_OBJECT + WrongObject = 1347, + /// + ///ER_NONUPDATEABLE_COLUMN + NonUpdateableColumn = 1348, + /// + ///ER_VIEW_SELECT_DERIVED + ViewSelectDerived = 1349, + /// + ///ER_VIEW_SELECT_CLAUSE + ViewSelectClause = 1350, + /// + ///ER_VIEW_SELECT_VARIABLE + ViewSelectVariable = 1351, + /// + ///ER_VIEW_SELECT_TMPTABLE + ViewSelectTempTable = 1352, + /// + ///ER_VIEW_WRONG_LIST + ViewWrongList = 1353, + /// + ///ER_WARN_VIEW_MERGE + WarningViewMerge = 1354, + /// + ///ER_WARN_VIEW_WITHOUT_KEY + WarningViewWithoutKey = 1355, + /// + ///ER_VIEW_INVALID + ViewInvalid = 1356, + /// + ///ER_SP_NO_DROP_SP + StoredProcedureNoDropStoredProcedure = 1357, + /// + ///ER_SP_GOTO_IN_HNDLR + StoredProcedureGotoInHandler = 1358, + /// + ///ER_TRG_ALREADY_EXISTS + TriggerAlreadyExists = 1359, + /// + ///ER_TRG_DOES_NOT_EXIST + TriggerDoesNotExist = 1360, + /// + ///ER_TRG_ON_VIEW_OR_TEMP_TABLE + TriggerOnViewOrTempTable = 1361, + /// + ///ER_TRG_CANT_CHANGE_ROW + TriggerCannotChangeRow = 1362, + /// + ///ER_TRG_NO_SUCH_ROW_IN_TRG + TriggerNoSuchRowInTrigger = 1363, + /// + ///ER_NO_DEFAULT_FOR_FIELD + NoDefaultForField = 1364, + /// + ///ER_DIVISION_BY_ZERO + DivisionByZero = 1365, + /// + ///ER_TRUNCATED_WRONG_VALUE_FOR_FIELD + TruncatedWrongValueForField = 1366, + /// + ///ER_ILLEGAL_VALUE_FOR_TYPE + IllegalValueForType = 1367, + /// + ///ER_VIEW_NONUPD_CHECK + ViewNonUpdatableCheck = 1368, + /// + ///ER_VIEW_CHECK_FAILED + ViewCheckFailed = 1369, + /// + ///ER_PROCACCESS_DENIED_ERROR + PrecedureAccessDenied = 1370, + /// + ///ER_RELAY_LOG_FAIL + RelayLogFail = 1371, + /// + ///ER_PASSWD_LENGTH + PasswordLength = 1372, + /// + ///ER_UNKNOWN_TARGET_BINLOG + UnknownTargetBinLog = 1373, + /// + ///ER_IO_ERR_LOG_INDEX_READ + IOErrorLogIndexRead = 1374, + /// + ///ER_BINLOG_PURGE_PROHIBITED + BinLogPurgeProhibited = 1375, + /// + ///ER_FSEEK_FAIL + FSeekFail = 1376, + /// + ///ER_BINLOG_PURGE_FATAL_ERR + BinLogPurgeFatalError = 1377, + /// + ///ER_LOG_IN_USE + LogInUse = 1378, + /// + ///ER_LOG_PURGE_UNKNOWN_ERR + LogPurgeUnknownError = 1379, + /// + ///ER_RELAY_LOG_INIT + RelayLogInit = 1380, + /// + ///ER_NO_BINARY_LOGGING + NoBinaryLogging = 1381, + /// + ///ER_RESERVED_SYNTAX + ReservedSyntax = 1382, + /// + ///ER_WSAS_FAILED + WSAStartupFailed = 1383, + /// + ///ER_DIFF_GROUPS_PROC + DifferentGroupsProcedure = 1384, + /// + ///ER_NO_GROUP_FOR_PROC + NoGroupForProcedure = 1385, + /// + ///ER_ORDER_WITH_PROC + OrderWithProcedure = 1386, + /// + ///ER_LOGGING_PROHIBIT_CHANGING_OF + LoggingProhibitsChangingOf = 1387, + /// + ///ER_NO_FILE_MAPPING + NoFileMapping = 1388, + /// + ///ER_WRONG_MAGIC + WrongMagic = 1389, + /// + ///ER_PS_MANY_PARAM + PreparedStatementManyParameters = 1390, + /// + ///ER_KEY_PART_0 + KeyPartZero = 1391, + /// + ///ER_VIEW_CHECKSUM + ViewChecksum = 1392, + /// + ///ER_VIEW_MULTIUPDATE + ViewMultiUpdate = 1393, + /// + ///ER_VIEW_NO_INSERT_FIELD_LIST + ViewNoInsertFieldList = 1394, + /// + ///ER_VIEW_DELETE_MERGE_VIEW + ViewDeleteMergeView = 1395, + /// + ///ER_CANNOT_USER + CannotUser = 1396, + /// + ///ER_XAER_NOTA + XAERNotA = 1397, + /// + ///ER_XAER_INVAL + XAERInvalid = 1398, + /// + ///ER_XAER_RMFAIL + XAERRemoveFail = 1399, + /// + ///ER_XAER_OUTSIDE + XAEROutside = 1400, + /// + ///ER_XAER_RMERR + XAERRemoveError = 1401, + /// + ///ER_XA_RBROLLBACK + XARBRollback = 1402, + /// + ///ER_NONEXISTING_PROC_GRANT + NonExistingProcedureGrant = 1403, + /// + ///ER_PROC_AUTO_GRANT_FAIL + ProcedureAutoGrantFail = 1404, + /// + ///ER_PROC_AUTO_REVOKE_FAIL + ProcedureAutoRevokeFail = 1405, + /// + ///ER_DATA_TOO_LONG + DataTooLong = 1406, + /// + ///ER_SP_BAD_SQLSTATE + StoredProcedureSQLState = 1407, + /// + ///ER_STARTUP + StartupError = 1408, + /// + ///ER_LOAD_FROM_FIXED_SIZE_ROWS_TO_VAR + LoadFromFixedSizeRowsToVariable = 1409, + /// + ///ER_CANT_CREATE_USER_WITH_GRANT + CannotCreateUserWithGrant = 1410, + /// + ///ER_WRONG_VALUE_FOR_TYPE + WrongValueForType = 1411, + /// + ///ER_TABLE_DEF_CHANGED + TableDefinitionChanged = 1412, + /// + ///ER_SP_DUP_HANDLER + StoredProcedureDuplicateHandler = 1413, + /// + ///ER_SP_NOT_VAR_ARG + StoredProcedureNotVariableArgument = 1414, + /// + ///ER_SP_NO_RETSET + StoredProcedureNoReturnSet = 1415, + /// + ///ER_CANT_CREATE_GEOMETRY_OBJECT + CannotCreateGeometryObject = 1416, + /// + ///ER_FAILED_ROUTINE_BREAK_BINLOG + FailedRoutineBreaksBinLog = 1417, + /// + ///ER_BINLOG_UNSAFE_ROUTINE + BinLogUnsafeRoutine = 1418, + /// + ///ER_BINLOG_CREATE_ROUTINE_NEED_SUPER + BinLogCreateRoutineNeedSuper = 1419, + /// + ///ER_EXEC_STMT_WITH_OPEN_CURSOR + ExecuteStatementWithOpenCursor = 1420, + /// + ///ER_STMT_HAS_NO_OPEN_CURSOR + StatementHasNoOpenCursor = 1421, + /// + ///ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG + CommitNotAllowedIfStoredFunctionOrTrigger = 1422, + /// + ///ER_NO_DEFAULT_FOR_VIEW_FIELD + NoDefaultForViewField = 1423, + /// + ///ER_SP_NO_RECURSION + StoredProcedureNoRecursion = 1424, + /// + ///ER_TOO_BIG_SCALE + TooBigScale = 1425, + /// + ///ER_TOO_BIG_PRECISION + TooBigPrecision = 1426, + /// + ///ER_M_BIGGER_THAN_D + MBiggerThanD = 1427, + /// + ///ER_WRONG_LOCK_OF_SYSTEM_TABLE + WrongLockOfSystemTable = 1428, + /// + ///ER_CONNECT_TO_FOREIGN_DATA_SOURCE + ConnectToForeignDataSource = 1429, + /// + ///ER_QUERY_ON_FOREIGN_DATA_SOURCE + QueryOnForeignDataSource = 1430, + /// + ///ER_FOREIGN_DATA_SOURCE_DOESNT_EXIST + ForeignDataSourceDoesNotExist = 1431, + /// + ///ER_FOREIGN_DATA_STRING_INVALID_CANT_CREATE + ForeignDataStringInvalidCannotCreate = 1432, + /// + ///ER_FOREIGN_DATA_STRING_INVALID + ForeignDataStringInvalid = 1433, + /// + ///ER_CANT_CREATE_FEDERATED_TABLE + CannotCreateFederatedTable = 1434, + /// + ///ER_TRG_IN_WRONG_SCHEMA + TriggerInWrongSchema = 1435, + /// + ///ER_STACK_OVERRUN_NEED_MORE + StackOverrunNeedMore = 1436, + /// + ///ER_TOO_LONG_BODY + TooLongBody = 1437, + /// + ///ER_WARN_CANT_DROP_DEFAULT_KEYCACHE + WarningCannotDropDefaultKeyCache = 1438, + /// + ///ER_TOO_BIG_DISPLAYWIDTH + TooBigDisplayWidth = 1439, + /// + ///ER_XAER_DUPID + XAERDuplicateID = 1440, + /// + ///ER_DATETIME_FUNCTION_OVERFLOW + DateTimeFunctionOverflow = 1441, + /// + ///ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG + CannotUpdateUsedTableInStoredFunctionOrTrigger = 1442, + /// + ///ER_VIEW_PREVENT_UPDATE + ViewPreventUpdate = 1443, + /// + ///ER_PS_NO_RECURSION + PreparedStatementNoRecursion = 1444, + /// + ///ER_SP_CANT_SET_AUTOCOMMIT + StoredProcedureCannotSetAutoCommit = 1445, + /// + ///ER_MALFORMED_DEFINER + MalformedDefiner = 1446, + /// + ///ER_VIEW_FRM_NO_USER + ViewFrmNoUser = 1447, + /// + ///ER_VIEW_OTHER_USER + ViewOtherUser = 1448, + /// + ///ER_NO_SUCH_USER + NoSuchUser = 1449, + /// + ///ER_FORBID_SCHEMA_CHANGE + ForbidSchemaChange = 1450, + /// + ///ER_ROW_IS_REFERENCED_2 + RowIsReferenced2 = 1451, + /// + ///ER_NO_REFERENCED_ROW_2 + NoReferencedRow2 = 1452, + /// + ///ER_SP_BAD_VAR_SHADOW + StoredProcedureBadVariableShadow = 1453, + /// + ///ER_TRG_NO_DEFINER + TriggerNoDefiner = 1454, + /// + ///ER_OLD_FILE_FORMAT + OldFileFormat = 1455, + /// + ///ER_SP_RECURSION_LIMIT + StoredProcedureRecursionLimit = 1456, + /// + ///ER_SP_PROC_TABLE_CORRUPT + StoredProcedureTableCorrupt = 1457, + /// + ///ER_SP_WRONG_NAME + StoredProcedureWrongName = 1458, + /// + ///ER_TABLE_NEEDS_UPGRADE + TableNeedsUpgrade = 1459, + /// + ///ER_SP_NO_AGGREGATE + StoredProcedureNoAggregate = 1460, + /// + ///ER_MAX_PREPARED_STMT_COUNT_REACHED + MaxPreparedStatementCountReached = 1461, + /// + ///ER_VIEW_RECURSIVE + ViewRecursive = 1462, + /// + ///ER_NON_GROUPING_FIELD_USED + NonGroupingFieldUsed = 1463, + /// + ///ER_TABLE_CANT_HANDLE_SPKEYS + TableCannotHandleSpatialKeys = 1464, + /// + ///ER_NO_TRIGGERS_ON_SYSTEM_SCHEMA + NoTriggersOnSystemSchema = 1465, + /// + ///ER_REMOVED_SPACES + RemovedSpaces = 1466, + /// + ///ER_AUTOINC_READ_FAILED + AutoIncrementReadFailed = 1467, + /// + ///ER_USERNAME + UserNameError = 1468, + /// + ///ER_HOSTNAME + HostNameError = 1469, + /// + ///ER_WRONG_STRING_LENGTH + WrongStringLength = 1470, + /// + ///ER_NON_INSERTABLE_TABLE + NonInsertableTable = 1471, + /// + ///ER_ADMIN_WRONG_MRG_TABLE + AdminWrongMergeTable = 1472, + /// + ///ER_TOO_HIGH_LEVEL_OF_NESTING_FOR_SELECT + TooHighLevelOfNestingForSelect = 1473, + /// + ///ER_NAME_BECOMES_EMPTY + NameBecomesEmpty = 1474, + /// + ///ER_AMBIGUOUS_FIELD_TERM + AmbiguousFieldTerm = 1475, + /// + ///ER_FOREIGN_SERVER_EXISTS + ForeignServerExists = 1476, + /// + ///ER_FOREIGN_SERVER_DOESNT_EXIST + ForeignServerDoesNotExist = 1477, + /// + ///ER_ILLEGAL_HA_CREATE_OPTION + IllegalHACreateOption = 1478, + /// + ///ER_PARTITION_REQUIRES_VALUES_ERROR + PartitionRequiresValues = 1479, + /// + ///ER_PARTITION_WRONG_VALUES_ERROR + PartitionWrongValues = 1480, + /// + ///ER_PARTITION_MAXVALUE_ERROR + PartitionMaxValue = 1481, + /// + ///ER_PARTITION_SUBPARTITION_ERROR + PartitionSubPartition = 1482, + /// + ///ER_PARTITION_SUBPART_MIX_ERROR + PartitionSubPartMix = 1483, + /// + ///ER_PARTITION_WRONG_NO_PART_ERROR + PartitionWrongNoPart = 1484, + /// + ///ER_PARTITION_WRONG_NO_SUBPART_ERROR + PartitionWrongNoSubPart = 1485, + /// + ///ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR + WrongExpressionInParitionFunction = 1486, + /// + ///ER_NO_CONST_EXPR_IN_RANGE_OR_LIST_ERROR + NoConstantExpressionInRangeOrListError = 1487, + /// + ///ER_FIELD_NOT_FOUND_PART_ERROR + FieldNotFoundPartitionErrror = 1488, + /// + ///ER_LIST_OF_FIELDS_ONLY_IN_HASH_ERROR + ListOfFieldsOnlyInHash = 1489, + /// + ///ER_INCONSISTENT_PARTITION_INFO_ERROR + InconsistentPartitionInfo = 1490, + /// + ///ER_PARTITION_FUNC_NOT_ALLOWED_ERROR + PartitionFunctionNotAllowed = 1491, + /// + ///ER_PARTITIONS_MUST_BE_DEFINED_ERROR + PartitionsMustBeDefined = 1492, + /// + ///ER_RANGE_NOT_INCREASING_ERROR + RangeNotIncreasing = 1493, + /// + ///ER_INCONSISTENT_TYPE_OF_FUNCTIONS_ERROR + InconsistentTypeOfFunctions = 1494, + /// + ///ER_MULTIPLE_DEF_CONST_IN_LIST_PART_ERROR + MultipleDefinitionsConstantInListPartition = 1495, + /// + ///ER_PARTITION_ENTRY_ERROR + PartitionEntryError = 1496, + /// + ///ER_MIX_HANDLER_ERROR + MixHandlerError = 1497, + /// + ///ER_PARTITION_NOT_DEFINED_ERROR + PartitionNotDefined = 1498, + /// + ///ER_TOO_MANY_PARTITIONS_ERROR + TooManyPartitions = 1499, + /// + ///ER_SUBPARTITION_ERROR + SubPartitionError = 1500, + /// + ///ER_CANT_CREATE_HANDLER_FILE + CannotCreateHandlerFile = 1501, + /// + ///ER_BLOB_FIELD_IN_PART_FUNC_ERROR + BlobFieldInPartitionFunction = 1502, + /// + ///ER_UNIQUE_KEY_NEED_ALL_FIELDS_IN_PF + UniqueKeyNeedAllFieldsInPartitioningFunction = 1503, + /// + ///ER_NO_PARTS_ERROR + NoPartitions = 1504, + /// + ///ER_PARTITION_MGMT_ON_NONPARTITIONED + PartitionManagementOnNoPartitioned = 1505, + /// + ///ER_FOREIGN_KEY_ON_PARTITIONED + ForeignKeyOnPartitioned = 1506, + /// + ///ER_DROP_PARTITION_NON_EXISTENT + DropPartitionNonExistent = 1507, + /// + ///ER_DROP_LAST_PARTITION + DropLastPartition = 1508, + /// + ///ER_COALESCE_ONLY_ON_HASH_PARTITION + CoalesceOnlyOnHashPartition = 1509, + /// + ///ER_REORG_HASH_ONLY_ON_SAME_NO + ReorganizeHashOnlyOnSameNumber = 1510, + /// + ///ER_REORG_NO_PARAM_ERROR + ReorganizeNoParameter = 1511, + /// + ///ER_ONLY_ON_RANGE_LIST_PARTITION + OnlyOnRangeListPartition = 1512, + /// + ///ER_ADD_PARTITION_SUBPART_ERROR + AddPartitionSubPartition = 1513, + /// + ///ER_ADD_PARTITION_NO_NEW_PARTITION + AddPartitionNoNewPartition = 1514, + /// + ///ER_COALESCE_PARTITION_NO_PARTITION + CoalescePartitionNoPartition = 1515, + /// + ///ER_REORG_PARTITION_NOT_EXIST + ReorganizePartitionNotExist = 1516, + /// + ///ER_SAME_NAME_PARTITION + SameNamePartition = 1517, + /// + ///ER_NO_BINLOG_ERROR + NoBinLog = 1518, + /// + ///ER_CONSECUTIVE_REORG_PARTITIONS + ConsecutiveReorganizePartitions = 1519, + /// + ///ER_REORG_OUTSIDE_RANGE + ReorganizeOutsideRange = 1520, + /// + ///ER_PARTITION_FUNCTION_FAILURE + PartitionFunctionFailure = 1521, + /// + ///ER_PART_STATE_ERROR + PartitionStateError = 1522, + /// + ///ER_LIMITED_PART_RANGE + LimitedPartitionRange = 1523, + /// + ///ER_PLUGIN_IS_NOT_LOADED + PluginIsNotLoaded = 1524, + /// + ///ER_WRONG_VALUE + WrongValue = 1525, + /// + ///ER_NO_PARTITION_FOR_GIVEN_VALUE + NoPartitionForGivenValue = 1526, + /// + ///ER_FILEGROUP_OPTION_ONLY_ONCE + FileGroupOptionOnlyOnce = 1527, + /// + ///ER_CREATE_FILEGROUP_FAILED + CreateFileGroupFailed = 1528, + /// + ///ER_DROP_FILEGROUP_FAILED + DropFileGroupFailed = 1529, + /// + ///ER_TABLESPACE_AUTO_EXTEND_ERROR + TableSpaceAutoExtend = 1530, + /// + ///ER_WRONG_SIZE_NUMBER + WrongSizeNumber = 1531, + /// + ///ER_SIZE_OVERFLOW_ERROR + SizeOverflow = 1532, + /// + ///ER_ALTER_FILEGROUP_FAILED + AlterFileGroupFailed = 1533, + /// + ///ER_BINLOG_ROW_LOGGING_FAILED + BinLogRowLogginFailed = 1534, + /// + ///ER_BINLOG_ROW_WRONG_TABLE_DEF + BinLogRowWrongTableDefinition = 1535, + /// + ///ER_BINLOG_ROW_RBR_TO_SBR + BinLogRowRBRToSBR = 1536, + /// + ///ER_EVENT_ALREADY_EXISTS + EventAlreadyExists = 1537, + /// + ///ER_EVENT_STORE_FAILED + EventStoreFailed = 1538, + /// + ///ER_EVENT_DOES_NOT_EXIST + EventDoesNotExist = 1539, + /// + ///ER_EVENT_CANT_ALTER + EventCannotAlter = 1540, + /// + ///ER_EVENT_DROP_FAILED + EventDropFailed = 1541, + /// + ///ER_EVENT_INTERVAL_NOT_POSITIVE_OR_TOO_BIG + EventIntervalNotPositiveOrTooBig = 1542, + /// + ///ER_EVENT_ENDS_BEFORE_STARTS + EventEndsBeforeStarts = 1543, + /// + ///ER_EVENT_EXEC_TIME_IN_THE_PAST + EventExecTimeInThePast = 1544, + /// + ///ER_EVENT_OPEN_TABLE_FAILED + EventOpenTableFailed = 1545, + /// + ///ER_EVENT_NEITHER_M_EXPR_NOR_M_AT + EventNeitherMExpresssionNorMAt = 1546, + /// + ///ER_COL_COUNT_DOESNT_MATCH_CORRUPTED + ColumnCountDoesNotMatchCorrupted = 1547, + /// + ///ER_CANNOT_LOAD_FROM_TABLE + CannotLoadFromTable = 1548, + /// + ///ER_EVENT_CANNOT_DELETE + EventCannotDelete = 1549, + /// + ///ER_EVENT_COMPILE_ERROR + EventCompileError = 1550, + /// + ///ER_EVENT_SAME_NAME + EventSameName = 1551, + /// + ///ER_EVENT_DATA_TOO_LONG + EventDataTooLong = 1552, + /// + ///ER_DROP_INDEX_FK + DropIndexForeignKey = 1553, + /// + ///ER_WARN_DEPRECATED_SYNTAX_WITH_VER + WarningDeprecatedSyntaxWithVersion = 1554, + /// + ///ER_CANT_WRITE_LOCK_LOG_TABLE + CannotWriteLockLogTable = 1555, + /// + ///ER_CANT_LOCK_LOG_TABLE + CannotLockLogTable = 1556, + /// + ///ER_FOREIGN_DUPLICATE_KEY + ForeignDuplicateKey = 1557, + /// + ///ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE + ColumnCountDoesNotMatchPleaseUpdate = 1558, + /// + ///ER_TEMP_TABLE_PREVENTS_SWITCH_OUT_OF_RBR + TemoraryTablePreventSwitchOutOfRBR = 1559, + /// + ///ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_FORMAT + StoredFunctionPreventsSwitchBinLogFormat = 1560, + /// + ///ER_NDB_CANT_SWITCH_BINLOG_FORMAT + NDBCannotSwitchBinLogFormat = 1561, + /// + ///ER_PARTITION_NO_TEMPORARY + PartitionNoTemporary = 1562, + /// + ///ER_PARTITION_CONST_DOMAIN_ERROR + PartitionConstantDomain = 1563, + /// + ///ER_PARTITION_FUNCTION_IS_NOT_ALLOWED + PartitionFunctionIsNotAllowed = 1564, + /// + ///ER_DDL_LOG_ERROR + DDLLogError = 1565, + /// + ///ER_NULL_IN_VALUES_LESS_THAN + NullInValuesLessThan = 1566, + /// + ///ER_WRONG_PARTITION_NAME + WrongPartitionName = 1567, + /// + ///ER_CANT_CHANGE_TRANSACTION_ISOLATION + CannotChangeTransactionIsolation = 1568, + /// + ///ER_DUP_ENTRY_AUTOINCREMENT_CASE + DuplicateEntryAutoIncrementCase = 1569, + /// + ///ER_EVENT_MODIFY_QUEUE_ERROR + EventModifyQueueError = 1570, + /// + ///ER_EVENT_SET_VAR_ERROR + EventSetVariableError = 1571, + /// + ///ER_PARTITION_MERGE_ERROR + PartitionMergeError = 1572, + /// + ///ER_CANT_ACTIVATE_LOG + CannotActivateLog = 1573, + /// + ///ER_RBR_NOT_AVAILABLE + RBRNotAvailable = 1574, + /// + ///ER_BASE64_DECODE_ERROR + Base64DecodeError = 1575, + /// + ///ER_EVENT_RECURSION_FORBIDDEN + EventRecursionForbidden = 1576, + /// + ///ER_EVENTS_DB_ERROR + EventsDatabaseError = 1577, + /// + ///ER_ONLY_INTEGERS_ALLOWED + OnlyIntegersAllowed = 1578, + /// + ///ER_UNSUPORTED_LOG_ENGINE + UnsupportedLogEngine = 1579, + /// + ///ER_BAD_LOG_STATEMENT + BadLogStatement = 1580, + /// + ///ER_CANT_RENAME_LOG_TABLE + CannotRenameLogTable = 1581, + /// + ///ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT + WrongParameterCountToNativeFCT = 1582, + /// + ///ER_WRONG_PARAMETERS_TO_NATIVE_FCT + WrongParametersToNativeFCT = 1583, + /// + ///ER_WRONG_PARAMETERS_TO_STORED_FCT + WrongParametersToStoredFCT = 1584, + /// + ///ER_NATIVE_FCT_NAME_COLLISION + NativeFCTNameCollision = 1585, + /// + ///ER_DUP_ENTRY_WITH_KEY_NAME + DuplicateEntryWithKeyName = 1586, + /// + ///ER_BINLOG_PURGE_EMFILE + BinLogPurgeEMFile = 1587, + /// + ///ER_EVENT_CANNOT_CREATE_IN_THE_PAST + EventCannotCreateInThePast = 1588, + /// + ///ER_EVENT_CANNOT_ALTER_IN_THE_PAST + EventCannotAlterInThePast = 1589, + /// + ///ER_REPLICA_INCIDENT + ReplicaIncident = 1590, + /// + ///ER_NO_PARTITION_FOR_GIVEN_VALUE_SILENT + NoPartitionForGivenValueSilent = 1591, + /// + ///ER_BINLOG_UNSAFE_STATEMENT + BinLogUnsafeStatement = 1592, + /// + ///ER_REPLICA_FATAL_ERROR + ReplicaFatalError = 1593, + /// + ///ER_REPLICA_RELAY_LOG_READ_FAILURE + ReplicaRelayLogReadFailure = 1594, + /// + ///ER_REPLICA_RELAY_LOG_WRITE_FAILURE + ReplicaRelayLogWriteFailure = 1595, + /// + ///ER_REPLICA_CREATE_EVENT_FAILURE + ReplicaCreateEventFailure = 1596, + /// + ///ER_REPLICA_SOURCE_COM_FAILURE + ReplicaSourceComFailure = 1597, + /// + ///ER_BINLOG_LOGGING_IMPOSSIBLE + BinLogLoggingImpossible = 1598, + /// + ///ER_VIEW_NO_CREATION_CTX + ViewNoCreationContext = 1599, + /// + ///ER_VIEW_INVALID_CREATION_CTX + ViewInvalidCreationContext = 1600, + /// + ///ER_SR_INVALID_CREATION_CTX + StoredRoutineInvalidCreateionContext = 1601, + /// + ///ER_TRG_CORRUPTED_FILE + TiggerCorruptedFile = 1602, + /// + ///ER_TRG_NO_CREATION_CTX + TriggerNoCreationContext = 1603, + /// + ///ER_TRG_INVALID_CREATION_CTX + TriggerInvalidCreationContext = 1604, + /// + ///ER_EVENT_INVALID_CREATION_CTX + EventInvalidCreationContext = 1605, + /// + ///ER_TRG_CANT_OPEN_TABLE + TriggerCannotOpenTable = 1606, + /// + ///ER_CANT_CREATE_SROUTINE + CannoCreateSubRoutine = 1607, + /// + ///ER_REPLICA_AMBIGOUS_EXEC_MODE + ReplicaAmbiguousExecMode = 1608, + /// + ///ER_NO_FORMAT_DESCRIPTION_EVENT_BEFORE_BINLOG_STATEMENT + NoFormatDescriptionEventBeforeBinLogStatement = 1609, + /// + ///ER_REPLICA_CORRUPT_EVENT + ReplicaCorruptEvent = 1610, + /// + ///ER_LOAD_DATA_INVALID_COLUMN + LoadDataInvalidColumn = 1611, + /// + ///ER_LOG_PURGE_NO_FILE + LogPurgeNoFile = 1612, + /// + ///ER_XA_RBTIMEOUT + XARBTimeout = 1613, + /// + ///ER_XA_RBDEADLOCK + XARBDeadlock = 1614, + /// + ///ER_NEED_REPREPARE + NeedRePrepare = 1615, + /// + ///ER_DELAYED_NOT_SUPPORTED + DelayedNotSupported = 1616, + /// + ///WARN_NO_SOURCE_INFO + WarningNoSourceInfo = 1617, + /// + ///WARN_OPTION_IGNORED + WarningOptionIgnored = 1618, + /// + ///WARN_PLUGIN_DELETE_BUILTIN + WarningPluginDeleteBuiltIn = 1619, + /// + ///WARN_PLUGIN_BUSY + WarningPluginBusy = 1620, + /// + ///ER_VARIABLE_IS_READONLY + VariableIsReadonly = 1621, + /// + ///ER_WARN_ENGINE_TRANSACTION_ROLLBACK + WarningEngineTransactionRollback = 1622, + /// + ///ER_REPLICA_HEARTBEAT_FAILURE + ReplicaHeartbeatFailure = 1623, + /// + ///ER_REPLICA_HEARTBEAT_VALUE_OUT_OF_RANGE + ReplicaHeartbeatValueOutOfRange = 1624, + /// + ///ER_NDB_REPLICATION_SCHEMA_ERROR + NDBReplicationSchemaError = 1625, + /// + ///ER_CONFLICT_FN_PARSE_ERROR + ConflictFunctionParseError = 1626, + /// + ///ER_EXCEPTIONS_WRITE_ERROR + ExcepionsWriteError = 1627, + /// + ///ER_TOO_LONG_TABLE_COMMENT + TooLongTableComment = 1628, + /// + ///ER_TOO_LONG_FIELD_COMMENT + TooLongFieldComment = 1629, + /// + ///ER_FUNC_INEXISTENT_NAME_COLLISION + FunctionInExistentNameCollision = 1630, + /// + ///ER_DATABASE_NAME + DatabaseNameError = 1631, + /// + ///ER_TABLE_NAME + TableNameErrror = 1632, + /// + ///ER_PARTITION_NAME + PartitionNameError = 1633, + /// + ///ER_SUBPARTITION_NAME + SubPartitionNameError = 1634, + /// + ///ER_TEMPORARY_NAME + TemporaryNameError = 1635, + /// + ///ER_RENAMED_NAME + RenamedNameError = 1636, + /// + ///ER_TOO_MANY_CONCURRENT_TRXS + TooManyConcurrentTransactions = 1637, + /// + ///WARN_NON_ASCII_SEPARATOR_NOT_IMPLEMENTED + WarningNonASCIISeparatorNotImplemented = 1638, + /// + ///ER_DEBUG_SYNC_TIMEOUT + DebugSyncTimeout = 1639, + /// + ///ER_DEBUG_SYNC_HIT_LIMIT + DebugSyncHitLimit = 1640, + /// + ///ER_ERROR_LAST + ErrorLast = 1640, + /// + ///ER_CLIENT_INTERACTION_TIMEOUT + ErrorClientInteractionTimeout = 4031 + } +} diff --git a/MySQL.Data/src/MySqlHelper.cs b/MySQL.Data/src/MySqlHelper.cs index b1891556e..9d33fa16d 100644 --- a/MySQL.Data/src/MySqlHelper.cs +++ b/MySQL.Data/src/MySqlHelper.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2004, 2023, Oracle and/or its affiliates. +// Copyright © 2004, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -263,7 +263,7 @@ private static async Task ExecuteReaderAsync(bool execAsync, st /// Command text to use. /// An array of objects to use with the command. /// object ready to read the results of the command. - public static Task ExecuteReaderAsync(string connectionString, string commandText, params MySqlParameter[] commandParameters) => ExecuteReaderAsync(connectionString, commandText, commandParameters: commandParameters); + public static Task ExecuteReaderAsync(string connectionString, string commandText, params MySqlParameter[] commandParameters) => ExecuteReaderAsync(true, connectionString, commandText, commandParameters: commandParameters); public static Task ExecuteReaderAsync(string connectionString, string commandText, CancellationToken cancellationToken, params MySqlParameter[] commandParameters) => ExecuteReaderAsync(true, connectionString, commandText, cancellationToken, commandParameters); diff --git a/MySQL.Data/src/MySqlPacket.cs b/MySQL.Data/src/MySqlPacket.cs index cfe054174..db939cca3 100644 --- a/MySQL.Data/src/MySqlPacket.cs +++ b/MySQL.Data/src/MySqlPacket.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2004, 2023, Oracle and/or its affiliates. +// Copyright © 2004, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -222,9 +222,9 @@ public long ReadLong(int numbytes) switch (numbytes) { - case 2: return BitConverter.ToUInt16(bits, pos); - case 4: return BitConverter.ToUInt32(bits, pos); - case 8: return BitConverter.ToInt64(bits, pos); + case 2: return PacketBitConverter.ToUInt16(bits, pos); + case 4: return PacketBitConverter.ToUInt32(bits, pos); + case 8: return PacketBitConverter.ToInt64(bits, pos); } throw new NotSupportedException("Only byte lengths of 2, 4, or 8 are supported"); } @@ -240,9 +240,9 @@ public ulong ReadULong(int numbytes) switch (numbytes) { - case 2: return BitConverter.ToUInt16(bits, pos); - case 4: return BitConverter.ToUInt32(bits, pos); - case 8: return BitConverter.ToUInt64(bits, pos); + case 2: return PacketBitConverter.ToUInt16(bits, pos); + case 4: return PacketBitConverter.ToUInt32(bits, pos); + case 8: return PacketBitConverter.ToUInt64(bits, pos); } throw new NotSupportedException("Only byte lengths of 2, 4, or 8 are supported"); } diff --git a/MySQL.Data/src/MySqlParameter.cs b/MySQL.Data/src/MySqlParameter.cs index 1170afb30..4377aeb69 100644 --- a/MySQL.Data/src/MySqlParameter.cs +++ b/MySQL.Data/src/MySqlParameter.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2004, 2022, Oracle and/or its affiliates. +// Copyright © 2004, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/MySqlParameterCollection.cs b/MySQL.Data/src/MySqlParameterCollection.cs index 5a530a597..530ea93d6 100644 --- a/MySQL.Data/src/MySqlParameterCollection.cs +++ b/MySQL.Data/src/MySqlParameterCollection.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2004, 2022, Oracle and/or its affiliates. +// Copyright © 2004, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/MySqlPool.cs b/MySQL.Data/src/MySqlPool.cs index a92dc0625..01826550d 100644 --- a/MySQL.Data/src/MySqlPool.cs +++ b/MySQL.Data/src/MySqlPool.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2004, 2022, Oracle and/or its affiliates. +// Copyright © 2004, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -49,7 +49,9 @@ internal sealed class MySqlPool private readonly AutoResetEvent _autoEvent; private int _available; // Object used to lock the list of host obtained from DNS SRV lookup. - private readonly object _dnsSrvLock = new object(); + private readonly SemaphoreSlim inUsePoolSemaphore = new SemaphoreSlim(1, 1); + private readonly SemaphoreSlim idlePoolSemaphore = new SemaphoreSlim(1, 1); + private readonly SemaphoreSlim dnsSrvSemaphore = new SemaphoreSlim(1, 1); private void EnqueueIdle(Driver driver) { @@ -121,14 +123,23 @@ private async Task GetPooledConnectionAsync(bool execAsync, Cancellation // if we don't have an idle connection but we have room for a new // one, then create it here. - lock ((_idlePool as ICollection).SyncRoot) + if (execAsync) + await idlePoolSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); + else + idlePoolSemaphore.Wait(cancellationToken); + + try { if (HasIdleConnections) { - driver = _idlePool.Last.Value; - _idlePool.RemoveLast(); + driver = _idlePool.First.Value; + _idlePool.RemoveFirst(); } } + finally + { + idlePoolSemaphore.Release(); + } // Obey the connection timeout if (driver != null) @@ -164,10 +175,20 @@ private async Task GetPooledConnectionAsync(bool execAsync, Cancellation driver = await CreateNewPooledConnectionAsync(execAsync, cancellationToken).ConfigureAwait(false); Debug.Assert(driver != null); - lock ((_inUsePool as ICollection).SyncRoot) + if (execAsync) + await inUsePoolSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); + else + inUsePoolSemaphore.Wait(cancellationToken); + + try { _inUsePool.Add(driver); } + finally + { + inUsePoolSemaphore.Release(); + } + return driver; } @@ -185,11 +206,20 @@ private async Task CreateNewPooledConnectionAsync(bool execAsync, Cancel public async Task ReleaseConnectionAsync(Driver driver, bool execAsync) { - lock ((_inUsePool as ICollection).SyncRoot) + if (execAsync) + await inUsePoolSemaphore.WaitAsync().ConfigureAwait(false); + else + inUsePoolSemaphore.Wait(); + + try { if (_inUsePool.Contains(driver)) _inUsePool.Remove(driver); } + finally + { + inUsePoolSemaphore.Release(); + } if (driver.ConnectionLifetimeExpired() || BeingCleared) { @@ -198,32 +228,48 @@ public async Task ReleaseConnectionAsync(Driver driver, bool execAsync) } else { - lock ((_idlePool as ICollection).SyncRoot) + if (execAsync) + await idlePoolSemaphore.WaitAsync().ConfigureAwait(false); + else + idlePoolSemaphore.Wait(); + + try { EnqueueIdle(driver); } + finally + { + idlePoolSemaphore.Release(); + } } - SemaphoreSlim semaphoreSlim = new SemaphoreSlim(1); - semaphoreSlim.Wait(); + if (execAsync) + await dnsSrvSemaphore.WaitAsync().ConfigureAwait(false); + else + dnsSrvSemaphore.Wait(); - if (driver.Settings.DnsSrv) + try { - var dnsSrvRecords = DnsSrv.GetDnsSrvRecords(DnsSrv.ServiceName); - FailoverManager.SetHostList(dnsSrvRecords.ConvertAll(r => new FailoverServer(r.Target, r.Port, null)), - FailoverMethod.Sequential); - - foreach (var idleConnection in _idlePool) + if (driver.Settings.DnsSrv) { - string idleServer = idleConnection.Settings.Server; - if (!FailoverManager.FailoverGroup.Hosts.Exists(h => h.Host == idleServer) && !idleConnection.IsInActiveUse) + var dnsSrvRecords = DnsSrv.GetDnsSrvRecords(DnsSrv.ServiceName); + FailoverManager.SetHostList(dnsSrvRecords.ConvertAll(r => new FailoverServer(r.Target, r.Port, null)), + FailoverMethod.Sequential); + + foreach (var idleConnection in _idlePool) { - await idleConnection.CloseAsync(execAsync).ConfigureAwait(false); + string idleServer = idleConnection.Settings.Server; + if (!FailoverManager.FailoverGroup.Hosts.Exists(h => h.Host == idleServer) && !idleConnection.IsInActiveUse) + { + await idleConnection.CloseAsync(execAsync).ConfigureAwait(false); + } } } } - - semaphoreSlim.Release(); + finally + { + dnsSrvSemaphore.Release(); + } Interlocked.Increment(ref _available); _autoEvent.Set(); @@ -238,7 +284,8 @@ public async Task ReleaseConnectionAsync(Driver driver, bool execAsync) /// public void RemoveConnection(Driver driver) { - lock ((_inUsePool as ICollection).SyncRoot) + inUsePoolSemaphore.Wait(); + try { if (_inUsePool.Contains(driver)) { @@ -247,6 +294,10 @@ public void RemoveConnection(Driver driver) _autoEvent.Set(); } } + finally + { + inUsePoolSemaphore.Release(); + } // if we are being cleared and we are out of connections then have // the manager destroy us. @@ -301,21 +352,28 @@ public async Task GetConnectionAsync(bool execAsync, CancellationToken c /// internal async Task ClearAsync(bool execAsync) { - SemaphoreSlim semaphoreSlim = new SemaphoreSlim(1); - semaphoreSlim.Wait(); + if (execAsync) + await idlePoolSemaphore.WaitAsync().ConfigureAwait(false); + else + idlePoolSemaphore.Wait(); - // first, mark ourselves as being cleared - BeingCleared = true; + try + { + // first, mark ourselves as being cleared + BeingCleared = true; - // then we remove all connections sitting in the idle pool - while (_idlePool.Count > 0) + // then we remove all connections sitting in the idle pool + while (_idlePool.Count > 0) + { + Driver d = _idlePool.Last.Value; + await d.CloseAsync(execAsync).ConfigureAwait(false); + _idlePool.RemoveLast(); + } + } + finally { - Driver d = _idlePool.Last.Value; - await d.CloseAsync(execAsync).ConfigureAwait(false); - _idlePool.RemoveLast(); + idlePoolSemaphore.Release(); } - - semaphoreSlim.Release(); // there is nothing left to do here. Now we just wait for all // in use connections to be returned to the pool. When they are // they will be closed. When the last one is closed, the pool will @@ -338,23 +396,29 @@ internal List RemoveOldIdleConnections() var connectionsToClose = new List(); DateTime now = DateTime.Now; - lock ((_idlePool as ICollection).SyncRoot) + idlePoolSemaphore.Wait(); + + try { while (_idlePool.Count > _minSize) { - var iddleConnection = _idlePool.First.Value; - DateTime expirationTime = iddleConnection.IdleSince.Add( + var idleConnection = _idlePool.First.Value; + DateTime expirationTime = idleConnection.IdleSince.Add( new TimeSpan(0, 0, MySqlPoolManager.maxConnectionIdleTime)); if (expirationTime.CompareTo(now) < 0) { - connectionsToClose.Add(iddleConnection); + connectionsToClose.Add(idleConnection); _idlePool.RemoveFirst(); } else break; } } + finally + { + idlePoolSemaphore.Release(); + } return connectionsToClose; } } diff --git a/MySQL.Data/src/MySqlPoolManager.cs b/MySQL.Data/src/MySqlPoolManager.cs index 7ee452d25..e3dea7676 100644 --- a/MySQL.Data/src/MySqlPoolManager.cs +++ b/MySQL.Data/src/MySqlPoolManager.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2004, 2023, Oracle and/or its affiliates. +// Copyright © 2004, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -49,7 +49,7 @@ internal class MySqlPoolManager private static readonly Dictionary Pools = new Dictionary(); private static readonly List ClearingPools = new List(); internal const int DEMOTED_TIMEOUT = 120000; - private static SemaphoreSlim waitHandle = new(1); + private static SemaphoreSlim waitHandle = new(1, 1); #region Properties /// @@ -139,20 +139,29 @@ public static async Task GetPoolAsync(MySqlConnectionStringBuilder se { string text = GetKey(settings); - await waitHandle.WaitAsync(CancellationToken.None); - MySqlPool pool; - Pools.TryGetValue(text, out pool); + if (execAsync) + await waitHandle.WaitAsync(CancellationToken.None).ConfigureAwait(false); + else + waitHandle.Wait(cancellationToken); - if (pool == null) + try { - pool = await MySqlPool.CreateMySqlPoolAsync(settings, execAsync, cancellationToken).ConfigureAwait(false); - Pools.Add(text, pool); - } - else - pool.Settings = settings; + MySqlPool pool; + Pools.TryGetValue(text, out pool); + if (pool == null) + { + pool = await MySqlPool.CreateMySqlPoolAsync(settings, execAsync, cancellationToken).ConfigureAwait(false); + Pools.Add(text, pool); + } + else + pool.Settings = settings; - waitHandle.Release(); - return pool; + return pool; + } + finally + { + waitHandle.Release(); + } } public static void RemoveConnection(Driver driver) @@ -170,7 +179,8 @@ public static async Task ReleaseConnectionAsync(Driver driver, bool execAsync) MySqlPool pool = driver.Pool; - await pool?.ReleaseConnectionAsync(driver, execAsync); + if (pool != null) + await pool.ReleaseConnectionAsync(driver, execAsync).ConfigureAwait(false); } public static async Task ClearPoolAsync(MySqlConnectionStringBuilder settings, bool execAsync) @@ -193,33 +203,50 @@ public static async Task ClearPoolAsync(MySqlConnectionStringBuilder settings, b private static async Task ClearPoolByTextAsync(string key, bool execAsync) { - // if pools doesn't have it, then this pool must already have been cleared - if (!Pools.ContainsKey(key)) return; + if (execAsync) + await waitHandle.WaitAsync().ConfigureAwait(false); + else + waitHandle.Wait(); - // add the pool to our list of pools being cleared - MySqlPool pool = (Pools[key] as MySqlPool); - ClearingPools.Add(pool); + try + { + // if pools doesn't have it, then this pool must already have been cleared + if (!Pools.ContainsKey(key)) return; + + // add the pool to our list of pools being cleared + MySqlPool pool = (Pools[key] as MySqlPool); + ClearingPools.Add(pool); - // now tell the pool to clear itself - await pool.ClearAsync(execAsync).ConfigureAwait(false); + // now tell the pool to clear itself + await pool.ClearAsync(execAsync).ConfigureAwait(false); - // and then remove the pool from the active pools list - Pools.Remove(key); + // and then remove the pool from the active pools list + Pools.Remove(key); + } + finally + { + waitHandle.Release(); + } } public static async Task ClearAllPoolsAsync(bool execAsync) { - await waitHandle.WaitAsync(); - // Create separate keys list. - List keys = new List(Pools.Count); - keys.AddRange(Pools.Keys); - // Remove all pools by key. - foreach (string key in keys) - await ClearPoolByTextAsync(key, execAsync).ConfigureAwait(false); + try + { + // Create separate keys list. + List keys = new List(Pools.Count); + keys.AddRange(Pools.Keys); - waitHandle.Release(); + // Remove all pools by key. + foreach (string key in keys) + await ClearPoolByTextAsync(key, execAsync).ConfigureAwait(false); + } + catch + { + throw; + } if (DemotedServersTimer != null) { @@ -281,4 +308,4 @@ internal static void ReleaseDemotedHosts(object state) DemotedServersTimer.Change(DEMOTED_TIMEOUT, Timeout.Infinite); } } -} \ No newline at end of file +} diff --git a/MySQL.Data/src/MySqlScript.cs b/MySQL.Data/src/MySqlScript.cs index acd54537d..d36b8ff02 100644 --- a/MySQL.Data/src/MySqlScript.cs +++ b/MySQL.Data/src/MySqlScript.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2004, 2019, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2004, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/MySqlStream.cs b/MySQL.Data/src/MySqlStream.cs index cb2e2726f..60f79c199 100644 --- a/MySQL.Data/src/MySqlStream.cs +++ b/MySQL.Data/src/MySqlStream.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2004, 2023, Oracle and/or its affiliates. +// Copyright © 2004, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/MySqlTrace.cs b/MySQL.Data/src/MySqlTrace.cs index 2a10dd575..f3282e5d4 100644 --- a/MySQL.Data/src/MySqlTrace.cs +++ b/MySQL.Data/src/MySqlTrace.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2009, 2022, Oracle and/or its affiliates. +// Copyright © 2009, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/MySqlTransaction.cs b/MySQL.Data/src/MySqlTransaction.cs index bfbd1fca0..a8b0c0c29 100644 --- a/MySQL.Data/src/MySqlTransaction.cs +++ b/MySQL.Data/src/MySqlTransaction.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2004, 2022, Oracle and/or its affiliates. +// Copyright © 2004, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/MysqlDefs.cs b/MySQL.Data/src/MysqlDefs.cs index 4e25e56e2..e2d54081d 100644 --- a/MySQL.Data/src/MysqlDefs.cs +++ b/MySQL.Data/src/MysqlDefs.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2004, 2022, Oracle and/or its affiliates. +// Copyright © 2004, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -223,6 +223,12 @@ public enum MySqlDbType /// Bit-field data type /// Bit = 16, + + /// + /// Vector type + /// + Vector=242, + /// /// JSON /// diff --git a/MySQL.Data/src/NativeDriver.cs b/MySQL.Data/src/NativeDriver.cs index c7f518b19..a726c2376 100644 --- a/MySQL.Data/src/NativeDriver.cs +++ b/MySQL.Data/src/NativeDriver.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2004, 2023, Oracle and/or its affiliates. +// Copyright © 2004, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -117,7 +117,7 @@ private async Task HandleExceptionAsync(MySqlException ex, bool execAsync) internal async Task SendPacketAsync(MySqlPacket p, bool execAsync) { - await stream.SendPacketAsync(p, execAsync); + await stream.SendPacketAsync(p, execAsync).ConfigureAwait(false); } internal async Task SendEmptyPacketAsync(bool execAsync) @@ -421,7 +421,7 @@ public async Task AuthenticateAsync(string authMethod, bool reset, bool execAsyn authPlugin = await MySqlAuthenticationPlugin.GetPluginAsync(authMethod, this, encryptionSeed, execAsync).ConfigureAwait(false); } - await authPlugin.AuthenticateAsync(reset, execAsync); + await authPlugin.AuthenticateAsync(reset, execAsync).ConfigureAwait(false); } #endregion diff --git a/MySQL.Data/src/OkPacket.cs b/MySQL.Data/src/OkPacket.cs index 0a8d101cf..45a05f8ff 100644 --- a/MySQL.Data/src/OkPacket.cs +++ b/MySQL.Data/src/OkPacket.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/PacketBitConverter.cs b/MySQL.Data/src/PacketBitConverter.cs new file mode 100644 index 000000000..9c20ae703 --- /dev/null +++ b/MySQL.Data/src/PacketBitConverter.cs @@ -0,0 +1,115 @@ +// Copyright © 2004, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +namespace MySql.Data +{ + public static class PacketBitConverter + { + // Due to the lack of support of the C# BinaryPrimitives class + // on net452 and net48 this class is necessary for back compatibility. + // All instances of PacketBitConverter can be replaced with corresponding + // BinaryPrimitives methods for future versions. + + // The server sends MySql Packets in LittleEndian encoding + // The methods provided by the BitConverter class check for the + // endian-ness of the client system and do conversions accordingly + // which lead to incorrect conversions on BigEndian systems + + // Following function are analogues with BinaryPrimitives.Write*LittleEndian + public static byte[] GetBytes(int value) + { + return new byte[] { + (byte)value, (byte)(value >> 8), (byte)(value >> 16), (byte)(value >> 24) + }; + } + + public static byte[] GetBytes(long value) + { + return new byte[] { + (byte)value, (byte)(value >> 8), (byte)(value >> 16), (byte)(value >> 24), + (byte)(value >> 32), (byte)(value >> 40), (byte)(value >> 48), (byte)(value >> 56) + }; + } + + unsafe public static byte[] GetBytes(float value) + { + int val = *(int*)&value; + return GetBytes(val); + } + + unsafe public static byte[] GetBytes(double value) + { + long val = *(long*)&value; + return GetBytes(val); + } + + // Following functions are analogous to BinaryPrimitives.Read*LittleEndian + unsafe public static float ToSingle(byte[] byteArray, int startIndex) + { + int val = ToInt32(byteArray, startIndex); + return *(float*)&val; + } + + unsafe public static double ToDouble(byte[] byteArray, int startIndex) + { + long val = ToInt64(byteArray, startIndex); + return *(double*)&val; + } + + public static ushort ToUInt16(byte[] byteArray, int startIndex) + { + return (ushort)(byteArray[startIndex++] | byteArray[startIndex] << 8); + } + + public static uint ToUInt32(byte[] byteArray, int startIndex) + { + return (uint)(byteArray[startIndex++] | byteArray[startIndex++] << 8 + | byteArray[startIndex++] << 16 | byteArray[startIndex] << 24); + } + + public static ulong ToUInt64(byte[] byteArray, int startIndex) + { + return (ulong)ToUInt32(byteArray, startIndex) + ((ulong)ToUInt32(byteArray, startIndex + 4) << 32); + } + + public static short ToInt16(byte[] byteArray, int startIndex) + { + return (short)ToUInt16(byteArray, startIndex); + } + + public static int ToInt32(byte[] byteArray, int startIndex) + { + return (int)ToUInt32(byteArray, startIndex); + } + + public static long ToInt64(byte[] byteArray, int startIndex) + { + return (long)ToUInt64(byteArray, startIndex); + } + } +} diff --git a/MySQL.Data/src/PerformanceMonitor.cs b/MySQL.Data/src/PerformanceMonitor.cs index eeb239c7c..3f786dfc7 100644 --- a/MySQL.Data/src/PerformanceMonitor.cs +++ b/MySQL.Data/src/PerformanceMonitor.cs @@ -1,52 +1,52 @@ -// Copyright (c) 2004, 2016, Oracle and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using System; -using System.Diagnostics; - - -namespace MySql.Data.MySqlClient -{ - internal class PerformanceMonitor - { - public PerformanceMonitor(MySqlConnection connection) - { - Connection = connection; - } - - public MySqlConnection Connection { get; private set; } - - public virtual void AddHardProcedureQuery() - { - } - - public virtual void AddSoftProcedureQuery() - { - } - } -} \ No newline at end of file +// Copyright © 2004, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using System; +using System.Diagnostics; + + +namespace MySql.Data.MySqlClient +{ + internal class PerformanceMonitor + { + public PerformanceMonitor(MySqlConnection connection) + { + Connection = connection; + } + + public MySqlConnection Connection { get; private set; } + + public virtual void AddHardProcedureQuery() + { + } + + public virtual void AddSoftProcedureQuery() + { + } + } +} diff --git a/MySQL.Data/src/PreparableStatement.cs b/MySQL.Data/src/PreparableStatement.cs index 68565114a..0f67d6413 100644 --- a/MySQL.Data/src/PreparableStatement.cs +++ b/MySQL.Data/src/PreparableStatement.cs @@ -1,258 +1,258 @@ -// Copyright (c) 2004, 2022, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data.Common; -using System; -using System.Collections; -using System.Collections.Generic; -using System.Data; -using System.Text; -using System.Threading.Tasks; - -namespace MySql.Data.MySqlClient -{ - /// - /// Summary description for PreparedStatement. - /// - internal class PreparableStatement : Statement - { - BitArray _nullMap; - readonly List _parametersToSend = new List(); - MySqlPacket _packet; - int _dataPosition; - int _nullMapPosition; - - const int PARAMETER_COUNT_AVAILABLE = 0x08; // QueryAttributes should be sent to the server - - public PreparableStatement(MySqlCommand command, string text) - : base(command, text) - { - } - - #region Properties - - public int ExecutionCount { get; set; } - - public bool IsPrepared => StatementId > 0; - - public int StatementId { get; private set; } - - #endregion - - public async Task PrepareAsync(bool execAsync) - { - // strip out names from parameter markers - string text; - List parameterNames = PrepareCommandText(out text); - - // ask our connection to send the prepare command - var result = await Driver.PrepareStatementAsync(text, execAsync).ConfigureAwait(false); - StatementId = result.Item1; - MySqlField[] paramList = result.Item2; - - // now we need to assign our field names since we stripped them out - // for the prepare - for (int i = 0; i < parameterNames.Count; i++) - { - string parameterName = (string)parameterNames[i]; - MySqlParameter p = Parameters.GetParameterFlexible(parameterName, false); - if (p == null) - throw new InvalidOperationException( - String.Format(Resources.ParameterNotFoundDuringPrepare, parameterName)); - p.Encoding = paramList[i].Encoding; - _parametersToSend.Add(p); - } - - if (Attributes.Count > 0 && !Driver.SupportsQueryAttributes) - MySqlTrace.LogWarning(Connection.ServerThread, string.Format(Resources.QueryAttributesNotSupported, Driver.Version)); - - _packet = new MySqlPacket(Driver.Encoding); - - // write out some values that do not change run to run - _packet.WriteByte(0); - await _packet.WriteIntegerAsync(StatementId, 4, execAsync).ConfigureAwait(false); - // flags; if server supports query attributes, then set PARAMETER_COUNT_AVAILABLE (0x08) in the flags block - int flags = Driver.SupportsQueryAttributes && Driver.Version.isAtLeast(8, 0, 26) ? PARAMETER_COUNT_AVAILABLE : 0; - await _packet.WriteIntegerAsync(flags, 1, execAsync).ConfigureAwait(false); - await _packet.WriteIntegerAsync(1, 4, execAsync).ConfigureAwait(false); // iteration count; 1 for 4.1 - int num_params = paramList != null ? paramList.Length : 0; - // we don't send QA with PS when MySQL Server is not at least 8.0.26 - if (!Driver.Version.isAtLeast(8, 0, 26) && Attributes.Count > 0) - { - MySqlTrace.LogWarning(Connection.ServerThread, Resources.QueryAttributesNotSupportedByCnet); - Attributes.Clear(); - } - - if (num_params > 0 || - (Driver.SupportsQueryAttributes && flags == PARAMETER_COUNT_AVAILABLE)) // if num_params > 0 - { - int paramCount = num_params; - - if (Driver.SupportsQueryAttributes) // if CLIENT_QUERY_ATTRIBUTES is on - { - paramCount += Attributes.Count; - await _packet.WriteLengthAsync(paramCount, execAsync).ConfigureAwait(false); - } - - if (paramCount > 0) - { - // now prepare our null map - _nullMap = new BitArray(paramCount); - int numNullBytes = (_nullMap.Length + 7) / 8; - _nullMapPosition = _packet.Position; - _packet.Position += numNullBytes; // leave room for our null map - _packet.WriteByte(1); // new_params_bind_flag - - // write out the parameter types and names - foreach (MySqlParameter p in _parametersToSend) - { - // parameter type - await _packet.WriteIntegerAsync(p.GetPSType(), 2, execAsync).ConfigureAwait(false); - - // parameter name - if (Driver.SupportsQueryAttributes) // if CLIENT_QUERY_ATTRIBUTES is on - await _packet.WriteLenStringAsync(String.Empty, execAsync).ConfigureAwait(false); - } - - // write out the attributes types and names - foreach (MySqlAttribute a in Attributes) - { - // attribute type - await _packet.WriteIntegerAsync(a.GetPSType(), 2, execAsync).ConfigureAwait(false); - - // attribute name - if (Driver.SupportsQueryAttributes) // if CLIENT_QUERY_ATTRIBUTES is on - await _packet.WriteLenStringAsync(a.AttributeName, execAsync).ConfigureAwait(false); - } - } - } - - _dataPosition = _packet.Position; - } - - public override async Task ExecuteAsync(bool execAsync) - { - // if we are not prepared, then call down to our base - if (!IsPrepared) - { - await base.ExecuteAsync(execAsync).ConfigureAwait(false); - return; - } - - // now write out all non-null values - _packet.Position = _dataPosition; - - // set value for each parameter - for (int i = 0; i < _parametersToSend.Count; i++) - { - MySqlParameter p = _parametersToSend[i]; - _nullMap[i] = (p.Value == DBNull.Value || p.Value == null) || - p.Direction == ParameterDirection.Output; - if (_nullMap[i]) continue; - _packet.Encoding = p.Encoding; - await p.SerializeAsync(_packet, true, Connection.Settings, execAsync).ConfigureAwait(false); - } - - // // set value for each attribute - for (int i = 0; i < Attributes.Count; i++) - { - MySqlAttribute attr = Attributes[i]; - _nullMap[i] = (attr.Value == DBNull.Value || attr.Value == null); - if (_nullMap[i]) continue; - await attr.SerializeAsync(_packet, true, Connection.Settings, execAsync).ConfigureAwait(false); - } - - if (_nullMap != null) - { - byte[] tempByteArray = new byte[(_nullMap.Length + 7) >> 3]; - _nullMap.CopyTo(tempByteArray, 0); - - Array.Copy(tempByteArray, 0, _packet.Buffer, _nullMapPosition, tempByteArray.Length); - } - - ExecutionCount++; - - await Driver.ExecuteStatementAsync(_packet, execAsync).ConfigureAwait(false); - } - - public override async Task ExecuteNextAsync(bool execAsync) - { - if (!IsPrepared) - return await base.ExecuteNextAsync(execAsync).ConfigureAwait(false); - return false; - } - - /// - /// Prepares CommandText for use with the Prepare method - /// - /// Command text stripped of all paramter names - /// - /// Takes the output of TokenizeSql and creates a single string of SQL - /// that only contains '?' markers for each parameter. It also creates - /// the parameterMap array list that includes all the paramter names in the - /// order they appeared in the SQL - /// - private List PrepareCommandText(out string stripped_sql) - { - StringBuilder newSQL = new StringBuilder(); - List parameterMap = new List(); - - int startPos = 0; - string sql = ResolvedCommandText; - MySqlTokenizer tokenizer = new MySqlTokenizer(sql); - string parameter = tokenizer.NextParameter(); - int paramIndex = 0; - while (parameter != null) - { - if (parameter.IndexOf(StoredProcedure.ParameterPrefix) == -1) - { - newSQL.Append(sql.Substring(startPos, tokenizer.StartIndex - startPos)); - newSQL.Append("?"); - if (parameter.Length == 1 && tokenizer.IsParameterMarker(parameter.ToCharArray()[0])) - parameterMap.Add(Parameters[paramIndex].ParameterName); - else - parameterMap.Add(parameter); - startPos = tokenizer.StopIndex; - } - parameter = tokenizer.NextParameter(); - paramIndex++; - } - newSQL.Append(sql.Substring(startPos)); - stripped_sql = newSQL.ToString(); - return parameterMap; - } - - public virtual async Task CloseStatementAsync(bool execAsync) - { - if (!IsPrepared) return; - - await Driver.CloseStatementAsync(StatementId, execAsync).ConfigureAwait(false); - StatementId = 0; - } - } -} +// Copyright © 2004, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data.Common; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Data; +using System.Text; +using System.Threading.Tasks; + +namespace MySql.Data.MySqlClient +{ + /// + /// Summary description for PreparedStatement. + /// + internal class PreparableStatement : Statement + { + BitArray _nullMap; + readonly List _parametersToSend = new List(); + MySqlPacket _packet; + int _dataPosition; + int _nullMapPosition; + + const int PARAMETER_COUNT_AVAILABLE = 0x08; // QueryAttributes should be sent to the server + + public PreparableStatement(MySqlCommand command, string text) + : base(command, text) + { + } + + #region Properties + + public int ExecutionCount { get; set; } + + public bool IsPrepared => StatementId > 0; + + public int StatementId { get; private set; } + + #endregion + + public async Task PrepareAsync(bool execAsync) + { + // strip out names from parameter markers + string text; + List parameterNames = PrepareCommandText(out text); + + // ask our connection to send the prepare command + var result = await Driver.PrepareStatementAsync(text, execAsync).ConfigureAwait(false); + StatementId = result.Item1; + MySqlField[] paramList = result.Item2; + + // now we need to assign our field names since we stripped them out + // for the prepare + for (int i = 0; i < parameterNames.Count; i++) + { + string parameterName = (string)parameterNames[i]; + MySqlParameter p = Parameters.GetParameterFlexible(parameterName, false); + if (p == null) + throw new InvalidOperationException( + String.Format(Resources.ParameterNotFoundDuringPrepare, parameterName)); + p.Encoding = paramList[i].Encoding; + _parametersToSend.Add(p); + } + + if (Attributes.Count > 0 && !Driver.SupportsQueryAttributes) + MySqlTrace.LogWarning(Connection.ServerThread, string.Format(Resources.QueryAttributesNotSupported, Driver.Version)); + + _packet = new MySqlPacket(Driver.Encoding); + + // write out some values that do not change run to run + _packet.WriteByte(0); + await _packet.WriteIntegerAsync(StatementId, 4, execAsync).ConfigureAwait(false); + // flags; if server supports query attributes, then set PARAMETER_COUNT_AVAILABLE (0x08) in the flags block + int flags = Driver.SupportsQueryAttributes && Driver.Version.isAtLeast(8, 0, 26) ? PARAMETER_COUNT_AVAILABLE : 0; + await _packet.WriteIntegerAsync(flags, 1, execAsync).ConfigureAwait(false); + await _packet.WriteIntegerAsync(1, 4, execAsync).ConfigureAwait(false); // iteration count; 1 for 4.1 + int num_params = paramList != null ? paramList.Length : 0; + // we don't send QA with PS when MySQL Server is not at least 8.0.26 + if (!Driver.Version.isAtLeast(8, 0, 26) && Attributes.Count > 0) + { + MySqlTrace.LogWarning(Connection.ServerThread, Resources.QueryAttributesNotSupportedByCnet); + Attributes.Clear(); + } + + if (num_params > 0 || + (Driver.SupportsQueryAttributes && flags == PARAMETER_COUNT_AVAILABLE)) // if num_params > 0 + { + int paramCount = num_params; + + if (Driver.SupportsQueryAttributes) // if CLIENT_QUERY_ATTRIBUTES is on + { + paramCount += Attributes.Count; + await _packet.WriteLengthAsync(paramCount, execAsync).ConfigureAwait(false); + } + + if (paramCount > 0) + { + // now prepare our null map + _nullMap = new BitArray(paramCount); + int numNullBytes = (_nullMap.Length + 7) / 8; + _nullMapPosition = _packet.Position; + _packet.Position += numNullBytes; // leave room for our null map + _packet.WriteByte(1); // new_params_bind_flag + + // write out the parameter types and names + foreach (MySqlParameter p in _parametersToSend) + { + // parameter type + await _packet.WriteIntegerAsync(p.GetPSType(), 2, execAsync).ConfigureAwait(false); + + // parameter name + if (Driver.SupportsQueryAttributes) // if CLIENT_QUERY_ATTRIBUTES is on + await _packet.WriteLenStringAsync(String.Empty, execAsync).ConfigureAwait(false); + } + + // write out the attributes types and names + foreach (MySqlAttribute a in Attributes) + { + // attribute type + await _packet.WriteIntegerAsync(a.GetPSType(), 2, execAsync).ConfigureAwait(false); + + // attribute name + if (Driver.SupportsQueryAttributes) // if CLIENT_QUERY_ATTRIBUTES is on + await _packet.WriteLenStringAsync(a.AttributeName, execAsync).ConfigureAwait(false); + } + } + } + + _dataPosition = _packet.Position; + } + + public override async Task ExecuteAsync(bool execAsync) + { + // if we are not prepared, then call down to our base + if (!IsPrepared) + { + await base.ExecuteAsync(execAsync).ConfigureAwait(false); + return; + } + + // now write out all non-null values + _packet.Position = _dataPosition; + + // set value for each parameter + for (int i = 0; i < _parametersToSend.Count; i++) + { + MySqlParameter p = _parametersToSend[i]; + _nullMap[i] = (p.Value == DBNull.Value || p.Value == null) || + p.Direction == ParameterDirection.Output; + if (_nullMap[i]) continue; + _packet.Encoding = p.Encoding; + await p.SerializeAsync(_packet, true, Connection.Settings, execAsync).ConfigureAwait(false); + } + + // // set value for each attribute + for (int i = 0; i < Attributes.Count; i++) + { + MySqlAttribute attr = Attributes[i]; + _nullMap[i] = (attr.Value == DBNull.Value || attr.Value == null); + if (_nullMap[i]) continue; + await attr.SerializeAsync(_packet, true, Connection.Settings, execAsync).ConfigureAwait(false); + } + + if (_nullMap != null) + { + byte[] tempByteArray = new byte[(_nullMap.Length + 7) >> 3]; + _nullMap.CopyTo(tempByteArray, 0); + + Array.Copy(tempByteArray, 0, _packet.Buffer, _nullMapPosition, tempByteArray.Length); + } + + ExecutionCount++; + + await Driver.ExecuteStatementAsync(_packet, execAsync).ConfigureAwait(false); + } + + public override async Task ExecuteNextAsync(bool execAsync) + { + if (!IsPrepared) + return await base.ExecuteNextAsync(execAsync).ConfigureAwait(false); + return false; + } + + /// + /// Prepares CommandText for use with the Prepare method + /// + /// Command text stripped of all paramter names + /// + /// Takes the output of TokenizeSql and creates a single string of SQL + /// that only contains '?' markers for each parameter. It also creates + /// the parameterMap array list that includes all the paramter names in the + /// order they appeared in the SQL + /// + private List PrepareCommandText(out string stripped_sql) + { + StringBuilder newSQL = new StringBuilder(); + List parameterMap = new List(); + + int startPos = 0; + string sql = ResolvedCommandText; + MySqlTokenizer tokenizer = new MySqlTokenizer(sql); + string parameter = tokenizer.NextParameter(); + int paramIndex = 0; + while (parameter != null) + { + if (parameter.IndexOf(StoredProcedure.ParameterPrefix) == -1) + { + newSQL.Append(sql.Substring(startPos, tokenizer.StartIndex - startPos)); + newSQL.Append("?"); + if (parameter.Length == 1 && tokenizer.IsParameterMarker(parameter.ToCharArray()[0])) + parameterMap.Add(Parameters[paramIndex].ParameterName); + else + parameterMap.Add(parameter); + startPos = tokenizer.StopIndex; + } + parameter = tokenizer.NextParameter(); + paramIndex++; + } + newSQL.Append(sql.Substring(startPos)); + stripped_sql = newSQL.ToString(); + return parameterMap; + } + + public virtual async Task CloseStatementAsync(bool execAsync) + { + if (!IsPrepared) return; + + await Driver.CloseStatementAsync(StatementId, execAsync).ConfigureAwait(false); + StatementId = 0; + } + } +} diff --git a/MySQL.Data/src/ProcedureCache.cs b/MySQL.Data/src/ProcedureCache.cs index 968808608..0e9aada5c 100644 --- a/MySQL.Data/src/ProcedureCache.cs +++ b/MySQL.Data/src/ProcedureCache.cs @@ -1,230 +1,230 @@ -// Copyright (c) 2004, 2022, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace MySql.Data.MySqlClient -{ - internal class ProcedureCacheEntry - { - public MySqlSchemaCollection procedure; - public MySqlSchemaCollection parameters; - } - - internal class ProcedureCache - { - private readonly Dictionary _procHash; - private readonly Queue _hashQueue; - private readonly int _maxSize; - - public ProcedureCache(int size) - { - _maxSize = size; - _hashQueue = new Queue(_maxSize); - _procHash = new Dictionary(_maxSize); - } - - public async Task GetProcedureAsync(MySqlConnection conn, string spName, string cacheKey, bool execAsync) - { - ProcedureCacheEntry proc = null; - - if (cacheKey != null) - { - int hash = cacheKey.GetHashCode(); - - lock (_procHash) - { - _procHash.TryGetValue(hash, out proc); - } - } - if (proc == null) - { - proc = await AddNewAsync(conn, spName, execAsync).ConfigureAwait(false); - conn.PerfMonitor.AddHardProcedureQuery(); - if (conn.Settings.Logging) - MySqlTrace.LogInformation(conn.ServerThread, - String.Format(Resources.HardProcQuery, spName)); - } - else - { - conn.PerfMonitor.AddSoftProcedureQuery(); - if (conn.Settings.Logging) - MySqlTrace.LogInformation(conn.ServerThread, - String.Format(Resources.SoftProcQuery, spName)); - } - return proc; - } - - internal string GetCacheKey(string spName, ProcedureCacheEntry proc) - { - string retValue = String.Empty; - StringBuilder key = new StringBuilder(spName); - key.Append("("); - string delimiter = ""; - if (proc.parameters != null) - { - foreach (MySqlSchemaRow row in proc.parameters.Rows) - { - if (row["ORDINAL_POSITION"].Equals(0)) - retValue = "?="; - else - { - key.AppendFormat(CultureInfo.InvariantCulture, "{0}?", delimiter); - delimiter = ","; - } - } - } - key.Append(")"); - return retValue + key.ToString(); - } - - private async Task AddNewAsync(MySqlConnection connection, string spName, bool execAsync) - { - ProcedureCacheEntry procData = await GetProcDataAsync(connection, spName, execAsync).ConfigureAwait(false); - - if (_maxSize <= 0) return procData; - - string cacheKey = GetCacheKey(spName, procData); - int hash = cacheKey.GetHashCode(); - lock (_procHash) - { - if (_procHash.Keys.Count >= _maxSize) - TrimHash(); - if (!_procHash.ContainsKey(hash)) - { - _procHash[hash] = procData; - _hashQueue.Enqueue(hash); - } - } - return procData; - } - - private void TrimHash() - { - int oldestHash = _hashQueue.Dequeue(); - _procHash.Remove(oldestHash); - } - - private static async Task GetProcDataAsync(MySqlConnection connection, string spName, bool execAsync) - { - SplitSchemaAndEntity(spName, out string schema, out string entity); - - string[] restrictions = new string[4]; - restrictions[1] = string.IsNullOrEmpty(schema) ? connection.CurrentDatabase() : Utils.UnquoteString(schema); - restrictions[2] = Utils.UnquoteString(entity); - MySqlSchemaCollection proc = connection.GetSchemaCollection("procedures", restrictions); - if (proc.Rows.Count > 1) - throw new MySqlException(Resources.ProcAndFuncSameName); - if (proc.Rows.Count == 0) - { - string msg = string.Format(Resources.InvalidProcName, entity, schema) + " " + - string.Format(Resources.ExecuteProcedureUnauthorized, connection.Settings.UserID, connection.Settings.Server); - throw new MySqlException(msg); - } - - ProcedureCacheEntry entry = new ProcedureCacheEntry(); - entry.procedure = proc; - - // we don't use GetSchema here because that would cause another - // query of procedures and we don't need that since we already - // know the procedure we care about. - ISSchemaProvider isp = new ISSchemaProvider(connection); - string[] rest = isp.CleanRestrictions(restrictions); - MySqlSchemaCollection parameters = await isp.GetProcedureParametersAsync(rest, proc, execAsync).ConfigureAwait(false); - entry.parameters = parameters; - - return entry; - } - - /// - /// Splits the schema and the entity from a syntactically correct "spName"; - /// if there's no schema, then schema will be an empty string. - /// - /// string to inspect. - /// The schema. - /// The entity. - private static void SplitSchemaAndEntity(string spName, out string schema, out string entity) - { - int dotIndex = ExtractDotIndex(spName); - - if (dotIndex != -1) - { - schema = spName.Substring(0, dotIndex); - entity = spName.Substring(dotIndex + 1); - } - else - { - schema = string.Empty; - entity = spName; - } - } - - /// - /// Obtains the dot index that separates the schema from the entity if there's one; - /// otherwise, returns -1. It expects a syntactically correct "spName". - /// - /// string to inspect. - /// Value of the dot index. - /// The dot index. - private static int ExtractDotIndex(string spName, int dotIndex = -1) - { - int backticks, _dotIndexTemp; - _dotIndexTemp = spName.IndexOf('.'); // looks for a '.' in the string passed as argument - string subString; - - if (_dotIndexTemp != -1) - { - subString = spName.Substring(_dotIndexTemp + 1); // gets a substring from the found '.' to the end of the string - backticks = subString.Count(c => c == '`'); // counts backticks in the substring - - // if the count of backticks in the substring is an odd number, - // that means that this '.' is part of the schema or entity and will continue looking; - // otherwise, returns the index. - if (backticks % 2 == 0) - dotIndex = dotIndex == -1 ? _dotIndexTemp : dotIndex + _dotIndexTemp; - else - dotIndex = ExtractDotIndex(subString, _dotIndexTemp + 1); - } - else if (_dotIndexTemp == -1 && dotIndex != -1) - dotIndex = -1; - - return dotIndex; - } - - internal void Clear() - { - _procHash.Clear(); - _hashQueue.Clear(); - } - } -} \ No newline at end of file +// Copyright © 2004, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MySql.Data.MySqlClient +{ + internal class ProcedureCacheEntry + { + public MySqlSchemaCollection procedure; + public MySqlSchemaCollection parameters; + } + + internal class ProcedureCache + { + private readonly Dictionary _procHash; + private readonly Queue _hashQueue; + private readonly int _maxSize; + + public ProcedureCache(int size) + { + _maxSize = size; + _hashQueue = new Queue(_maxSize); + _procHash = new Dictionary(_maxSize); + } + + public async Task GetProcedureAsync(MySqlConnection conn, string spName, string cacheKey, bool execAsync) + { + ProcedureCacheEntry proc = null; + + if (cacheKey != null) + { + int hash = cacheKey.GetHashCode(); + + lock (_procHash) + { + _procHash.TryGetValue(hash, out proc); + } + } + if (proc == null) + { + proc = await AddNewAsync(conn, spName, execAsync).ConfigureAwait(false); + conn.PerfMonitor.AddHardProcedureQuery(); + if (conn.Settings.Logging) + MySqlTrace.LogInformation(conn.ServerThread, + String.Format(Resources.HardProcQuery, spName)); + } + else + { + conn.PerfMonitor.AddSoftProcedureQuery(); + if (conn.Settings.Logging) + MySqlTrace.LogInformation(conn.ServerThread, + String.Format(Resources.SoftProcQuery, spName)); + } + return proc; + } + + internal string GetCacheKey(string spName, ProcedureCacheEntry proc) + { + string retValue = String.Empty; + StringBuilder key = new StringBuilder(spName); + key.Append("("); + string delimiter = ""; + if (proc.parameters != null) + { + foreach (MySqlSchemaRow row in proc.parameters.Rows) + { + if (row["ORDINAL_POSITION"].Equals(0)) + retValue = "?="; + else + { + key.AppendFormat(CultureInfo.InvariantCulture, "{0}?", delimiter); + delimiter = ","; + } + } + } + key.Append(")"); + return retValue + key.ToString(); + } + + private async Task AddNewAsync(MySqlConnection connection, string spName, bool execAsync) + { + ProcedureCacheEntry procData = await GetProcDataAsync(connection, spName, execAsync).ConfigureAwait(false); + + if (_maxSize <= 0) return procData; + + string cacheKey = GetCacheKey(spName, procData); + int hash = cacheKey.GetHashCode(); + lock (_procHash) + { + if (_procHash.Keys.Count >= _maxSize) + TrimHash(); + if (!_procHash.ContainsKey(hash)) + { + _procHash[hash] = procData; + _hashQueue.Enqueue(hash); + } + } + return procData; + } + + private void TrimHash() + { + int oldestHash = _hashQueue.Dequeue(); + _procHash.Remove(oldestHash); + } + + private static async Task GetProcDataAsync(MySqlConnection connection, string spName, bool execAsync) + { + SplitSchemaAndEntity(spName, out string schema, out string entity); + + string[] restrictions = new string[4]; + restrictions[1] = string.IsNullOrEmpty(schema) ? connection.CurrentDatabase() : Utils.UnquoteString(schema); + restrictions[2] = Utils.UnquoteString(entity); + MySqlSchemaCollection proc = connection.GetSchemaCollection("procedures", restrictions); + if (proc.Rows.Count > 1) + throw new MySqlException(Resources.ProcAndFuncSameName); + if (proc.Rows.Count == 0) + { + string msg = string.Format(Resources.InvalidProcName, entity, schema) + " " + + string.Format(Resources.ExecuteProcedureUnauthorized, connection.Settings.UserID, connection.Settings.Server); + throw new MySqlException(msg); + } + + ProcedureCacheEntry entry = new ProcedureCacheEntry(); + entry.procedure = proc; + + // we don't use GetSchema here because that would cause another + // query of procedures and we don't need that since we already + // know the procedure we care about. + ISSchemaProvider isp = new ISSchemaProvider(connection); + string[] rest = isp.CleanRestrictions(restrictions); + MySqlSchemaCollection parameters = await isp.GetProcedureParametersAsync(rest, proc, execAsync).ConfigureAwait(false); + entry.parameters = parameters; + + return entry; + } + + /// + /// Splits the schema and the entity from a syntactically correct "spName"; + /// if there's no schema, then schema will be an empty string. + /// + /// string to inspect. + /// The schema. + /// The entity. + private static void SplitSchemaAndEntity(string spName, out string schema, out string entity) + { + int dotIndex = ExtractDotIndex(spName); + + if (dotIndex != -1) + { + schema = spName.Substring(0, dotIndex); + entity = spName.Substring(dotIndex + 1); + } + else + { + schema = string.Empty; + entity = spName; + } + } + + /// + /// Obtains the dot index that separates the schema from the entity if there's one; + /// otherwise, returns -1. It expects a syntactically correct "spName". + /// + /// string to inspect. + /// Value of the dot index. + /// The dot index. + private static int ExtractDotIndex(string spName, int dotIndex = -1) + { + int backticks, _dotIndexTemp; + _dotIndexTemp = spName.IndexOf('.'); // looks for a '.' in the string passed as argument + string subString; + + if (_dotIndexTemp != -1) + { + subString = spName.Substring(_dotIndexTemp + 1); // gets a substring from the found '.' to the end of the string + backticks = subString.Count(c => c == '`'); // counts backticks in the substring + + // if the count of backticks in the substring is an odd number, + // that means that this '.' is part of the schema or entity and will continue looking; + // otherwise, returns the index. + if (backticks % 2 == 0) + dotIndex = dotIndex == -1 ? _dotIndexTemp : dotIndex + _dotIndexTemp; + else + dotIndex = ExtractDotIndex(subString, _dotIndexTemp + 1); + } + else if (_dotIndexTemp == -1 && dotIndex != -1) + dotIndex = -1; + + return dotIndex; + } + + internal void Clear() + { + _procHash.Clear(); + _hashQueue.Clear(); + } + } +} diff --git a/MySQL.Data/src/Properties/AssemblyInfo.cs b/MySQL.Data/src/Properties/AssemblyInfo.cs index 6a4877d13..402af246b 100644 --- a/MySQL.Data/src/Properties/AssemblyInfo.cs +++ b/MySQL.Data/src/Properties/AssemblyInfo.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2004, 2023, Oracle and/or its affiliates. +// Copyright © 2004, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -36,12 +36,12 @@ // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("MySql.Data")] -[assembly: AssemblyDescription("ADO.Net driver for MySQL for .Net Framework and .Net Core")] +[assembly: AssemblyDescription("MySql.Data.MySqlClient .Net Core Class Library.")] [assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Oracle")] -[assembly: AssemblyProduct("MySql.Data.Core")] -[assembly: AssemblyCopyright("Copyright (c) 2016, 2023, Oracle and/or its affiliates.")] -[assembly: AssemblyTrademark("")] +[assembly: AssemblyCompany("Oracle Corporation")] +[assembly: AssemblyProduct("MySQL Connector/NET")] +[assembly: AssemblyCopyright("Copyright © 2004, 2025, Oracle and/or its affiliates.")] +[assembly: AssemblyTrademark("Oracle®, Java, MySQL, and NetSuite are registered trademarks of Oracle and/or its affiliates.")] [assembly: AssemblyCulture("")] [assembly: SecurityRules(SecurityRuleSet.Level1)] [assembly: CLSCompliant(false)] @@ -88,4 +88,4 @@ [assembly: InternalsVisibleTo("MySql.Data.EntityFrameworkCore, PublicKey = 0024000004800000940000000602000000240000525341310004000001000100d973bda91f71752c78294126974a41a08643168271f65fc0fb3cd45f658da01fbca75ac74067d18e7afbf1467d7a519ce0248b13719717281bb4ddd4ecd71a580dfe0912dfc3690b1d24c7e1975bf7eed90e4ab14e10501eedf763bff8ac204f955c9c15c2cf4ebf6563d8320b6ea8d1ea3807623141f4b81ae30a6c886b3ee1")] [assembly: InternalsVisibleTo("MySql.EntityFrameworkCore.Basic.Tests, PublicKey = 0024000004800000940000000602000000240000525341310004000001000100d973bda91f71752c78294126974a41a08643168271f65fc0fb3cd45f658da01fbca75ac74067d18e7afbf1467d7a519ce0248b13719717281bb4ddd4ecd71a580dfe0912dfc3690b1d24c7e1975bf7eed90e4ab14e10501eedf763bff8ac204f955c9c15c2cf4ebf6563d8320b6ea8d1ea3807623141f4b81ae30a6c886b3ee1")] [assembly: InternalsVisibleTo("MySql.Data.EntityFramework, PublicKey = 0024000004800000940000000602000000240000525341310004000001000100d973bda91f71752c78294126974a41a08643168271f65fc0fb3cd45f658da01fbca75ac74067d18e7afbf1467d7a519ce0248b13719717281bb4ddd4ecd71a580dfe0912dfc3690b1d24c7e1975bf7eed90e4ab14e10501eedf763bff8ac204f955c9c15c2cf4ebf6563d8320b6ea8d1ea3807623141f4b81ae30a6c886b3ee1")] -[assembly: InternalsVisibleTo("MySql.Web.Tests, PublicKey = 0024000004800000940000000602000000240000525341310004000001000100d973bda91f71752c78294126974a41a08643168271f65fc0fb3cd45f658da01fbca75ac74067d18e7afbf1467d7a519ce0248b13719717281bb4ddd4ecd71a580dfe0912dfc3690b1d24c7e1975bf7eed90e4ab14e10501eedf763bff8ac204f955c9c15c2cf4ebf6563d8320b6ea8d1ea3807623141f4b81ae30a6c886b3ee1")] \ No newline at end of file +[assembly: InternalsVisibleTo("MySql.Web.Tests, PublicKey = 0024000004800000940000000602000000240000525341310004000001000100d973bda91f71752c78294126974a41a08643168271f65fc0fb3cd45f658da01fbca75ac74067d18e7afbf1467d7a519ce0248b13719717281bb4ddd4ecd71a580dfe0912dfc3690b1d24c7e1975bf7eed90e4ab14e10501eedf763bff8ac204f955c9c15c2cf4ebf6563d8320b6ea8d1ea3807623141f4b81ae30a6c886b3ee1")] diff --git a/MySQL.Data/src/Properties/VersionInfo.cs b/MySQL.Data/src/Properties/VersionInfo.cs index 05a18cd26..e26c5117d 100644 --- a/MySQL.Data/src/Properties/VersionInfo.cs +++ b/MySQL.Data/src/Properties/VersionInfo.cs @@ -1,45 +1,46 @@ -// Copyright (c) 2004, 2023, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using System.Reflection; -using System.Resources; - -// -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Revision and Build Numbers -// by using the '*' as shown below: - -[assembly: AssemblyVersion("8.2.0")] -[assembly: AssemblyInformationalVersion("8.2.0")] -[assembly: NeutralResourcesLanguage("en-US")] \ No newline at end of file +// Copyright © 2004, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using System.Reflection; +using System.Resources; + +// +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: + +[assembly: AssemblyVersion("9.4.0")] +[assembly: AssemblyInformationalVersion("9.4.0.0")] +[assembly: AssemblyFileVersion("9.4.0.0")] +[assembly: NeutralResourcesLanguage("en-US")] diff --git a/MySQL.Data/src/Replication/ReplicationConfiguration.cs b/MySQL.Data/src/Replication/ReplicationConfiguration.cs index 9229717ec..8cbd52523 100644 --- a/MySQL.Data/src/Replication/ReplicationConfiguration.cs +++ b/MySQL.Data/src/Replication/ReplicationConfiguration.cs @@ -1,146 +1,146 @@ -// Copyright © 2013, 2020, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using System; -using System.Collections.Generic; -using System.Configuration; -using System.Text; - -namespace MySql.Data.MySqlClient -{ - /// - /// Defines a replication configurarion element in the configuration file. - /// - public sealed class ReplicationConfigurationElement : ConfigurationElement - { - /// - /// Gets a collection of objects representing the server groups. - /// - [ConfigurationProperty("ServerGroups", IsRequired = true)] - [ConfigurationCollection(typeof(ReplicationServerGroupConfigurationElement), AddItemName = "Group")] - public GenericConfigurationElementCollection ServerGroups - { - get { return (GenericConfigurationElementCollection)this["ServerGroups"]; } - } - } - - /// - /// Defines a replication server group in the configuration file. - /// - public sealed class ReplicationServerGroupConfigurationElement : ConfigurationElement - { - /// - /// Gets or sets the name of the replication server group configuration. - /// - [ConfigurationProperty("name", IsRequired = true)] - public string Name - { - get { return (string)this["name"]; } - set { this["name"] = value; } - } - - /// - /// Gets or sets the group type of the replication server group configuration. - /// - [ConfigurationProperty("groupType", IsRequired = false)] - public string GroupType - { - get { return (string)this["groupType"]; } - set { this["groupType"] = value; } - } - - /// - /// Gets or sets the number of seconds to wait for retry. - /// - [ConfigurationProperty("retryTime", IsRequired = false, DefaultValue = 60)] - public int RetryTime - { - get { return (int)this["retryTime"]; } - set { this["retryTime"] = value; } - } - - /// - /// Gets a collection of objects representing the - /// server configurations associated to this group configuration. - /// - [ConfigurationProperty("Servers")] - [ConfigurationCollection(typeof(ReplicationServerConfigurationElement), AddItemName = "Server")] - public GenericConfigurationElementCollection Servers - { - get { return (GenericConfigurationElementCollection)this["Servers"]; } - } - } - - /// - /// Defines a replication server in configuration file. - /// - public sealed class ReplicationServerConfigurationElement : ConfigurationElement - { - /// - /// Gets or sets the name of the replication server configuration. - /// - [ConfigurationProperty("name", IsRequired = true)] - public string Name - { - get { return (string)this["name"]; } - set { this["name"] = value; } - } - - /// - /// Gets or sets whether the replication server is configured as source. - /// - [ConfigurationProperty("IsMaster", IsRequired = false, DefaultValue = false)] - [Obsolete("This property is deprecated, please use IsSource instead.")] - public bool IsMaster - { - get { return (bool)this["IsMaster"]; } - set { this["IsMaster"] = value; } - } - - /// - /// Gets or sets whether the replication server is configured as source. - /// - [ConfigurationProperty("IsSource", IsRequired = false, DefaultValue = false)] - public bool IsSource - { - get { return (bool)this["IsSource"]; } - set { this["IsSource"] = value; } - } - - - /// - /// Gets or sets the connection string associated to this replication server. - /// - [ConfigurationProperty("connectionstring", IsRequired = true)] - public string ConnectionString - { - get { return (string)this["connectionstring"]; } - set { this["connectionstring"] = value; } - } - } -} +// Copyright © 2013, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Text; + +namespace MySql.Data.MySqlClient +{ + /// + /// Defines a replication configurarion element in the configuration file. + /// + public sealed class ReplicationConfigurationElement : ConfigurationElement + { + /// + /// Gets a collection of objects representing the server groups. + /// + [ConfigurationProperty("ServerGroups", IsRequired = true)] + [ConfigurationCollection(typeof(ReplicationServerGroupConfigurationElement), AddItemName = "Group")] + public GenericConfigurationElementCollection ServerGroups + { + get { return (GenericConfigurationElementCollection)this["ServerGroups"]; } + } + } + + /// + /// Defines a replication server group in the configuration file. + /// + public sealed class ReplicationServerGroupConfigurationElement : ConfigurationElement + { + /// + /// Gets or sets the name of the replication server group configuration. + /// + [ConfigurationProperty("name", IsRequired = true)] + public string Name + { + get { return (string)this["name"]; } + set { this["name"] = value; } + } + + /// + /// Gets or sets the group type of the replication server group configuration. + /// + [ConfigurationProperty("groupType", IsRequired = false)] + public string GroupType + { + get { return (string)this["groupType"]; } + set { this["groupType"] = value; } + } + + /// + /// Gets or sets the number of seconds to wait for retry. + /// + [ConfigurationProperty("retryTime", IsRequired = false, DefaultValue = 60)] + public int RetryTime + { + get { return (int)this["retryTime"]; } + set { this["retryTime"] = value; } + } + + /// + /// Gets a collection of objects representing the + /// server configurations associated to this group configuration. + /// + [ConfigurationProperty("Servers")] + [ConfigurationCollection(typeof(ReplicationServerConfigurationElement), AddItemName = "Server")] + public GenericConfigurationElementCollection Servers + { + get { return (GenericConfigurationElementCollection)this["Servers"]; } + } + } + + /// + /// Defines a replication server in configuration file. + /// + public sealed class ReplicationServerConfigurationElement : ConfigurationElement + { + /// + /// Gets or sets the name of the replication server configuration. + /// + [ConfigurationProperty("name", IsRequired = true)] + public string Name + { + get { return (string)this["name"]; } + set { this["name"] = value; } + } + + /// + /// Gets or sets whether the replication server is configured as source. + /// + [ConfigurationProperty("IsMaster", IsRequired = false, DefaultValue = false)] + [Obsolete("This property is deprecated, please use IsSource instead.")] + public bool IsMaster + { + get { return (bool)this["IsMaster"]; } + set { this["IsMaster"] = value; } + } + + /// + /// Gets or sets whether the replication server is configured as source. + /// + [ConfigurationProperty("IsSource", IsRequired = false, DefaultValue = false)] + public bool IsSource + { + get { return (bool)this["IsSource"]; } + set { this["IsSource"] = value; } + } + + + /// + /// Gets or sets the connection string associated to this replication server. + /// + [ConfigurationProperty("connectionstring", IsRequired = true)] + public string ConnectionString + { + get { return (string)this["connectionstring"]; } + set { this["connectionstring"] = value; } + } + } +} diff --git a/MySQL.Data/src/Replication/ReplicationManager.cs b/MySQL.Data/src/Replication/ReplicationManager.cs index 4c43f44fc..bd6f696ed 100644 --- a/MySQL.Data/src/Replication/ReplicationManager.cs +++ b/MySQL.Data/src/Replication/ReplicationManager.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2014, 2023, Oracle and/or its affiliates. +// Copyright © 2014, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -41,8 +41,7 @@ namespace MySql.Data.MySqlClient.Replication internal static class ReplicationManager { private static List groups = new List(); - private static Object thisLock = new Object(); - //private static Dictionary selectors = new Dictionary(); + private static SemaphoreSlim semaphoreSlim = new SemaphoreSlim(1, 1); static ReplicationManager() { @@ -147,55 +146,61 @@ internal static async Task GetNewConnectionAsync(string groupName, bool source, { do { - SemaphoreSlim semaphoreSlim = new SemaphoreSlim(1); - semaphoreSlim.Wait(); + if (execAsync) + await semaphoreSlim.WaitAsync(cancellationToken).ConfigureAwait(false); + else + semaphoreSlim.Wait(cancellationToken); - if (!IsReplicationGroup(groupName)) return; + try + { + if (!IsReplicationGroup(groupName)) return; - ReplicationServerGroup group = GetGroup(groupName); - ReplicationServer server = group.GetServer(source, connection.Settings); + ReplicationServerGroup group = GetGroup(groupName); + ReplicationServer server = group.GetServer(source, connection.Settings); - if (server == null) - throw new MySqlException(Resources.Replication_NoAvailableServer); + if (server == null) + throw new MySqlException(Resources.Replication_NoAvailableServer); - try - { - bool isNewServer = false; - if (connection.driver == null || !connection.driver.IsOpen) + try { - isNewServer = true; - } - else - { - MySqlConnectionStringBuilder msb = new MySqlConnectionStringBuilder(server.ConnectionString); - if (!msb.Equals(connection.driver.Settings)) + bool isNewServer = false; + if (connection.driver == null || !connection.driver.IsOpen) { isNewServer = true; } + else + { + MySqlConnectionStringBuilder msb = new MySqlConnectionStringBuilder(server.ConnectionString); + if (!msb.Equals(connection.driver.Settings)) + { + isNewServer = true; + } + } + if (isNewServer) + { + Driver driver = await Driver.CreateAsync(new MySqlConnectionStringBuilder(server.ConnectionString), execAsync, cancellationToken).ConfigureAwait(false); + connection.driver = driver; + } + return; } - if (isNewServer) + catch (MySqlException ex) { - Driver driver = await Driver.CreateAsync(new MySqlConnectionStringBuilder(server.ConnectionString), execAsync, cancellationToken).ConfigureAwait(false); - connection.driver = driver; + connection.driver = null; + server.IsAvailable = false; + MySqlTrace.LogError(ex.Number, ex.ToString()); + if (ex.Number == 1042) + { + // retry to open a failed connection and update its status + group.HandleFailover(server, ex); + } + else + throw; } - return; } - catch (MySqlException ex) + finally { - connection.driver = null; - server.IsAvailable = false; - MySqlTrace.LogError(ex.Number, ex.ToString()); - if (ex.Number == 1042) - { - // retry to open a failed connection and update its status - group.HandleFailover(server, ex); - } - else - throw; + semaphoreSlim.Release(); } - - semaphoreSlim.Release(); - } while (true); } } diff --git a/MySQL.Data/src/Replication/ReplicationRoundRobinServerGroup.cs b/MySQL.Data/src/Replication/ReplicationRoundRobinServerGroup.cs index 3128beddb..6fae451fc 100644 --- a/MySQL.Data/src/Replication/ReplicationRoundRobinServerGroup.cs +++ b/MySQL.Data/src/Replication/ReplicationRoundRobinServerGroup.cs @@ -1,67 +1,67 @@ -// Copyright � 2013, 2020, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using System; -using System.Collections.Generic; -using System.Text; - -namespace MySql.Data.MySqlClient.Replication -{ - /// - /// Class that implements Round Robing Load Balancing technique. - /// - public class ReplicationRoundRobinServerGroup : ReplicationServerGroup - { - private int nextServer; - - public ReplicationRoundRobinServerGroup(string name, int retryTime) : base(name, retryTime) - { - nextServer = -1; - } - - /// - /// Gets an available server based on Round Robin load balancing. - /// - /// Flag indicating if the server to return must be a source. - /// A object representing the next available server. - internal protected override ReplicationServer GetServer(bool isSource) - { - for (int i = 0; i < Servers.Count; i++) - { - nextServer++; - if (nextServer == Servers.Count) - nextServer = 0; - ReplicationServer s = Servers[nextServer]; - if (!s.IsAvailable) continue; - if (isSource && !s.IsSource) continue; - return s; - } - return null; - } - } -} +// Copyright © 2013, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using System; +using System.Collections.Generic; +using System.Text; + +namespace MySql.Data.MySqlClient.Replication +{ + /// + /// Class that implements Round Robing Load Balancing technique. + /// + public class ReplicationRoundRobinServerGroup : ReplicationServerGroup + { + private int nextServer; + + public ReplicationRoundRobinServerGroup(string name, int retryTime) : base(name, retryTime) + { + nextServer = -1; + } + + /// + /// Gets an available server based on Round Robin load balancing. + /// + /// Flag indicating if the server to return must be a source. + /// A object representing the next available server. + internal protected override ReplicationServer GetServer(bool isSource) + { + for (int i = 0; i < Servers.Count; i++) + { + nextServer++; + if (nextServer == Servers.Count) + nextServer = 0; + ReplicationServer s = Servers[nextServer]; + if (!s.IsAvailable) continue; + if (isSource && !s.IsSource) continue; + return s; + } + return null; + } + } +} diff --git a/MySQL.Data/src/Replication/ReplicationServer.cs b/MySQL.Data/src/Replication/ReplicationServer.cs index 07c062bf7..c1b14506c 100644 --- a/MySQL.Data/src/Replication/ReplicationServer.cs +++ b/MySQL.Data/src/Replication/ReplicationServer.cs @@ -1,70 +1,70 @@ -// Copyright � 2014, 2020, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using System; -using System.Collections.Generic; -using System.Text; - -namespace MySql.Data.MySqlClient.Replication -{ - /// - /// Represents a server in a Replication environment. - /// - public class ReplicationServer - { - public ReplicationServer(string name, bool isSource, string connectionString) - { - Name = name; - IsSource = isSource; - ConnectionString = connectionString; - IsAvailable = true; - } - - /// - /// Gets the server name. - /// - public string Name { get; private set; } - /// - /// Gets a value indicating whether the server is source or replica. - /// - [Obsolete("This property is deprecated please use IsSource instead.")] - public bool IsMaster { get; private set; } - /// - /// Gets a value indicating whether the server is source or replica. - /// - public bool IsSource { get; private set; } - /// - /// Gets the connection string used to connect to the server. - /// - public string ConnectionString { get; internal set; } - /// - /// Gets a flag indicating if the server is available to be considered in load balancing. - /// - public bool IsAvailable { get; set; } - } -} +// Copyright © 2014, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using System; +using System.Collections.Generic; +using System.Text; + +namespace MySql.Data.MySqlClient.Replication +{ + /// + /// Represents a server in a Replication environment. + /// + public class ReplicationServer + { + public ReplicationServer(string name, bool isSource, string connectionString) + { + Name = name; + IsSource = isSource; + ConnectionString = connectionString; + IsAvailable = true; + } + + /// + /// Gets the server name. + /// + public string Name { get; private set; } + /// + /// Gets a value indicating whether the server is source or replica. + /// + [Obsolete("This property is deprecated please use IsSource instead.")] + public bool IsMaster { get; private set; } + /// + /// Gets a value indicating whether the server is source or replica. + /// + public bool IsSource { get; private set; } + /// + /// Gets the connection string used to connect to the server. + /// + public string ConnectionString { get; internal set; } + /// + /// Gets a flag indicating if the server is available to be considered in load balancing. + /// + public bool IsAvailable { get; set; } + } +} diff --git a/MySQL.Data/src/Replication/ReplicationServerGroup.cs b/MySQL.Data/src/Replication/ReplicationServerGroup.cs index 3a23ec27d..237348ba6 100644 --- a/MySQL.Data/src/Replication/ReplicationServerGroup.cs +++ b/MySQL.Data/src/Replication/ReplicationServerGroup.cs @@ -1,185 +1,185 @@ -// Copyright (c) 2014, 2020, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - - - -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Text; - -namespace MySql.Data.MySqlClient.Replication -{ - /// - /// Base class used to implement load balancing features. - /// - public abstract class ReplicationServerGroup - { - /// - /// List of servers available for replication. - /// - protected List servers = new List(); - - /// The group name. - /// The number of seconds to perform a retry. - public ReplicationServerGroup(string name, int retryTime) - { - Servers = servers; - Name = name; - RetryTime = retryTime; - } - - /// - /// Gets the group name. - /// - public string Name { get; protected set; } - /// - /// Gets the retry time between connections to failed servers. - /// - public int RetryTime { get; protected set; } - /// - /// Gets the server list in the group. - /// - protected IList Servers { get; private set; } - - /// - /// Adds a server into the group. - /// - /// The server name. - /// A flag indicating if the server to add is source or replica. - /// The connection string used by this server. - /// A object representing the recently added object. - internal protected ReplicationServer AddServer(string name, bool isSource, string connectionString) - { - ReplicationServer server = new ReplicationServer(name, isSource, connectionString); - servers.Add(server); - return server; - } - - /// - /// Removes a server from the group. - /// - /// The server name. - internal protected void RemoveServer(string name) - { - ReplicationServer serverToRemove = GetServer(name); - if (serverToRemove == null) - throw new MySqlException(String.Format(Resources.ReplicationServerNotFound, name)); - servers.Remove(serverToRemove); - } - - /// - /// Gets a server by name. - /// - /// The server name. - /// The replication server. - internal protected ReplicationServer GetServer(string name) - { - foreach (var server in servers) - if (String.Compare(name, server.Name, StringComparison.OrdinalIgnoreCase) == 0) return server; - return null; - } - - /// - /// Must be implemented. Defines the next server for a custom load balancing implementation. - /// - /// Defines if the server to return is a source or any. - /// The next server based on the load balancing implementation. - /// Null if no available server is found. - /// - internal protected abstract ReplicationServer GetServer(bool isSource); - - /// - /// Defines the next server for a custom load balancing implementation. - /// - /// Defines if the server to return is a source or any. - /// Currently not being used. - /// The next server based on the load balancing implementation. - /// Null if no available server is found. - /// - internal protected virtual ReplicationServer GetServer(bool isSource, MySqlConnectionStringBuilder settings) - { - return GetServer(isSource); - } - - /// - /// Handles a failed connection to a server. - /// - /// The failed server. - /// This method can be overrided to implement a custom failover handling. - internal protected virtual void HandleFailover(ReplicationServer server) - { - BackgroundWorker worker = new BackgroundWorker(); - worker.DoWork += delegate(object sender, DoWorkEventArgs e) - { - bool isRunning = false; - ReplicationServer server1 = e.Argument as ReplicationServer; - System.Timers.Timer timer = new System.Timers.Timer(RetryTime * 1000.0); - - System.Timers.ElapsedEventHandler elapsedEvent = delegate(object sender1, System.Timers.ElapsedEventArgs e1) - { - if (isRunning) return; - try - { - isRunning = true; - using (MySqlConnection connectionFailed = new MySqlConnection(server.ConnectionString)) - { - connectionFailed.Open(); - server1.IsAvailable = true; - timer.Stop(); - } - } - catch - { - MySqlTrace.LogWarning(0, - string.Format(Resources.Replication_ConnectionAttemptFailed, server1.Name)); - } - finally - { - isRunning = false; - } - }; - timer.Elapsed += elapsedEvent; - timer.Start(); - elapsedEvent(sender, null); - }; - - worker.RunWorkerAsync(server); - } - - /// - /// Handles a failed connection to a server. - /// - /// The failed server. - /// The exception that caused the failover. - internal protected virtual void HandleFailover(ReplicationServer server, Exception exception) - { - HandleFailover(server); - } - } -} +// Copyright © 2014, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Text; + +namespace MySql.Data.MySqlClient.Replication +{ + /// + /// Base class used to implement load balancing features. + /// + public abstract class ReplicationServerGroup + { + /// + /// List of servers available for replication. + /// + protected List servers = new List(); + + /// The group name. + /// The number of seconds to perform a retry. + public ReplicationServerGroup(string name, int retryTime) + { + Servers = servers; + Name = name; + RetryTime = retryTime; + } + + /// + /// Gets the group name. + /// + public string Name { get; protected set; } + /// + /// Gets the retry time between connections to failed servers. + /// + public int RetryTime { get; protected set; } + /// + /// Gets the server list in the group. + /// + protected IList Servers { get; private set; } + + /// + /// Adds a server into the group. + /// + /// The server name. + /// A flag indicating if the server to add is source or replica. + /// The connection string used by this server. + /// A object representing the recently added object. + internal protected ReplicationServer AddServer(string name, bool isSource, string connectionString) + { + ReplicationServer server = new ReplicationServer(name, isSource, connectionString); + servers.Add(server); + return server; + } + + /// + /// Removes a server from the group. + /// + /// The server name. + internal protected void RemoveServer(string name) + { + ReplicationServer serverToRemove = GetServer(name); + if (serverToRemove == null) + throw new MySqlException(String.Format(Resources.ReplicationServerNotFound, name)); + servers.Remove(serverToRemove); + } + + /// + /// Gets a server by name. + /// + /// The server name. + /// The replication server. + internal protected ReplicationServer GetServer(string name) + { + foreach (var server in servers) + if (String.Compare(name, server.Name, StringComparison.OrdinalIgnoreCase) == 0) return server; + return null; + } + + /// + /// Must be implemented. Defines the next server for a custom load balancing implementation. + /// + /// Defines if the server to return is a source or any. + /// The next server based on the load balancing implementation. + /// Null if no available server is found. + /// + internal protected abstract ReplicationServer GetServer(bool isSource); + + /// + /// Defines the next server for a custom load balancing implementation. + /// + /// Defines if the server to return is a source or any. + /// Currently not being used. + /// The next server based on the load balancing implementation. + /// Null if no available server is found. + /// + internal protected virtual ReplicationServer GetServer(bool isSource, MySqlConnectionStringBuilder settings) + { + return GetServer(isSource); + } + + /// + /// Handles a failed connection to a server. + /// + /// The failed server. + /// This method can be overrided to implement a custom failover handling. + internal protected virtual void HandleFailover(ReplicationServer server) + { + BackgroundWorker worker = new BackgroundWorker(); + worker.DoWork += delegate(object sender, DoWorkEventArgs e) + { + bool isRunning = false; + ReplicationServer server1 = e.Argument as ReplicationServer; + System.Timers.Timer timer = new System.Timers.Timer(RetryTime * 1000.0); + + System.Timers.ElapsedEventHandler elapsedEvent = delegate(object sender1, System.Timers.ElapsedEventArgs e1) + { + if (isRunning) return; + try + { + isRunning = true; + using (MySqlConnection connectionFailed = new MySqlConnection(server.ConnectionString)) + { + connectionFailed.Open(); + server1.IsAvailable = true; + timer.Stop(); + } + } + catch + { + MySqlTrace.LogWarning(0, + string.Format(Resources.Replication_ConnectionAttemptFailed, server1.Name)); + } + finally + { + isRunning = false; + } + }; + timer.Elapsed += elapsedEvent; + timer.Start(); + elapsedEvent(sender, null); + }; + + worker.RunWorkerAsync(server); + } + + /// + /// Handles a failed connection to a server. + /// + /// The failed server. + /// The exception that caused the failover. + internal protected virtual void HandleFailover(ReplicationServer server, Exception exception) + { + HandleFailover(server); + } + } +} diff --git a/MySQL.Data/src/Resources.Designer.cs b/MySQL.Data/src/Resources.Designer.cs index 8b7f60be2..8a38ca951 100644 --- a/MySQL.Data/src/Resources.Designer.cs +++ b/MySQL.Data/src/Resources.Designer.cs @@ -97,7 +97,7 @@ internal static string AuthenticationFailed { } /// - /// Looks up a localized string similar to Authentication method '{0}' not supported by any of the available plugins.. + /// Looks up a localized string similar to Authentication method '{0}' not supported by any of the available plugins. /// internal static string AuthenticationMethodNotSupported { get { @@ -106,7 +106,7 @@ internal static string AuthenticationMethodNotSupported { } /// - /// Looks up a localized string similar to Authentication plugin '{0}' is currently not supported.. + /// Looks up a localized string similar to Authentication plugin '{0}' is currently not supported. /// internal static string AuthenticationPluginNotSupported { get { @@ -142,7 +142,7 @@ internal static string BufferNotLargeEnough { } /// - /// Looks up a localized string similar to Canceling an executing query requires MySQL 5.0 or higher.. + /// Looks up a localized string similar to Canceling an executing query requires MySQL 5.0 or higher. /// internal static string CancelNeeds50 { get { @@ -151,7 +151,7 @@ internal static string CancelNeeds50 { } /// - /// Looks up a localized string similar to Canceling an active query is only supported on MySQL 5.0.0 and above. . + /// Looks up a localized string similar to Canceling an active query is only supported on MySQL 5.0.0 and above. /// internal static string CancelNotSupported { get { @@ -160,7 +160,7 @@ internal static string CancelNotSupported { } /// - /// Looks up a localized string similar to Parameters can only be derived for commands using the StoredProcedure command type.. + /// Looks up a localized string similar to Parameters can only be derived for commands using the StoredProcedure command type. /// internal static string CanNotDeriveParametersForTextCommands { get { @@ -196,7 +196,7 @@ internal static string ChaosNotSupported { } /// - /// Looks up a localized string similar to Clear-password authentication is not supported over insecure channels.. + /// Looks up a localized string similar to Clear-password authentication is not supported over insecure channels. /// internal static string ClearPasswordNotSupported { get { @@ -205,7 +205,7 @@ internal static string ClearPasswordNotSupported { } /// - /// Looks up a localized string similar to The CommandText property has not been properly initialized.. + /// Looks up a localized string similar to The CommandText property has not been properly initialized. /// internal static string CommandTextNotInitialized { get { @@ -214,7 +214,7 @@ internal static string CommandTextNotInitialized { } /// - /// Looks up a localized string similar to Compression is not supported.. + /// Looks up a localized string similar to Compression is not supported. /// internal static string CompressionNotSupported { get { @@ -223,7 +223,7 @@ internal static string CompressionNotSupported { } /// - /// Looks up a localized string similar to The connection is already open.. + /// Looks up a localized string similar to The connection is already open. /// internal static string ConnectionAlreadyOpen { get { @@ -232,7 +232,7 @@ internal static string ConnectionAlreadyOpen { } /// - /// Looks up a localized string similar to Connection unexpectedly terminated.. + /// Looks up a localized string similar to Connection unexpectedly terminated. /// internal static string ConnectionBroken { get { @@ -250,7 +250,7 @@ internal static string ConnectionMustBeOpen { } /// - /// Looks up a localized string similar to The connection is not open.. + /// Looks up a localized string similar to The connection is not open. /// internal static string ConnectionNotOpen { get { @@ -259,7 +259,7 @@ internal static string ConnectionNotOpen { } /// - /// Looks up a localized string similar to The connection property has not been set or is null.. + /// Looks up a localized string similar to The connection property has not been set or is null. /// internal static string ConnectionNotSet { get { @@ -295,7 +295,7 @@ internal static string CSNoSetLength { } /// - /// Looks up a localized string similar to The given value was not in a supported format.. + /// Looks up a localized string similar to The given value was not in a supported format. /// internal static string DataNotInSupportedFormat { get { @@ -304,7 +304,7 @@ internal static string DataNotInSupportedFormat { } /// - /// Looks up a localized string similar to There is already an open DataReader associated with this Connection which must be closed first.. + /// Looks up a localized string similar to There is already an open DataReader associated with this Connection which must be closed first. /// internal static string DataReaderOpen { get { @@ -313,7 +313,7 @@ internal static string DataReaderOpen { } /// - /// Looks up a localized string similar to The default connection encoding was not found. Please report this as a bug along with your connection string and system details.. + /// Looks up a localized string similar to The default connection encoding was not found. Please report this as a bug along with your connection string and system details. /// internal static string DefaultEncodingNotFound { get { @@ -322,7 +322,7 @@ internal static string DefaultEncodingNotFound { } /// - /// Looks up a localized string similar to MySQL Connector/NET does not currently support distributed transactions.. + /// Looks up a localized string similar to MySQL Connector/NET does not currently support distributed transactions. /// internal static string DistributedTxnNotSupported { get { @@ -331,7 +331,7 @@ internal static string DistributedTxnNotSupported { } /// - /// Looks up a localized string similar to Specifying multiple host names with DNS SRV lookup is not permitted.. + /// Looks up a localized string similar to Specifying multiple host names with DNS SRV lookup is not permitted. /// internal static string DnsSrvInvalidConnOptionMultihost { get { @@ -340,7 +340,7 @@ internal static string DnsSrvInvalidConnOptionMultihost { } /// - /// Looks up a localized string similar to Specifying a port number with DNS SRV lookup is not permitted.. + /// Looks up a localized string similar to Specifying a port number with DNS SRV lookup is not permitted. /// internal static string DnsSrvInvalidConnOptionPort { get { @@ -349,7 +349,7 @@ internal static string DnsSrvInvalidConnOptionPort { } /// - /// Looks up a localized string similar to Using Unix domain sockets with DNS SRV lookup is not permitted.. + /// Looks up a localized string similar to Using Unix domain sockets with DNS SRV lookup is not permitted. /// internal static string DnsSrvInvalidConnOptionUnixSocket { get { @@ -358,7 +358,7 @@ internal static string DnsSrvInvalidConnOptionUnixSocket { } /// - /// Looks up a localized string similar to Unable to locate any hosts for {0}.. + /// Looks up a localized string similar to Unable to locate any hosts for {0}. /// internal static string DnsSrvNoHostsAvailable { get { @@ -367,7 +367,7 @@ internal static string DnsSrvNoHostsAvailable { } /// - /// Looks up a localized string similar to Encoding error during validation.. + /// Looks up a localized string similar to Encoding error during validation. /// internal static string EncodingError { get { @@ -385,7 +385,7 @@ internal static string ErrorCreatingSocket { } /// - /// Looks up a localized string similar to Verify that user '{0}'@'{1}' has enough privileges to execute.. + /// Looks up a localized string similar to Verify that user '{0}'@'{1}' has enough privileges to execute. /// internal static string ExecuteProcedureUnauthorized { get { @@ -394,7 +394,7 @@ internal static string ExecuteProcedureUnauthorized { } /// - /// Looks up a localized string similar to Fatal error encountered during command execution.. + /// Looks up a localized string similar to Fatal error encountered during command execution. /// internal static string FatalErrorDuringExecute { get { @@ -403,7 +403,7 @@ internal static string FatalErrorDuringExecute { } /// - /// Looks up a localized string similar to Fatal error encountered during data read.. + /// Looks up a localized string similar to Fatal error encountered during data read. /// internal static string FatalErrorDuringRead { get { @@ -412,7 +412,7 @@ internal static string FatalErrorDuringRead { } /// - /// Looks up a localized string similar to Fatal error encountered attempting to read the resultset.. + /// Looks up a localized string similar to Fatal error encountered attempting to read the resultset. /// internal static string FatalErrorReadingResult { get { @@ -421,7 +421,7 @@ internal static string FatalErrorReadingResult { } /// - /// Looks up a localized string similar to Challenge received is corrupt.. + /// Looks up a localized string similar to Challenge received is corrupt. /// internal static string FidoChallengeCorrupt { get { @@ -430,16 +430,7 @@ internal static string FidoChallengeCorrupt { } /// - /// Looks up a localized string similar to An event handler for FidoActionRequested was not specified.. - /// - internal static string FidoMissingHandler { - get { - return ResourceManager.GetString("FidoMissingHandler", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to FIDO registration is missing.. + /// Looks up a localized string similar to FIDO registration is missing. /// internal static string FidoRegistrationMissing { get { @@ -448,7 +439,7 @@ internal static string FidoRegistrationMissing { } /// - /// Looks up a localized string similar to File based certificates are only supported when connecting to MySQL Server 5.1 or greater.. + /// Looks up a localized string similar to File based certificates are only supported when connecting to MySQL Server 5.1 or greater. /// internal static string FileBasedCertificateNotSupported { get { @@ -457,7 +448,7 @@ internal static string FileBasedCertificateNotSupported { } /// - /// Looks up a localized string similar to The specified file cannot be converted to a certificate.. + /// Looks up a localized string similar to The specified file cannot be converted to a certificate. /// internal static string FileIsNotACertificate { get { @@ -466,7 +457,7 @@ internal static string FileIsNotACertificate { } /// - /// Looks up a localized string similar to The specified file cannot be converted to a key.. + /// Looks up a localized string similar to The specified file cannot be converted to a key. /// internal static string FileIsNotAKey { get { @@ -475,7 +466,7 @@ internal static string FileIsNotAKey { } /// - /// Looks up a localized string similar to Failed to read file at the specified location.. + /// Looks up a localized string similar to Failed to read file at the specified location. /// internal static string FileNotFound { get { @@ -484,7 +475,7 @@ internal static string FileNotFound { } /// - /// Looks up a localized string similar to No file path has been provided for the connection option {0}.. + /// Looks up a localized string similar to No file path has been provided for the connection option {0}. /// internal static string FilePathNotSet { get { @@ -511,7 +502,7 @@ internal static string FromIndexMustBeValid { } /// - /// Looks up a localized string similar to Call to GetHostEntry failed after {0} while querying for hostname '{1}': SocketErrorCode={2}, ErrorCode={3}, NativeErrorCode={4}.. + /// Looks up a localized string similar to Call to GetHostEntry failed after {0} while querying for hostname '{1}': SocketErrorCode={2}, ErrorCode={3}, NativeErrorCode={4}. /// internal static string GetHostEntryFailed { get { @@ -520,7 +511,7 @@ internal static string GetHostEntryFailed { } /// - /// Looks up a localized string similar to Retrieving procedure metadata for {0} from server.. + /// Looks up a localized string similar to Retrieving procedure metadata for {0} from server. /// internal static string HardProcQuery { get { @@ -529,7 +520,7 @@ internal static string HardProcQuery { } /// - /// Looks up a localized string similar to Value has an unsupported format.. + /// Looks up a localized string similar to Value has an unsupported format. /// internal static string ImproperValueFormat { get { @@ -538,7 +529,7 @@ internal static string ImproperValueFormat { } /// - /// Looks up a localized string similar to An incorrect response was received from the server.. + /// Looks up a localized string similar to An incorrect response was received from the server. /// internal static string IncorrectTransmission { get { @@ -565,7 +556,7 @@ internal static string IndexMustBeValid { } /// - /// Looks up a localized string similar to The provided key is invalid.. + /// Looks up a localized string similar to The provided key is invalid. /// internal static string InvalidCertificateKey { get { @@ -574,7 +565,7 @@ internal static string InvalidCertificateKey { } /// - /// Looks up a localized string similar to Certificate with Thumbprint '{0}' not found.. + /// Looks up a localized string similar to Certificate with Thumbprint '{0}' not found. /// internal static string InvalidCertificateThumbprint { get { @@ -583,7 +574,7 @@ internal static string InvalidCertificateThumbprint { } /// - /// Looks up a localized string similar to You have specified an invalid column ordinal.. + /// Looks up a localized string similar to You have specified an invalid column ordinal. /// internal static string InvalidColumnOrdinal { get { @@ -592,7 +583,7 @@ internal static string InvalidColumnOrdinal { } /// - /// Looks up a localized string similar to The requested value '{0}' is invalid for the given keyword '{1}'.. + /// Looks up a localized string similar to The requested value '{0}' is invalid for the given keyword '{1}'. /// internal static string InvalidConnectionStringValue { get { @@ -601,7 +592,7 @@ internal static string InvalidConnectionStringValue { } /// - /// Looks up a localized string similar to The host name or IP address is invalid.. + /// Looks up a localized string similar to The host name or IP address is invalid. /// internal static string InvalidHostNameOrAddress { get { @@ -610,7 +601,7 @@ internal static string InvalidHostNameOrAddress { } /// - /// Looks up a localized string similar to Microsecond must be a value between 0 and 999999.. + /// Looks up a localized string similar to Microsecond must be a value between 0 and 999999. /// internal static string InvalidMicrosecondValue { get { @@ -619,7 +610,7 @@ internal static string InvalidMicrosecondValue { } /// - /// Looks up a localized string similar to Millisecond must be a value between 0 and 999. For more precision use Microsecond.. + /// Looks up a localized string similar to Millisecond must be a value between 0 and 999. For more precision use Microsecond. /// internal static string InvalidMillisecondValue { get { @@ -628,7 +619,7 @@ internal static string InvalidMillisecondValue { } /// - /// Looks up a localized string similar to Either provide a valid path for 'allowloadlocalinfileinpath' or enable 'allowloadlocalinfile'.. + /// Looks up a localized string similar to Either provide a valid path for 'allowloadlocalinfileinpath' or enable 'allowloadlocalinfile'. /// internal static string InvalidPathForLoadLocalInfile { get { @@ -637,7 +628,7 @@ internal static string InvalidPathForLoadLocalInfile { } /// - /// Looks up a localized string similar to Procedure or function '{0}' cannot be found in database '{1}'.. + /// Looks up a localized string similar to Procedure or function '{0}' cannot be found in database '{1}'. /// internal static string InvalidProcName { get { @@ -646,7 +637,7 @@ internal static string InvalidProcName { } /// - /// Looks up a localized string similar to The certificate is invalid.. + /// Looks up a localized string similar to The certificate is invalid. /// internal static string InvalidSslCertificate { get { @@ -655,7 +646,7 @@ internal static string InvalidSslCertificate { } /// - /// Looks up a localized string similar to Unable to validate the signature.. + /// Looks up a localized string similar to Unable to validate the signature. /// internal static string InvalidSslCertificateSignature { get { @@ -664,7 +655,7 @@ internal static string InvalidSslCertificateSignature { } /// - /// Looks up a localized string similar to Unable to verify the signature.. + /// Looks up a localized string similar to Unable to verify the signature. /// internal static string InvalidSslCertificateSignatureGeneral { get { @@ -673,7 +664,7 @@ internal static string InvalidSslCertificateSignatureGeneral { } /// - /// Looks up a localized string similar to Value '{0}' is not of the correct type.. + /// Looks up a localized string similar to Value '{0}' is not of the correct type. /// internal static string InvalidSslMode { get { @@ -682,7 +673,7 @@ internal static string InvalidSslMode { } /// - /// Looks up a localized string similar to '{0}' is an illegal value for a boolean option.. + /// Looks up a localized string similar to '{0}' is an illegal value for a boolean option. /// internal static string InvalidValueForBoolean { get { @@ -691,7 +682,7 @@ internal static string InvalidValueForBoolean { } /// - /// Looks up a localized string similar to Keyword does not allow null values.. + /// Looks up a localized string similar to Keyword does not allow null values. /// internal static string KeywordNoNull { get { @@ -700,7 +691,7 @@ internal static string KeywordNoNull { } /// - /// Looks up a localized string similar to Option not supported.. + /// Looks up a localized string similar to Option not supported. /// internal static string KeywordNotSupported { get { @@ -709,7 +700,7 @@ internal static string KeywordNotSupported { } /// - /// Looks up a localized string similar to Server asked for stream in response to LOAD DATA LOCAL INFILE, but the functionality is disabled by the client setting 'allowlocalinfile' to 'false'.. + /// Looks up a localized string similar to Server asked for stream in response to LOAD DATA LOCAL INFILE, but the functionality is disabled by the client setting 'allowlocalinfile' to 'false'. /// internal static string LocalInfileDisabled { get { @@ -718,7 +709,7 @@ internal static string LocalInfileDisabled { } /// - /// Looks up a localized string similar to Mixing named and unnamed parameters is not allowed.. + /// Looks up a localized string similar to Mixing named and unnamed parameters is not allowed. /// internal static string MixedParameterNamingNotAllowed { get { @@ -727,7 +718,7 @@ internal static string MixedParameterNamingNotAllowed { } /// - /// Looks up a localized string similar to INTERNAL ERROR: More than one output parameter row detected.. + /// Looks up a localized string similar to INTERNAL ERROR: More than one output parameter row detected. /// internal static string MoreThanOneOPRow { get { @@ -736,7 +727,7 @@ internal static string MoreThanOneOPRow { } /// - /// Looks up a localized string similar to Multiple simultaneous connections or connections with different connection strings inside the same transaction are not currently supported.. + /// Looks up a localized string similar to Multiple simultaneous connections or connections with different connection strings inside the same transaction are not currently supported. /// internal static string MultipleConnectionsInTransactionNotSupported { get { @@ -763,7 +754,7 @@ internal static string NamedPipeNoSetLength { } /// - /// Looks up a localized string similar to The new value must be a MySqlParameter object.. + /// Looks up a localized string similar to The new value must be a MySqlParameter object. /// internal static string NewValueShouldBeMySqlParameter { get { @@ -772,7 +763,7 @@ internal static string NewValueShouldBeMySqlParameter { } /// - /// Looks up a localized string similar to Invalid attempt to call NextResult when the reader is closed.. + /// Looks up a localized string similar to Invalid attempt to call NextResult when the reader is closed. /// internal static string NextResultIsClosed { get { @@ -781,7 +772,7 @@ internal static string NextResultIsClosed { } /// - /// Looks up a localized string similar to When calling stored procedures and 'Use Procedure Bodies' is false, all parameters must have their type explicitly set.. + /// Looks up a localized string similar to When calling stored procedures and 'Use Procedure Bodies' is false, all parameters must have their type explicitly set. /// internal static string NoBodiesAndTypeNotSet { get { @@ -790,7 +781,7 @@ internal static string NoBodiesAndTypeNotSet { } /// - /// Looks up a localized string similar to Nested transactions are not supported.. + /// Looks up a localized string similar to Nested transactions are not supported. /// internal static string NoNestedTransactions { get { @@ -799,7 +790,7 @@ internal static string NoNestedTransactions { } /// - /// Looks up a localized string similar to The host {0} does not support SSL connections.. + /// Looks up a localized string similar to The host {0} does not support SSL connections. /// internal static string NoServerSSLSupport { get { @@ -808,7 +799,7 @@ internal static string NoServerSSLSupport { } /// - /// Looks up a localized string similar to Unix sockets are not supported on Windows.. + /// Looks up a localized string similar to Unix sockets are not supported on Windows. /// internal static string NoUnixSocketsOnWindows { get { @@ -817,7 +808,7 @@ internal static string NoUnixSocketsOnWindows { } /// - /// Looks up a localized string similar to Cannot retrieve Windows identity for current user. Connections that use IntegratedSecurity cannot be pooled. Use either 'ConnectionReset=true' or 'Pooling=false' in the connection string to fix.. + /// Looks up a localized string similar to Cannot retrieve Windows identity for current user. Connections that use IntegratedSecurity cannot be pooled. Use either 'ConnectionReset=true' or 'Pooling=false' in the connection string to fix. /// internal static string NoWindowsIdentity { get { @@ -826,7 +817,7 @@ internal static string NoWindowsIdentity { } /// - /// Looks up a localized string similar to The object is not open or has been disposed.. + /// Looks up a localized string similar to The object is not open or has been disposed. /// internal static string ObjectDisposed { get { @@ -835,7 +826,7 @@ internal static string ObjectDisposed { } /// - /// Looks up a localized string similar to OCI configuration file could not be read.. + /// Looks up a localized string similar to OCI configuration file could not be read. /// internal static string OciConfigFileNotFound { get { @@ -844,7 +835,7 @@ internal static string OciConfigFileNotFound { } /// - /// Looks up a localized string similar to OCI configuration profile not found.. + /// Looks up a localized string similar to OCI configuration profile not found. /// internal static string OciConfigProfileNotFound { get { @@ -853,7 +844,7 @@ internal static string OciConfigProfileNotFound { } /// - /// Looks up a localized string similar to OCI configuration file does not contain a 'fingerprint' or 'key_file' entry.. + /// Looks up a localized string similar to OCI configuration file does not contain a 'fingerprint' or 'key_file' entry. /// internal static string OciEntryNotFound { get { @@ -862,7 +853,7 @@ internal static string OciEntryNotFound { } /// - /// Looks up a localized string similar to OCI configuration entry 'key_file' does not reference a valid key file.. + /// Looks up a localized string similar to OCI configuration entry 'key_file' does not reference a valid key file. /// internal static string OciInvalidKeyFile { get { @@ -871,7 +862,7 @@ internal static string OciInvalidKeyFile { } /// - /// Looks up a localized string similar to Private key could not be found at location given by OCI configuration entry 'key_file'.. + /// Looks up a localized string similar to Private key could not be found at location given by OCI configuration entry 'key_file'. /// internal static string OciKeyFileDoesNotExists { get { @@ -880,7 +871,7 @@ internal static string OciKeyFileDoesNotExists { } /// - /// Looks up a localized string similar to The OCI SDK cannot be found or is not installed.. + /// Looks up a localized string similar to The OCI SDK cannot be found or is not installed. /// internal static string OciSDKNotFound { get { @@ -889,7 +880,7 @@ internal static string OciSDKNotFound { } /// - /// Looks up a localized string similar to Security token file could not be found at location given by OCI configuration entry 'security_token_file'.. + /// Looks up a localized string similar to Secutiry token file could not be found at location given by OCI configuration entry 'security_token_file'. /// internal static string OciSecurityTokenDoesNotExists { get { @@ -898,7 +889,7 @@ internal static string OciSecurityTokenDoesNotExists { } /// - /// Looks up a localized string similar to The size of the OCI security token file exceeds the maximum value of 10KB allowed.. + /// Looks up a localized string similar to The size of the OCI security token file exceeds the maximum value of 10KB allowed. /// internal static string OciSecurityTokenFileExceeds10KB { get { @@ -925,7 +916,7 @@ internal static string OffsetMustBeValid { } /// - /// Looks up a localized string similar to Authentication with old password no longer supported, use 4.1 style passwords.. + /// Looks up a localized string similar to Authentication with old password no longer supported, use 4.1 style passwords. /// internal static string OldPasswordsNotSupported { get { @@ -933,6 +924,24 @@ internal static string OldPasswordsNotSupported { } } + /// + /// Looks up a localized string similar to The OpenID Connect Identity Token is empty. + /// + internal static string OpenIdIdentityTokenIsEmpty { + get { + return ResourceManager.GetString("OpenIdIdentityTokenIsEmpty", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The OpenID Connect Identity Token is invalid. + /// + internal static string OpenIdIdentityTokenTooBig { + get { + return ResourceManager.GetString("OpenIdIdentityTokenTooBig", resourceCulture); + } + } + /// /// Looks up a localized string similar to The option '{0}' is not currently supported.. /// @@ -943,7 +952,7 @@ internal static string OptionNotCurrentlySupported { } /// - /// Looks up a localized string similar to Parameter '{0}' has already been defined.. + /// Looks up a localized string similar to Parameter '{0}' has already been defined. /// internal static string ParameterAlreadyDefined { get { @@ -970,7 +979,7 @@ internal static string ParameterCannotBeNull { } /// - /// Looks up a localized string similar to Parameter '{0}' can't be null or empty.. + /// Looks up a localized string similar to Parameter '{0}' can't be null or empty. /// internal static string ParameterCannotBeNullOrEmpty { get { @@ -979,7 +988,7 @@ internal static string ParameterCannotBeNullOrEmpty { } /// - /// Looks up a localized string similar to Parameter index was not found in Parameter Collection.. + /// Looks up a localized string similar to Parameter index was not found in Parameter Collection. /// internal static string ParameterIndexNotFound { get { @@ -988,7 +997,7 @@ internal static string ParameterIndexNotFound { } /// - /// Looks up a localized string similar to Parameter is invalid.. + /// Looks up a localized string similar to Parameter is invalid. /// internal static string ParameterIsInvalid { get { @@ -997,7 +1006,7 @@ internal static string ParameterIsInvalid { } /// - /// Looks up a localized string similar to Parameter '{0}' must be defined.. + /// Looks up a localized string similar to Parameter '{0}' must be defined. /// internal static string ParameterMustBeDefined { get { @@ -1006,7 +1015,7 @@ internal static string ParameterMustBeDefined { } /// - /// Looks up a localized string similar to Parameter '{0}' was not found during prepare.. + /// Looks up a localized string similar to Parameter '{0}' was not found during prepare. /// internal static string ParameterNotFoundDuringPrepare { get { @@ -1015,7 +1024,7 @@ internal static string ParameterNotFoundDuringPrepare { } /// - /// Looks up a localized string similar to Parameter can't be null or empty.. + /// Looks up a localized string similar to Parameter can't be null or empty. /// internal static string ParameterNullOrEmpty { get { @@ -1051,7 +1060,7 @@ internal static string PerfMonCategoryName { } /// - /// Looks up a localized string similar to The number of times a procedures metadata had to be queried from the server.. + /// Looks up a localized string similar to The number of times a procedures metadata had to be queried from the server. /// internal static string PerfMonHardProcHelp { get { @@ -1069,7 +1078,7 @@ internal static string PerfMonHardProcName { } /// - /// Looks up a localized string similar to The number of times a procedures metadata was retrieved from the client-side cache.. + /// Looks up a localized string similar to The number of times a procedures metadata was retrieved from the client-side cache. /// internal static string PerfMonSoftProcHelp { get { @@ -1087,7 +1096,7 @@ internal static string PerfMonSoftProcName { } /// - /// Looks up a localized string similar to same name are not supported.. + /// Looks up a localized string similar to same name are not supported. /// internal static string ProcAndFuncSameName { get { @@ -1096,7 +1105,7 @@ internal static string ProcAndFuncSameName { } /// - /// Looks up a localized string similar to MySQL Server {0} dos not support query attributes.. + /// Looks up a localized string similar to MySQL Server {0} dos not support query attributes. /// internal static string QueryAttributesNotSupported { get { @@ -1105,7 +1114,7 @@ internal static string QueryAttributesNotSupported { } /// - /// Looks up a localized string similar to MySQL Connector/NET does not support query attributes with prepared statements for this version of MySQL Server.. + /// Looks up a localized string similar to MySQL Connector/NET does not support query attributes with prepared statements for this version of MySQL Server. /// internal static string QueryAttributesNotSupportedByCnet { get { @@ -1114,7 +1123,7 @@ internal static string QueryAttributesNotSupportedByCnet { } /// - /// Looks up a localized string similar to Packets larger than max_allowed_packet are not allowed.. + /// Looks up a localized string similar to Packets larger than max_allowed_packet are not allowed. /// internal static string QueryTooLarge { get { @@ -1123,7 +1132,7 @@ internal static string QueryTooLarge { } /// - /// Looks up a localized string similar to Reading from the stream has failed.. + /// Looks up a localized string similar to Reading from the stream has failed. /// internal static string ReadFromStreamFailed { get { @@ -1141,7 +1150,7 @@ internal static string ReadingPriorColumnUsingSeqAccess { } /// - /// Looks up a localized string similar to Replicated connections allow only readonly statements.. + /// Looks up a localized string similar to Replicated connections allow only readonly statements. /// internal static string ReplicatedConnectionsAllowOnlyReadonlyStatements { get { @@ -1150,7 +1159,7 @@ internal static string ReplicatedConnectionsAllowOnlyReadonlyStatements { } /// - /// Looks up a localized string similar to Attempt to connect to '{0}' server failed.. + /// Looks up a localized string similar to Attempt to connect to '{0}' server failed. /// internal static string Replication_ConnectionAttemptFailed { get { @@ -1159,7 +1168,7 @@ internal static string Replication_ConnectionAttemptFailed { } /// - /// Looks up a localized string similar to No available server found.. + /// Looks up a localized string similar to No available server found. /// internal static string Replication_NoAvailableServer { get { @@ -1168,7 +1177,7 @@ internal static string Replication_NoAvailableServer { } /// - /// Looks up a localized string similar to Replication group '{0}' not found.. + /// Looks up a localized string similar to Replication group '{0}' not found. /// internal static string ReplicationGroupNotFound { get { @@ -1186,7 +1195,7 @@ internal static string ReplicationServerNotFound { } /// - /// Looks up a localized string similar to Routine '{0}' cannot be found. Either check the spelling or make sure you have sufficient rights to execute the routine.. + /// Looks up a localized string similar to Routine '{0}' cannot be found. Either check the spelling or make sure you have sufficient rights to execute the routine. /// internal static string RoutineNotFound { get { @@ -1204,7 +1213,7 @@ internal static string RoutineRequiresReturnParameter { } /// - /// Looks up a localized string similar to Retrieval of the RSA public key is not enabled for insecure connections.. + /// Looks up a localized string similar to Retrieval of the RSA public key is not enabled for insecure connections. /// internal static string RSAPublicKeyRetrievalNotEnabled { get { @@ -1222,7 +1231,7 @@ internal static string ServerTooOld { } /// - /// Looks up a localized string similar to Snapshot isolation level is not supported.. + /// Looks up a localized string similar to Snapshot isolation level is not supported. /// internal static string SnapshotNotSupported { get { @@ -1240,7 +1249,7 @@ internal static string SocketNoSeek { } /// - /// Looks up a localized string similar to Retrieving procedure metadata for {0} from procedure cache.. + /// Looks up a localized string similar to Retrieving procedure metadata for {0} from procedure cache. /// internal static string SoftProcQuery { get { @@ -1258,7 +1267,7 @@ internal static string SPNotSupported { } /// - /// Looks up a localized string similar to The certificate authority (CA) does not match.. + /// Looks up a localized string similar to The certificate authority (CA) does not match. /// internal static string SslCertificateCAMismatch { get { @@ -1267,7 +1276,7 @@ internal static string SslCertificateCAMismatch { } /// - /// Looks up a localized string similar to The host name does not match the name on the certificate.. + /// Looks up a localized string similar to The host name does not match the name on the certificate. /// internal static string SslCertificateHostNameMismatch { get { @@ -1276,7 +1285,7 @@ internal static string SslCertificateHostNameMismatch { } /// - /// Looks up a localized string similar to The certificate is not a certificate authority (CA).. + /// Looks up a localized string similar to The certificate is not a certificate authority (CA). /// internal static string SslCertificateIsNotCA { get { @@ -1285,7 +1294,7 @@ internal static string SslCertificateIsNotCA { } /// - /// Looks up a localized string similar to SSL Connection error.. + /// Looks up a localized string similar to SSL Connection error. /// internal static string SslConnectionError { get { @@ -1294,7 +1303,7 @@ internal static string SslConnectionError { } /// - /// Looks up a localized string similar to Connection protocol '{0}' does not support SSL connections.. + /// Looks up a localized string similar to Connection protocol '{0}' does not support SSL connections. /// internal static string SslNotAllowedForConnectionProtocol { get { @@ -1330,7 +1339,7 @@ internal static string StreamNoWrite { } /// - /// Looks up a localized string similar to String can't be empty.. + /// Looks up a localized string similar to String can't be empty. /// internal static string StringEmpty { get { @@ -1339,7 +1348,7 @@ internal static string StringEmpty { } /// - /// Looks up a localized string similar to Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding.. + /// Looks up a localized string similar to Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding. /// internal static string Timeout { get { @@ -1348,7 +1357,7 @@ internal static string Timeout { } /// - /// Looks up a localized string similar to error connecting: Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached.. + /// Looks up a localized string similar to error connecting: Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached. /// internal static string TimeoutGettingConnection { get { @@ -1357,7 +1366,7 @@ internal static string TimeoutGettingConnection { } /// - /// Looks up a localized string similar to All server connection attempts were aborted. Timeout of {0} seconds was exceeded for each selected server.. + /// Looks up a localized string similar to All server connection attempts were aborted. Timeout of {0} seconds was exceeded for each selected server. /// internal static string TimeOutMultipleHost { get { @@ -1383,15 +1392,6 @@ internal static string TlsUnsupportedVersions { } } - /// - /// Looks up a localized string similar to TLSv1.3 is not supported by this framework.. - /// - internal static string Tlsv13NotSupported { - get { - return ResourceManager.GetString("Tlsv13NotSupported", resourceCulture); - } - } - /// /// Looks up a localized string similar to Specified list of TLS versions is empty. Accepted values are TLSv1.2 and TLSv1.3. /// @@ -1411,7 +1411,7 @@ internal static string TraceCloseConnection { } /// - /// Looks up a localized string similar to Unable to trace. There are more than Int32.MaxValue connections in use.. + /// Looks up a localized string similar to Unable to trace. There are more than Int32.MaxValue connections in use. /// internal static string TraceErrorMoreThanMaxValueConnections { get { @@ -1564,7 +1564,7 @@ internal static string TraceUAWarningSkippedColumns { } /// - /// Looks up a localized string similar to {0}: Usage Advisor Warning: Skipped {2} rows. Consider a more focused query.. + /// Looks up a localized string similar to {0}: Usage Advisor Warning: Skipped {2} rows. Consider a more focused query. /// internal static string TraceUAWarningSkippedRows { get { @@ -1600,7 +1600,7 @@ internal static string TypeIsNotExceptionInterceptor { } /// - /// Looks up a localized string similar to Unable to connect to any of the specified MySQL hosts.. + /// Looks up a localized string similar to Unable to connect to any of the specified MySQL hosts. /// internal static string UnableToConnectToHost { get { @@ -1609,7 +1609,7 @@ internal static string UnableToConnectToHost { } /// - /// Looks up a localized string similar to Unable to create plugin for authentication method '{0}'. Please see inner exception for details.. + /// Looks up a localized string similar to Unable to create plugin for authentication method '{0}'. Please see inner exception for details. /// internal static string UnableToCreateAuthPlugin { get { @@ -1618,7 +1618,7 @@ internal static string UnableToCreateAuthPlugin { } /// - /// Looks up a localized string similar to Unable to derive stored routine parameters. The 'Parameters' information schema table is not available and access to the stored procedure body has been disabled.. + /// Looks up a localized string similar to Unable to derive stored routine parameters. The 'Parameters' information schema table is not available and access to the stored procedure body has been disabled. /// internal static string UnableToDeriveParameters { get { @@ -1627,7 +1627,7 @@ internal static string UnableToDeriveParameters { } /// - /// Looks up a localized string similar to Unable to enable query analysis. Be sure the MySql.Data.EMTrace assembly is properly located and registered.. + /// Looks up a localized string similar to Unable to enable query analysis. Be sure the MySql.Data.EMTrace assembly is properly located and registered. /// internal static string UnableToEnableQueryAnalysis { get { @@ -1645,7 +1645,7 @@ internal static string UnableToEnumerateUDF { } /// - /// Looks up a localized string similar to Unable to execute stored procedure '{0}'.. + /// Looks up a localized string similar to Unable to execute stored procedure '{0}'. /// internal static string UnableToExecuteSP { get { @@ -1654,7 +1654,7 @@ internal static string UnableToExecuteSP { } /// - /// Looks up a localized string similar to There was an error parsing the foreign key definition.. + /// Looks up a localized string similar to There was an error parsing the foreign key definition. /// internal static string UnableToParseFK { get { @@ -1663,7 +1663,7 @@ internal static string UnableToParseFK { } /// - /// Looks up a localized string similar to Error encountered reading the RSA public key.. + /// Looks up a localized string similar to Error encountered reading the RSA public key. /// internal static string UnableToReadRSAKey { get { @@ -1672,7 +1672,7 @@ internal static string UnableToReadRSAKey { } /// - /// Looks up a localized string similar to Unable to retrieve stored procedure metadata for routine '{0}'. Either grant SELECT privilege to mysql.proc for this user or use "check parameters=false" with your connection string.. + /// Looks up a localized string similar to Unable to retrieve stored procedure metadata for routine '{0}'. Either grant SELECT privilege to mysql.proc for this user or use "check parameters=false" with your connection string. /// internal static string UnableToRetrieveParameters { get { @@ -1681,7 +1681,7 @@ internal static string UnableToRetrieveParameters { } /// - /// Looks up a localized string similar to Unable to start a second async operation while one is running.. + /// Looks up a localized string similar to Unable to start a second async operation while one is running. /// internal static string UnableToStartSecondAsyncOp { get { @@ -1699,7 +1699,7 @@ internal static string UnixSocketsNotSupported { } /// - /// Looks up a localized string similar to Unknown authentication method '{0}' was requested.. + /// Looks up a localized string similar to Unknown authentication method '{0}' was requested. /// internal static string UnknownAuthenticationMethod { get { @@ -1717,7 +1717,7 @@ internal static string UnknownConnectionProtocol { } /// - /// Looks up a localized string similar to MySQL user '{0}' does not equal the logged-in Windows user '{1}'.. + /// Looks up a localized string similar to MySQL user '{0}' does not equal the logged-in Windows user '{1}'. /// internal static string UnmatchedWinUserAndMySqlUser { get { @@ -1726,7 +1726,7 @@ internal static string UnmatchedWinUserAndMySqlUser { } /// - /// Looks up a localized string similar to Trying to upload a file from outside the path set on 'allowloadlocalinfileinpath' is invalid.. + /// Looks up a localized string similar to Trying to upload a file from outside the path set on 'allowloadlocalinfileinpath' is invalid. /// internal static string UnsafePathForLoadLocalInfile { get { @@ -1735,7 +1735,7 @@ internal static string UnsafePathForLoadLocalInfile { } /// - /// Looks up a localized string similar to Value '{0}' is not of the correct type.. + /// Looks up a localized string similar to Value '{0}' is not of the correct type. /// internal static string ValueNotCorrectType { get { @@ -1744,7 +1744,7 @@ internal static string ValueNotCorrectType { } /// - /// Looks up a localized string similar to The requested column value could not be treated as or conveted to a Guid.. + /// Looks up a localized string similar to The requested column value could not be treated as or conveted to a Guid. /// internal static string ValueNotSupportedForGuid { get { @@ -1753,7 +1753,7 @@ internal static string ValueNotSupportedForGuid { } /// - /// Looks up a localized string similar to An event handler for WebAuthnActionRequested was not specified.. + /// Looks up a localized string similar to An event handler for WebAuthnActionRequested was not specified. /// internal static string WebAuthnMissingHandler { get { @@ -1762,7 +1762,7 @@ internal static string WebAuthnMissingHandler { } /// - /// Looks up a localized string similar to The timeout of 15 seconds for user interaction with FIDO device has been exceeded.. + /// Looks up a localized string similar to The timeout of 15 seconds for user interaction with FIDO device has been exceeded. /// internal static string WebAuthnTimeout { get { @@ -1780,7 +1780,7 @@ internal static string WinAuthNotSupportOnPlatform { } /// - /// Looks up a localized string similar to Writing to the stream failed.. + /// Looks up a localized string similar to Writing to the stream failed. /// internal static string WriteToStreamFailed { get { @@ -1789,7 +1789,7 @@ internal static string WriteToStreamFailed { } /// - /// Looks up a localized string similar to Parameter '{0}' is not found but a parameter with the name '{1}' is found. Parameter names must include the leading parameter marker.. + /// Looks up a localized string similar to Parameter '{0}' is not found but a parameter with the name '{1}' is found. Parameter names must include the leading parameter marker. /// internal static string WrongParameterName { get { diff --git a/MySQL.Data/src/Resources.resx b/MySQL.Data/src/Resources.resx index 728f43d23..9b6998c6e 100644 --- a/MySQL.Data/src/Resources.resx +++ b/MySQL.Data/src/Resources.resx @@ -184,16 +184,16 @@ Connection must be valid and open - There is already an open DataReader associated with this Connection which must be closed first. + There is already an open DataReader associated with this Connection which must be closed first Stored procedures are not supported on this version of MySQL - The connection property has not been set or is null. + The connection property has not been set or is null - The connection is not open. + The connection is not open Improper MySqlCommandBuilder state: adapter is null @@ -214,67 +214,67 @@ Chaos isolation level is not supported - Parameter is invalid. + Parameter is invalid - The connection is already open. + The connection is already open - Option not supported. + Option not supported - Writing to the stream failed. + Writing to the stream failed - Reading from the stream has failed. + Reading from the stream has failed - Packets larger than max_allowed_packet are not allowed. + Packets larger than max_allowed_packet are not allowed - Unable to execute stored procedure '{0}'. + Unable to execute stored procedure '{0}' - same name are not supported. + same name are not supported - Keyword does not allow null values. + Keyword does not allow null values - Value has an unsupported format. + Value has an unsupported format - Procedure or function '{0}' cannot be found in database '{1}'. + Procedure or function '{0}' cannot be found in database '{1}' - Retrieving procedure metadata for {0} from server. + Retrieving procedure metadata for {0} from server - Retrieving procedure metadata for {0} from procedure cache. + Retrieving procedure metadata for {0} from procedure cache - Connection unexpectedly terminated. + Connection unexpectedly terminated - An incorrect response was received from the server. + An incorrect response was received from the server - Canceling an active query is only supported on MySQL 5.0.0 and above. + Canceling an active query is only supported on MySQL 5.0.0 and above - Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding. + Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding - Canceling an executing query requires MySQL 5.0 or higher. + Canceling an executing query requires MySQL 5.0 or higher - Nested transactions are not supported. + Nested transactions are not supported - The CommandText property has not been properly initialized. + The CommandText property has not been properly initialized - There was an error parsing the foreign key definition. + There was an error parsing the foreign key definition This category includes a series of counters for MySQL @@ -283,91 +283,91 @@ .NET Data Provider for MySQL - The number of times a procedures metadata had to be queried from the server. + The number of times a procedures metadata had to be queried from the server Hard Procedure Queries - The number of times a procedures metadata was retrieved from the client-side cache. + The number of times a procedures metadata was retrieved from the client-side cache Soft Procedure Queries - Parameter '{0}' is not found but a parameter with the name '{1}' is found. Parameter names must include the leading parameter marker. + Parameter '{0}' is not found but a parameter with the name '{1}' is found. Parameter names must include the leading parameter marker - Unable to connect to any of the specified MySQL hosts. + Unable to connect to any of the specified MySQL hosts - Unable to retrieve stored procedure metadata for routine '{0}'. Either grant SELECT privilege to mysql.proc for this user or use "check parameters=false" with your connection string. + Unable to retrieve stored procedure metadata for routine '{0}'. Either grant SELECT privilege to mysql.proc for this user or use "check parameters=false" with your connection string - Invalid attempt to call NextResult when the reader is closed. + Invalid attempt to call NextResult when the reader is closed - When calling stored procedures and 'Use Procedure Bodies' is false, all parameters must have their type explicitly set. + When calling stored procedures and 'Use Procedure Bodies' is false, all parameters must have their type explicitly set - error connecting: Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached. + error connecting: Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached - Parameter '{0}' has already been defined. + Parameter '{0}' has already been defined - Parameter '{0}' must be defined. + Parameter '{0}' must be defined - The object is not open or has been disposed. + The object is not open or has been disposed - Multiple simultaneous connections or connections with different connection strings inside the same transaction are not currently supported. + Multiple simultaneous connections or connections with different connection strings inside the same transaction are not currently supported - MySQL Connector/NET does not currently support distributed transactions. + MySQL Connector/NET does not currently support distributed transactions - Fatal error encountered during command execution. + Fatal error encountered during command execution - Fatal error encountered during data read. + Fatal error encountered during data read - Fatal error encountered attempting to read the resultset. + Fatal error encountered attempting to read the resultset - Routine '{0}' cannot be found. Either check the spelling or make sure you have sufficient rights to execute the routine. + Routine '{0}' cannot be found. Either check the spelling or make sure you have sufficient rights to execute the routine - Parameter '{0}' was not found during prepare. + Parameter '{0}' was not found during prepare - The requested column value could not be treated as or conveted to a Guid. + The requested column value could not be treated as or conveted to a Guid - Unable to derive stored routine parameters. The 'Parameters' information schema table is not available and access to the stored procedure body has been disabled. + Unable to derive stored routine parameters. The 'Parameters' information schema table is not available and access to the stored procedure body has been disabled - The default connection encoding was not found. Please report this as a bug along with your connection string and system details. + The default connection encoding was not found. Please report this as a bug along with your connection string and system details - Call to GetHostEntry failed after {0} while querying for hostname '{1}': SocketErrorCode={2}, ErrorCode={3}, NativeErrorCode={4}. + Call to GetHostEntry failed after {0} while querying for hostname '{1}': SocketErrorCode={2}, ErrorCode={3}, NativeErrorCode={4} An error occured attempting to enumerate the user-defined functions. Do you have SELECT privileges on the mysql.func table? - The given value was not in a supported format. + The given value was not in a supported format - The host {0} does not support SSL connections. + The host {0} does not support SSL connections Could not find specified column in results: {0} - You have specified an invalid column ordinal. + You have specified an invalid column ordinal Invalid attempt to read a prior column using SequentialAccess @@ -376,19 +376,19 @@ Invalid attempt to access a field before calling Read() - Unable to start a second async operation while one is running. + Unable to start a second async operation while one is running - INTERNAL ERROR: More than one output parameter row detected. + INTERNAL ERROR: More than one output parameter row detected - '{0}' is an illegal value for a boolean option. + '{0}' is an illegal value for a boolean option Connector/NET no longer supports server versions prior to 5.0 - The requested value '{0}' is invalid for the given keyword '{1}'. + The requested value '{0}' is invalid for the given keyword '{1}' {0}: Connection Closed @@ -418,7 +418,7 @@ {0}: Resultset Closed. Total rows={1}, skipped rows={2}, size (bytes)={3} - {0}: Usage Advisor Warning: Skipped {2} rows. Consider a more focused query. + {0}: Usage Advisor Warning: Skipped {2} rows. Consider a more focused query {0}: Usage Advisor Warning: The following columns were not accessed: {2} @@ -436,7 +436,7 @@ {0}: MySql Warning: Level={1}, Code={2}, Message={3} - Unable to trace. There are more than Int32.MaxValue connections in use. + Unable to trace. There are more than Int32.MaxValue connections in use {0}: Statement prepared: sql='{1}', statement id={2} @@ -448,28 +448,28 @@ {0}: Statement executed: statement id = {1} - Unable to enable query analysis. Be sure the MySql.Data.EMTrace assembly is properly located and registered. + Unable to enable query analysis. Be sure the MySql.Data.EMTrace assembly is properly located and registered {0}: Query Normalized: {2} - Cannot retrieve Windows identity for current user. Connections that use IntegratedSecurity cannot be pooled. Use either 'ConnectionReset=true' or 'Pooling=false' in the connection string to fix. + Cannot retrieve Windows identity for current user. Connections that use IntegratedSecurity cannot be pooled. Use either 'ConnectionReset=true' or 'Pooling=false' in the connection string to fix Attempt to call stored function '{0}' without specifying a return parameter - Parameters can only be derived for commands using the StoredProcedure command type. + Parameters can only be derived for commands using the StoredProcedure command type - Replicated connections allow only readonly statements. + Replicated connections allow only readonly statements - File based certificates are only supported when connecting to MySQL Server 5.1 or greater. + File based certificates are only supported when connecting to MySQL Server 5.1 or greater - Snapshot isolation level is not supported. + Snapshot isolation level is not supported Type '{0}' is not derived from BaseExceptionInterceptor @@ -478,7 +478,7 @@ Type '{0}' is not derived from BaseCommandInterceptor - Unknown authentication method '{0}' was requested. + Unknown authentication method '{0}' was requested Authentication to host '{0}' for user '{1}' using method '{2}' failed with message: {3} @@ -487,204 +487,213 @@ Windows authentication connections are not supported on {0} - Authentication method '{0}' not supported by any of the available plugins. + Authentication method '{0}' not supported by any of the available plugins - Unable to create plugin for authentication method '{0}'. Please see inner exception for details. + Unable to create plugin for authentication method '{0}'. Please see inner exception for details - Mixing named and unnamed parameters is not allowed. + Mixing named and unnamed parameters is not allowed - Parameter index was not found in Parameter Collection. + Parameter index was not found in Parameter Collection - Authentication with old password no longer supported, use 4.1 style passwords. + Authentication with old password no longer supported, use 4.1 style passwords - Microsecond must be a value between 0 and 999999. + Microsecond must be a value between 0 and 999999 - Millisecond must be a value between 0 and 999. For more precision use Microsecond. + Millisecond must be a value between 0 and 999. For more precision use Microsecond - No available server found. + No available server found - Attempt to connect to '{0}' server failed. + Attempt to connect to '{0}' server failed Unknown connection protocol - Unix sockets are not supported on Windows. + Unix sockets are not supported on Windows Replicated server not found: '{0}' - Replication group '{0}' not found. + Replication group '{0}' not found - The new value must be a MySqlParameter object. + The new value must be a MySqlParameter object - Value '{0}' is not of the correct type. + Value '{0}' is not of the correct type - Compression is not supported. + Compression is not supported - SSL Connection error. + SSL Connection error - The option '{0}' is not currently supported. + The option '{0}' is not currently supported - Parameter can't be null or empty. + Parameter can't be null or empty - Error encountered reading the RSA public key. + Error encountered reading the RSA public key - Retrieval of the RSA public key is not enabled for insecure connections. + Retrieval of the RSA public key is not enabled for insecure connections - String can't be empty. + String can't be empty - Value '{0}' is not of the correct type. + Value '{0}' is not of the correct type - Parameter '{0}' can't be null or empty. + Parameter '{0}' can't be null or empty - Encoding error during validation. + Encoding error during validation - The specified file cannot be converted to a certificate. + The specified file cannot be converted to a certificate - The specified file cannot be converted to a key. + The specified file cannot be converted to a key - Failed to read file at the specified location. + Failed to read file at the specified location - No file path has been provided for the connection option {0}. + No file path has been provided for the connection option {0} - The provided key is invalid. + The provided key is invalid - The certificate is invalid. + The certificate is invalid - Unable to validate the signature. + Unable to validate the signature - Unable to verify the signature. + Unable to verify the signature - The certificate authority (CA) does not match. + The certificate authority (CA) does not match - The host name does not match the name on the certificate. + The host name does not match the name on the certificate - The certificate is not a certificate authority (CA). + The certificate is not a certificate authority (CA) - Server asked for stream in response to LOAD DATA LOCAL INFILE, but the functionality is disabled by the client setting 'allowlocalinfile' to 'false'. + Server asked for stream in response to LOAD DATA LOCAL INFILE, but the functionality is disabled by the client setting 'allowlocalinfile' to 'false' - The host name or IP address is invalid. + The host name or IP address is invalid - All server connection attempts were aborted. Timeout of {0} seconds was exceeded for each selected server. + All server connection attempts were aborted. Timeout of {0} seconds was exceeded for each selected server - Specifying multiple host names with DNS SRV lookup is not permitted. + Specifying multiple host names with DNS SRV lookup is not permitted - Specifying a port number with DNS SRV lookup is not permitted. + Specifying a port number with DNS SRV lookup is not permitted - Using Unix domain sockets with DNS SRV lookup is not permitted. + Using Unix domain sockets with DNS SRV lookup is not permitted - Unable to locate any hosts for {0}. + Unable to locate any hosts for {0} Specified list of TLS versions only contains non valid TLS protocols. Accepted values are TLSv1.2 and TLSv1.3 - - TLSv1.3 is not supported by this framework. - Specified list of TLS versions is empty. Accepted values are TLSv1.2 and TLSv1.3 - Verify that user '{0}'@'{1}' has enough privileges to execute. + Verify that user '{0}'@'{1}' has enough privileges to execute - Clear-password authentication is not supported over insecure channels. + Clear-password authentication is not supported over insecure channels - Trying to upload a file from outside the path set on 'allowloadlocalinfileinpath' is invalid. + Trying to upload a file from outside the path set on 'allowloadlocalinfileinpath' is invalid - Either provide a valid path for 'allowloadlocalinfileinpath' or enable 'allowloadlocalinfile'. + Either provide a valid path for 'allowloadlocalinfileinpath' or enable 'allowloadlocalinfile' - Certificate with Thumbprint '{0}' not found. + Certificate with Thumbprint '{0}' not found - MySQL Server {0} dos not support query attributes. + MySQL Server {0} dos not support query attributes - MySQL Connector/NET does not support query attributes with prepared statements for this version of MySQL Server. + MySQL Connector/NET does not support query attributes with prepared statements for this version of MySQL Server - Connection protocol '{0}' does not support SSL connections. + Connection protocol '{0}' does not support SSL connections - Authentication plugin '{0}' is currently not supported. + Authentication plugin '{0}' is currently not supported - MySQL user '{0}' does not equal the logged-in Windows user '{1}'. + MySQL user '{0}' does not equal the logged-in Windows user '{1}' - The OCI SDK cannot be found or is not installed. + The OCI SDK cannot be found or is not installed - OCI configuration file could not be read. + OCI configuration file could not be read - OCI configuration file does not contain a 'fingerprint' or 'key_file' entry. + OCI configuration file does not contain a 'fingerprint' or 'key_file' entry - OCI configuration entry 'key_file' does not reference a valid key file. + OCI configuration entry 'key_file' does not reference a valid key file - Private key could not be found at location given by OCI configuration entry 'key_file'. + Private key could not be found at location given by OCI configuration entry 'key_file' + + + The size of the OCI security token file exceeds the maximum value of 10KB allowed + + + OCI configuration profile not found + + + Secutiry token file could not be found at location given by OCI configuration entry 'security_token_file' TLS protocols TLSv1 and TLSv1.1 are no longer supported. Accepted values are TLSv1.2 and TLSv1.3 - Challenge received is corrupt. - - - An event handler for FidoActionRequested was not specified. + Challenge received is corrupt - FIDO registration is missing. + FIDO registration is missing - An event handler for WebAuthnActionRequested was not specified. + An event handler for WebAuthnActionRequested was not specified - The timeout of 15 seconds for user interaction with FIDO device has been exceeded. + The timeout of 15 seconds for user interaction with FIDO device has been exceeded + + + The OpenID Connect Identity Token is empty + + + The OpenID Connect Identity Token is invalid \ No newline at end of file diff --git a/MySQL.Data/src/ResourcesX.Designer.cs b/MySQL.Data/src/ResourcesX.Designer.cs index 2802d4afa..e1b04614d 100644 --- a/MySQL.Data/src/ResourcesX.Designer.cs +++ b/MySQL.Data/src/ResourcesX.Designer.cs @@ -1,721 +1,721 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace MySql.Data { - using System; - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class ResourcesX { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal ResourcesX() { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("MySql.Data.ResourcesX", typeof(ResourcesX).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - /// - /// Looks up a localized string similar to Appdata path is not defined.. - /// - internal static string AppdataNotDefined { - get { - return ResourceManager.GetString("AppdataNotDefined", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Authentication failed using MYSQL41 and SHA256_MEMORY. Check the user name and password or try using a secure connection.. - /// - internal static string AuthenticationFailed { - get { - return ResourceManager.GetString("AuthenticationFailed", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to You can't get more sessions because Client is closed.. - /// - internal static string ClientIsClosed { - get { - return ResourceManager.GetString("ClientIsClosed", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Client option '{0}' does not support value '{1}'.. - /// - internal static string ClientOptionInvalidValue { - get { - return ResourceManager.GetString("ClientOptionInvalidValue", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Client option '{0}' is not recognized as valid.. - /// - internal static string ClientOptionNotValid { - get { - return ResourceManager.GetString("ClientOptionNotValid", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to {0} '{1}' does not exist in schema '{2}'.. - /// - internal static string CollectionTableDoesNotExist { - get { - return ResourceManager.GetString("CollectionTableDoesNotExist", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Compression requested but the compression algorithm negotiation failed.. - /// - internal static string CompressionAlgorithmNegotiationFailed { - get { - return ResourceManager.GetString("CompressionAlgorithmNegotiationFailed", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Compression using {0} is not supported.. - /// - internal static string CompressionAlgorithmNotSupported { - get { - return ResourceManager.GetString("CompressionAlgorithmNotSupported", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Compression using {0} is not supported in .NET Framework.. - /// - internal static string CompressionForSpecificAlgorithmNotSupportedInNetFramework { - get { - return ResourceManager.GetString("CompressionForSpecificAlgorithmNotSupportedInNetFramework", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The connection property 'compression' acceptable values are: 'preferred', 'required' or 'disabled'. The value '{0}' is not acceptable.. - /// - internal static string CompressionInvalidValue { - get { - return ResourceManager.GetString("CompressionInvalidValue", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Compression is not enabled.. - /// - internal static string CompressionNotEnabled { - get { - return ResourceManager.GetString("CompressionNotEnabled", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Compression requested but the server does not support it.. - /// - internal static string CompressionNotSupportedByServer { - get { - return ResourceManager.GetString("CompressionNotSupportedByServer", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to There are still decompressed messages pending to be processed.. - /// - internal static string CompressionPendingMessagesToProcess { - get { - return ResourceManager.GetString("CompressionPendingMessagesToProcess", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Custom type mapping is only supported from .NET Core 3.1 and later.. - /// - internal static string CustomTypeNotSupported { - get { - return ResourceManager.GetString("CustomTypeNotSupported", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to '{0}' cannot be set to false with DNS SRV lookup enabled.. - /// - internal static string DnsSrvConflictingOptions { - get { - return ResourceManager.GetString("DnsSrvConflictingOptions", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Scheme '{0}' is not valid.. - /// - internal static string DnsSrvInvalidScheme { - get { - return ResourceManager.GetString("DnsSrvInvalidScheme", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The document path cannot be null or an empty string.. - /// - internal static string DocPathNullOrEmpty { - get { - return ResourceManager.GetString("DocPathNullOrEmpty", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Duplicate key '{0}' used in "connection-attributes".. - /// - internal static string DuplicateUserDefinedAttribute { - get { - return ResourceManager.GetString("DuplicateUserDefinedAttribute", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Key name in connection attribute cannot be an empty string.. - /// - internal static string EmptyKeyConnectionAttribute { - get { - return ResourceManager.GetString("EmptyKeyConnectionAttribute", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to At least one option must be specified.. - /// - internal static string EmptyOptions { - get { - return ResourceManager.GetString("EmptyOptions", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to This feature is currently not supported.. - /// - internal static string FeatureNotSupported { - get { - return ResourceManager.GetString("FeatureNotSupported", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to This functionality is only supported in MySQL {0} and higher.. - /// - internal static string FunctionalityNotSupported { - get { - return ResourceManager.GetString("FunctionalityNotSupported", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Collation with id '{0}' not found.. - /// - internal static string InvalidCollationId { - get { - return ResourceManager.GetString("InvalidCollationId", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The value of "connection-attributes" must be either a boolean or a list of key-value pairs.. - /// - internal static string InvalidConnectionAttributes { - get { - return ResourceManager.GetString("InvalidConnectionAttributes", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Connection Data is incorrect.. - /// - internal static string InvalidConnectionData { - get { - return ResourceManager.GetString("InvalidConnectionData", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The connection string is invalid.. - /// - internal static string InvalidConnectionString { - get { - return ResourceManager.GetString("InvalidConnectionString", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to '{0}' is not a valid connection string attribute.. - /// - internal static string InvalidConnectionStringAttribute { - get { - return ResourceManager.GetString("InvalidConnectionStringAttribute", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The connection timeout value must be a positive integer (including 0).. - /// - internal static string InvalidConnectionTimeoutValue { - get { - return ResourceManager.GetString("InvalidConnectionTimeoutValue", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Decimal (BCD) format is invalid.. - /// - internal static string InvalidDecimalFormat { - get { - return ResourceManager.GetString("InvalidDecimalFormat", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Field type with name '{0}' not found.. - /// - internal static string InvalidFieldType { - get { - return ResourceManager.GetString("InvalidFieldType", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Index type with name '{0}' not found.. - /// - internal static string InvalidIndexType { - get { - return ResourceManager.GetString("InvalidIndexType", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The value provided is not a valid JSON document. {0}. - /// - internal static string InvalidJsonDocument { - get { - return ResourceManager.GetString("InvalidJsonDocument", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to {0} is not a valid column name in the row.. - /// - internal static string InvalidNameIndex { - get { - return ResourceManager.GetString("InvalidNameIndex", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to {0} is not a valid index for the row.. - /// - internal static string InvalidRowIndex { - get { - return ResourceManager.GetString("InvalidRowIndex", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Session state is not valid.. - /// - internal static string InvalidSession { - get { - return ResourceManager.GetString("InvalidSession", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Invalid Uri . - /// - internal static string InvalidUriData { - get { - return ResourceManager.GetString("InvalidUriData", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Invalid uri query value. - /// - internal static string InvalidUriQuery { - get { - return ResourceManager.GetString("InvalidUriQuery", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Key names in "connection-attributes" cannot start with "_".. - /// - internal static string InvalidUserDefinedAttribute { - get { - return ResourceManager.GetString("InvalidUserDefinedAttribute", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Json configuration must contain 'uri' or 'host' but not both.. - /// - internal static string JsonUriOrHost { - get { - return ResourceManager.GetString("JsonUriOrHost", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Keyword '{0}' not found.. - /// - internal static string KeywordNotFound { - get { - return ResourceManager.GetString("KeywordNotFound", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Keyword not supported.. - /// - internal static string KeywordNotSupported { - get { - return ResourceManager.GetString("KeywordNotSupported", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Field '{0}' is mandatory.. - /// - internal static string MandatoryFieldNotFound { - get { - return ResourceManager.GetString("MandatoryFieldNotFound", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Missed required schema option.. - /// - internal static string MissingSchemaOption { - get { - return ResourceManager.GetString("MissingSchemaOption", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to More than one document id was generated. Please use the DocumentIds property instead.. - /// - internal static string MoreThanOneDocumentId { - get { - return ResourceManager.GetString("MoreThanOneDocumentId", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to There is no data at index {0}. - /// - internal static string NoDataAtIndex { - get { - return ResourceManager.GetString("NoDataAtIndex", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to No 'host' has been specified.. - /// - internal static string NoHost { - get { - return ResourceManager.GetString("NoHost", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to No more data in resultset.. - /// - internal static string NoMoreData { - get { - return ResourceManager.GetString("NoMoreData", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Object '{0}' not found. - /// - internal static string NoObjectFound { - get { - return ResourceManager.GetString("NoObjectFound", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to No placeholders.. - /// - internal static string NoPlaceholders { - get { - return ResourceManager.GetString("NoPlaceholders", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Connection closed. Reason: connection idle was too long. - /// - internal static string NoticeIdleConnection { - get { - return ResourceManager.GetString("NoticeIdleConnection", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Connection closed. Reason: connection was killed by a different session. - /// - internal static string NoticeKilledConnection { - get { - return ResourceManager.GetString("NoticeKilledConnection", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Connection closed. Reason: server was shutdown. - /// - internal static string NoticeServerShutdown { - get { - return ResourceManager.GetString("NoticeServerShutdown", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to {0} must be a value greater than 0.. - /// - internal static string NumberNotGreaterThanZero { - get { - return ResourceManager.GetString("NumberNotGreaterThanZero", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Path not found '{0}'.. - /// - internal static string PathNotFound { - get { - return ResourceManager.GetString("PathNotFound", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Queue timeout expired. The timeout period elapsed prior to getting a session from the pool.. - /// - internal static string PoolingQueueTimeout { - get { - return ResourceManager.GetString("PoolingQueueTimeout", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Providing a port number as part of the host address isn't supported when using connection strings in basic format or anonymous objects. Use URI format instead.. - /// - internal static string PortNotSupported { - get { - return ResourceManager.GetString("PortNotSupported", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to You must either assign no priority to any of the hosts or give a priority for every host.. - /// - internal static string PriorityForAllOrNoHosts { - get { - return ResourceManager.GetString("PriorityForAllOrNoHosts", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The priority must be between 0 and 100.. - /// - internal static string PriorityOutOfLimits { - get { - return ResourceManager.GetString("PriorityOutOfLimits", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to ProgramData path is not defined.. - /// - internal static string ProgramDataNotDefined { - get { - return ResourceManager.GetString("ProgramDataNotDefined", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Replacement document has an '_id' that is - ///different from the matched document.. - /// - internal static string ReplaceWithNoMatchingId { - get { - return ResourceManager.GetString("ReplaceWithNoMatchingId", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The server doesn't support the requested operation. Please update the MySQL Server, client library, or both.. - /// - internal static string SchemaCreateCollectionMsg { - get { - return ResourceManager.GetString("SchemaCreateCollectionMsg", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The process of closing the resultset and resulted in results being lost.. - /// - internal static string ThrowingAwayResults { - get { - return ResourceManager.GetString("ThrowingAwayResults", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to All server connection attempts were aborted. Timeout of {0} milliseconds was exceeded for each selected server.. - /// - internal static string TimeOutMultipleHost { - get { - return ResourceManager.GetString("TimeOutMultipleHost", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to All server connection attempts were aborted. Timeout was exceeded for each selected server.. - /// - internal static string TimeOutMultipleHost0ms { - get { - return ResourceManager.GetString("TimeOutMultipleHost0ms", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Connection attempt to the server was aborted. Timeout of {0} milliseconds was exceeded.. - /// - internal static string TimeOutSingleHost { - get { - return ResourceManager.GetString("TimeOutSingleHost", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Connection attempt to the server was aborted. Timeout was exceeded.. - /// - internal static string TimeOutSingleHost0ms { - get { - return ResourceManager.GetString("TimeOutSingleHost0ms", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Unable to connect to any specified host.. - /// - internal static string UnableToConnect { - get { - return ResourceManager.GetString("UnableToConnect", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Unable to read or decode data value.. - /// - internal static string UnableToDecodeDataValue { - get { - return ResourceManager.GetString("UnableToDecodeDataValue", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Unable to open a session.. - /// - internal static string UnableToOpenSession { - get { - return ResourceManager.GetString("UnableToOpenSession", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Unexpected end of packet found while reading data values. - /// - internal static string UnexpectedEndOfPacketFound { - get { - return ResourceManager.GetString("UnexpectedEndOfPacketFound", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Field name '{0}' is not allowed.. - /// - internal static string UnexpectedField { - get { - return ResourceManager.GetString("UnexpectedField", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Unknown placeholder :{0}. - /// - internal static string UnknownPlaceholder { - get { - return ResourceManager.GetString("UnknownPlaceholder", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Value '{0}' is not of the correct type.. - /// - internal static string ValueNotCorrectType { - get { - return ResourceManager.GetString("ValueNotCorrectType", resourceCulture); - } - } - } -} +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace MySql.Data { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class ResourcesX { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal ResourcesX() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("MySql.Data.ResourcesX", typeof(ResourcesX).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to Appdata path is not defined. + /// + internal static string AppdataNotDefined { + get { + return ResourceManager.GetString("AppdataNotDefined", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Authentication failed using MYSQL41 and SHA256_MEMORY. Check the user name and password or try using a secure connection. + /// + internal static string AuthenticationFailed { + get { + return ResourceManager.GetString("AuthenticationFailed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to You can't get more sessions because Client is closed. + /// + internal static string ClientIsClosed { + get { + return ResourceManager.GetString("ClientIsClosed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Client option '{0}' does not support value '{1}'. + /// + internal static string ClientOptionInvalidValue { + get { + return ResourceManager.GetString("ClientOptionInvalidValue", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Client option '{0}' is not recognized as valid. + /// + internal static string ClientOptionNotValid { + get { + return ResourceManager.GetString("ClientOptionNotValid", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} '{1}' does not exist in schema '{2}'. + /// + internal static string CollectionTableDoesNotExist { + get { + return ResourceManager.GetString("CollectionTableDoesNotExist", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Compression requested but the compression algorithm negotiation failed. + /// + internal static string CompressionAlgorithmNegotiationFailed { + get { + return ResourceManager.GetString("CompressionAlgorithmNegotiationFailed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Compression using {0} is not supported. + /// + internal static string CompressionAlgorithmNotSupported { + get { + return ResourceManager.GetString("CompressionAlgorithmNotSupported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Compression using {0} is not supported in .NET Framework. + /// + internal static string CompressionForSpecificAlgorithmNotSupportedInNetFramework { + get { + return ResourceManager.GetString("CompressionForSpecificAlgorithmNotSupportedInNetFramework", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The connection property 'compression' acceptable values are: 'preferred', 'required' or 'disabled'. The value '{0}' is not acceptable. + /// + internal static string CompressionInvalidValue { + get { + return ResourceManager.GetString("CompressionInvalidValue", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Compression is not enabled. + /// + internal static string CompressionNotEnabled { + get { + return ResourceManager.GetString("CompressionNotEnabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Compression requested but the server does not support it. + /// + internal static string CompressionNotSupportedByServer { + get { + return ResourceManager.GetString("CompressionNotSupportedByServer", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to There are still decompressed messages pending to be processed. + /// + internal static string CompressionPendingMessagesToProcess { + get { + return ResourceManager.GetString("CompressionPendingMessagesToProcess", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Custom type mapping is only supported from .NET Core 3.1 and later. + /// + internal static string CustomTypeNotSupported { + get { + return ResourceManager.GetString("CustomTypeNotSupported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to '{0}' cannot be set to false with DNS SRV lookup enabled. + /// + internal static string DnsSrvConflictingOptions { + get { + return ResourceManager.GetString("DnsSrvConflictingOptions", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Scheme '{0}' is not valid. + /// + internal static string DnsSrvInvalidScheme { + get { + return ResourceManager.GetString("DnsSrvInvalidScheme", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The document path cannot be null or an empty string. + /// + internal static string DocPathNullOrEmpty { + get { + return ResourceManager.GetString("DocPathNullOrEmpty", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Duplicate key '{0}' used in "connection-attributes". + /// + internal static string DuplicateUserDefinedAttribute { + get { + return ResourceManager.GetString("DuplicateUserDefinedAttribute", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Key name in connection attribute cannot be an empty string. + /// + internal static string EmptyKeyConnectionAttribute { + get { + return ResourceManager.GetString("EmptyKeyConnectionAttribute", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to At least one option must be specified. + /// + internal static string EmptyOptions { + get { + return ResourceManager.GetString("EmptyOptions", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to This feature is currently not supported. + /// + internal static string FeatureNotSupported { + get { + return ResourceManager.GetString("FeatureNotSupported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to This functionality is only supported in MySQL {0} and higher. + /// + internal static string FunctionalityNotSupported { + get { + return ResourceManager.GetString("FunctionalityNotSupported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Collation with id '{0}' not found. + /// + internal static string InvalidCollationId { + get { + return ResourceManager.GetString("InvalidCollationId", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The value of "connection-attributes" must be either a boolean or a list of key-value pairs. + /// + internal static string InvalidConnectionAttributes { + get { + return ResourceManager.GetString("InvalidConnectionAttributes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Connection Data is incorrect. + /// + internal static string InvalidConnectionData { + get { + return ResourceManager.GetString("InvalidConnectionData", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The connection string is invalid. + /// + internal static string InvalidConnectionString { + get { + return ResourceManager.GetString("InvalidConnectionString", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to '{0}' is not a valid connection string attribute. + /// + internal static string InvalidConnectionStringAttribute { + get { + return ResourceManager.GetString("InvalidConnectionStringAttribute", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The connection timeout value must be a positive integer (including 0). + /// + internal static string InvalidConnectionTimeoutValue { + get { + return ResourceManager.GetString("InvalidConnectionTimeoutValue", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Decimal (BCD) format is invalid. + /// + internal static string InvalidDecimalFormat { + get { + return ResourceManager.GetString("InvalidDecimalFormat", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Field type with name '{0}' not found. + /// + internal static string InvalidFieldType { + get { + return ResourceManager.GetString("InvalidFieldType", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Index type with name '{0}' not found. + /// + internal static string InvalidIndexType { + get { + return ResourceManager.GetString("InvalidIndexType", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The value provided is not a valid JSON document. {0}. + /// + internal static string InvalidJsonDocument { + get { + return ResourceManager.GetString("InvalidJsonDocument", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} is not a valid column name in the row. + /// + internal static string InvalidNameIndex { + get { + return ResourceManager.GetString("InvalidNameIndex", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} is not a valid index for the row. + /// + internal static string InvalidRowIndex { + get { + return ResourceManager.GetString("InvalidRowIndex", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Session state is not valid. + /// + internal static string InvalidSession { + get { + return ResourceManager.GetString("InvalidSession", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid Uri . + /// + internal static string InvalidUriData { + get { + return ResourceManager.GetString("InvalidUriData", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid uri query value. + /// + internal static string InvalidUriQuery { + get { + return ResourceManager.GetString("InvalidUriQuery", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Key names in "connection-attributes" cannot start with "_". + /// + internal static string InvalidUserDefinedAttribute { + get { + return ResourceManager.GetString("InvalidUserDefinedAttribute", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Json configuration must contain 'uri' or 'host' but not both. + /// + internal static string JsonUriOrHost { + get { + return ResourceManager.GetString("JsonUriOrHost", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Keyword '{0}' not found. + /// + internal static string KeywordNotFound { + get { + return ResourceManager.GetString("KeywordNotFound", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Keyword not supported. + /// + internal static string KeywordNotSupported { + get { + return ResourceManager.GetString("KeywordNotSupported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Field '{0}' is mandatory. + /// + internal static string MandatoryFieldNotFound { + get { + return ResourceManager.GetString("MandatoryFieldNotFound", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Missed required schema option. + /// + internal static string MissingSchemaOption { + get { + return ResourceManager.GetString("MissingSchemaOption", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to More than one document id was generated. Please use the DocumentIds property instead. + /// + internal static string MoreThanOneDocumentId { + get { + return ResourceManager.GetString("MoreThanOneDocumentId", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to There is no data at index {0}. + /// + internal static string NoDataAtIndex { + get { + return ResourceManager.GetString("NoDataAtIndex", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No 'host' has been specified. + /// + internal static string NoHost { + get { + return ResourceManager.GetString("NoHost", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No more data in resultset. + /// + internal static string NoMoreData { + get { + return ResourceManager.GetString("NoMoreData", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Object '{0}' not found. + /// + internal static string NoObjectFound { + get { + return ResourceManager.GetString("NoObjectFound", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No placeholders. + /// + internal static string NoPlaceholders { + get { + return ResourceManager.GetString("NoPlaceholders", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Connection closed. Reason: connection idle was too long. + /// + internal static string NoticeIdleConnection { + get { + return ResourceManager.GetString("NoticeIdleConnection", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Connection closed. Reason: connection was killed by a different session. + /// + internal static string NoticeKilledConnection { + get { + return ResourceManager.GetString("NoticeKilledConnection", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Connection closed. Reason: server was shutdown. + /// + internal static string NoticeServerShutdown { + get { + return ResourceManager.GetString("NoticeServerShutdown", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} must be a value greater than 0. + /// + internal static string NumberNotGreaterThanZero { + get { + return ResourceManager.GetString("NumberNotGreaterThanZero", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Path not found '{0}'. + /// + internal static string PathNotFound { + get { + return ResourceManager.GetString("PathNotFound", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Queue timeout expired. The timeout period elapsed prior to getting a session from the pool. + /// + internal static string PoolingQueueTimeout { + get { + return ResourceManager.GetString("PoolingQueueTimeout", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Providing a port number as part of the host address isn't supported when using connection strings in basic format or anonymous objects. Use URI format instead. + /// + internal static string PortNotSupported { + get { + return ResourceManager.GetString("PortNotSupported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to You must either assign no priority to any of the hosts or give a priority for every host. + /// + internal static string PriorityForAllOrNoHosts { + get { + return ResourceManager.GetString("PriorityForAllOrNoHosts", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The priority must be between 0 and 100. + /// + internal static string PriorityOutOfLimits { + get { + return ResourceManager.GetString("PriorityOutOfLimits", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ProgramData path is not defined. + /// + internal static string ProgramDataNotDefined { + get { + return ResourceManager.GetString("ProgramDataNotDefined", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Replacement document has an '_id' that is + ///different from the matched document. + /// + internal static string ReplaceWithNoMatchingId { + get { + return ResourceManager.GetString("ReplaceWithNoMatchingId", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The server doesn't support the requested operation. Please update the MySQL Server, client library, or both. + /// + internal static string SchemaCreateCollectionMsg { + get { + return ResourceManager.GetString("SchemaCreateCollectionMsg", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The process of closing the resultset and resulted in results being lost. + /// + internal static string ThrowingAwayResults { + get { + return ResourceManager.GetString("ThrowingAwayResults", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to All server connection attempts were aborted. Timeout of {0} milliseconds was exceeded for each selected server. + /// + internal static string TimeOutMultipleHost { + get { + return ResourceManager.GetString("TimeOutMultipleHost", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to All server connection attempts were aborted. Timeout was exceeded for each selected server. + /// + internal static string TimeOutMultipleHost0ms { + get { + return ResourceManager.GetString("TimeOutMultipleHost0ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Connection attempt to the server was aborted. Timeout of {0} milliseconds was exceeded. + /// + internal static string TimeOutSingleHost { + get { + return ResourceManager.GetString("TimeOutSingleHost", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Connection attempt to the server was aborted. Timeout was exceeded. + /// + internal static string TimeOutSingleHost0ms { + get { + return ResourceManager.GetString("TimeOutSingleHost0ms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to connect to any specified host. + /// + internal static string UnableToConnect { + get { + return ResourceManager.GetString("UnableToConnect", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to read or decode data value. + /// + internal static string UnableToDecodeDataValue { + get { + return ResourceManager.GetString("UnableToDecodeDataValue", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to open a session. + /// + internal static string UnableToOpenSession { + get { + return ResourceManager.GetString("UnableToOpenSession", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unexpected end of packet found while reading data values. + /// + internal static string UnexpectedEndOfPacketFound { + get { + return ResourceManager.GetString("UnexpectedEndOfPacketFound", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Field name '{0}' is not allowed. + /// + internal static string UnexpectedField { + get { + return ResourceManager.GetString("UnexpectedField", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown placeholder :{0}. + /// + internal static string UnknownPlaceholder { + get { + return ResourceManager.GetString("UnknownPlaceholder", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Value '{0}' is not of the correct type. + /// + internal static string ValueNotCorrectType { + get { + return ResourceManager.GetString("ValueNotCorrectType", resourceCulture); + } + } + } +} diff --git a/MySQL.Data/src/ResourcesX.resx b/MySQL.Data/src/ResourcesX.resx index 7ec1a4298..c32081e6c 100644 --- a/MySQL.Data/src/ResourcesX.resx +++ b/MySQL.Data/src/ResourcesX.resx @@ -118,52 +118,52 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - Collation with id '{0}' not found. + Collation with id '{0}' not found - Connection Data is incorrect. + Connection Data is incorrect - '{0}' is not a valid connection string attribute. + '{0}' is not a valid connection string attribute - The connection string is invalid. + The connection string is invalid - Decimal (BCD) format is invalid. + Decimal (BCD) format is invalid - {0} is not a valid column name in the row. + {0} is not a valid column name in the row - {0} is not a valid index for the row. + {0} is not a valid index for the row - Keyword not supported. + Keyword not supported - More than one document id was generated. Please use the DocumentIds property instead. + More than one document id was generated. Please use the DocumentIds property instead There is no data at index {0} - No more data in resultset. + No more data in resultset - No placeholders. + No placeholders - Path not found '{0}'. + Path not found '{0}' - The process of closing the resultset and resulted in results being lost. + The process of closing the resultset and resulted in results being lost - Unable to connect to any specified host. + Unable to connect to any specified host - Unable to read or decode data value. + Unable to read or decode data value Unexpected end of packet found while reading data values @@ -172,7 +172,7 @@ Unknown placeholder :{0} - Value '{0}' is not of the correct type. + Value '{0}' is not of the correct type Object '{0}' not found @@ -184,139 +184,139 @@ Invalid uri query value - Json configuration must contain 'uri' or 'host' but not both. + Json configuration must contain 'uri' or 'host' but not both - No 'host' has been specified. + No 'host' has been specified - Appdata path is not defined. + Appdata path is not defined - ProgramData path is not defined. + ProgramData path is not defined - Keyword '{0}' not found. + Keyword '{0}' not found - You must either assign no priority to any of the hosts or give a priority for every host. + You must either assign no priority to any of the hosts or give a priority for every host - The priority must be between 0 and 100. + The priority must be between 0 and 100 - Providing a port number as part of the host address isn't supported when using connection strings in basic format or anonymous objects. Use URI format instead. + Providing a port number as part of the host address isn't supported when using connection strings in basic format or anonymous objects. Use URI format instead - {0} must be a value greater than 0. + {0} must be a value greater than 0 - This functionality is only supported in MySQL {0} and higher. + This functionality is only supported in MySQL {0} and higher - Field '{0}' is mandatory. + Field '{0}' is mandatory - Field name '{0}' is not allowed. + Field name '{0}' is not allowed - Field type with name '{0}' not found. + Field type with name '{0}' not found - Index type with name '{0}' not found. + Index type with name '{0}' not found - Authentication failed using MYSQL41 and SHA256_MEMORY. Check the user name and password or try using a secure connection. + Authentication failed using MYSQL41 and SHA256_MEMORY. Check the user name and password or try using a secure connection - This feature is currently not supported. + This feature is currently not supported The value provided is not a valid JSON document. {0} - The connection timeout value must be a positive integer (including 0). + The connection timeout value must be a positive integer (including 0) - All server connection attempts were aborted. Timeout of {0} milliseconds was exceeded for each selected server. + All server connection attempts were aborted. Timeout of {0} milliseconds was exceeded for each selected server - Connection attempt to the server was aborted. Timeout of {0} milliseconds was exceeded. + Connection attempt to the server was aborted. Timeout of {0} milliseconds was exceeded - All server connection attempts were aborted. Timeout was exceeded for each selected server. + All server connection attempts were aborted. Timeout was exceeded for each selected server - Connection attempt to the server was aborted. Timeout was exceeded. + Connection attempt to the server was aborted. Timeout was exceeded - Client option '{0}' does not support value '{1}'. + Client option '{0}' does not support value '{1}' - Client option '{0}' is not recognized as valid. + Client option '{0}' is not recognized as valid - Queue timeout expired. The timeout period elapsed prior to getting a session from the pool. + Queue timeout expired. The timeout period elapsed prior to getting a session from the pool - Session state is not valid. + Session state is not valid - Unable to open a session. + Unable to open a session - You can't get more sessions because Client is closed. + You can't get more sessions because Client is closed - {0} '{1}' does not exist in schema '{2}'. + {0} '{1}' does not exist in schema '{2}' - Duplicate key '{0}' used in "connection-attributes". + Duplicate key '{0}' used in "connection-attributes" - Key names in "connection-attributes" cannot start with "_". + Key names in "connection-attributes" cannot start with "_" - The value of "connection-attributes" must be either a boolean or a list of key-value pairs. + The value of "connection-attributes" must be either a boolean or a list of key-value pairs - Key name in connection attribute cannot be an empty string. + Key name in connection attribute cannot be an empty string - The server doesn't support the requested operation. Please update the MySQL Server, client library, or both. + The server doesn't support the requested operation. Please update the MySQL Server, client library, or both - At least one option must be specified. + At least one option must be specified - Missed required schema option. + Missed required schema option - Scheme '{0}' is not valid. + Scheme '{0}' is not valid - '{0}' cannot be set to false with DNS SRV lookup enabled. + '{0}' cannot be set to false with DNS SRV lookup enabled - Compression requested but the compression algorithm negotiation failed. + Compression requested but the compression algorithm negotiation failed - The connection property 'compression' acceptable values are: 'preferred', 'required' or 'disabled'. The value '{0}' is not acceptable. + The connection property 'compression' acceptable values are: 'preferred', 'required' or 'disabled'. The value '{0}' is not acceptable - Compression requested but the server does not support it. + Compression requested but the server does not support it - Compression using {0} is not supported. + Compression using {0} is not supported - Compression using {0} is not supported in .NET Framework. + Compression using {0} is not supported in .NET Framework - Compression is not enabled. + Compression is not enabled - There are still decompressed messages pending to be processed. + There are still decompressed messages pending to be processed Connection closed. Reason: connection idle was too long @@ -329,12 +329,12 @@ Replacement document has an '_id' that is -different from the matched document. +different from the matched document - The document path cannot be null or an empty string. + The document path cannot be null or an empty string - Custom type mapping is only supported from .NET Core 3.1 and later. + Custom type mapping is only supported from .NET Core 3.1 and later \ No newline at end of file diff --git a/MySQL.Data/src/ResultSet.cs b/MySQL.Data/src/ResultSet.cs index 99d41d9ec..3b7fa890f 100644 --- a/MySQL.Data/src/ResultSet.cs +++ b/MySQL.Data/src/ResultSet.cs @@ -1,339 +1,339 @@ -// Copyright (c) 2009, 2022, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data.Types; -using System; -using System.Collections.Generic; -using System.Data; -using System.Diagnostics; -using System.Threading.Tasks; - -namespace MySql.Data.MySqlClient -{ - internal class ResultSet - { - private Driver _driver; - private bool[] _uaFieldsUsed; - private Dictionary _fieldHashCi; - private int _rowIndex; - private bool _readDone; - private bool _isSequential; - private int _seqIndex; - private readonly int _statementId; - private bool _cached; - private List _cachedValues; - - public ResultSet(int affectedRows, long insertedId) - { - AffectedRows = affectedRows; - InsertedId = insertedId; - _readDone = true; - } - - public static async Task CreateResultSetAsync(Driver d, int statementId, int numCols, bool execAsync) - { - ResultSet resultSet = new ResultSet(d, statementId); - await resultSet.InitializeAsync(numCols, execAsync).ConfigureAwait(false); - return resultSet; - } - - private ResultSet(Driver d, int statementId) - { - AffectedRows = -1; - InsertedId = -1; - _driver = d; - _statementId = statementId; - _rowIndex = -1; - } - - private async Task InitializeAsync(int numCols, bool execAsync) - { - await LoadColumnsAsync(numCols, execAsync).ConfigureAwait(false); - IsOutputParameters = IsOutputParameterResultSet(); - HasRows = await GetNextRowAsync(execAsync).ConfigureAwait(false); - _readDone = !HasRows; - } - - #region Properties - - public bool HasRows { get; private set; } - - public int Size => Fields?.Length ?? 0; - - public MySqlField[] Fields { get; private set; } - - public IMySqlValue[] Values { get; private set; } - - public bool IsOutputParameters { get; set; } - - public int AffectedRows { get; private set; } - - public long InsertedId { get; private set; } - - public int TotalRows { get; private set; } - - public int SkippedRows { get; private set; } - - public bool Cached - { - get { return _cached; } - set - { - _cached = value; - if (_cached && _cachedValues == null) - _cachedValues = new List(); - } - } - - #endregion - - /// - /// return the ordinal for the given column name - /// - /// - /// - public int GetOrdinal(string name) - { - int ordinal; - - // quick hash lookup using CI hash - if (_fieldHashCi.TryGetValue(name, out ordinal)) - return ordinal; - - // Throw an exception if the ordinal cannot be found. - throw new IndexOutOfRangeException( - String.Format(Resources.CouldNotFindColumnName, name)); - } - - /// - /// Retrieve the value as the given column index - /// - /// The column value to retrieve - /// The value as the given column - public IMySqlValue this[int index] - { - get - { - if (_rowIndex < 0) - throw new MySqlException(Resources.AttemptToAccessBeforeRead); - - // keep count of how many columns we have left to access - _uaFieldsUsed[index] = true; - - if (_isSequential && index != _seqIndex) - { - if (index < _seqIndex) - throw new MySqlException(Resources.ReadingPriorColumnUsingSeqAccess); - while (_seqIndex < (index - 1)) - _driver.SkipColumnValue(Values[++_seqIndex]); - Values[index] = _driver.ReadColumnValueAsync(index, Fields[index], Values[index], false).GetAwaiter().GetResult(); - _seqIndex = index; - } - - return Values[index]; - } - } - - private async Task GetNextRowAsync(bool execAsync) - { - bool fetched = await _driver.FetchDataRowAsync(_statementId, Size, execAsync).ConfigureAwait(false); - - if (fetched) - TotalRows++; - - return fetched; - } - - public async Task NextRowAsync(CommandBehavior behavior, bool execAsync) - { - if (_readDone) - { - if (Cached) return CachedNextRow(behavior); - return false; - } - - if ((behavior & CommandBehavior.SingleRow) != 0 && _rowIndex == 0) - return false; - - _isSequential = (behavior & CommandBehavior.SequentialAccess) != 0; - _seqIndex = -1; - - // if we are at row index >= 0 then we need to fetch the data row and load it - if (_rowIndex >= 0) - { - bool fetched; - try - { - fetched = await GetNextRowAsync(execAsync).ConfigureAwait(false); - } - catch (MySqlException ex) - { - if (ex.IsQueryAborted) - { - // avoid hanging on Close() - _readDone = true; - } - throw; - } - - if (!fetched) - { - _readDone = true; - return false; - } - } - - if (!_isSequential) - await ReadColumnDataAsync(false, execAsync).ConfigureAwait(false); - - _rowIndex++; - return true; - } - - private bool CachedNextRow(CommandBehavior behavior) - { - if ((behavior & CommandBehavior.SingleRow) != 0 && _rowIndex == 0) - return false; - if (_rowIndex == (TotalRows - 1)) return false; - _rowIndex++; - Values = _cachedValues[_rowIndex]; - return true; - } - - /// - /// Closes the current resultset, dumping any data still on the wire - /// - public async Task CloseAsync(bool execAsync) - { - if (!_readDone) - { - - // if we have rows but the user didn't read the first one then mark it as skipped - if (HasRows && _rowIndex == -1) - SkippedRows++; - try - { - while (_driver.IsOpen && await _driver.SkipDataRowAsync(execAsync).ConfigureAwait(false)) - { - TotalRows++; - SkippedRows++; - } - } - catch (System.IO.IOException) - { - // it is ok to eat IO exceptions here, we just want to - // close the result set - } - _readDone = true; - } - else if (_driver == null) - CacheClose(); - - _driver = null; - if (Cached) CacheReset(); - } - - private void CacheClose() - { - SkippedRows = TotalRows - _rowIndex - 1; - } - - private void CacheReset() - { - if (!Cached) return; - _rowIndex = -1; - AffectedRows = -1; - InsertedId = -1; - SkippedRows = 0; - } - - public bool FieldRead(int index) - { - Debug.Assert(Size > index); - return _uaFieldsUsed[index]; - } - - public void SetValueObject(int i, IMySqlValue valueObject) - { - Debug.Assert(Values != null); - Debug.Assert(i < Values.Length); - Values[i] = valueObject; - } - - private bool IsOutputParameterResultSet() - { - if (_driver.HasStatus(ServerStatusFlags.OutputParameters)) return true; - - if (Fields.Length == 0) return false; - - for (int x = 0; x < Fields.Length; x++) - if (!Fields[x].ColumnName.StartsWith("@" + StoredProcedure.ParameterPrefix, StringComparison.OrdinalIgnoreCase)) return false; - return true; - } - - /// - /// Loads the column metadata for the current resultset - /// - private async Task LoadColumnsAsync(int numCols, bool execAsync) - { - Fields = await _driver.GetColumnsAsync(numCols, execAsync).ConfigureAwait(false); - - Values = new IMySqlValue[numCols]; - _uaFieldsUsed = new bool[numCols]; - _fieldHashCi = new Dictionary(StringComparer.OrdinalIgnoreCase); - - for (int i = 0; i < Fields.Length; i++) - { - string columnName = Fields[i].ColumnName; - if (!_fieldHashCi.ContainsKey(columnName)) - _fieldHashCi.Add(columnName, i); - Values[i] = Fields[i].GetValueObject(); - } - } - - private async Task ReadColumnDataAsync(bool outputParms, bool execAsync) - { - for (int i = 0; i < Size; i++) - Values[i] = await _driver.ReadColumnValueAsync(i, Fields[i], Values[i], execAsync).ConfigureAwait(false); - - // if we are caching then we need to save a copy of this row of data values - if (Cached) - _cachedValues.Add((IMySqlValue[])Values.Clone()); - - // we don't need to worry about caching the following since you won't have output - // params with TableDirect commands - if (!outputParms) return; - - bool rowExists = await _driver.FetchDataRowAsync(_statementId, Fields.Length, execAsync).ConfigureAwait(false); - _rowIndex = 0; - - if (rowExists) - throw new MySqlException(Resources.MoreThanOneOPRow); - } - } -} +// Copyright © 2009, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data.Types; +using System; +using System.Collections.Generic; +using System.Data; +using System.Diagnostics; +using System.Threading.Tasks; + +namespace MySql.Data.MySqlClient +{ + internal class ResultSet + { + private Driver _driver; + private bool[] _uaFieldsUsed; + private Dictionary _fieldHashCi; + private int _rowIndex; + private bool _readDone; + private bool _isSequential; + private int _seqIndex; + private readonly int _statementId; + private bool _cached; + private List _cachedValues; + + public ResultSet(int affectedRows, long insertedId) + { + AffectedRows = affectedRows; + InsertedId = insertedId; + _readDone = true; + } + + public static async Task CreateResultSetAsync(Driver d, int statementId, int numCols, bool execAsync) + { + ResultSet resultSet = new ResultSet(d, statementId); + await resultSet.InitializeAsync(numCols, execAsync).ConfigureAwait(false); + return resultSet; + } + + private ResultSet(Driver d, int statementId) + { + AffectedRows = -1; + InsertedId = -1; + _driver = d; + _statementId = statementId; + _rowIndex = -1; + } + + private async Task InitializeAsync(int numCols, bool execAsync) + { + await LoadColumnsAsync(numCols, execAsync).ConfigureAwait(false); + IsOutputParameters = IsOutputParameterResultSet(); + HasRows = await GetNextRowAsync(execAsync).ConfigureAwait(false); + _readDone = !HasRows; + } + + #region Properties + + public bool HasRows { get; private set; } + + public int Size => Fields?.Length ?? 0; + + public MySqlField[] Fields { get; private set; } + + public IMySqlValue[] Values { get; private set; } + + public bool IsOutputParameters { get; set; } + + public int AffectedRows { get; private set; } + + public long InsertedId { get; private set; } + + public int TotalRows { get; private set; } + + public int SkippedRows { get; private set; } + + public bool Cached + { + get { return _cached; } + set + { + _cached = value; + if (_cached && _cachedValues == null) + _cachedValues = new List(); + } + } + + #endregion + + /// + /// return the ordinal for the given column name + /// + /// + /// + public int GetOrdinal(string name) + { + int ordinal; + + // quick hash lookup using CI hash + if (_fieldHashCi.TryGetValue(name, out ordinal)) + return ordinal; + + // Throw an exception if the ordinal cannot be found. + throw new IndexOutOfRangeException( + String.Format(Resources.CouldNotFindColumnName, name)); + } + + /// + /// Retrieve the value as the given column index + /// + /// The column value to retrieve + /// The value as the given column + public IMySqlValue this[int index] + { + get + { + if (_rowIndex < 0) + throw new MySqlException(Resources.AttemptToAccessBeforeRead); + + // keep count of how many columns we have left to access + _uaFieldsUsed[index] = true; + + if (_isSequential && index != _seqIndex) + { + if (index < _seqIndex) + throw new MySqlException(Resources.ReadingPriorColumnUsingSeqAccess); + while (_seqIndex < (index - 1)) + _driver.SkipColumnValue(Values[++_seqIndex]); + Values[index] = _driver.ReadColumnValueAsync(index, Fields[index], Values[index], false).GetAwaiter().GetResult(); + _seqIndex = index; + } + + return Values[index]; + } + } + + private async Task GetNextRowAsync(bool execAsync) + { + bool fetched = await _driver.FetchDataRowAsync(_statementId, Size, execAsync).ConfigureAwait(false); + + if (fetched) + TotalRows++; + + return fetched; + } + + public async Task NextRowAsync(CommandBehavior behavior, bool execAsync) + { + if (_readDone) + { + if (Cached) return CachedNextRow(behavior); + return false; + } + + if ((behavior & CommandBehavior.SingleRow) != 0 && _rowIndex == 0) + return false; + + _isSequential = (behavior & CommandBehavior.SequentialAccess) != 0; + _seqIndex = -1; + + // if we are at row index >= 0 then we need to fetch the data row and load it + if (_rowIndex >= 0) + { + bool fetched; + try + { + fetched = await GetNextRowAsync(execAsync).ConfigureAwait(false); + } + catch (MySqlException ex) + { + if (ex.IsQueryAborted) + { + // avoid hanging on Close() + _readDone = true; + } + throw; + } + + if (!fetched) + { + _readDone = true; + return false; + } + } + + if (!_isSequential) + await ReadColumnDataAsync(false, execAsync).ConfigureAwait(false); + + _rowIndex++; + return true; + } + + private bool CachedNextRow(CommandBehavior behavior) + { + if ((behavior & CommandBehavior.SingleRow) != 0 && _rowIndex == 0) + return false; + if (_rowIndex == (TotalRows - 1)) return false; + _rowIndex++; + Values = _cachedValues[_rowIndex]; + return true; + } + + /// + /// Closes the current resultset, dumping any data still on the wire + /// + public async Task CloseAsync(bool execAsync) + { + if (!_readDone) + { + + // if we have rows but the user didn't read the first one then mark it as skipped + if (HasRows && _rowIndex == -1) + SkippedRows++; + try + { + while (_driver.IsOpen && await _driver.SkipDataRowAsync(execAsync).ConfigureAwait(false)) + { + TotalRows++; + SkippedRows++; + } + } + catch (System.IO.IOException) + { + // it is ok to eat IO exceptions here, we just want to + // close the result set + } + _readDone = true; + } + else if (_driver == null) + CacheClose(); + + _driver = null; + if (Cached) CacheReset(); + } + + private void CacheClose() + { + SkippedRows = TotalRows - _rowIndex - 1; + } + + private void CacheReset() + { + if (!Cached) return; + _rowIndex = -1; + AffectedRows = -1; + InsertedId = -1; + SkippedRows = 0; + } + + public bool FieldRead(int index) + { + Debug.Assert(Size > index); + return _uaFieldsUsed[index]; + } + + public void SetValueObject(int i, IMySqlValue valueObject) + { + Debug.Assert(Values != null); + Debug.Assert(i < Values.Length); + Values[i] = valueObject; + } + + private bool IsOutputParameterResultSet() + { + if (_driver.HasStatus(ServerStatusFlags.OutputParameters)) return true; + + if (Fields.Length == 0) return false; + + for (int x = 0; x < Fields.Length; x++) + if (!Fields[x].ColumnName.StartsWith("@" + StoredProcedure.ParameterPrefix, StringComparison.OrdinalIgnoreCase)) return false; + return true; + } + + /// + /// Loads the column metadata for the current resultset + /// + private async Task LoadColumnsAsync(int numCols, bool execAsync) + { + Fields = await _driver.GetColumnsAsync(numCols, execAsync).ConfigureAwait(false); + + Values = new IMySqlValue[numCols]; + _uaFieldsUsed = new bool[numCols]; + _fieldHashCi = new Dictionary(StringComparer.OrdinalIgnoreCase); + + for (int i = 0; i < Fields.Length; i++) + { + string columnName = Fields[i].ColumnName; + if (!_fieldHashCi.ContainsKey(columnName)) + _fieldHashCi.Add(columnName, i); + Values[i] = Fields[i].GetValueObject(); + } + } + + private async Task ReadColumnDataAsync(bool outputParms, bool execAsync) + { + for (int i = 0; i < Size; i++) + Values[i] = await _driver.ReadColumnValueAsync(i, Fields[i], Values[i], execAsync).ConfigureAwait(false); + + // if we are caching then we need to save a copy of this row of data values + if (Cached) + _cachedValues.Add((IMySqlValue[])Values.Clone()); + + // we don't need to worry about caching the following since you won't have output + // params with TableDirect commands + if (!outputParms) return; + + bool rowExists = await _driver.FetchDataRowAsync(_statementId, Fields.Length, execAsync).ConfigureAwait(false); + _rowIndex = 0; + + if (rowExists) + throw new MySqlException(Resources.MoreThanOneOPRow); + } + } +} diff --git a/MySQL.Data/src/Runtime.cs b/MySQL.Data/src/Runtime.cs index dba59e3ae..beb65869b 100644 --- a/MySQL.Data/src/Runtime.cs +++ b/MySQL.Data/src/Runtime.cs @@ -1,56 +1,56 @@ -// Copyright © 2014, 2016, Oracle and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - - -using System; - -namespace MySql.Web.Security -{ - internal static class Runtime - { - private static bool inited; - private static bool isMono; - - public static bool IsMono - { - get - { - if (!inited) - Init(); - return isMono; - } - } - - private static void Init() - { - Type t = Type.GetType("Mono.Runtime"); - isMono = t != null; - inited = true; - } - } -} +// Copyright © 2014, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +using System; + +namespace MySql.Web.Security +{ + internal static class Runtime + { + private static bool inited; + private static bool isMono; + + public static bool IsMono + { + get + { + if (!inited) + Init(); + return isMono; + } + } + + private static void Init() + { + Type t = Type.GetType("Mono.Runtime"); + isMono = t != null; + inited = true; + } + } +} diff --git a/MySQL.Data/src/Schema.cs b/MySQL.Data/src/Schema.cs index 0f04fcfb5..d63a28d86 100644 --- a/MySQL.Data/src/Schema.cs +++ b/MySQL.Data/src/Schema.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/SchemaProvider.cs b/MySQL.Data/src/SchemaProvider.cs index eae7efdc6..468521d66 100644 --- a/MySQL.Data/src/SchemaProvider.cs +++ b/MySQL.Data/src/SchemaProvider.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2004, 2023, Oracle and/or its affiliates. +// Copyright © 2004, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -295,9 +295,7 @@ public virtual async Task GetIndexesAsync(string[] restri foreach (MySqlSchemaRow index in indexes.Rows) { - if (1 != (connection.driver.Version.isAtLeast(8, 0, 1) ? - (uint)index["SEQ_IN_INDEX"] : - (long)index["SEQ_IN_INDEX"])) + if (!index["SEQ_IN_INDEX"].Equals(Convert.ChangeType(1, index["SEQ_IN_INDEX"].GetType()))) continue; if (restrictions != null && restrictions.Length == 4 && restrictions[3] != null && diff --git a/MySQL.Data/src/Statement.cs b/MySQL.Data/src/Statement.cs index e847a3f03..2b3c81d54 100644 --- a/MySQL.Data/src/Statement.cs +++ b/MySQL.Data/src/Statement.cs @@ -1,351 +1,356 @@ -// Copyright (c) 2004, 2023, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data.Common; -using System; -using System.Collections; -using System.Collections.Generic; -using System.Data; -using System.Globalization; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace MySql.Data.MySqlClient -{ - internal abstract class Statement - { - protected MySqlCommand command; - private readonly List _buffers; - protected string commandText; - protected int paramsPosition; - - internal const string ParameterPrefix = "_cnet_param_"; - public virtual bool ServerProvidingOutputParameters { get; internal set; } - - private Statement(MySqlCommand cmd) - { - command = cmd; - _buffers = new List(); - } - - protected Statement(MySqlCommand cmd, string text) - : this(cmd) - { - commandText = text; - } - - #region Properties - - public virtual string ResolvedCommandText - { - get { return commandText; } - } - - protected Driver Driver => command.Connection.driver; - - protected MySqlConnection Connection => command.Connection; - - protected MySqlParameterCollection Parameters => command.Parameters; - - protected MySqlAttributeCollection Attributes => command.Attributes; - - #endregion - - public virtual void Close(MySqlDataReader reader) { } - - public virtual void Resolve(bool preparing) - { - if (!command.InternallyCreated || !(ResolvedCommandText != null && Parameters.Count == 0)) - { - ServerProvidingOutputParameters = Driver.SupportsOutputParameters && preparing; - if (Parameters.Cast().Where(x => x.Direction == ParameterDirection.Output).Any()) - { - string setSql = SetSql(Parameters, preparing); - string outSql = CreateOutputSelect(Parameters, preparing); - commandText = String.Format("{0}{1}", setSql, outSql); - } - } - } - - private string SetSql(MySqlParameterCollection parms, bool preparing) - { - StringBuilder setSql = new StringBuilder(); - setSql.Append(commandText); - foreach (MySqlParameter p in parms) - { - if (p.Direction != ParameterDirection.Output) continue; - - string uName = "@" + ParameterPrefix + p.BaseName; - setSql.Replace(p.ParameterName, uName); - } - return setSql.ToString(); - } - - private string CreateOutputSelect(MySqlParameterCollection parms, bool preparing) - { - StringBuilder outputSql = new StringBuilder(); - string delimiter = string.Empty; - - foreach (MySqlParameter p in parms) - { - if (p.Direction == ParameterDirection.Output) - { - string uName = "@" + ParameterPrefix + p.BaseName; - outputSql.AppendFormat(CultureInfo.InvariantCulture, "{0}{1}", delimiter, uName); - delimiter = ", "; - } - } - - if (outputSql.Length == 0) return String.Empty; - - else if (command.Connection.Settings.AllowBatch && !preparing) - return String.Format("; SELECT {0}", outputSql.ToString()); - else - { - command.OutSql = String.Format("SELECT {0}", outputSql.ToString()); - return String.Empty; - } - } - - public virtual async Task ExecuteAsync(bool execAsync) - { - // we keep a reference to this until we are done - await BindParametersAsync(execAsync).ConfigureAwait(false); - await ExecuteNextAsync(execAsync).ConfigureAwait(false); - } - - public virtual async Task ExecuteNextAsync(bool execAsync) - { - if (_buffers.Count == 0) - return false; - - MySqlPacket packet = _buffers[0]; - await Driver.SendQueryAsync(packet, paramsPosition, execAsync).ConfigureAwait(false); - _buffers.RemoveAt(0); - return true; - } - - protected async Task BindParametersAsync(bool execAsync) - { - MySqlParameterCollection parameters = command.Parameters; - MySqlAttributeCollection attributes = command.Attributes; - int index = 0; - - while (true) - { - MySqlPacket packet = await BuildQueryAttributesPacketAsync(attributes, execAsync).ConfigureAwait(false); - await InternalBindParametersAsync(ResolvedCommandText, parameters, packet, execAsync).ConfigureAwait(false); - - // if we are not batching, then we are done. This is only really relevant the - // first time through - if (command.Batch == null) return; - while (index < command.Batch.Count) - { - MySqlCommand batchedCmd = command.Batch[index++]; - packet = (MySqlPacket)_buffers[_buffers.Count - 1]; - - // now we make a guess if this statement will fit in our current stream - long estimatedCmdSize = batchedCmd.EstimatedSize(); - if (((packet.Length - 4) + estimatedCmdSize) > Connection.driver.MaxPacketSize) - // it won't, so we raise an exception to avoid a partial batch - throw new MySqlException(Resources.QueryTooLarge, (int)MySqlErrorCode.PacketTooLarge); - - // looks like we might have room for it so we remember the current end of the stream - _buffers.RemoveAt(_buffers.Count - 1); - //long originalLength = packet.Length - 4; - - // and attempt to stream the next command - string text = ResolvedCommandText; - if (text.StartsWith("(", StringComparison.Ordinal)) - await packet.WriteStringNoNullAsync(", ", execAsync).ConfigureAwait(false); - else - await packet.WriteStringNoNullAsync("; ", execAsync).ConfigureAwait(false); - - await InternalBindParametersAsync(text, batchedCmd.Parameters, packet, execAsync).ConfigureAwait(false); - if ((packet.Length - 4) > Connection.driver.MaxPacketSize) - { - //TODO - //stream.InternalBuffer.SetLength(originalLength); - parameters = batchedCmd.Parameters; - break; - } - } - if (index == command.Batch.Count) - return; - } - } - - /// - /// Builds the initial part of the COM_QUERY packet - /// - /// Collection of attributes - /// A - /// Boolean that indicates if the function will be executed asynchronously. - private async Task BuildQueryAttributesPacketAsync(MySqlAttributeCollection attributes, bool execAsync) - { - MySqlPacket packet; - packet = new MySqlPacket(Driver.Encoding) { Version = Driver.Version }; - packet.WriteByte(0); - - if (attributes.Count > 0 && !Driver.SupportsQueryAttributes) - MySqlTrace.LogWarning(Connection.ServerThread, string.Format(Resources.QueryAttributesNotSupported, Driver.Version)); - else if (Driver.SupportsQueryAttributes) - { - int paramCount = attributes.Count; - await packet.WriteLengthAsync(paramCount, execAsync).ConfigureAwait(false); // int parameter_count - Number of parameters - packet.WriteByte(1); // int parameter_set_count - Number of parameter sets. Currently always 1 - - if (paramCount > 0) - { - // now prepare our null map - BitArray _nullMap = new BitArray(paramCount); - int numNullBytes = (_nullMap.Length + 7) / 8; - int _nullMapPosition = packet.Position; - packet.Position += numNullBytes; // leave room for our null map - packet.WriteByte((byte)1); // new_params_bind_flag - Always 1. Malformed packet error if not 1 - - // set type and name for each attribute - foreach (MySqlAttribute attribute in attributes) - { - await packet.WriteIntegerAsync(attribute.GetPSType(), 2, execAsync).ConfigureAwait(false); - await packet.WriteLenStringAsync(attribute.AttributeName, execAsync).ConfigureAwait(false); - } - - // set value for each attribute - for (int i = 0; i < attributes.Count; i++) - { - MySqlAttribute attr = attributes[i]; - _nullMap[i] = (attr.Value == DBNull.Value || attr.Value == null); - if (_nullMap[i]) continue; - await attr.SerializeAsync(packet, true, Connection.Settings, execAsync).ConfigureAwait(false); - } - - byte[] tempByteArray = new byte[(_nullMap.Length + 7) >> 3]; - _nullMap.CopyTo(tempByteArray, 0); - - Array.Copy(tempByteArray, 0, packet.Buffer, _nullMapPosition, tempByteArray.Length); - } - } - - paramsPosition = packet.Position; - return packet; - } - - private async Task InternalBindParametersAsync(string sql, MySqlParameterCollection parameters, MySqlPacket packet, bool execAsync) - { - bool sqlServerMode = command.Connection.Settings.SqlServerMode; - - MySqlTokenizer tokenizer = new MySqlTokenizer(sql) - { - ReturnComments = true, - SqlServerMode = sqlServerMode - }; - - int pos = 0; - string token = tokenizer.NextToken(); - int parameterCount = 0; - while (token != null) - { - // serialize everything that came before the token (i.e. whitespace) - await packet.WriteStringNoNullAsync(sql.Substring(pos, tokenizer.StartIndex - pos), execAsync).ConfigureAwait(false); - pos = tokenizer.StopIndex; - - if (MySqlTokenizer.IsParameter(token)) - { - if ((!parameters.containsUnnamedParameters && token.Length == 1 && parameterCount > 0) || parameters.containsUnnamedParameters && token.Length > 1) - throw new MySqlException(Resources.MixedParameterNamingNotAllowed); - - parameters.containsUnnamedParameters = token.Length == 1; - if (await SerializeParameterAsync(parameters, packet, token, parameterCount, execAsync).ConfigureAwait(false)) - token = null; - parameterCount++; - } - - if (token != null) - { - if (sqlServerMode && tokenizer.Quoted && token.StartsWith("[", StringComparison.Ordinal)) - token = String.Format("`{0}`", token.Substring(1, token.Length - 2)); - - await packet.WriteStringNoNullAsync(token, execAsync).ConfigureAwait(false); - } - token = tokenizer.NextToken(); - } - _buffers.Add(packet); - } - - protected virtual bool ShouldIgnoreMissingParameter(string parameterName) - { - if (Connection.Settings.AllowUserVariables) - return true; - if (parameterName.StartsWith("@" + StoredProcedure.ParameterPrefix, StringComparison.OrdinalIgnoreCase)) - return true; - if (parameterName.Length > 1 && - (parameterName[1] == '`' || parameterName[1] == '\'')) - return true; - return false; - } - - /// - /// Serializes the given parameter to the given memory stream - /// - /// - /// This method is called by PrepareSqlBuffers to convert the given - /// parameter to bytes and write those bytes to the given memory stream. - /// - /// - /// True if the parameter was successfully serialized, false otherwise. - private async Task SerializeParameterAsync(MySqlParameterCollection parameters, MySqlPacket packet, string parmName, int parameterIndex, bool execAsync) - { - MySqlParameter parameter = null; - - if (!parameters.containsUnnamedParameters) - parameter = parameters.GetParameterFlexible(parmName, false); - else - { - if (parameterIndex <= parameters.Count) - parameter = parameters[parameterIndex]; - else - throw new MySqlException(Resources.ParameterIndexNotFound); - } - - if (parameter == null) - { - // if we are allowing user variables and the parameter name starts with @ - // then we can't throw an exception - if (parmName.StartsWith("@", StringComparison.Ordinal) && ShouldIgnoreMissingParameter(parmName)) - return false; - throw new MySqlException( - String.Format(Resources.ParameterMustBeDefined, parmName)); - } - - await parameter.SerializeAsync(packet, false, Connection.Settings, execAsync).ConfigureAwait(false); - return true; - } - } -} +// Copyright © 2004, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data.Common; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Data; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MySql.Data.MySqlClient +{ + internal abstract class Statement + { + protected MySqlCommand command; + private readonly List _buffers; + protected string commandText; + protected int paramsPosition; + + internal const string ParameterPrefix = "_cnet_param_"; + public virtual bool ServerProvidingOutputParameters { get; internal set; } + + private Statement(MySqlCommand cmd) + { + command = cmd; + _buffers = new List(); + } + + protected Statement(MySqlCommand cmd, string text) + : this(cmd) + { + commandText = text; + } + + #region Properties + + public virtual string ResolvedCommandText + { + get { return commandText; } + } + + protected Driver Driver => command.Connection.driver; + + protected MySqlConnection Connection => command.Connection; + + protected MySqlParameterCollection Parameters => command.Parameters; + + protected MySqlAttributeCollection Attributes => command.Attributes; + + #endregion + + public virtual void Close(MySqlDataReader reader) { } + + public virtual void Resolve(bool preparing) + { + if (!command.InternallyCreated || !(ResolvedCommandText != null && Parameters.Count == 0)) + { + ServerProvidingOutputParameters = Driver.SupportsOutputParameters && preparing; + if (Parameters.Cast().Where(x => x.Direction == ParameterDirection.Output).Any()) + { + string setSql = SetSql(Parameters, preparing); + string outSql = CreateOutputSelect(Parameters, preparing); + commandText = String.Format("{0}{1}", setSql, outSql); + } + } + } + + private string SetSql(MySqlParameterCollection parms, bool preparing) + { + StringBuilder setSql = new StringBuilder(); + setSql.Append(commandText); + foreach (MySqlParameter p in parms) + { + if (p.Direction != ParameterDirection.Output) continue; + + string uName = "@" + ParameterPrefix + p.BaseName; + setSql.Replace(p.ParameterName, uName); + } + return setSql.ToString(); + } + + private string CreateOutputSelect(MySqlParameterCollection parms, bool preparing) + { + StringBuilder outputSql = new StringBuilder(); + string delimiter = string.Empty; + + foreach (MySqlParameter p in parms) + { + if (p.Direction == ParameterDirection.Output) + { + string uName = "@" + ParameterPrefix + p.BaseName; + outputSql.AppendFormat(CultureInfo.InvariantCulture, "{0}{1}", delimiter, uName); + delimiter = ", "; + } + } + + if (outputSql.Length == 0) return String.Empty; + + else if (command.Connection.Settings.AllowBatch && !preparing) + return String.Format("; SELECT {0}", outputSql.ToString()); + else + { + command.OutSql = String.Format("SELECT {0}", outputSql.ToString()); + return String.Empty; + } + } + + public virtual async Task ExecuteAsync(bool execAsync) + { + // we keep a reference to this until we are done + await BindParametersAsync(execAsync).ConfigureAwait(false); + await ExecuteNextAsync(execAsync).ConfigureAwait(false); + } + + public virtual async Task ExecuteNextAsync(bool execAsync) + { + if (_buffers.Count == 0) + return false; + + MySqlPacket packet = _buffers[0]; + await Driver.SendQueryAsync(packet, paramsPosition, execAsync).ConfigureAwait(false); + _buffers.RemoveAt(0); + return true; + } + + protected async Task BindParametersAsync(bool execAsync) + { + MySqlParameterCollection parameters = command.Parameters; + MySqlAttributeCollection attributes = command.Attributes; + int index = 0; + + while (true) + { + MySqlPacket packet = await BuildQueryAttributesPacketAsync(attributes, execAsync).ConfigureAwait(false); + await InternalBindParametersAsync(ResolvedCommandText, parameters, packet, execAsync).ConfigureAwait(false); + + // if we are not batching, then we are done. This is only really relevant the + // first time through + if (command.Batch == null) return; + while (index < command.Batch.Count) + { + MySqlCommand batchedCmd = command.Batch[index++]; + packet = (MySqlPacket)_buffers[_buffers.Count - 1]; + + // now we make a guess if this statement will fit in our current stream + long estimatedCmdSize = batchedCmd.EstimatedSize(); + if (((packet.Length - 4) + estimatedCmdSize) > Connection.driver.MaxPacketSize) + // it won't, so we raise an exception to avoid a partial batch + throw new MySqlException(Resources.QueryTooLarge, (int)MySqlErrorCode.PacketTooLarge); + + // looks like we might have room for it so we remember the current end of the stream + _buffers.RemoveAt(_buffers.Count - 1); + //long originalLength = packet.Length - 4; + + // and attempt to stream the next command + string text = ""; + if (Connection.driver.Settings.RewriteBatchedStatements) + text = batchedCmd.BatchableCommandText; + else + text = ResolvedCommandText; + + if (text.StartsWith("(", StringComparison.Ordinal)) + await packet.WriteStringNoNullAsync(", ", execAsync).ConfigureAwait(false); + else + await packet.WriteStringNoNullAsync("; ", execAsync).ConfigureAwait(false); + + await InternalBindParametersAsync(text, batchedCmd.Parameters, packet, execAsync).ConfigureAwait(false); + if ((packet.Length - 4) > Connection.driver.MaxPacketSize) + { + //TODO + //stream.InternalBuffer.SetLength(originalLength); + parameters = batchedCmd.Parameters; + break; + } + } + if (index == command.Batch.Count) + return; + } + } + + /// + /// Builds the initial part of the COM_QUERY packet + /// + /// Collection of attributes + /// A + /// Boolean that indicates if the function will be executed asynchronously. + private async Task BuildQueryAttributesPacketAsync(MySqlAttributeCollection attributes, bool execAsync) + { + MySqlPacket packet; + packet = new MySqlPacket(Driver.Encoding) { Version = Driver.Version }; + packet.WriteByte(0); + + if (attributes.Count > 0 && !Driver.SupportsQueryAttributes) + MySqlTrace.LogWarning(Connection.ServerThread, string.Format(Resources.QueryAttributesNotSupported, Driver.Version)); + else if (Driver.SupportsQueryAttributes) + { + int paramCount = attributes.Count; + await packet.WriteLengthAsync(paramCount, execAsync).ConfigureAwait(false); // int parameter_count - Number of parameters + packet.WriteByte(1); // int parameter_set_count - Number of parameter sets. Currently always 1 + + if (paramCount > 0) + { + // now prepare our null map + BitArray _nullMap = new BitArray(paramCount); + int numNullBytes = (_nullMap.Length + 7) / 8; + int _nullMapPosition = packet.Position; + packet.Position += numNullBytes; // leave room for our null map + packet.WriteByte((byte)1); // new_params_bind_flag - Always 1. Malformed packet error if not 1 + + // set type and name for each attribute + foreach (MySqlAttribute attribute in attributes) + { + await packet.WriteIntegerAsync(attribute.GetPSType(), 2, execAsync).ConfigureAwait(false); + await packet.WriteLenStringAsync(attribute.AttributeName, execAsync).ConfigureAwait(false); + } + + // set value for each attribute + for (int i = 0; i < attributes.Count; i++) + { + MySqlAttribute attr = attributes[i]; + _nullMap[i] = (attr.Value == DBNull.Value || attr.Value == null); + if (_nullMap[i]) continue; + await attr.SerializeAsync(packet, true, Connection.Settings, execAsync).ConfigureAwait(false); + } + + byte[] tempByteArray = new byte[(_nullMap.Length + 7) >> 3]; + _nullMap.CopyTo(tempByteArray, 0); + + Array.Copy(tempByteArray, 0, packet.Buffer, _nullMapPosition, tempByteArray.Length); + } + } + + paramsPosition = packet.Position; + return packet; + } + + private async Task InternalBindParametersAsync(string sql, MySqlParameterCollection parameters, MySqlPacket packet, bool execAsync) + { + bool sqlServerMode = command.Connection.Settings.SqlServerMode; + + MySqlTokenizer tokenizer = new MySqlTokenizer(sql) + { + ReturnComments = true, + SqlServerMode = sqlServerMode + }; + + int pos = 0; + string token = tokenizer.NextToken(); + int parameterCount = 0; + while (token != null) + { + // serialize everything that came before the token (i.e. whitespace) + await packet.WriteStringNoNullAsync(sql.Substring(pos, tokenizer.StartIndex - pos), execAsync).ConfigureAwait(false); + pos = tokenizer.StopIndex; + + if (MySqlTokenizer.IsParameter(token)) + { + if ((!parameters.containsUnnamedParameters && token.Length == 1 && parameterCount > 0) || parameters.containsUnnamedParameters && token.Length > 1) + throw new MySqlException(Resources.MixedParameterNamingNotAllowed); + + parameters.containsUnnamedParameters = token.Length == 1; + if (await SerializeParameterAsync(parameters, packet, token, parameterCount, execAsync).ConfigureAwait(false)) + token = null; + parameterCount++; + } + + if (token != null) + { + if (sqlServerMode && tokenizer.Quoted && token.StartsWith("[", StringComparison.Ordinal)) + token = String.Format("`{0}`", token.Substring(1, token.Length - 2)); + + await packet.WriteStringNoNullAsync(token, execAsync).ConfigureAwait(false); + } + token = tokenizer.NextToken(); + } + _buffers.Add(packet); + } + + protected virtual bool ShouldIgnoreMissingParameter(string parameterName) + { + if (Connection.Settings.AllowUserVariables) + return true; + if (parameterName.StartsWith("@" + StoredProcedure.ParameterPrefix, StringComparison.OrdinalIgnoreCase)) + return true; + if (parameterName.Length > 1 && + (parameterName[1] == '`' || parameterName[1] == '\'')) + return true; + return false; + } + + /// + /// Serializes the given parameter to the given memory stream + /// + /// + /// This method is called by PrepareSqlBuffers to convert the given + /// parameter to bytes and write those bytes to the given memory stream. + /// + /// + /// True if the parameter was successfully serialized, false otherwise. + private async Task SerializeParameterAsync(MySqlParameterCollection parameters, MySqlPacket packet, string parmName, int parameterIndex, bool execAsync) + { + MySqlParameter parameter = null; + + if (!parameters.containsUnnamedParameters) + parameter = parameters.GetParameterFlexible(parmName, false); + else + { + if (parameterIndex <= parameters.Count) + parameter = parameters[parameterIndex]; + else + throw new MySqlException(Resources.ParameterIndexNotFound); + } + + if (parameter == null) + { + // if we are allowing user variables and the parameter name starts with @ + // then we can't throw an exception + if (parmName.StartsWith("@", StringComparison.Ordinal) && ShouldIgnoreMissingParameter(parmName)) + return false; + throw new MySqlException( + String.Format(Resources.ParameterMustBeDefined, parmName)); + } + + await parameter.SerializeAsync(packet, false, Connection.Settings, execAsync).ConfigureAwait(false); + return true; + } + } +} diff --git a/MySQL.Data/src/StoredProcedure.cs b/MySQL.Data/src/StoredProcedure.cs index 80a56d1d7..4a7cc52bc 100644 --- a/MySQL.Data/src/StoredProcedure.cs +++ b/MySQL.Data/src/StoredProcedure.cs @@ -1,377 +1,377 @@ -// Copyright (c) 2004, 2023, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data.Common; -using MySql.Data.Types; -using System; -using System.Data; -using System.Globalization; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace MySql.Data.MySqlClient -{ - /// - /// Summary description for StoredProcedure. - /// - internal class StoredProcedure : PreparableStatement - { - private string _outSelect; - private string resolvedCommandText; - - public StoredProcedure(MySqlCommand cmd, string text) - : base(cmd, text) - { - } - - private MySqlParameter GetReturnParameter() - { - return Parameters?.Cast().FirstOrDefault(p => p.Direction == ParameterDirection.ReturnValue); - } - - public override string ResolvedCommandText - { - get { return resolvedCommandText; } - } - - internal string GetCacheKey(string spName) - { - string retValue = String.Empty; - StringBuilder key = new StringBuilder(spName); - key.Append("("); - string delimiter = ""; - foreach (MySqlParameter p in command.Parameters) - { - if (p.Direction == ParameterDirection.ReturnValue) - retValue = "?="; - else - { - key.AppendFormat(CultureInfo.InvariantCulture, "{0}?", delimiter); - delimiter = ","; - } - } - key.Append(")"); - return retValue + key.ToString(); - } - - private async Task GetParametersAsync(string procName, bool execAsync) - { - string procCacheKey = GetCacheKey(procName); - ProcedureCacheEntry entry = await Connection.ProcedureCache.GetProcedureAsync(Connection, procName, procCacheKey, execAsync).ConfigureAwait(false); - return entry; - } - - public static string GetFlags(string dtd) - { - int x = dtd.Length - 1; - while (x > 0 && (Char.IsLetterOrDigit(dtd[x]) || dtd[x] == ' ')) - x--; - string dtdSubstring = dtd.Substring(x); - return StringUtility.ToUpperInvariant(dtdSubstring); - } - - internal static string FixProcedureName(string spName) - { - if (IsSyntacticallyCorrect(spName)) return spName; - - return $"`{spName.Replace("`", "``")}`"; - } - - /// - /// Verify if the string passed as argument is syntactically correct. - /// - /// String to be analyzed - /// true if is correct; otherwise, false. - internal static bool IsSyntacticallyCorrect(string spName) - { - const char backtick = '`', dot = '.'; - - char[] spNameArray = spName.ToArray(); - bool quoted = spName.StartsWith("`"); - bool splittingDot = false; - - for (int i = 1; i < spNameArray.Length; i++) - { - if (spNameArray[i] == backtick) - { - // We are in quoted mode. - if (quoted) - { - // we are not in the last char of the string. - if (i < spNameArray.Length - 1) - { - // Get the next char. - char nextChar = spNameArray[i + 1]; - - // If the next char are neither a dot nor a backtick, - // it means the input string is not well quoted and exits the loop. - if (nextChar != dot && nextChar != backtick) - return false; - - // If the next char is a backtick, move forward 2 positions. - if (nextChar == backtick) - i++; - - // If the next char is a dot, that means we are not in quoted mode anymore. - if (nextChar == dot) - { - quoted = false; - splittingDot = true; - i++; - } - } - } - // Not quoted mode - else - { - // If the previous char is not a dot or the string does not end with a backtick, - // it means the input string is not well quoted and exits the loop; - // otherwise, enter quoted mode. - if (spNameArray[i - 1] != dot || !spName.EndsWith("`")) - return false; - - quoted = true; - } - } - else if (spNameArray[i] == dot && !quoted) - if (splittingDot) - return false; - else - splittingDot = true; - } - - // If we reach to the very last char of the string, it means the string is well written. - return true; - } - - private MySqlParameter GetAndFixParameter(string spName, MySqlSchemaRow param, bool realAsFloat, MySqlParameter returnParameter) - { - string mode = (string)param["PARAMETER_MODE"]; - string pName = (string)param["PARAMETER_NAME"]; - string datatype = (string)param["DATA_TYPE"]; - bool unsigned = GetFlags(param["DTD_IDENTIFIER"].ToString()).IndexOf("UNSIGNED") != -1; - - if (Convert.ToUInt64(param["ORDINAL_POSITION"]) == 0) - { - if (returnParameter == null) - throw new InvalidOperationException(String.Format(Resources.RoutineRequiresReturnParameter, spName)); - pName = returnParameter.ParameterName; - } - - // make sure the parameters given to us have an appropriate type set if it's not already - MySqlParameter p = command.Parameters.GetParameterFlexible(pName, true); - if (!p.TypeHasBeenSet) - p.MySqlDbType = MetaData.NameToType(datatype, unsigned, realAsFloat, Connection); - - return p; - } - - private async Task CheckParametersAsync(string spName, bool execAsync) - { - MySqlParameterCollection newParms = new MySqlParameterCollection(command); - MySqlParameter returnParameter = GetReturnParameter(); - - ProcedureCacheEntry entry = await GetParametersAsync(spName, execAsync).ConfigureAwait(false); - if (entry.procedure == null || entry.procedure.Rows.Count == 0) - throw new InvalidOperationException(String.Format(Resources.RoutineNotFound, spName)); - - bool realAsFloat = entry.procedure.Rows[0]["SQL_MODE"].ToString().IndexOf("REAL_AS_FLOAT") != -1; - - foreach (MySqlSchemaRow param in entry.parameters.Rows) - newParms.Add(GetAndFixParameter(spName, param, realAsFloat, returnParameter)); - return newParms; - } - - public override void Resolve(bool preparing) - { - // check to see if we are already resolved - if (ResolvedCommandText != null) return; - - ServerProvidingOutputParameters = Driver.SupportsOutputParameters && preparing; - - // first retrieve the procedure definition from our - // procedure cache - string spName = commandText; - spName = FixProcedureName(spName); - - MySqlParameter returnParameter = GetReturnParameter(); - - MySqlParameterCollection parms = command.Connection.Settings.CheckParameters ? - CheckParametersAsync(spName, false).GetAwaiter().GetResult() : Parameters; - - string setSql = SetUserVariables(parms, preparing); - string callSql = CreateCallStatement(spName, returnParameter, parms); - string outSql = CreateOutputSelect(parms, preparing); - resolvedCommandText = String.Format("{0}{1}{2}", setSql, callSql, outSql); - } - - private string SetUserVariables(MySqlParameterCollection parms, bool preparing) - { - StringBuilder setSql = new StringBuilder(); - - if (ServerProvidingOutputParameters) return setSql.ToString(); - - string delimiter = String.Empty; - foreach (MySqlParameter p in parms) - { - if (p.Direction != ParameterDirection.InputOutput) continue; - - string pName = "@" + p.BaseName; - string uName = "@" + ParameterPrefix + p.BaseName; - string sql = String.Format("SET {0}={1}", uName, pName); - - if (command.Connection.Settings.AllowBatch && !preparing) - { - setSql.AppendFormat(CultureInfo.InvariantCulture, "{0}{1}", delimiter, sql); - delimiter = "; "; - } - else - { - MySqlCommand cmd = new MySqlCommand(sql, command.Connection); - cmd.Parameters.Add(p); - cmd.ExecuteNonQuery(); - } - } - if (setSql.Length > 0) - setSql.Append("; "); - return setSql.ToString(); - } - - private string CreateCallStatement(string spName, MySqlParameter returnParameter, MySqlParameterCollection parms) - { - StringBuilder callSql = new StringBuilder(); - - string delimiter = String.Empty; - foreach (MySqlParameter p in parms) - { - if (p.Direction == ParameterDirection.ReturnValue) continue; - - string pName = "@" + p.BaseName; - string uName = "@" + ParameterPrefix + p.BaseName; - - bool useRealVar = p.Direction == ParameterDirection.Input || ServerProvidingOutputParameters; - callSql.AppendFormat(CultureInfo.InvariantCulture, "{0}{1}", delimiter, useRealVar ? pName : uName); - delimiter = ", "; - } - - if (returnParameter == null) - return String.Format("CALL {0}({1})", spName, callSql.ToString()); - else - return String.Format("SET @{0}{1}={2}({3})", ParameterPrefix, returnParameter.BaseName, spName, callSql.ToString()); - } - - private string CreateOutputSelect(MySqlParameterCollection parms, bool preparing) - { - StringBuilder outSql = new StringBuilder(); - - string delimiter = String.Empty; - foreach (MySqlParameter p in parms) - { - if (p.Direction == ParameterDirection.Input) continue; - if ((p.Direction == ParameterDirection.InputOutput || - p.Direction == ParameterDirection.Output) && - ServerProvidingOutputParameters) continue; - string pName = "@" + p.BaseName; - string uName = "@" + ParameterPrefix + p.BaseName; - - outSql.AppendFormat(CultureInfo.InvariantCulture, "{0}{1}", delimiter, uName); - delimiter = ", "; - } - - if (outSql.Length == 0) return String.Empty; - - if (command.Connection.Settings.AllowBatch && !preparing) - return String.Format(";SELECT {0}", outSql.ToString()); - - _outSelect = String.Format("SELECT {0}", outSql.ToString()); - return String.Empty; - } - - internal void ProcessOutputParameters(MySqlDataReader reader) - { - // We apparently need to always adjust our output types since the server - // provided data types are not always right - AdjustOutputTypes(reader); - - if ((reader.CommandBehavior & CommandBehavior.SchemaOnly) != 0) - return; - - // now read the output parameters data row - reader.Read(); - - string prefix = "@" + StoredProcedure.ParameterPrefix; - - for (int i = 0; i < reader.FieldCount; i++) - { - string fieldName = reader.GetName(i); - if (fieldName.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) - fieldName = fieldName.Remove(0, prefix.Length); - MySqlParameter parameter = command.Parameters.GetParameterFlexible(fieldName, true); - parameter.Value = reader.GetValue(i); - } - } - - private void AdjustOutputTypes(MySqlDataReader reader) - { - // since MySQL likes to return user variables as strings - // we reset the types of the readers internal value objects - // this will allow those value objects to parse the string based - // return values - for (int i = 0; i < reader.FieldCount; i++) - { - string fieldName = reader.GetName(i); - if (fieldName.IndexOf(StoredProcedure.ParameterPrefix) != -1) - fieldName = fieldName.Remove(0, StoredProcedure.ParameterPrefix.Length + 1); - MySqlParameter parameter = command.Parameters.GetParameterFlexible(fieldName, true); - - IMySqlValue v = MySqlField.GetIMySqlValue(parameter.MySqlDbType); - if (v is MySqlBit) - { - MySqlBit bit = (MySqlBit)v; - bit.ReadAsString = true; - reader.ResultSet.SetValueObject(i, bit); - } - else - reader.ResultSet.SetValueObject(i, v); - } - } - - public override void Close(MySqlDataReader reader) - { - if (String.IsNullOrEmpty(_outSelect)) return; - if ((reader.CommandBehavior & CommandBehavior.SchemaOnly) != 0) return; - - MySqlCommand cmd = new MySqlCommand(_outSelect, command.Connection); - cmd.InternallyCreated = true; - - using (MySqlDataReader rdr = cmd.ExecuteReader(reader.CommandBehavior)) - ProcessOutputParameters(rdr); - } - } -} +// Copyright © 2004, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data.Common; +using MySql.Data.Types; +using System; +using System.Data; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MySql.Data.MySqlClient +{ + /// + /// Summary description for StoredProcedure. + /// + internal class StoredProcedure : PreparableStatement + { + private string _outSelect; + private string resolvedCommandText; + + public StoredProcedure(MySqlCommand cmd, string text) + : base(cmd, text) + { + } + + private MySqlParameter GetReturnParameter() + { + return Parameters?.Cast().FirstOrDefault(p => p.Direction == ParameterDirection.ReturnValue); + } + + public override string ResolvedCommandText + { + get { return resolvedCommandText; } + } + + internal string GetCacheKey(string spName) + { + string retValue = String.Empty; + StringBuilder key = new StringBuilder(spName); + key.Append("("); + string delimiter = ""; + foreach (MySqlParameter p in command.Parameters) + { + if (p.Direction == ParameterDirection.ReturnValue) + retValue = "?="; + else + { + key.AppendFormat(CultureInfo.InvariantCulture, "{0}?", delimiter); + delimiter = ","; + } + } + key.Append(")"); + return retValue + key.ToString(); + } + + private async Task GetParametersAsync(string procName, bool execAsync) + { + string procCacheKey = GetCacheKey(procName); + ProcedureCacheEntry entry = await Connection.ProcedureCache.GetProcedureAsync(Connection, procName, procCacheKey, execAsync).ConfigureAwait(false); + return entry; + } + + public static string GetFlags(string dtd) + { + int x = dtd.Length - 1; + while (x > 0 && (Char.IsLetterOrDigit(dtd[x]) || dtd[x] == ' ')) + x--; + string dtdSubstring = dtd.Substring(x); + return StringUtility.ToUpperInvariant(dtdSubstring); + } + + internal static string FixProcedureName(string spName) + { + if (IsSyntacticallyCorrect(spName)) return spName; + + return $"`{spName.Replace("`", "``")}`"; + } + + /// + /// Verify if the string passed as argument is syntactically correct. + /// + /// String to be analyzed + /// true if is correct; otherwise, false. + internal static bool IsSyntacticallyCorrect(string spName) + { + const char backtick = '`', dot = '.'; + + char[] spNameArray = spName.ToArray(); + bool quoted = spName.StartsWith("`"); + bool splittingDot = false; + + for (int i = 1; i < spNameArray.Length; i++) + { + if (spNameArray[i] == backtick) + { + // We are in quoted mode. + if (quoted) + { + // we are not in the last char of the string. + if (i < spNameArray.Length - 1) + { + // Get the next char. + char nextChar = spNameArray[i + 1]; + + // If the next char are neither a dot nor a backtick, + // it means the input string is not well quoted and exits the loop. + if (nextChar != dot && nextChar != backtick) + return false; + + // If the next char is a backtick, move forward 2 positions. + if (nextChar == backtick) + i++; + + // If the next char is a dot, that means we are not in quoted mode anymore. + if (nextChar == dot) + { + quoted = false; + splittingDot = true; + i++; + } + } + } + // Not quoted mode + else + { + // If the previous char is not a dot or the string does not end with a backtick, + // it means the input string is not well quoted and exits the loop; + // otherwise, enter quoted mode. + if (spNameArray[i - 1] != dot || !spName.EndsWith("`")) + return false; + + quoted = true; + } + } + else if (spNameArray[i] == dot && !quoted) + if (splittingDot) + return false; + else + splittingDot = true; + } + + // If we reach to the very last char of the string, it means the string is well written. + return true; + } + + private MySqlParameter GetAndFixParameter(string spName, MySqlSchemaRow param, bool realAsFloat, MySqlParameter returnParameter) + { + string mode = (string)param["PARAMETER_MODE"]; + string pName = (string)param["PARAMETER_NAME"]; + string datatype = (string)param["DATA_TYPE"]; + bool unsigned = GetFlags(param["DTD_IDENTIFIER"].ToString()).IndexOf("UNSIGNED") != -1; + + if (Convert.ToUInt64(param["ORDINAL_POSITION"]) == 0) + { + if (returnParameter == null) + throw new InvalidOperationException(String.Format(Resources.RoutineRequiresReturnParameter, spName)); + pName = returnParameter.ParameterName; + } + + // make sure the parameters given to us have an appropriate type set if it's not already + MySqlParameter p = command.Parameters.GetParameterFlexible(pName, true); + if (!p.TypeHasBeenSet) + p.MySqlDbType = MetaData.NameToType(datatype, unsigned, realAsFloat, Connection); + + return p; + } + + private async Task CheckParametersAsync(string spName, bool execAsync) + { + MySqlParameterCollection newParms = new MySqlParameterCollection(command); + MySqlParameter returnParameter = GetReturnParameter(); + + ProcedureCacheEntry entry = await GetParametersAsync(spName, execAsync).ConfigureAwait(false); + if (entry.procedure == null || entry.procedure.Rows.Count == 0) + throw new InvalidOperationException(String.Format(Resources.RoutineNotFound, spName)); + + bool realAsFloat = entry.procedure.Rows[0]["SQL_MODE"].ToString().IndexOf("REAL_AS_FLOAT") != -1; + + foreach (MySqlSchemaRow param in entry.parameters.Rows) + newParms.Add(GetAndFixParameter(spName, param, realAsFloat, returnParameter)); + return newParms; + } + + public override void Resolve(bool preparing) + { + // check to see if we are already resolved + if (ResolvedCommandText != null) return; + + ServerProvidingOutputParameters = Driver.SupportsOutputParameters && preparing; + + // first retrieve the procedure definition from our + // procedure cache + string spName = commandText; + spName = FixProcedureName(spName); + + MySqlParameter returnParameter = GetReturnParameter(); + + MySqlParameterCollection parms = command.Connection.Settings.CheckParameters ? + CheckParametersAsync(spName, false).GetAwaiter().GetResult() : Parameters; + + string setSql = SetUserVariables(parms, preparing); + string callSql = CreateCallStatement(spName, returnParameter, parms); + string outSql = CreateOutputSelect(parms, preparing); + resolvedCommandText = String.Format("{0}{1}{2}", setSql, callSql, outSql); + } + + private string SetUserVariables(MySqlParameterCollection parms, bool preparing) + { + StringBuilder setSql = new StringBuilder(); + + if (ServerProvidingOutputParameters) return setSql.ToString(); + + string delimiter = String.Empty; + foreach (MySqlParameter p in parms) + { + if (p.Direction != ParameterDirection.InputOutput) continue; + + string pName = "@" + p.BaseName; + string uName = "@" + ParameterPrefix + p.BaseName; + string sql = String.Format("SET {0}={1}", uName, pName); + + if (command.Connection.Settings.AllowBatch && !preparing) + { + setSql.AppendFormat(CultureInfo.InvariantCulture, "{0}{1}", delimiter, sql); + delimiter = "; "; + } + else + { + MySqlCommand cmd = new MySqlCommand(sql, command.Connection); + cmd.Parameters.Add(p); + cmd.ExecuteNonQuery(); + } + } + if (setSql.Length > 0) + setSql.Append("; "); + return setSql.ToString(); + } + + private string CreateCallStatement(string spName, MySqlParameter returnParameter, MySqlParameterCollection parms) + { + StringBuilder callSql = new StringBuilder(); + + string delimiter = String.Empty; + foreach (MySqlParameter p in parms) + { + if (p.Direction == ParameterDirection.ReturnValue) continue; + + string pName = "@" + p.BaseName; + string uName = "@" + ParameterPrefix + p.BaseName; + + bool useRealVar = p.Direction == ParameterDirection.Input || ServerProvidingOutputParameters; + callSql.AppendFormat(CultureInfo.InvariantCulture, "{0}{1}", delimiter, useRealVar ? pName : uName); + delimiter = ", "; + } + + if (returnParameter == null) + return String.Format("CALL {0}({1})", spName, callSql.ToString()); + else + return String.Format("SET @{0}{1}={2}({3})", ParameterPrefix, returnParameter.BaseName, spName, callSql.ToString()); + } + + private string CreateOutputSelect(MySqlParameterCollection parms, bool preparing) + { + StringBuilder outSql = new StringBuilder(); + + string delimiter = String.Empty; + foreach (MySqlParameter p in parms) + { + if (p.Direction == ParameterDirection.Input) continue; + if ((p.Direction == ParameterDirection.InputOutput || + p.Direction == ParameterDirection.Output) && + ServerProvidingOutputParameters) continue; + string pName = "@" + p.BaseName; + string uName = "@" + ParameterPrefix + p.BaseName; + + outSql.AppendFormat(CultureInfo.InvariantCulture, "{0}{1}", delimiter, uName); + delimiter = ", "; + } + + if (outSql.Length == 0) return String.Empty; + + if (command.Connection.Settings.AllowBatch && !preparing) + return String.Format(";SELECT {0}", outSql.ToString()); + + _outSelect = String.Format("SELECT {0}", outSql.ToString()); + return String.Empty; + } + + internal void ProcessOutputParameters(MySqlDataReader reader) + { + // We apparently need to always adjust our output types since the server + // provided data types are not always right + AdjustOutputTypes(reader); + + if ((reader.CommandBehavior & CommandBehavior.SchemaOnly) != 0) + return; + + // now read the output parameters data row + reader.Read(); + + string prefix = "@" + StoredProcedure.ParameterPrefix; + + for (int i = 0; i < reader.FieldCount; i++) + { + string fieldName = reader.GetName(i); + if (fieldName.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) + fieldName = fieldName.Remove(0, prefix.Length); + MySqlParameter parameter = command.Parameters.GetParameterFlexible(fieldName, true); + parameter.Value = reader.GetValue(i); + } + } + + private void AdjustOutputTypes(MySqlDataReader reader) + { + // since MySQL likes to return user variables as strings + // we reset the types of the readers internal value objects + // this will allow those value objects to parse the string based + // return values + for (int i = 0; i < reader.FieldCount; i++) + { + string fieldName = reader.GetName(i); + if (fieldName.IndexOf(StoredProcedure.ParameterPrefix) != -1) + fieldName = fieldName.Remove(0, StoredProcedure.ParameterPrefix.Length + 1); + MySqlParameter parameter = command.Parameters.GetParameterFlexible(fieldName, true); + + IMySqlValue v = MySqlField.GetIMySqlValue(parameter.MySqlDbType); + if (v is MySqlBit) + { + MySqlBit bit = (MySqlBit)v; + bit.ReadAsString = true; + reader.ResultSet.SetValueObject(i, bit); + } + else + reader.ResultSet.SetValueObject(i, v); + } + } + + public override void Close(MySqlDataReader reader) + { + if (String.IsNullOrEmpty(_outSelect)) return; + if ((reader.CommandBehavior & CommandBehavior.SchemaOnly) != 0) return; + + MySqlCommand cmd = new MySqlCommand(_outSelect, command.Connection); + cmd.InternallyCreated = true; + + using (MySqlDataReader rdr = cmd.ExecuteReader(reader.CommandBehavior)) + ProcessOutputParameters(rdr); + } + } +} diff --git a/MySQL.Data/src/TableCache.cs b/MySQL.Data/src/TableCache.cs index 5d54a9e16..2944cb380 100644 --- a/MySQL.Data/src/TableCache.cs +++ b/MySQL.Data/src/TableCache.cs @@ -1,164 +1,164 @@ -// Copyright � 2016, 2018, Oracle and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using System; -using System.Collections.Generic; -using System.Linq; - -namespace MySql.Data.MySqlClient -{ - internal class TableCache - { - private static readonly BaseTableCache cache; - - static TableCache() - { - cache = new BaseTableCache(480 /* 8 hour max by default */); - } - - public static void AddToCache(string commandText, ResultSet resultSet) - { - cache.AddToCache(commandText, resultSet); - } - - public static ResultSet RetrieveFromCache(string commandText, int cacheAge) - { - return (ResultSet)cache.RetrieveFromCache(commandText, cacheAge); - } - - public static void RemoveFromCache(string commandText) - { - cache.RemoveFromCache(commandText); - } - - public static void DumpCache() - { - cache.Dump(); - } - } - - /// - /// Defines the basic operations to be performed on the table cache. - /// - public class BaseTableCache - { - /// - /// The maximum age allowed for cache entries. - /// - protected int MaxCacheAge; - - private Dictionary cache = new Dictionary(); - - public BaseTableCache(int maxCacheAge) - { - MaxCacheAge = maxCacheAge; - } - - /// - /// Adds the given command and result set to the cache. - /// - /// The command to store in the cache. - /// The resultset associated to the stored command. - public virtual void AddToCache(string commandText, object resultSet) - { - CleanCache(); - CacheEntry entry = new CacheEntry(); - entry.CacheTime = DateTime.Now; - entry.CacheElement = resultSet; - lock (cache) - { - if (cache.ContainsKey(commandText)) return; - cache.Add(commandText, entry); - } - } - - /// - /// Retrieves the specified command from the cache. - /// - /// The command to retrieve. - /// The allowed age for the cache entry. - /// - public virtual object RetrieveFromCache(string commandText, int cacheAge) - { - CleanCache(); - lock (cache) - { - if (!cache.ContainsKey(commandText)) return null; - CacheEntry entry = cache[commandText]; - if (DateTime.Now.Subtract(entry.CacheTime).TotalSeconds > cacheAge) return null; - return entry.CacheElement; - } - } - - /// - /// Removes the specified command from the cache. - /// - /// The command to remove from the cache. - public void RemoveFromCache(string commandText) - { - lock (cache) - { - if (!cache.ContainsKey(commandText)) return; - cache.Remove(commandText); - } - } - - /// - /// Clears the cache. - /// - public virtual void Dump() - { - lock (cache) - cache.Clear(); - } - - /// - /// Removes cache entries older than the value defined by . - /// - protected virtual void CleanCache() - { - DateTime now = DateTime.Now; - List keysToRemove = new List(); - - lock (cache) - { - keysToRemove.AddRange(from key in cache.Keys let diff = now.Subtract(cache[key].CacheTime) where diff.TotalSeconds > MaxCacheAge select key); - - foreach (string key in keysToRemove) - cache.Remove(key); - } - } - - private struct CacheEntry - { - public DateTime CacheTime; - public object CacheElement; - } - } - -} \ No newline at end of file +// Copyright © 2016, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using System; +using System.Collections.Generic; +using System.Linq; + +namespace MySql.Data.MySqlClient +{ + internal class TableCache + { + private static readonly BaseTableCache cache; + + static TableCache() + { + cache = new BaseTableCache(480 /* 8 hour max by default */); + } + + public static void AddToCache(string commandText, ResultSet resultSet) + { + cache.AddToCache(commandText, resultSet); + } + + public static ResultSet RetrieveFromCache(string commandText, int cacheAge) + { + return (ResultSet)cache.RetrieveFromCache(commandText, cacheAge); + } + + public static void RemoveFromCache(string commandText) + { + cache.RemoveFromCache(commandText); + } + + public static void DumpCache() + { + cache.Dump(); + } + } + + /// + /// Defines the basic operations to be performed on the table cache. + /// + public class BaseTableCache + { + /// + /// The maximum age allowed for cache entries. + /// + protected int MaxCacheAge; + + private Dictionary cache = new Dictionary(); + + public BaseTableCache(int maxCacheAge) + { + MaxCacheAge = maxCacheAge; + } + + /// + /// Adds the given command and result set to the cache. + /// + /// The command to store in the cache. + /// The resultset associated to the stored command. + public virtual void AddToCache(string commandText, object resultSet) + { + CleanCache(); + CacheEntry entry = new CacheEntry(); + entry.CacheTime = DateTime.Now; + entry.CacheElement = resultSet; + lock (cache) + { + if (cache.ContainsKey(commandText)) return; + cache.Add(commandText, entry); + } + } + + /// + /// Retrieves the specified command from the cache. + /// + /// The command to retrieve. + /// The allowed age for the cache entry. + /// + public virtual object RetrieveFromCache(string commandText, int cacheAge) + { + CleanCache(); + lock (cache) + { + if (!cache.ContainsKey(commandText)) return null; + CacheEntry entry = cache[commandText]; + if (DateTime.Now.Subtract(entry.CacheTime).TotalSeconds > cacheAge) return null; + return entry.CacheElement; + } + } + + /// + /// Removes the specified command from the cache. + /// + /// The command to remove from the cache. + public void RemoveFromCache(string commandText) + { + lock (cache) + { + if (!cache.ContainsKey(commandText)) return; + cache.Remove(commandText); + } + } + + /// + /// Clears the cache. + /// + public virtual void Dump() + { + lock (cache) + cache.Clear(); + } + + /// + /// Removes cache entries older than the value defined by . + /// + protected virtual void CleanCache() + { + DateTime now = DateTime.Now; + List keysToRemove = new List(); + + lock (cache) + { + keysToRemove.AddRange(from key in cache.Keys let diff = now.Subtract(cache[key].CacheTime) where diff.TotalSeconds > MaxCacheAge select key); + + foreach (string key in keysToRemove) + cache.Remove(key); + } + } + + private struct CacheEntry + { + public DateTime CacheTime; + public object CacheElement; + } + } + +} diff --git a/MySQL.Data/src/TimedStream.cs b/MySQL.Data/src/TimedStream.cs index f8853b795..4d788cdb3 100644 --- a/MySQL.Data/src/TimedStream.cs +++ b/MySQL.Data/src/TimedStream.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2009, 2022, Oracle and/or its affiliates. +// Copyright © 2009, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/TracingDriver.cs b/MySQL.Data/src/TracingDriver.cs index 300fccf02..308b767cd 100644 --- a/MySQL.Data/src/TracingDriver.cs +++ b/MySQL.Data/src/TracingDriver.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2009, 2022, Oracle and/or its affiliates. +// Copyright © 2009, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/Types/IMySqlValue.cs b/MySQL.Data/src/Types/IMySqlValue.cs index e545560af..2b3df6aca 100644 --- a/MySQL.Data/src/Types/IMySqlValue.cs +++ b/MySQL.Data/src/Types/IMySqlValue.cs @@ -1,47 +1,47 @@ -// Copyright (c) 2004, 2022, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data.MySqlClient; -using System; -using System.Threading.Tasks; - -namespace MySql.Data.Types -{ - internal interface IMySqlValue - { - bool IsNull { get; } - MySqlDbType MySqlDbType { get; } - object Value { get; /*set;*/ } - Type SystemType { get; } - string MySqlTypeName { get; } - - Task WriteValueAsync(MySqlPacket packet, bool binary, object value, int length, bool execAsync); - Task ReadValueAsync(MySqlPacket packet, long length, bool isNull, bool execAsync); - void SkipValue(MySqlPacket packet); - } -} +// Copyright © 2004, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data.MySqlClient; +using System; +using System.Threading.Tasks; + +namespace MySql.Data.Types +{ + internal interface IMySqlValue + { + bool IsNull { get; } + MySqlDbType MySqlDbType { get; } + object Value { get; /*set;*/ } + Type SystemType { get; } + string MySqlTypeName { get; } + + Task WriteValueAsync(MySqlPacket packet, bool binary, object value, int length, bool execAsync); + Task ReadValueAsync(MySqlPacket packet, long length, bool isNull, bool execAsync); + void SkipValue(MySqlPacket packet); + } +} diff --git a/MySQL.Data/src/Types/MetaData.cs b/MySQL.Data/src/Types/MetaData.cs index 59a39f286..61fbb28de 100644 --- a/MySQL.Data/src/Types/MetaData.cs +++ b/MySQL.Data/src/Types/MetaData.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2004, 2020, Oracle and/or its affiliates. +// Copyright © 2004, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -162,4 +162,4 @@ public static MySqlDbType NameToType(string typeName, bool unsigned, throw new MySqlException("Unhandled type encountered"); } } -} \ No newline at end of file +} diff --git a/MySQL.Data/src/Types/MySqlBinary.cs b/MySQL.Data/src/Types/MySqlBinary.cs index 0ff7c5387..29faae119 100644 --- a/MySQL.Data/src/Types/MySqlBinary.cs +++ b/MySQL.Data/src/Types/MySqlBinary.cs @@ -1,209 +1,211 @@ -// Copyright (c) 2004, 2022, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data.MySqlClient; -using System; -using System.Threading.Tasks; - -namespace MySql.Data.Types -{ - - internal struct MySqlBinary : IMySqlValue - { - private readonly MySqlDbType _type; - private readonly byte[] _mValue; - - public MySqlBinary(MySqlDbType type, bool isNull) - { - _type = type; - IsNull = isNull; - _mValue = null; - } - - public MySqlBinary(MySqlDbType type, byte[] val) - { - _type = type; - IsNull = false; - _mValue = val; - } - - #region IMySqlValue Members - - public bool IsNull { get; } - - MySqlDbType IMySqlValue.MySqlDbType => _type; - - object IMySqlValue.Value => _mValue; - - public byte[] Value => _mValue; - - Type IMySqlValue.SystemType => typeof(byte[]); - - string IMySqlValue.MySqlTypeName - { - get - { - switch (_type) - { - case MySqlDbType.TinyBlob: return "TINY_BLOB"; - case MySqlDbType.MediumBlob: return "MEDIUM_BLOB"; - case MySqlDbType.LongBlob: return "LONG_BLOB"; - default: - return "BLOB"; - } - } - } - - async Task IMySqlValue.WriteValueAsync(MySqlPacket packet, bool binary, object val, int length, bool execAsync) - { - byte[] buffToWrite = (val as byte[]); - if (buffToWrite == null) - { - char[] valAsChar = (val as Char[]); - if (valAsChar != null) - buffToWrite = packet.Encoding.GetBytes(valAsChar); - else - { - string s = val.ToString(); - if (length == 0) - length = s.Length; - else - s = s.Substring(0, length); - buffToWrite = packet.Encoding.GetBytes(s); - } - } - - // we assume zero or maxsize length means write all of the value - if (length == 0 || buffToWrite.Length < length) - length = buffToWrite.Length; - - if (buffToWrite == null) - throw new MySqlException("Only byte arrays and strings can be serialized by MySqlBinary"); - - if (binary) - { - await packet.WriteLengthAsync(length, execAsync).ConfigureAwait(false); - await packet.WriteAsync(buffToWrite, 0, length, execAsync).ConfigureAwait(false); - } - else - { - await packet.WriteStringNoNullAsync("_binary ", execAsync).ConfigureAwait(false); - packet.WriteByte((byte)'\''); - EscapeByteArray(buffToWrite, length, packet); - packet.WriteByte((byte)'\''); - } - } - - private static void EscapeByteArray(byte[] bytes, int length, MySqlPacket packet) - { - for (int x = 0; x < length; x++) - { - byte b = bytes[x]; - if (b == '\0') - { - packet.WriteByte((byte)'\\'); - packet.WriteByte((byte)'0'); - } - - else if (b == '\\' || b == '\'' || b == '\"') - { - packet.WriteByte((byte)'\\'); - packet.WriteByte(b); - } - else - packet.WriteByte(b); - } - } - - async Task IMySqlValue.ReadValueAsync(MySqlPacket packet, long length, bool nullVal, bool execAsync) - { - MySqlBinary b; - if (nullVal) - b = new MySqlBinary(_type, true); - else - { - if (length == -1) - length = (long)packet.ReadFieldLength(); - - byte[] newBuff = new byte[length]; - await packet.ReadAsync(newBuff, 0, (int)length, execAsync).ConfigureAwait(false); - b = new MySqlBinary(_type, newBuff); - } - return b; - } - - void IMySqlValue.SkipValue(MySqlPacket packet) - { - int len = (int)packet.ReadFieldLength(); - packet.Position += len; - } - - #endregion - - public static void SetDSInfo(MySqlSchemaCollection sc) - { - string[] types = new string[] { "BLOB", "TINYBLOB", "MEDIUMBLOB", "LONGBLOB", "BINARY", "VARBINARY" }; - MySqlDbType[] dbtype = new MySqlDbType[] { MySqlDbType.Blob, - MySqlDbType.TinyBlob, MySqlDbType.MediumBlob, MySqlDbType.LongBlob, MySqlDbType.Binary, MySqlDbType.VarBinary }; - long[] sizes = new long[] { 65535L, 255L, 16777215L, 4294967295L, 255L, 65535L }; - string[] format = new string[] { null, null, null, null, "binary({0})", "varbinary({0})" }; - string[] parms = new string[] { null, null, null, null, "length", "length" }; - - // we use name indexing because this method will only be called - // when GetSchema is called for the DataSourceInformation - // collection and then it wil be cached. - for (int x = 0; x < types.Length; x++) - { - MySqlSchemaRow row = sc.AddRow(); - row["TypeName"] = types[x]; - row["ProviderDbType"] = dbtype[x]; - row["ColumnSize"] = sizes[x]; - row["CreateFormat"] = format[x]; - row["CreateParameters"] = parms[x]; - row["DataType"] = "System.Byte[]"; - row["IsAutoincrementable"] = false; - row["IsBestMatch"] = true; - row["IsCaseSensitive"] = false; - row["IsFixedLength"] = x < 4 ? false : true; - row["IsFixedPrecisionScale"] = false; - row["IsLong"] = sizes[x] > 255; - row["IsNullable"] = true; - row["IsSearchable"] = false; - row["IsSearchableWithLike"] = false; - row["IsUnsigned"] = DBNull.Value; - row["MaximumScale"] = DBNull.Value; - row["MinimumScale"] = DBNull.Value; - row["IsConcurrencyType"] = DBNull.Value; - row["IsLiteralSupported"] = false; - row["LiteralPrefix"] = "0x"; - row["LiteralSuffix"] = DBNull.Value; - row["NativeDataType"] = DBNull.Value; - } - } - } -} +// Copyright © 2004, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data.MySqlClient; +using System; +using System.Threading.Tasks; + +namespace MySql.Data.Types +{ + + internal struct MySqlBinary : IMySqlValue + { + private readonly MySqlDbType _type; + private readonly byte[] _mValue; + + public MySqlBinary(MySqlDbType type, bool isNull) + { + _type = type; + IsNull = isNull; + _mValue = null; + } + + public MySqlBinary(MySqlDbType type, byte[] val) + { + _type = type; + IsNull = false; + _mValue = val; + } + + #region IMySqlValue Members + + public bool IsNull { get; } + + MySqlDbType IMySqlValue.MySqlDbType => _type; + + object IMySqlValue.Value => _mValue; + + public byte[] Value => _mValue; + + Type IMySqlValue.SystemType => typeof(byte[]); + + string IMySqlValue.MySqlTypeName + { + get + { + switch (_type) + { + case MySqlDbType.TinyBlob: return "TINY_BLOB"; + case MySqlDbType.MediumBlob: return "MEDIUM_BLOB"; + case MySqlDbType.LongBlob: return "LONG_BLOB"; + case MySqlDbType.Vector: return "VECTOR"; + default: + return "BLOB"; + } + } + } + + async Task IMySqlValue.WriteValueAsync(MySqlPacket packet, bool binary, object val, int length, bool execAsync) + { + byte[] buffToWrite = (val as byte[]); + if (buffToWrite == null) + { + char[] valAsChar = (val as Char[]); + if (valAsChar != null) + buffToWrite = packet.Encoding.GetBytes(valAsChar); + else + { + string s = val.ToString(); + if (length == 0) + length = s.Length; + else + s = s.Substring(0, length); + buffToWrite = packet.Encoding.GetBytes(s); + } + } + + // we assume zero or maxsize length means write all of the value + if (length == 0 || buffToWrite.Length < length) + length = buffToWrite.Length; + + if (buffToWrite == null) + throw new MySqlException("Only byte arrays and strings can be serialized by MySqlBinary"); + + if (binary) + { + await packet.WriteLengthAsync(length, execAsync).ConfigureAwait(false); + await packet.WriteAsync(buffToWrite, 0, length, execAsync).ConfigureAwait(false); + } + else + { + await packet.WriteStringNoNullAsync("_binary ", execAsync).ConfigureAwait(false); + packet.WriteByte((byte)'\''); + EscapeByteArray(buffToWrite, length, packet); + packet.WriteByte((byte)'\''); + } + } + + private static void EscapeByteArray(byte[] bytes, int length, MySqlPacket packet) + { + for (int x = 0; x < length; x++) + { + byte b = bytes[x]; + if (b == '\0') + { + packet.WriteByte((byte)'\\'); + packet.WriteByte((byte)'0'); + } + + else if (b == '\\' || b == '\'' || b == '\"') + { + packet.WriteByte((byte)'\\'); + packet.WriteByte(b); + } + else + packet.WriteByte(b); + } + } + + async Task IMySqlValue.ReadValueAsync(MySqlPacket packet, long length, bool nullVal, bool execAsync) + { + MySqlBinary b; + if (nullVal) + b = new MySqlBinary(_type, true); + else + { + if (length == -1) + length = (long)packet.ReadFieldLength(); + + byte[] newBuff = new byte[length]; + await packet.ReadAsync(newBuff, 0, (int)length, execAsync).ConfigureAwait(false); + b = new MySqlBinary(_type, newBuff); + } + return b; + } + + void IMySqlValue.SkipValue(MySqlPacket packet) + { + int len = (int)packet.ReadFieldLength(); + packet.Position += len; + } + + #endregion + + public static void SetDSInfo(MySqlSchemaCollection sc) + { + string[] types = new string[] { "BLOB", "TINYBLOB", "MEDIUMBLOB", "LONGBLOB", "BINARY", "VARBINARY", "VECTOR" }; + MySqlDbType[] dbtype = new MySqlDbType[] { MySqlDbType.Blob, + MySqlDbType.TinyBlob, MySqlDbType.MediumBlob, MySqlDbType.LongBlob, MySqlDbType.Binary, MySqlDbType.VarBinary, + MySqlDbType.Vector}; + long[] sizes = new long[] { 65535L, 255L, 16777215L, 4294967295L, 255L, 65535L, 16777215L }; + string[] format = new string[] { null, null, null, null, "binary({0})", "varbinary({0})", null }; + string[] parms = new string[] { null, null, null, null, "length", "length", null }; + + // we use name indexing because this method will only be called + // when GetSchema is called for the DataSourceInformation + // collection and then it wil be cached. + for (int x = 0; x < types.Length; x++) + { + MySqlSchemaRow row = sc.AddRow(); + row["TypeName"] = types[x]; + row["ProviderDbType"] = dbtype[x]; + row["ColumnSize"] = sizes[x]; + row["CreateFormat"] = format[x]; + row["CreateParameters"] = parms[x]; + row["DataType"] = "System.Byte[]"; + row["IsAutoincrementable"] = false; + row["IsBestMatch"] = true; + row["IsCaseSensitive"] = false; + row["IsFixedLength"] = x < 4 ? false : true; + row["IsFixedPrecisionScale"] = false; + row["IsLong"] = sizes[x] > 255; + row["IsNullable"] = true; + row["IsSearchable"] = false; + row["IsSearchableWithLike"] = false; + row["IsUnsigned"] = DBNull.Value; + row["MaximumScale"] = DBNull.Value; + row["MinimumScale"] = DBNull.Value; + row["IsConcurrencyType"] = DBNull.Value; + row["IsLiteralSupported"] = false; + row["LiteralPrefix"] = "0x"; + row["LiteralSuffix"] = DBNull.Value; + row["NativeDataType"] = DBNull.Value; + } + } + } +} diff --git a/MySQL.Data/src/Types/MySqlBit.cs b/MySQL.Data/src/Types/MySqlBit.cs index b43efa13b..31fd94db8 100644 --- a/MySQL.Data/src/Types/MySqlBit.cs +++ b/MySQL.Data/src/Types/MySqlBit.cs @@ -1,124 +1,124 @@ -// Copyright (c) 2004, 2022, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data.MySqlClient; -using System; -using System.Globalization; -using System.Threading.Tasks; - -namespace MySql.Data.Types -{ - /// - /// Summary description for MySqlUInt64. - /// - internal struct MySqlBit : IMySqlValue - { - private ulong _value; - - public MySqlBit(bool isnull) - { - _value = 0; - IsNull = isnull; - ReadAsString = false; - } - - public bool ReadAsString { get; set; } - - public bool IsNull { get; private set; } - - MySqlDbType IMySqlValue.MySqlDbType => MySqlDbType.Bit; - - object IMySqlValue.Value => _value; - - Type IMySqlValue.SystemType => typeof(ulong); - - string IMySqlValue.MySqlTypeName => "BIT"; - - async Task IMySqlValue.WriteValueAsync(MySqlPacket packet, bool binary, object value, int length, bool execAsync) - { - ulong v = value as ulong? ?? Convert.ToUInt64(value); - if (binary) - await packet.WriteIntegerAsync((long)v, 8, execAsync).ConfigureAwait(false); - else - await packet.WriteStringNoNullAsync(v.ToString(CultureInfo.InvariantCulture), execAsync).ConfigureAwait(false); - } - - async Task IMySqlValue.ReadValueAsync(MySqlPacket packet, long length, bool isNull, bool execAsync) - { - this.IsNull = isNull; - if (isNull) - return this; - - if (length == -1) - length = packet.ReadFieldLength(); - - if (ReadAsString) - _value = UInt64.Parse(await packet.ReadStringAsync(length, execAsync).ConfigureAwait(false), CultureInfo.InvariantCulture); - else - _value = (UInt64)packet.ReadBitValue((int)length); - return this; - } - - public void SkipValue(MySqlPacket packet) - { - int len = (int)packet.ReadFieldLength(); - packet.Position += len; - } - - internal static void SetDSInfo(MySqlSchemaCollection sc) - { - // we use name indexing because this method will only be called - // when GetSchema is called for the DataSourceInformation - // collection and then it wil be cached. - MySqlSchemaRow row = sc.AddRow(); - row["TypeName"] = "BIT"; - row["ProviderDbType"] = MySqlDbType.Bit; - row["ColumnSize"] = 64; - row["CreateFormat"] = "BIT"; - row["CreateParameters"] = DBNull.Value; - row["DataType"] = typeof(ulong).ToString(); - row["IsAutoincrementable"] = false; - row["IsBestMatch"] = true; - row["IsCaseSensitive"] = false; - row["IsFixedLength"] = false; - row["IsFixedPrecisionScale"] = true; - row["IsLong"] = false; - row["IsNullable"] = true; - row["IsSearchable"] = true; - row["IsSearchableWithLike"] = false; - row["IsUnsigned"] = false; - row["MaximumScale"] = 0; - row["MinimumScale"] = 0; - row["IsConcurrencyType"] = DBNull.Value; - row["IsLiteralSupported"] = false; - row["LiteralPrefix"] = DBNull.Value; - row["LiteralSuffix"] = DBNull.Value; - row["NativeDataType"] = DBNull.Value; - } - } -} +// Copyright © 2004, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data.MySqlClient; +using System; +using System.Globalization; +using System.Threading.Tasks; + +namespace MySql.Data.Types +{ + /// + /// Summary description for MySqlUInt64. + /// + internal struct MySqlBit : IMySqlValue + { + private ulong _value; + + public MySqlBit(bool isnull) + { + _value = 0; + IsNull = isnull; + ReadAsString = false; + } + + public bool ReadAsString { get; set; } + + public bool IsNull { get; private set; } + + MySqlDbType IMySqlValue.MySqlDbType => MySqlDbType.Bit; + + object IMySqlValue.Value => _value; + + Type IMySqlValue.SystemType => typeof(ulong); + + string IMySqlValue.MySqlTypeName => "BIT"; + + async Task IMySqlValue.WriteValueAsync(MySqlPacket packet, bool binary, object value, int length, bool execAsync) + { + ulong v = value as ulong? ?? Convert.ToUInt64(value); + if (binary) + await packet.WriteIntegerAsync((long)v, 8, execAsync).ConfigureAwait(false); + else + await packet.WriteStringNoNullAsync(v.ToString(CultureInfo.InvariantCulture), execAsync).ConfigureAwait(false); + } + + async Task IMySqlValue.ReadValueAsync(MySqlPacket packet, long length, bool isNull, bool execAsync) + { + this.IsNull = isNull; + if (isNull) + return this; + + if (length == -1) + length = packet.ReadFieldLength(); + + if (ReadAsString) + _value = UInt64.Parse(await packet.ReadStringAsync(length, execAsync).ConfigureAwait(false), CultureInfo.InvariantCulture); + else + _value = (UInt64)packet.ReadBitValue((int)length); + return this; + } + + public void SkipValue(MySqlPacket packet) + { + int len = (int)packet.ReadFieldLength(); + packet.Position += len; + } + + internal static void SetDSInfo(MySqlSchemaCollection sc) + { + // we use name indexing because this method will only be called + // when GetSchema is called for the DataSourceInformation + // collection and then it wil be cached. + MySqlSchemaRow row = sc.AddRow(); + row["TypeName"] = "BIT"; + row["ProviderDbType"] = MySqlDbType.Bit; + row["ColumnSize"] = 64; + row["CreateFormat"] = "BIT"; + row["CreateParameters"] = DBNull.Value; + row["DataType"] = typeof(ulong).ToString(); + row["IsAutoincrementable"] = false; + row["IsBestMatch"] = true; + row["IsCaseSensitive"] = false; + row["IsFixedLength"] = false; + row["IsFixedPrecisionScale"] = true; + row["IsLong"] = false; + row["IsNullable"] = true; + row["IsSearchable"] = true; + row["IsSearchableWithLike"] = false; + row["IsUnsigned"] = false; + row["MaximumScale"] = 0; + row["MinimumScale"] = 0; + row["IsConcurrencyType"] = DBNull.Value; + row["IsLiteralSupported"] = false; + row["LiteralPrefix"] = DBNull.Value; + row["LiteralSuffix"] = DBNull.Value; + row["NativeDataType"] = DBNull.Value; + } + } +} diff --git a/MySQL.Data/src/Types/MySqlByte.cs b/MySQL.Data/src/Types/MySqlByte.cs index cda104293..38b62bf8a 100644 --- a/MySQL.Data/src/Types/MySqlByte.cs +++ b/MySQL.Data/src/Types/MySqlByte.cs @@ -1,141 +1,141 @@ -// Copyright (c) 2004, 2022, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data.MySqlClient; -using System; -using System.Globalization; -using System.Threading.Tasks; - -namespace MySql.Data.Types -{ - internal struct MySqlByte : IMySqlValue - { - public MySqlByte(bool isNull) - { - IsNull = isNull; - Value = 0; - TreatAsBoolean = false; - } - - public MySqlByte(sbyte val) - { - IsNull = false; - Value = val; - TreatAsBoolean = false; - } - - #region IMySqlValue Members - - public bool IsNull { get; } - - MySqlDbType IMySqlValue.MySqlDbType => MySqlDbType.Byte; - - object IMySqlValue.Value - { - get - { - if (TreatAsBoolean) - return Convert.ToBoolean(Value); - return Value; - } - } - - public sbyte Value { get; set; } - - Type IMySqlValue.SystemType => TreatAsBoolean ? typeof(bool) : typeof(sbyte); - - string IMySqlValue.MySqlTypeName => "TINYINT"; - - async Task IMySqlValue.WriteValueAsync(MySqlPacket packet, bool binary, object val, int length, bool execAsync) - { - sbyte v = val as sbyte? ?? Convert.ToSByte(val); - if (binary) - packet.WriteByte((byte)v); - else - await packet.WriteStringNoNullAsync(v.ToString(CultureInfo.InvariantCulture), execAsync).ConfigureAwait(false); - } - - async Task IMySqlValue.ReadValueAsync(MySqlPacket packet, long length, bool nullVal, bool execAsync) - { - if (nullVal) - return new MySqlByte(true) { TreatAsBoolean = TreatAsBoolean }; - - MySqlByte b; - if (length == -1) - b = new MySqlByte((sbyte)packet.ReadByte()); - else - { - string s = await packet.ReadStringAsync(length, execAsync).ConfigureAwait(false); - b = new MySqlByte(SByte.Parse(s, NumberStyles.Any, CultureInfo.InvariantCulture)); - } - - b.TreatAsBoolean = TreatAsBoolean; - return b; - } - - void IMySqlValue.SkipValue(MySqlPacket packet) - { - packet.ReadByte(); - } - - #endregion - - internal bool TreatAsBoolean { get; set; } - - internal static void SetDSInfo(MySqlSchemaCollection sc) - { - // we use name indexing because this method will only be called - // when GetSchema is called for the DataSourceInformation - // collection and then it wil be cached. - MySqlSchemaRow row = sc.AddRow(); - row["TypeName"] = "TINYINT"; - row["ProviderDbType"] = MySqlDbType.Byte; - row["ColumnSize"] = 0; - row["CreateFormat"] = "TINYINT"; - row["CreateParameters"] = null; - row["DataType"] = "System.SByte"; - row["IsAutoincrementable"] = true; - row["IsBestMatch"] = true; - row["IsCaseSensitive"] = false; - row["IsFixedLength"] = true; - row["IsFixedPrecisionScale"] = true; - row["IsLong"] = false; - row["IsNullable"] = true; - row["IsSearchable"] = true; - row["IsSearchableWithLike"] = false; - row["IsUnsigned"] = false; - row["MaximumScale"] = 0; - row["MinimumScale"] = 0; - row["IsConcurrencyType"] = DBNull.Value; - row["IsLiteralSupported"] = false; - row["LiteralPrefix"] = null; - row["LiteralSuffix"] = null; - row["NativeDataType"] = null; - } - } -} +// Copyright © 2004, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data.MySqlClient; +using System; +using System.Globalization; +using System.Threading.Tasks; + +namespace MySql.Data.Types +{ + internal struct MySqlByte : IMySqlValue + { + public MySqlByte(bool isNull) + { + IsNull = isNull; + Value = 0; + TreatAsBoolean = false; + } + + public MySqlByte(sbyte val) + { + IsNull = false; + Value = val; + TreatAsBoolean = false; + } + + #region IMySqlValue Members + + public bool IsNull { get; } + + MySqlDbType IMySqlValue.MySqlDbType => MySqlDbType.Byte; + + object IMySqlValue.Value + { + get + { + if (TreatAsBoolean) + return Convert.ToBoolean(Value); + return Value; + } + } + + public sbyte Value { get; set; } + + Type IMySqlValue.SystemType => TreatAsBoolean ? typeof(bool) : typeof(sbyte); + + string IMySqlValue.MySqlTypeName => "TINYINT"; + + async Task IMySqlValue.WriteValueAsync(MySqlPacket packet, bool binary, object val, int length, bool execAsync) + { + sbyte v = val as sbyte? ?? Convert.ToSByte(val); + if (binary) + packet.WriteByte((byte)v); + else + await packet.WriteStringNoNullAsync(v.ToString(CultureInfo.InvariantCulture), execAsync).ConfigureAwait(false); + } + + async Task IMySqlValue.ReadValueAsync(MySqlPacket packet, long length, bool nullVal, bool execAsync) + { + if (nullVal) + return new MySqlByte(true) { TreatAsBoolean = TreatAsBoolean }; + + MySqlByte b; + if (length == -1) + b = new MySqlByte((sbyte)packet.ReadByte()); + else + { + string s = await packet.ReadStringAsync(length, execAsync).ConfigureAwait(false); + b = new MySqlByte(SByte.Parse(s, NumberStyles.Any, CultureInfo.InvariantCulture)); + } + + b.TreatAsBoolean = TreatAsBoolean; + return b; + } + + void IMySqlValue.SkipValue(MySqlPacket packet) + { + packet.ReadByte(); + } + + #endregion + + internal bool TreatAsBoolean { get; set; } + + internal static void SetDSInfo(MySqlSchemaCollection sc) + { + // we use name indexing because this method will only be called + // when GetSchema is called for the DataSourceInformation + // collection and then it wil be cached. + MySqlSchemaRow row = sc.AddRow(); + row["TypeName"] = "TINYINT"; + row["ProviderDbType"] = MySqlDbType.Byte; + row["ColumnSize"] = 0; + row["CreateFormat"] = "TINYINT"; + row["CreateParameters"] = null; + row["DataType"] = "System.SByte"; + row["IsAutoincrementable"] = true; + row["IsBestMatch"] = true; + row["IsCaseSensitive"] = false; + row["IsFixedLength"] = true; + row["IsFixedPrecisionScale"] = true; + row["IsLong"] = false; + row["IsNullable"] = true; + row["IsSearchable"] = true; + row["IsSearchableWithLike"] = false; + row["IsUnsigned"] = false; + row["MaximumScale"] = 0; + row["MinimumScale"] = 0; + row["IsConcurrencyType"] = DBNull.Value; + row["IsLiteralSupported"] = false; + row["LiteralPrefix"] = null; + row["LiteralSuffix"] = null; + row["NativeDataType"] = null; + } + } +} diff --git a/MySQL.Data/src/Types/MySqlConversionException.cs b/MySQL.Data/src/Types/MySqlConversionException.cs index 427bcdbbc..727fcd07a 100644 --- a/MySQL.Data/src/Types/MySqlConversionException.cs +++ b/MySQL.Data/src/Types/MySqlConversionException.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2004, 2017, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2004, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/Types/MySqlDateTime.cs b/MySQL.Data/src/Types/MySqlDateTime.cs index 478596996..e7d1ff9a1 100644 --- a/MySQL.Data/src/Types/MySqlDateTime.cs +++ b/MySQL.Data/src/Types/MySqlDateTime.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2004, 2022, Oracle and/or its affiliates. +// Copyright © 2004, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/Types/MySqlDecimal.cs b/MySQL.Data/src/Types/MySqlDecimal.cs index 13205b85e..13780c88c 100644 --- a/MySQL.Data/src/Types/MySqlDecimal.cs +++ b/MySQL.Data/src/Types/MySqlDecimal.cs @@ -1,162 +1,162 @@ -// Copyright (c) 2004, 2022, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data.MySqlClient; -using System; -using System.Globalization; -using System.Threading.Tasks; - -namespace MySql.Data.Types -{ - /// - /// Represents a decimal data type object in a MySql database. - /// - public struct MySqlDecimal : IMySqlValue - { - private readonly string _value; - - internal MySqlDecimal(bool isNull) - { - IsNull = isNull; - _value = null; - Precision = Scale = 0; - } - - internal MySqlDecimal(string val) - { - this.IsNull = false; - Precision = Scale = 0; - _value = val; - } - - #region IMySqlValue Members - - /// - /// Gets a boolean value signaling if the type is null. - /// - public bool IsNull { get; } - - MySqlDbType IMySqlValue.MySqlDbType => MySqlDbType.Decimal; - - /// - /// Gets or sets the decimal precision of the type. - /// - public byte Precision { get; set; } - - /// - /// Gets or sets the scale of the type. - /// - public byte Scale { get; set; } - - - object IMySqlValue.Value => Value; - - /// - /// Gets the decimal value associated to this type. - /// - public decimal Value => Convert.ToDecimal(_value, CultureInfo.InvariantCulture); - - /// - /// Converts this decimal value to a double value. - /// - /// The value of this type converted to a dobule value. - public double ToDouble() - { - return Double.Parse(_value, CultureInfo.InvariantCulture); - } - - public override string ToString() - { - return _value; - } - - Type IMySqlValue.SystemType => typeof(decimal); - - string IMySqlValue.MySqlTypeName => "DECIMAL"; - - async Task IMySqlValue.WriteValueAsync(MySqlPacket packet, bool binary, object val, int length, bool execAsync) - { - decimal v = val as decimal? ?? Convert.ToDecimal(val); - string valStr = v.ToString(CultureInfo.InvariantCulture); - - if (binary) - await packet.WriteLenStringAsync(valStr, execAsync).ConfigureAwait(false); - else - await packet.WriteStringNoNullAsync(valStr, execAsync).ConfigureAwait(false); - } - - async Task IMySqlValue.ReadValueAsync(MySqlPacket packet, long length, bool nullVal, bool execAsync) - { - if (nullVal) - return new MySqlDecimal(true); - - string s = String.Empty; - s = length == -1 ? await packet.ReadLenStringAsync(execAsync).ConfigureAwait(false) : await packet.ReadStringAsync(length, execAsync).ConfigureAwait(false); - return new MySqlDecimal(s); - } - - void IMySqlValue.SkipValue(MySqlPacket packet) - { - int len = (int)packet.ReadFieldLength(); - packet.Position += len; - } - - #endregion - - internal static void SetDSInfo(MySqlSchemaCollection sc) - { - // we use name indexing because this method will only be called - // when GetSchema is called for the DataSourceInformation - // collection and then it wil be cached. - MySqlSchemaRow row = sc.AddRow(); - row["TypeName"] = "DECIMAL"; - row["ProviderDbType"] = MySqlDbType.NewDecimal; - row["ColumnSize"] = 0; - row["CreateFormat"] = "DECIMAL({0},{1})"; - row["CreateParameters"] = "precision,scale"; - row["DataType"] = "System.Decimal"; - row["IsAutoincrementable"] = false; - row["IsBestMatch"] = true; - row["IsCaseSensitive"] = false; - row["IsFixedLength"] = true; - row["IsFixedPrecisionScale"] = true; - row["IsLong"] = false; - row["IsNullable"] = true; - row["IsSearchable"] = true; - row["IsSearchableWithLike"] = false; - row["IsUnsigned"] = false; - row["MaximumScale"] = 0; - row["MinimumScale"] = 0; - row["IsConcurrencyType"] = DBNull.Value; - row["IsLiteralSupported"] = false; - row["LiteralPrefix"] = null; - row["LiteralSuffix"] = null; - row["NativeDataType"] = null; - } - } -} +// Copyright © 2004, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data.MySqlClient; +using System; +using System.Globalization; +using System.Threading.Tasks; + +namespace MySql.Data.Types +{ + /// + /// Represents a decimal data type object in a MySql database. + /// + public struct MySqlDecimal : IMySqlValue + { + private readonly string _value; + + internal MySqlDecimal(bool isNull) + { + IsNull = isNull; + _value = null; + Precision = Scale = 0; + } + + internal MySqlDecimal(string val) + { + this.IsNull = false; + Precision = Scale = 0; + _value = val; + } + + #region IMySqlValue Members + + /// + /// Gets a boolean value signaling if the type is null. + /// + public bool IsNull { get; } + + MySqlDbType IMySqlValue.MySqlDbType => MySqlDbType.Decimal; + + /// + /// Gets or sets the decimal precision of the type. + /// + public byte Precision { get; set; } + + /// + /// Gets or sets the scale of the type. + /// + public byte Scale { get; set; } + + + object IMySqlValue.Value => Value; + + /// + /// Gets the decimal value associated to this type. + /// + public decimal Value => Convert.ToDecimal(_value, CultureInfo.InvariantCulture); + + /// + /// Converts this decimal value to a double value. + /// + /// The value of this type converted to a dobule value. + public double ToDouble() + { + return Double.Parse(_value, CultureInfo.InvariantCulture); + } + + public override string ToString() + { + return _value; + } + + Type IMySqlValue.SystemType => typeof(decimal); + + string IMySqlValue.MySqlTypeName => "DECIMAL"; + + async Task IMySqlValue.WriteValueAsync(MySqlPacket packet, bool binary, object val, int length, bool execAsync) + { + decimal v = val as decimal? ?? Convert.ToDecimal(val); + string valStr = v.ToString(CultureInfo.InvariantCulture); + + if (binary) + await packet.WriteLenStringAsync(valStr, execAsync).ConfigureAwait(false); + else + await packet.WriteStringNoNullAsync(valStr, execAsync).ConfigureAwait(false); + } + + async Task IMySqlValue.ReadValueAsync(MySqlPacket packet, long length, bool nullVal, bool execAsync) + { + if (nullVal) + return new MySqlDecimal(true); + + string s = String.Empty; + s = length == -1 ? await packet.ReadLenStringAsync(execAsync).ConfigureAwait(false) : await packet.ReadStringAsync(length, execAsync).ConfigureAwait(false); + return new MySqlDecimal(s); + } + + void IMySqlValue.SkipValue(MySqlPacket packet) + { + int len = (int)packet.ReadFieldLength(); + packet.Position += len; + } + + #endregion + + internal static void SetDSInfo(MySqlSchemaCollection sc) + { + // we use name indexing because this method will only be called + // when GetSchema is called for the DataSourceInformation + // collection and then it wil be cached. + MySqlSchemaRow row = sc.AddRow(); + row["TypeName"] = "DECIMAL"; + row["ProviderDbType"] = MySqlDbType.NewDecimal; + row["ColumnSize"] = 0; + row["CreateFormat"] = "DECIMAL({0},{1})"; + row["CreateParameters"] = "precision,scale"; + row["DataType"] = "System.Decimal"; + row["IsAutoincrementable"] = false; + row["IsBestMatch"] = true; + row["IsCaseSensitive"] = false; + row["IsFixedLength"] = true; + row["IsFixedPrecisionScale"] = true; + row["IsLong"] = false; + row["IsNullable"] = true; + row["IsSearchable"] = true; + row["IsSearchableWithLike"] = false; + row["IsUnsigned"] = false; + row["MaximumScale"] = 0; + row["MinimumScale"] = 0; + row["IsConcurrencyType"] = DBNull.Value; + row["IsLiteralSupported"] = false; + row["LiteralPrefix"] = null; + row["LiteralSuffix"] = null; + row["NativeDataType"] = null; + } + } +} diff --git a/MySQL.Data/src/Types/MySqlDouble.cs b/MySQL.Data/src/Types/MySqlDouble.cs index 4e8989569..de72338fe 100644 --- a/MySQL.Data/src/Types/MySqlDouble.cs +++ b/MySQL.Data/src/Types/MySqlDouble.cs @@ -1,145 +1,145 @@ -// Copyright (c) 2004, 2022, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data.MySqlClient; -using System; -using System.Globalization; -using System.Threading.Tasks; - -namespace MySql.Data.Types -{ - - internal struct MySqlDouble : IMySqlValue - { - public MySqlDouble(bool isNull) - { - IsNull = isNull; - Value = 0.0; - } - - public MySqlDouble(double val) - { - IsNull = false; - Value = val; - } - - #region IMySqlValue Members - - public bool IsNull { get; } - - MySqlDbType IMySqlValue.MySqlDbType => MySqlDbType.Double; - - object IMySqlValue.Value => Value; - - public double Value { get; } - - Type IMySqlValue.SystemType => typeof(double); - - string IMySqlValue.MySqlTypeName => "DOUBLE"; - - async Task IMySqlValue.WriteValueAsync(MySqlPacket packet, bool binary, object val, int length, bool execAsync) - { - double v = val as double? ?? Convert.ToDouble(val); - if (binary) - await packet.WriteAsync(BitConverter.GetBytes(v), execAsync).ConfigureAwait(false); - else - await packet.WriteStringNoNullAsync(v.ToString("R", CultureInfo.InvariantCulture), execAsync).ConfigureAwait(false); - } - - async Task IMySqlValue.ReadValueAsync(MySqlPacket packet, long length, bool nullVal, bool execAsync) - { - if (nullVal) - return new MySqlDouble(true); - - if (length == -1) - { - byte[] b = new byte[8]; - await packet.ReadAsync(b, 0, 8, execAsync).ConfigureAwait(false); - return new MySqlDouble(BitConverter.ToDouble(b, 0)); - } - - string s = await packet.ReadStringAsync(length, execAsync).ConfigureAwait(false); - double d; - - try - { - d = Double.Parse(s, CultureInfo.InvariantCulture); - } - catch (OverflowException) - { - // MySQL server < 5.5 can return values not compatible with - // Double.Parse(), i.e out of range for double. - - if (s.StartsWith("-", StringComparison.Ordinal)) - d = double.MinValue; - else - d = double.MaxValue; - } - - return new MySqlDouble(d); - } - - void IMySqlValue.SkipValue(MySqlPacket packet) - { - packet.Position += 8; - } - - #endregion - - internal static void SetDSInfo(MySqlSchemaCollection sc) - { - // we use name indexing because this method will only be called - // when GetSchema is called for the DataSourceInformation - // collection and then it wil be cached. - MySqlSchemaRow row = sc.AddRow(); - row["TypeName"] = "DOUBLE"; - row["ProviderDbType"] = MySqlDbType.Double; - row["ColumnSize"] = 0; - row["CreateFormat"] = "DOUBLE"; - row["CreateParameters"] = null; - row["DataType"] = "System.Double"; - row["IsAutoincrementable"] = false; - row["IsBestMatch"] = true; - row["IsCaseSensitive"] = false; - row["IsFixedLength"] = true; - row["IsFixedPrecisionScale"] = true; - row["IsLong"] = false; - row["IsNullable"] = true; - row["IsSearchable"] = true; - row["IsSearchableWithLike"] = false; - row["IsUnsigned"] = false; - row["MaximumScale"] = 0; - row["MinimumScale"] = 0; - row["IsConcurrencyType"] = DBNull.Value; - row["IsLiteralSupported"] = false; - row["LiteralPrefix"] = null; - row["LiteralSuffix"] = null; - row["NativeDataType"] = null; - } - } -} \ No newline at end of file +// Copyright © 2004, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data.MySqlClient; +using System; +using System.Globalization; +using System.Threading.Tasks; + +namespace MySql.Data.Types +{ + + internal struct MySqlDouble : IMySqlValue + { + public MySqlDouble(bool isNull) + { + IsNull = isNull; + Value = 0.0; + } + + public MySqlDouble(double val) + { + IsNull = false; + Value = val; + } + + #region IMySqlValue Members + + public bool IsNull { get; } + + MySqlDbType IMySqlValue.MySqlDbType => MySqlDbType.Double; + + object IMySqlValue.Value => Value; + + public double Value { get; } + + Type IMySqlValue.SystemType => typeof(double); + + string IMySqlValue.MySqlTypeName => "DOUBLE"; + + async Task IMySqlValue.WriteValueAsync(MySqlPacket packet, bool binary, object val, int length, bool execAsync) + { + double v = val as double? ?? Convert.ToDouble(val); + if (binary) + await packet.WriteAsync(PacketBitConverter.GetBytes(v), execAsync).ConfigureAwait(false); + else + await packet.WriteStringNoNullAsync(v.ToString("R", CultureInfo.InvariantCulture), execAsync).ConfigureAwait(false); + } + + async Task IMySqlValue.ReadValueAsync(MySqlPacket packet, long length, bool nullVal, bool execAsync) + { + if (nullVal) + return new MySqlDouble(true); + + if (length == -1) + { + byte[] b = new byte[8]; + await packet.ReadAsync(b, 0, 8, execAsync).ConfigureAwait(false); + return new MySqlDouble(PacketBitConverter.ToDouble(b, 0)); + } + + string s = await packet.ReadStringAsync(length, execAsync).ConfigureAwait(false); + double d; + + try + { + d = Double.Parse(s, CultureInfo.InvariantCulture); + } + catch (OverflowException) + { + // MySQL server < 5.5 can return values not compatible with + // Double.Parse(), i.e out of range for double. + + if (s.StartsWith("-", StringComparison.Ordinal)) + d = double.MinValue; + else + d = double.MaxValue; + } + + return new MySqlDouble(d); + } + + void IMySqlValue.SkipValue(MySqlPacket packet) + { + packet.Position += 8; + } + + #endregion + + internal static void SetDSInfo(MySqlSchemaCollection sc) + { + // we use name indexing because this method will only be called + // when GetSchema is called for the DataSourceInformation + // collection and then it wil be cached. + MySqlSchemaRow row = sc.AddRow(); + row["TypeName"] = "DOUBLE"; + row["ProviderDbType"] = MySqlDbType.Double; + row["ColumnSize"] = 0; + row["CreateFormat"] = "DOUBLE"; + row["CreateParameters"] = null; + row["DataType"] = "System.Double"; + row["IsAutoincrementable"] = false; + row["IsBestMatch"] = true; + row["IsCaseSensitive"] = false; + row["IsFixedLength"] = true; + row["IsFixedPrecisionScale"] = true; + row["IsLong"] = false; + row["IsNullable"] = true; + row["IsSearchable"] = true; + row["IsSearchableWithLike"] = false; + row["IsUnsigned"] = false; + row["MaximumScale"] = 0; + row["MinimumScale"] = 0; + row["IsConcurrencyType"] = DBNull.Value; + row["IsLiteralSupported"] = false; + row["LiteralPrefix"] = null; + row["LiteralSuffix"] = null; + row["NativeDataType"] = null; + } + } +} diff --git a/MySQL.Data/src/Types/MySqlGeometry.cs b/MySQL.Data/src/Types/MySqlGeometry.cs index cb56723fc..9472e4b51 100644 --- a/MySQL.Data/src/Types/MySqlGeometry.cs +++ b/MySQL.Data/src/Types/MySqlGeometry.cs @@ -1,395 +1,395 @@ -// Copyright (c) 2013, 2022, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data.MySqlClient; -using System; -using System.Globalization; -using System.Threading.Tasks; - -namespace MySql.Data.Types -{ - //Bytes structure is: - //SRID [0 - 3] - //Byte order [4] - //WKB type [5 - 8] - //X [9 - 16] - //Y [17 - 24] - //The byte order may be either 1 or 0 to indicate little-endian or - //big-endian storage. The little-endian and big-endian byte orders - //are also known as Network Data Representation (NDR) and External - //Data Representation (XDR), respectively. - - //The WKB type is a code that indicates the geometry type. Values - //from 1 through 7 indicate Point, LineString, Polygon, MultiPoint, - //MultiLineString, MultiPolygon, and GeometryCollection. - - /// - /// Represents a geometry data type object in a MySql database. - /// - public struct MySqlGeometry : IMySqlValue - { - private readonly MySqlDbType _type; - private readonly Double _xValue; - private readonly Double _yValue; - private readonly int _srid; - - private const int GEOMETRY_LENGTH = 25; - - /// - /// Gets the x coordinate. - /// - public Double? XCoordinate => _xValue; - - /// - /// Gets the y coordinate. - /// - public Double? YCoordinate => _yValue; - - /// - /// Gets the SRID value. - /// - public int? SRID => _srid; - - public MySqlGeometry(bool isNull) : this(MySqlDbType.Geometry, isNull) - { - } - - public MySqlGeometry(Double xValue, Double yValue) - : this(MySqlDbType.Geometry, xValue, yValue, 0) - { } - - public MySqlGeometry(Double xValue, Double yValue, int srid) - : this(MySqlDbType.Geometry, xValue, yValue, srid) - { } - - - internal MySqlGeometry(MySqlDbType type, bool isNull) - { - this._type = type; - isNull = true; - _xValue = 0; - _yValue = 0; - _srid = 0; - Value = null; - this.IsNull = isNull; - } - - - internal MySqlGeometry(MySqlDbType type, Double xValue, Double yValue, int srid) - { - this._type = type; - this._xValue = xValue; - this._yValue = yValue; - this.IsNull = false; - this._srid = srid; - this.Value = new byte[GEOMETRY_LENGTH]; - - byte[] sridBinary = BitConverter.GetBytes(srid); - - for (int i = 0; i < sridBinary.Length; i++) - Value[i] = sridBinary[i]; - - long xVal = BitConverter.DoubleToInt64Bits(xValue); - long yVal = BitConverter.DoubleToInt64Bits(yValue); - - Value[4] = 1; - Value[5] = 1; - - for (int i = 0; i < 8; i++) - { - Value[i + 9] = (byte)(xVal & 0xff); - xVal >>= 8; - } - - for (int i = 0; i < 8; i++) - { - Value[i + 17] = (byte)(yVal & 0xff); - yVal >>= 8; - } - } - - public MySqlGeometry(MySqlDbType type, byte[] val) - { - - if (val == null) - throw new ArgumentNullException(nameof(val)); - - byte[] buffValue = new byte[val.Length]; - - for (int i = 0; i < val.Length; i++) - buffValue[i] = val[i]; - - var xIndex = val.Length == GEOMETRY_LENGTH ? 9 : 5; - var yIndex = val.Length == GEOMETRY_LENGTH ? 17 : 13; - - Value = buffValue; - _xValue = val.Length >= xIndex + 8 ? BitConverter.ToDouble(val, xIndex) : 0; - _yValue = val.Length >= yIndex + 8 ? BitConverter.ToDouble(val, yIndex) : 0; - this._srid = val.Length == GEOMETRY_LENGTH ? BitConverter.ToInt32(val, 0) : 0; - this.IsNull = false; - this._type = type; - } - - #region IMySqlValue Members - - - MySqlDbType IMySqlValue.MySqlDbType => _type; - - /// - /// Gets a boolean value that signals if the type is null. - /// - public bool IsNull { get; } - - /// - /// Gets the value associated to this type. - /// - object IMySqlValue.Value => Value; - - /// - /// Gets the value associated to this type. - /// - public byte[] Value { get; } - - Type IMySqlValue.SystemType => typeof(byte[]); - - string IMySqlValue.MySqlTypeName => "GEOMETRY"; - - async Task IMySqlValue.WriteValueAsync(MySqlPacket packet, bool binary, object val, int length, bool execAsync) - { - byte[] buffToWrite = null; - - try - { - buffToWrite = ((MySqlGeometry)val).Value; - } - catch - { - buffToWrite = val as Byte[]; - } - - if (buffToWrite == null) - { - MySqlGeometry v = new MySqlGeometry(0, 0); - MySqlGeometry.TryParse(val.ToString(), out v); - buffToWrite = v.Value; - } - - byte[] result = new byte[GEOMETRY_LENGTH]; - - for (int i = 0; i < buffToWrite.Length; i++) - { - if (buffToWrite.Length < GEOMETRY_LENGTH) - result[i + 4] = buffToWrite[i]; - else - result[i] = buffToWrite[i]; - } - - if (!binary) - { - await packet.WriteStringNoNullAsync("_binary ", execAsync).ConfigureAwait(false); - packet.WriteByte((byte)'\''); - EscapeByteArray(result, GEOMETRY_LENGTH, packet); - packet.WriteByte((byte)'\''); - } - else - await packet.WriteLenStringAsync(val.ToString(), execAsync).ConfigureAwait(false); - } - - private static void EscapeByteArray(byte[] bytes, int length, MySqlPacket packet) - { - for (int x = 0; x < length; x++) - { - byte b = bytes[x]; - if (b == '\0') - { - packet.WriteByte((byte)'\\'); - packet.WriteByte((byte)'0'); - } - - else if (b == '\\' || b == '\'' || b == '\"') - { - packet.WriteByte((byte)'\\'); - packet.WriteByte(b); - } - else - packet.WriteByte(b); - } - } - - async Task IMySqlValue.ReadValueAsync(MySqlPacket packet, long length, bool nullVal, bool execAsync) - { - MySqlGeometry g; - if (nullVal) - g = new MySqlGeometry(_type, true); - else - { - if (length == -1) - length = (long)packet.ReadFieldLength(); - - byte[] newBuff = new byte[length]; - await packet.ReadAsync(newBuff, 0, (int)length, execAsync).ConfigureAwait(false); - g = new MySqlGeometry(_type, newBuff); - } - return g; - } - - void IMySqlValue.SkipValue(MySqlPacket packet) - { - int len = (int)packet.ReadFieldLength(); - packet.Position += len; - } - - #endregion - - - /// Returns the Well-Known Text representation of this value - /// POINT({0} {1})", longitude, latitude - /// http://dev.mysql.com/doc/refman/4.1/en/gis-wkt-format.html - public override string ToString() - { - if (!this.IsNull) - return _srid != 0 ? string.Format(CultureInfo.InvariantCulture.NumberFormat, "SRID={2};POINT({0} {1})", _xValue, _yValue, _srid) : string.Format(CultureInfo.InvariantCulture.NumberFormat, "POINT({0} {1})", _xValue, _yValue); - - return String.Empty; - } - - /// - /// Get value from WKT format - /// SRID=0;POINT (x y) or POINT (x y) - /// - /// WKT string format - public static MySqlGeometry Parse(string value) - { - if (String.IsNullOrEmpty(value)) - throw new ArgumentNullException(nameof(value)); - - if (!(value.Contains("SRID") || value.Contains("POINT(") || value.Contains("POINT ("))) - throw new FormatException("String does not contain a valid geometry value"); - - MySqlGeometry result = new MySqlGeometry(0, 0); - MySqlGeometry.TryParse(value, out result); - - return result; - } - - /// - /// Try to get value from WKT format - /// SRID=0;POINT (x y) or POINT (x y) - /// - /// WKT string format - /// Out mysqlGeometryValue - public static bool TryParse(string value, out MySqlGeometry mySqlGeometryValue) - { - string[] arrayResult = new string[0]; - string strResult = string.Empty; - bool hasX = false; - bool hasY = false; - Double xVal = 0; - Double yVal = 0; - int sridValue = 0; - - try - { - if (value.Contains(";")) - arrayResult = value.Split(';'); - else - strResult = value; - - if (arrayResult.Length > 1 || strResult != String.Empty) - { - string point = strResult != String.Empty ? strResult : arrayResult[1]; - point = point.Replace("POINT (", "").Replace("POINT(", "").Replace(")", ""); - var coord = point.Split(' '); - if (coord.Length > 1) - { - hasX = Double.TryParse(coord[0], out xVal); - hasY = Double.TryParse(coord[1], out yVal); - } - if (arrayResult.Length >= 1) - Int32.TryParse(arrayResult[0].Replace("SRID=", ""), out sridValue); - } - if (hasX && hasY) - { - mySqlGeometryValue = new MySqlGeometry(xVal, yVal, sridValue); - return true; - } - } - catch - { } - - mySqlGeometryValue = new MySqlGeometry(true); - return false; - } - - /// - /// Sets the DSInfo when GetSchema is called for the DataSourceInformation collection. - /// - public static void SetDSInfo(MySqlSchemaCollection dsTable) - { - // we use name indexing because this method will only be called - // when GetSchema is called for the DataSourceInformation - // collection and then it wil be cached. - MySqlSchemaRow row = dsTable.AddRow(); - row["TypeName"] = "GEOMETRY"; - row["ProviderDbType"] = MySqlDbType.Geometry; - row["ColumnSize"] = GEOMETRY_LENGTH; - row["CreateFormat"] = "GEOMETRY"; - row["CreateParameters"] = DBNull.Value; ; - row["DataType"] = "System.Byte[]"; - row["IsAutoincrementable"] = false; - row["IsBestMatch"] = true; - row["IsCaseSensitive"] = false; - row["IsFixedLength"] = false; - row["IsFixedPrecisionScale"] = true; - row["IsLong"] = false; - row["IsNullable"] = true; - row["IsSearchable"] = true; - row["IsSearchableWithLike"] = false; - row["IsUnsigned"] = false; - row["MaximumScale"] = 0; - row["MinimumScale"] = 0; - row["IsConcurrencyType"] = DBNull.Value; - row["IsLiteralSupported"] = false; - row["LiteralPrefix"] = DBNull.Value; - row["LiteralSuffix"] = DBNull.Value; - row["NativeDataType"] = DBNull.Value; - } - - /// - /// Gets the well-known text representation of the geomtry object. - /// - /// A string representation of the WKT. - public string GetWKT() - { - if (!this.IsNull) - return string.Format(CultureInfo.InvariantCulture.NumberFormat, "POINT({0} {1})", _xValue, _yValue); - - return String.Empty; - } - } -} +// Copyright © 2013, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data.MySqlClient; +using System; +using System.Globalization; +using System.Threading.Tasks; + +namespace MySql.Data.Types +{ + //Bytes structure is: + //SRID [0 - 3] + //Byte order [4] + //WKB type [5 - 8] + //X [9 - 16] + //Y [17 - 24] + //The byte order may be either 1 or 0 to indicate little-endian or + //big-endian storage. The little-endian and big-endian byte orders + //are also known as Network Data Representation (NDR) and External + //Data Representation (XDR), respectively. + + //The WKB type is a code that indicates the geometry type. Values + //from 1 through 7 indicate Point, LineString, Polygon, MultiPoint, + //MultiLineString, MultiPolygon, and GeometryCollection. + + /// + /// Represents a geometry data type object in a MySql database. + /// + public struct MySqlGeometry : IMySqlValue + { + private readonly MySqlDbType _type; + private readonly Double _xValue; + private readonly Double _yValue; + private readonly int _srid; + + private const int GEOMETRY_LENGTH = 25; + + /// + /// Gets the x coordinate. + /// + public Double? XCoordinate => _xValue; + + /// + /// Gets the y coordinate. + /// + public Double? YCoordinate => _yValue; + + /// + /// Gets the SRID value. + /// + public int? SRID => _srid; + + public MySqlGeometry(bool isNull) : this(MySqlDbType.Geometry, isNull) + { + } + + public MySqlGeometry(Double xValue, Double yValue) + : this(MySqlDbType.Geometry, xValue, yValue, 0) + { } + + public MySqlGeometry(Double xValue, Double yValue, int srid) + : this(MySqlDbType.Geometry, xValue, yValue, srid) + { } + + + internal MySqlGeometry(MySqlDbType type, bool isNull) + { + this._type = type; + isNull = true; + _xValue = 0; + _yValue = 0; + _srid = 0; + Value = null; + this.IsNull = isNull; + } + + + internal MySqlGeometry(MySqlDbType type, Double xValue, Double yValue, int srid) + { + this._type = type; + this._xValue = xValue; + this._yValue = yValue; + this.IsNull = false; + this._srid = srid; + this.Value = new byte[GEOMETRY_LENGTH]; + + byte[] sridBinary = PacketBitConverter.GetBytes(srid); + + for (int i = 0; i < sridBinary.Length; i++) + Value[i] = sridBinary[i]; + + long xVal = BitConverter.DoubleToInt64Bits(xValue); + long yVal = BitConverter.DoubleToInt64Bits(yValue); + + Value[4] = 1; + Value[5] = 1; + + for (int i = 0; i < 8; i++) + { + Value[i + 9] = (byte)(xVal & 0xff); + xVal >>= 8; + } + + for (int i = 0; i < 8; i++) + { + Value[i + 17] = (byte)(yVal & 0xff); + yVal >>= 8; + } + } + + public MySqlGeometry(MySqlDbType type, byte[] val) + { + + if (val == null) + throw new ArgumentNullException(nameof(val)); + + byte[] buffValue = new byte[val.Length]; + + for (int i = 0; i < val.Length; i++) + buffValue[i] = val[i]; + + var xIndex = val.Length == GEOMETRY_LENGTH ? 9 : 5; + var yIndex = val.Length == GEOMETRY_LENGTH ? 17 : 13; + + Value = buffValue; + _xValue = val.Length >= xIndex + 8 ? PacketBitConverter.ToDouble(val, xIndex) : 0; + _yValue = val.Length >= yIndex + 8 ? PacketBitConverter.ToDouble(val, yIndex) : 0; + this._srid = val.Length == GEOMETRY_LENGTH ? PacketBitConverter.ToInt32(val, 0) : 0; + this.IsNull = false; + this._type = type; + } + + #region IMySqlValue Members + + + MySqlDbType IMySqlValue.MySqlDbType => _type; + + /// + /// Gets a boolean value that signals if the type is null. + /// + public bool IsNull { get; } + + /// + /// Gets the value associated to this type. + /// + object IMySqlValue.Value => Value; + + /// + /// Gets the value associated to this type. + /// + public byte[] Value { get; } + + Type IMySqlValue.SystemType => typeof(byte[]); + + string IMySqlValue.MySqlTypeName => "GEOMETRY"; + + async Task IMySqlValue.WriteValueAsync(MySqlPacket packet, bool binary, object val, int length, bool execAsync) + { + byte[] buffToWrite = null; + + try + { + buffToWrite = ((MySqlGeometry)val).Value; + } + catch + { + buffToWrite = val as Byte[]; + } + + if (buffToWrite == null) + { + MySqlGeometry v = new MySqlGeometry(0, 0); + MySqlGeometry.TryParse(val.ToString(), out v); + buffToWrite = v.Value; + } + + byte[] result = new byte[GEOMETRY_LENGTH]; + + for (int i = 0; i < buffToWrite.Length; i++) + { + if (buffToWrite.Length < GEOMETRY_LENGTH) + result[i + 4] = buffToWrite[i]; + else + result[i] = buffToWrite[i]; + } + + if (!binary) + { + await packet.WriteStringNoNullAsync("_binary ", execAsync).ConfigureAwait(false); + packet.WriteByte((byte)'\''); + EscapeByteArray(result, GEOMETRY_LENGTH, packet); + packet.WriteByte((byte)'\''); + } + else + await packet.WriteLenStringAsync(val.ToString(), execAsync).ConfigureAwait(false); + } + + private static void EscapeByteArray(byte[] bytes, int length, MySqlPacket packet) + { + for (int x = 0; x < length; x++) + { + byte b = bytes[x]; + if (b == '\0') + { + packet.WriteByte((byte)'\\'); + packet.WriteByte((byte)'0'); + } + + else if (b == '\\' || b == '\'' || b == '\"') + { + packet.WriteByte((byte)'\\'); + packet.WriteByte(b); + } + else + packet.WriteByte(b); + } + } + + async Task IMySqlValue.ReadValueAsync(MySqlPacket packet, long length, bool nullVal, bool execAsync) + { + MySqlGeometry g; + if (nullVal) + g = new MySqlGeometry(_type, true); + else + { + if (length == -1) + length = (long)packet.ReadFieldLength(); + + byte[] newBuff = new byte[length]; + await packet.ReadAsync(newBuff, 0, (int)length, execAsync).ConfigureAwait(false); + g = new MySqlGeometry(_type, newBuff); + } + return g; + } + + void IMySqlValue.SkipValue(MySqlPacket packet) + { + int len = (int)packet.ReadFieldLength(); + packet.Position += len; + } + + #endregion + + + /// Returns the Well-Known Text representation of this value + /// POINT({0} {1})", longitude, latitude + /// http://dev.mysql.com/doc/refman/4.1/en/gis-wkt-format.html + public override string ToString() + { + if (!this.IsNull) + return _srid != 0 ? string.Format(CultureInfo.InvariantCulture.NumberFormat, "SRID={2};POINT({0} {1})", _xValue, _yValue, _srid) : string.Format(CultureInfo.InvariantCulture.NumberFormat, "POINT({0} {1})", _xValue, _yValue); + + return String.Empty; + } + + /// + /// Get value from WKT format + /// SRID=0;POINT (x y) or POINT (x y) + /// + /// WKT string format + public static MySqlGeometry Parse(string value) + { + if (String.IsNullOrEmpty(value)) + throw new ArgumentNullException(nameof(value)); + + if (!(value.Contains("SRID") || value.Contains("POINT(") || value.Contains("POINT ("))) + throw new FormatException("String does not contain a valid geometry value"); + + MySqlGeometry result = new MySqlGeometry(0, 0); + MySqlGeometry.TryParse(value, out result); + + return result; + } + + /// + /// Try to get value from WKT format + /// SRID=0;POINT (x y) or POINT (x y) + /// + /// WKT string format + /// Out mysqlGeometryValue + public static bool TryParse(string value, out MySqlGeometry mySqlGeometryValue) + { + string[] arrayResult = new string[0]; + string strResult = string.Empty; + bool hasX = false; + bool hasY = false; + Double xVal = 0; + Double yVal = 0; + int sridValue = 0; + + try + { + if (value.Contains(";")) + arrayResult = value.Split(';'); + else + strResult = value; + + if (arrayResult.Length > 1 || strResult != String.Empty) + { + string point = strResult != String.Empty ? strResult : arrayResult[1]; + point = point.Replace("POINT (", "").Replace("POINT(", "").Replace(")", ""); + var coord = point.Split(' '); + if (coord.Length > 1) + { + hasX = Double.TryParse(coord[0], out xVal); + hasY = Double.TryParse(coord[1], out yVal); + } + if (arrayResult.Length >= 1) + Int32.TryParse(arrayResult[0].Replace("SRID=", ""), out sridValue); + } + if (hasX && hasY) + { + mySqlGeometryValue = new MySqlGeometry(xVal, yVal, sridValue); + return true; + } + } + catch + { } + + mySqlGeometryValue = new MySqlGeometry(true); + return false; + } + + /// + /// Sets the DSInfo when GetSchema is called for the DataSourceInformation collection. + /// + public static void SetDSInfo(MySqlSchemaCollection dsTable) + { + // we use name indexing because this method will only be called + // when GetSchema is called for the DataSourceInformation + // collection and then it wil be cached. + MySqlSchemaRow row = dsTable.AddRow(); + row["TypeName"] = "GEOMETRY"; + row["ProviderDbType"] = MySqlDbType.Geometry; + row["ColumnSize"] = GEOMETRY_LENGTH; + row["CreateFormat"] = "GEOMETRY"; + row["CreateParameters"] = DBNull.Value; ; + row["DataType"] = "System.Byte[]"; + row["IsAutoincrementable"] = false; + row["IsBestMatch"] = true; + row["IsCaseSensitive"] = false; + row["IsFixedLength"] = false; + row["IsFixedPrecisionScale"] = true; + row["IsLong"] = false; + row["IsNullable"] = true; + row["IsSearchable"] = true; + row["IsSearchableWithLike"] = false; + row["IsUnsigned"] = false; + row["MaximumScale"] = 0; + row["MinimumScale"] = 0; + row["IsConcurrencyType"] = DBNull.Value; + row["IsLiteralSupported"] = false; + row["LiteralPrefix"] = DBNull.Value; + row["LiteralSuffix"] = DBNull.Value; + row["NativeDataType"] = DBNull.Value; + } + + /// + /// Gets the well-known text representation of the geomtry object. + /// + /// A string representation of the WKT. + public string GetWKT() + { + if (!this.IsNull) + return string.Format(CultureInfo.InvariantCulture.NumberFormat, "POINT({0} {1})", _xValue, _yValue); + + return String.Empty; + } + } +} diff --git a/MySQL.Data/src/Types/MySqlGuid.cs b/MySQL.Data/src/Types/MySqlGuid.cs index eb8606bf9..5651a7501 100644 --- a/MySQL.Data/src/Types/MySqlGuid.cs +++ b/MySQL.Data/src/Types/MySqlGuid.cs @@ -1,209 +1,209 @@ -// Copyright (c) 2004, 2022, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data.MySqlClient; -using System; -using System.Threading.Tasks; - -namespace MySql.Data.Types -{ - internal struct MySqlGuid : IMySqlValue - { - public MySqlGuid(byte[] buff) - { - OldGuids = false; - Value = new Guid(buff); - IsNull = false; - Bytes = buff; - } - - public byte[] Bytes { get; } - - public bool OldGuids { get; set; } - - #region IMySqlValue Members - - public bool IsNull { get; private set; } - - MySqlDbType IMySqlValue.MySqlDbType => MySqlDbType.Guid; - - object IMySqlValue.Value => Value; - - public Guid Value { get; private set; } - - Type IMySqlValue.SystemType => typeof(Guid); - - string IMySqlValue.MySqlTypeName => OldGuids ? "BINARY(16)" : "CHAR(36)"; - - async Task IMySqlValue.WriteValueAsync(MySqlPacket packet, bool binary, object val, int length, bool execAsync) - { - Guid guid = Guid.Empty; - string valAsString = val as string; - byte[] valAsByte = val as byte[]; - - if (val is Guid) - guid = (Guid)val; - else - { - try - { - if (valAsString != null) - guid = new Guid(valAsString); - else if (valAsByte != null) - guid = new Guid(valAsByte); - } - catch (Exception ex) - { - throw new MySqlException(Resources.DataNotInSupportedFormat, ex); - } - } - - if (OldGuids) - await WriteOldGuidAsync(packet, guid, binary, execAsync).ConfigureAwait(false); - else - { - guid.ToString("D"); - - if (binary) - await packet.WriteLenStringAsync(guid.ToString("D"), execAsync).ConfigureAwait(false); - else - await packet.WriteStringNoNullAsync("'" + MySqlHelper.EscapeString(guid.ToString("D")) + "'", execAsync).ConfigureAwait(false); - } - } - - private async Task WriteOldGuidAsync(MySqlPacket packet, Guid guid, bool binary, bool execAsync) - { - byte[] bytes = guid.ToByteArray(); - - if (binary) - { - await packet.WriteLengthAsync(bytes.Length, execAsync).ConfigureAwait(false); - await packet.WriteAsync(bytes, execAsync).ConfigureAwait(false); - } - else - { - await packet.WriteStringNoNullAsync("_binary ", execAsync).ConfigureAwait(false); - packet.WriteByte((byte)'\''); - EscapeByteArray(bytes, bytes.Length, packet); - packet.WriteByte((byte)'\''); - } - } - - private static void EscapeByteArray(byte[] bytes, int length, MySqlPacket packet) - { - for (int x = 0; x < length; x++) - { - byte b = bytes[x]; - if (b == '\0') - { - packet.WriteByte((byte)'\\'); - packet.WriteByte((byte)'0'); - } - - else if (b == '\\' || b == '\'' || b == '\"') - { - packet.WriteByte((byte)'\\'); - packet.WriteByte(b); - } - else - packet.WriteByte(b); - } - } - - private async Task ReadOldGuidAsync(MySqlPacket packet, long length, bool execAsync) - { - if (length == -1) - length = (long)packet.ReadFieldLength(); - - byte[] buff = new byte[length]; - await packet.ReadAsync(buff, 0, (int)length, execAsync).ConfigureAwait(false); - MySqlGuid g = new MySqlGuid(buff); - g.OldGuids = OldGuids; - return g; - } - - async Task IMySqlValue.ReadValueAsync(MySqlPacket packet, long length, bool nullVal, bool execAsync) - { - MySqlGuid g = new MySqlGuid(); - g.IsNull = true; - g.OldGuids = OldGuids; - if (!nullVal) - { - if (OldGuids) - return await ReadOldGuidAsync(packet, length, execAsync).ConfigureAwait(false); - string s = String.Empty; - if (length == -1) - s = await packet.ReadLenStringAsync(execAsync).ConfigureAwait(false); - else - s = await packet.ReadStringAsync(length, execAsync).ConfigureAwait(false); - g.Value = new Guid(s); - g.IsNull = false; - } - return g; - } - - void IMySqlValue.SkipValue(MySqlPacket packet) - { - int len = (int)packet.ReadFieldLength(); - packet.Position += len; - } - - #endregion - - public static void SetDSInfo(MySqlSchemaCollection sc) - { - // we use name indexing because this method will only be called - // when GetSchema is called for the DataSourceInformation - // collection and then it wil be cached. - MySqlSchemaRow row = sc.AddRow(); - row["TypeName"] = "GUID"; - row["ProviderDbType"] = MySqlDbType.Guid; - row["ColumnSize"] = 0; - row["CreateFormat"] = "BINARY(16)"; - row["CreateParameters"] = null; - row["DataType"] = "System.Guid"; - row["IsAutoincrementable"] = false; - row["IsBestMatch"] = true; - row["IsCaseSensitive"] = false; - row["IsFixedLength"] = true; - row["IsFixedPrecisionScale"] = true; - row["IsLong"] = false; - row["IsNullable"] = true; - row["IsSearchable"] = false; - row["IsSearchableWithLike"] = false; - row["IsUnsigned"] = false; - row["MaximumScale"] = 0; - row["MinimumScale"] = 0; - row["IsConcurrencyType"] = DBNull.Value; - row["IsLiteralSupported"] = false; - row["LiteralPrefix"] = null; - row["LiteralSuffix"] = null; - row["NativeDataType"] = null; - } - } -} +// Copyright © 2004, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data.MySqlClient; +using System; +using System.Threading.Tasks; + +namespace MySql.Data.Types +{ + internal struct MySqlGuid : IMySqlValue + { + public MySqlGuid(byte[] buff) + { + OldGuids = false; + Value = new Guid(buff); + IsNull = false; + Bytes = buff; + } + + public byte[] Bytes { get; } + + public bool OldGuids { get; set; } + + #region IMySqlValue Members + + public bool IsNull { get; private set; } + + MySqlDbType IMySqlValue.MySqlDbType => MySqlDbType.Guid; + + object IMySqlValue.Value => Value; + + public Guid Value { get; private set; } + + Type IMySqlValue.SystemType => typeof(Guid); + + string IMySqlValue.MySqlTypeName => OldGuids ? "BINARY(16)" : "CHAR(36)"; + + async Task IMySqlValue.WriteValueAsync(MySqlPacket packet, bool binary, object val, int length, bool execAsync) + { + Guid guid = Guid.Empty; + string valAsString = val as string; + byte[] valAsByte = val as byte[]; + + if (val is Guid) + guid = (Guid)val; + else + { + try + { + if (valAsString != null) + guid = new Guid(valAsString); + else if (valAsByte != null) + guid = new Guid(valAsByte); + } + catch (Exception ex) + { + throw new MySqlException(Resources.DataNotInSupportedFormat, ex); + } + } + + if (OldGuids) + await WriteOldGuidAsync(packet, guid, binary, execAsync).ConfigureAwait(false); + else + { + guid.ToString("D"); + + if (binary) + await packet.WriteLenStringAsync(guid.ToString("D"), execAsync).ConfigureAwait(false); + else + await packet.WriteStringNoNullAsync("'" + MySqlHelper.EscapeString(guid.ToString("D")) + "'", execAsync).ConfigureAwait(false); + } + } + + private async Task WriteOldGuidAsync(MySqlPacket packet, Guid guid, bool binary, bool execAsync) + { + byte[] bytes = guid.ToByteArray(); + + if (binary) + { + await packet.WriteLengthAsync(bytes.Length, execAsync).ConfigureAwait(false); + await packet.WriteAsync(bytes, execAsync).ConfigureAwait(false); + } + else + { + await packet.WriteStringNoNullAsync("_binary ", execAsync).ConfigureAwait(false); + packet.WriteByte((byte)'\''); + EscapeByteArray(bytes, bytes.Length, packet); + packet.WriteByte((byte)'\''); + } + } + + private static void EscapeByteArray(byte[] bytes, int length, MySqlPacket packet) + { + for (int x = 0; x < length; x++) + { + byte b = bytes[x]; + if (b == '\0') + { + packet.WriteByte((byte)'\\'); + packet.WriteByte((byte)'0'); + } + + else if (b == '\\' || b == '\'' || b == '\"') + { + packet.WriteByte((byte)'\\'); + packet.WriteByte(b); + } + else + packet.WriteByte(b); + } + } + + private async Task ReadOldGuidAsync(MySqlPacket packet, long length, bool execAsync) + { + if (length == -1) + length = (long)packet.ReadFieldLength(); + + byte[] buff = new byte[length]; + await packet.ReadAsync(buff, 0, (int)length, execAsync).ConfigureAwait(false); + MySqlGuid g = new MySqlGuid(buff); + g.OldGuids = OldGuids; + return g; + } + + async Task IMySqlValue.ReadValueAsync(MySqlPacket packet, long length, bool nullVal, bool execAsync) + { + MySqlGuid g = new MySqlGuid(); + g.IsNull = true; + g.OldGuids = OldGuids; + if (!nullVal) + { + if (OldGuids) + return await ReadOldGuidAsync(packet, length, execAsync).ConfigureAwait(false); + string s = String.Empty; + if (length == -1) + s = await packet.ReadLenStringAsync(execAsync).ConfigureAwait(false); + else + s = await packet.ReadStringAsync(length, execAsync).ConfigureAwait(false); + g.Value = new Guid(s); + g.IsNull = false; + } + return g; + } + + void IMySqlValue.SkipValue(MySqlPacket packet) + { + int len = (int)packet.ReadFieldLength(); + packet.Position += len; + } + + #endregion + + public static void SetDSInfo(MySqlSchemaCollection sc) + { + // we use name indexing because this method will only be called + // when GetSchema is called for the DataSourceInformation + // collection and then it wil be cached. + MySqlSchemaRow row = sc.AddRow(); + row["TypeName"] = "GUID"; + row["ProviderDbType"] = MySqlDbType.Guid; + row["ColumnSize"] = 0; + row["CreateFormat"] = "BINARY(16)"; + row["CreateParameters"] = null; + row["DataType"] = "System.Guid"; + row["IsAutoincrementable"] = false; + row["IsBestMatch"] = true; + row["IsCaseSensitive"] = false; + row["IsFixedLength"] = true; + row["IsFixedPrecisionScale"] = true; + row["IsLong"] = false; + row["IsNullable"] = true; + row["IsSearchable"] = false; + row["IsSearchableWithLike"] = false; + row["IsUnsigned"] = false; + row["MaximumScale"] = 0; + row["MinimumScale"] = 0; + row["IsConcurrencyType"] = DBNull.Value; + row["IsLiteralSupported"] = false; + row["LiteralPrefix"] = null; + row["LiteralSuffix"] = null; + row["NativeDataType"] = null; + } + } +} diff --git a/MySQL.Data/src/Types/MySqlInt16.cs b/MySQL.Data/src/Types/MySqlInt16.cs index 42f32947f..96a9577e0 100644 --- a/MySQL.Data/src/Types/MySqlInt16.cs +++ b/MySQL.Data/src/Types/MySqlInt16.cs @@ -1,123 +1,123 @@ -// Copyright (c) 2004, 2022, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data.MySqlClient; -using System; -using System.Globalization; -using System.Threading.Tasks; - -namespace MySql.Data.Types -{ - internal struct MySqlInt16 : IMySqlValue - { - public MySqlInt16(bool isNull) - { - IsNull = isNull; - Value = 0; - } - - public MySqlInt16(short val) - { - IsNull = false; - Value = val; - } - - #region IMySqlValue Members - - public bool IsNull { get; } - - MySqlDbType IMySqlValue.MySqlDbType => MySqlDbType.Int16; - - object IMySqlValue.Value => Value; - - public short Value { get; } - - Type IMySqlValue.SystemType => typeof(short); - - string IMySqlValue.MySqlTypeName => "SMALLINT"; - - async Task IMySqlValue.WriteValueAsync(MySqlPacket packet, bool binary, object val, int length, bool execAsync) - { - int v = val as int? ?? Convert.ToInt32(val); - - if (binary) - await packet.WriteIntegerAsync((long)v, 2, execAsync).ConfigureAwait(false); - else - await packet.WriteStringNoNullAsync(v.ToString(CultureInfo.InvariantCulture), execAsync).ConfigureAwait(false); - } - - async Task IMySqlValue.ReadValueAsync(MySqlPacket packet, long length, bool nullVal, bool execAsync) - { - if (nullVal) - return new MySqlInt16(true); - - if (length == -1) - return new MySqlInt16((short)packet.ReadInteger(2)); - else - return new MySqlInt16(Int16.Parse(await packet.ReadStringAsync(length, execAsync).ConfigureAwait(false), CultureInfo.InvariantCulture)); - } - - void IMySqlValue.SkipValue(MySqlPacket packet) - { - packet.Position += 2; - } - - #endregion - - internal static void SetDSInfo(MySqlSchemaCollection sc) - { - // we use name indexing because this method will only be called - // when GetSchema is called for the DataSourceInformation - // collection and then it wil be cached. - MySqlSchemaRow row = sc.AddRow(); - row["TypeName"] = "SMALLINT"; - row["ProviderDbType"] = MySqlDbType.Int16; - row["ColumnSize"] = 0; - row["CreateFormat"] = "SMALLINT"; - row["CreateParameters"] = null; - row["DataType"] = "System.Int16"; - row["IsAutoincrementable"] = true; - row["IsBestMatch"] = true; - row["IsCaseSensitive"] = false; - row["IsFixedLength"] = true; - row["IsFixedPrecisionScale"] = true; - row["IsLong"] = false; - row["IsNullable"] = true; - row["IsSearchable"] = true; - row["IsSearchableWithLike"] = false; - row["IsUnsigned"] = false; - row["MaximumScale"] = 0; - row["MinimumScale"] = 0; - row["IsConcurrencyType"] = DBNull.Value; - row["IsLiteralSupported"] = false; - row["LiteralPrefix"] = null; - row["LiteralSuffix"] = null; - row["NativeDataType"] = null; - } - } -} +// Copyright © 2004, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data.MySqlClient; +using System; +using System.Globalization; +using System.Threading.Tasks; + +namespace MySql.Data.Types +{ + internal struct MySqlInt16 : IMySqlValue + { + public MySqlInt16(bool isNull) + { + IsNull = isNull; + Value = 0; + } + + public MySqlInt16(short val) + { + IsNull = false; + Value = val; + } + + #region IMySqlValue Members + + public bool IsNull { get; } + + MySqlDbType IMySqlValue.MySqlDbType => MySqlDbType.Int16; + + object IMySqlValue.Value => Value; + + public short Value { get; } + + Type IMySqlValue.SystemType => typeof(short); + + string IMySqlValue.MySqlTypeName => "SMALLINT"; + + async Task IMySqlValue.WriteValueAsync(MySqlPacket packet, bool binary, object val, int length, bool execAsync) + { + int v = val as int? ?? Convert.ToInt32(val); + + if (binary) + await packet.WriteIntegerAsync((long)v, 2, execAsync).ConfigureAwait(false); + else + await packet.WriteStringNoNullAsync(v.ToString(CultureInfo.InvariantCulture), execAsync).ConfigureAwait(false); + } + + async Task IMySqlValue.ReadValueAsync(MySqlPacket packet, long length, bool nullVal, bool execAsync) + { + if (nullVal) + return new MySqlInt16(true); + + if (length == -1) + return new MySqlInt16((short)packet.ReadInteger(2)); + else + return new MySqlInt16(Int16.Parse(await packet.ReadStringAsync(length, execAsync).ConfigureAwait(false), CultureInfo.InvariantCulture)); + } + + void IMySqlValue.SkipValue(MySqlPacket packet) + { + packet.Position += 2; + } + + #endregion + + internal static void SetDSInfo(MySqlSchemaCollection sc) + { + // we use name indexing because this method will only be called + // when GetSchema is called for the DataSourceInformation + // collection and then it wil be cached. + MySqlSchemaRow row = sc.AddRow(); + row["TypeName"] = "SMALLINT"; + row["ProviderDbType"] = MySqlDbType.Int16; + row["ColumnSize"] = 0; + row["CreateFormat"] = "SMALLINT"; + row["CreateParameters"] = null; + row["DataType"] = "System.Int16"; + row["IsAutoincrementable"] = true; + row["IsBestMatch"] = true; + row["IsCaseSensitive"] = false; + row["IsFixedLength"] = true; + row["IsFixedPrecisionScale"] = true; + row["IsLong"] = false; + row["IsNullable"] = true; + row["IsSearchable"] = true; + row["IsSearchableWithLike"] = false; + row["IsUnsigned"] = false; + row["MaximumScale"] = 0; + row["MinimumScale"] = 0; + row["IsConcurrencyType"] = DBNull.Value; + row["IsLiteralSupported"] = false; + row["LiteralPrefix"] = null; + row["LiteralSuffix"] = null; + row["NativeDataType"] = null; + } + } +} diff --git a/MySQL.Data/src/Types/MySqlInt32.cs b/MySQL.Data/src/Types/MySqlInt32.cs index a4ca91846..81aaba5af 100644 --- a/MySQL.Data/src/Types/MySqlInt32.cs +++ b/MySQL.Data/src/Types/MySqlInt32.cs @@ -1,143 +1,143 @@ -// Copyright (c) 2004, 2022, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data.MySqlClient; -using System; -using System.Globalization; -using System.Threading.Tasks; - -namespace MySql.Data.Types -{ - internal struct MySqlInt32 : IMySqlValue - { - private readonly int _value; - private readonly bool _is24Bit; - - private MySqlInt32(MySqlDbType type) - { - _is24Bit = type == MySqlDbType.Int24; - IsNull = true; - _value = 0; - } - - public MySqlInt32(MySqlDbType type, bool isNull) - : this(type) - { - IsNull = isNull; - } - - public MySqlInt32(MySqlDbType type, int val) - : this(type) - { - IsNull = false; - _value = val; - } - - #region IMySqlValue Members - - public bool IsNull { get; } - - MySqlDbType IMySqlValue.MySqlDbType => MySqlDbType.Int32; - - object IMySqlValue.Value => _value; - - public int Value => _value; - - Type IMySqlValue.SystemType => typeof(Int32); - - string IMySqlValue.MySqlTypeName => _is24Bit ? "MEDIUMINT" : "INT"; - - async Task IMySqlValue.WriteValueAsync(MySqlPacket packet, bool binary, object val, int length, bool execAsync) - { - int v = val as int? ?? Convert.ToInt32(val); - - if (binary) - await packet.WriteIntegerAsync(v, 4, execAsync).ConfigureAwait(false); - else - await packet.WriteStringNoNullAsync(v.ToString(CultureInfo.InvariantCulture), execAsync).ConfigureAwait(false); - } - - async Task IMySqlValue.ReadValueAsync(MySqlPacket packet, long length, bool nullVal, bool execAsync) - { - if (nullVal) - return new MySqlInt32((this as IMySqlValue).MySqlDbType, true); - - if (length == -1) - return new MySqlInt32((this as IMySqlValue).MySqlDbType, - packet.ReadInteger(4)); - else - return new MySqlInt32((this as IMySqlValue).MySqlDbType, Int32.Parse(await packet.ReadStringAsync(length, execAsync).ConfigureAwait(false), - CultureInfo.InvariantCulture)); - } - - void IMySqlValue.SkipValue(MySqlPacket packet) - { - packet.Position += 4; - } - - #endregion - - internal static void SetDSInfo(MySqlSchemaCollection sc) - { - string[] types = new string[] { "INT", "YEAR", "MEDIUMINT" }; - MySqlDbType[] dbtype = new MySqlDbType[] { MySqlDbType.Int32, - MySqlDbType.Year, MySqlDbType.Int24 }; - - // we use name indexing because this method will only be called - // when GetSchema is called for the DataSourceInformation - // collection and then it wil be cached. - for (int x = 0; x < types.Length; x++) - { - MySqlSchemaRow row = sc.AddRow(); - row["TypeName"] = types[x]; - row["ProviderDbType"] = dbtype[x]; - row["ColumnSize"] = 0; - row["CreateFormat"] = types[x]; - row["CreateParameters"] = null; - row["DataType"] = "System.Int32"; - row["IsAutoincrementable"] = dbtype[x] != MySqlDbType.Year; - row["IsBestMatch"] = true; - row["IsCaseSensitive"] = false; - row["IsFixedLength"] = true; - row["IsFixedPrecisionScale"] = true; - row["IsLong"] = false; - row["IsNullable"] = true; - row["IsSearchable"] = true; - row["IsSearchableWithLike"] = false; - row["IsUnsigned"] = false; - row["MaximumScale"] = 0; - row["MinimumScale"] = 0; - row["IsConcurrencyType"] = DBNull.Value; - row["IsLiteralSupported"] = false; - row["LiteralPrefix"] = null; - row["LiteralSuffix"] = null; - row["NativeDataType"] = null; - } - } - } -} +// Copyright © 2004, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data.MySqlClient; +using System; +using System.Globalization; +using System.Threading.Tasks; + +namespace MySql.Data.Types +{ + internal struct MySqlInt32 : IMySqlValue + { + private readonly int _value; + private readonly bool _is24Bit; + + private MySqlInt32(MySqlDbType type) + { + _is24Bit = type == MySqlDbType.Int24; + IsNull = true; + _value = 0; + } + + public MySqlInt32(MySqlDbType type, bool isNull) + : this(type) + { + IsNull = isNull; + } + + public MySqlInt32(MySqlDbType type, int val) + : this(type) + { + IsNull = false; + _value = val; + } + + #region IMySqlValue Members + + public bool IsNull { get; } + + MySqlDbType IMySqlValue.MySqlDbType => MySqlDbType.Int32; + + object IMySqlValue.Value => _value; + + public int Value => _value; + + Type IMySqlValue.SystemType => typeof(Int32); + + string IMySqlValue.MySqlTypeName => _is24Bit ? "MEDIUMINT" : "INT"; + + async Task IMySqlValue.WriteValueAsync(MySqlPacket packet, bool binary, object val, int length, bool execAsync) + { + int v = val as int? ?? Convert.ToInt32(val); + + if (binary) + await packet.WriteIntegerAsync(v, 4, execAsync).ConfigureAwait(false); + else + await packet.WriteStringNoNullAsync(v.ToString(CultureInfo.InvariantCulture), execAsync).ConfigureAwait(false); + } + + async Task IMySqlValue.ReadValueAsync(MySqlPacket packet, long length, bool nullVal, bool execAsync) + { + if (nullVal) + return new MySqlInt32((this as IMySqlValue).MySqlDbType, true); + + if (length == -1) + return new MySqlInt32((this as IMySqlValue).MySqlDbType, + packet.ReadInteger(4)); + else + return new MySqlInt32((this as IMySqlValue).MySqlDbType, Int32.Parse(await packet.ReadStringAsync(length, execAsync).ConfigureAwait(false), + CultureInfo.InvariantCulture)); + } + + void IMySqlValue.SkipValue(MySqlPacket packet) + { + packet.Position += 4; + } + + #endregion + + internal static void SetDSInfo(MySqlSchemaCollection sc) + { + string[] types = new string[] { "INT", "YEAR", "MEDIUMINT" }; + MySqlDbType[] dbtype = new MySqlDbType[] { MySqlDbType.Int32, + MySqlDbType.Year, MySqlDbType.Int24 }; + + // we use name indexing because this method will only be called + // when GetSchema is called for the DataSourceInformation + // collection and then it wil be cached. + for (int x = 0; x < types.Length; x++) + { + MySqlSchemaRow row = sc.AddRow(); + row["TypeName"] = types[x]; + row["ProviderDbType"] = dbtype[x]; + row["ColumnSize"] = 0; + row["CreateFormat"] = types[x]; + row["CreateParameters"] = null; + row["DataType"] = "System.Int32"; + row["IsAutoincrementable"] = dbtype[x] != MySqlDbType.Year; + row["IsBestMatch"] = true; + row["IsCaseSensitive"] = false; + row["IsFixedLength"] = true; + row["IsFixedPrecisionScale"] = true; + row["IsLong"] = false; + row["IsNullable"] = true; + row["IsSearchable"] = true; + row["IsSearchableWithLike"] = false; + row["IsUnsigned"] = false; + row["MaximumScale"] = 0; + row["MinimumScale"] = 0; + row["IsConcurrencyType"] = DBNull.Value; + row["IsLiteralSupported"] = false; + row["LiteralPrefix"] = null; + row["LiteralSuffix"] = null; + row["NativeDataType"] = null; + } + } + } +} diff --git a/MySQL.Data/src/Types/MySqlInt64.cs b/MySQL.Data/src/Types/MySqlInt64.cs index 3c14ac0a7..b0bae03ed 100644 --- a/MySQL.Data/src/Types/MySqlInt64.cs +++ b/MySQL.Data/src/Types/MySqlInt64.cs @@ -1,125 +1,125 @@ -// Copyright (c) 2004, 2022, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data.MySqlClient; -using System; -using System.Globalization; -using System.Threading.Tasks; - -namespace MySql.Data.Types -{ - internal struct MySqlInt64 : IMySqlValue - { - public MySqlInt64(bool isNull) - { - IsNull = isNull; - Value = 0; - } - - public MySqlInt64(long val) - { - IsNull = false; - Value = val; - } - - #region IMySqlValue Members - - public bool IsNull { get; } - - MySqlDbType IMySqlValue.MySqlDbType => MySqlDbType.Int64; - - object IMySqlValue.Value => Value; - - public long Value { get; } - - Type IMySqlValue.SystemType => typeof(long); - - string IMySqlValue.MySqlTypeName - { - get { return "BIGINT"; } - } - - async Task IMySqlValue.WriteValueAsync(MySqlPacket packet, bool binary, object val, int length, bool execAsync) - { - long v = val as Int64? ?? Convert.ToInt64(val); - if (binary) - await packet.WriteIntegerAsync(v, 8, execAsync).ConfigureAwait(false); - else - await packet.WriteStringNoNullAsync(v.ToString(CultureInfo.InvariantCulture), execAsync).ConfigureAwait(false); - } - - async Task IMySqlValue.ReadValueAsync(MySqlPacket packet, long length, bool nullVal, bool execAsync) - { - if (nullVal) - return new MySqlInt64(true); - - if (length == -1) - return new MySqlInt64((long)packet.ReadULong(8)); - else - return new MySqlInt64(Int64.Parse(await packet.ReadStringAsync(length, execAsync).ConfigureAwait(false), CultureInfo.InvariantCulture)); - } - - void IMySqlValue.SkipValue(MySqlPacket packet) - { - packet.Position += 8; - } - - #endregion - - internal static void SetDSInfo(MySqlSchemaCollection sc) - { - // we use name indexing because this method will only be called - // when GetSchema is called for the DataSourceInformation - // collection and then it wil be cached. - MySqlSchemaRow row = sc.AddRow(); - row["TypeName"] = "BIGINT"; - row["ProviderDbType"] = MySqlDbType.Int64; - row["ColumnSize"] = 0; - row["CreateFormat"] = "BIGINT"; - row["CreateParameters"] = null; - row["DataType"] = "System.Int64"; - row["IsAutoincrementable"] = true; - row["IsBestMatch"] = true; - row["IsCaseSensitive"] = false; - row["IsFixedLength"] = true; - row["IsFixedPrecisionScale"] = true; - row["IsLong"] = false; - row["IsNullable"] = true; - row["IsSearchable"] = true; - row["IsSearchableWithLike"] = false; - row["IsUnsigned"] = false; - row["MaximumScale"] = 0; - row["MinimumScale"] = 0; - row["IsConcurrencyType"] = DBNull.Value; - row["IsLiteralSupported"] = false; - row["LiteralPrefix"] = null; - row["LiteralSuffix"] = null; - row["NativeDataType"] = null; - } - } -} +// Copyright © 2004, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data.MySqlClient; +using System; +using System.Globalization; +using System.Threading.Tasks; + +namespace MySql.Data.Types +{ + internal struct MySqlInt64 : IMySqlValue + { + public MySqlInt64(bool isNull) + { + IsNull = isNull; + Value = 0; + } + + public MySqlInt64(long val) + { + IsNull = false; + Value = val; + } + + #region IMySqlValue Members + + public bool IsNull { get; } + + MySqlDbType IMySqlValue.MySqlDbType => MySqlDbType.Int64; + + object IMySqlValue.Value => Value; + + public long Value { get; } + + Type IMySqlValue.SystemType => typeof(long); + + string IMySqlValue.MySqlTypeName + { + get { return "BIGINT"; } + } + + async Task IMySqlValue.WriteValueAsync(MySqlPacket packet, bool binary, object val, int length, bool execAsync) + { + long v = val as Int64? ?? Convert.ToInt64(val); + if (binary) + await packet.WriteIntegerAsync(v, 8, execAsync).ConfigureAwait(false); + else + await packet.WriteStringNoNullAsync(v.ToString(CultureInfo.InvariantCulture), execAsync).ConfigureAwait(false); + } + + async Task IMySqlValue.ReadValueAsync(MySqlPacket packet, long length, bool nullVal, bool execAsync) + { + if (nullVal) + return new MySqlInt64(true); + + if (length == -1) + return new MySqlInt64((long)packet.ReadULong(8)); + else + return new MySqlInt64(Int64.Parse(await packet.ReadStringAsync(length, execAsync).ConfigureAwait(false), CultureInfo.InvariantCulture)); + } + + void IMySqlValue.SkipValue(MySqlPacket packet) + { + packet.Position += 8; + } + + #endregion + + internal static void SetDSInfo(MySqlSchemaCollection sc) + { + // we use name indexing because this method will only be called + // when GetSchema is called for the DataSourceInformation + // collection and then it wil be cached. + MySqlSchemaRow row = sc.AddRow(); + row["TypeName"] = "BIGINT"; + row["ProviderDbType"] = MySqlDbType.Int64; + row["ColumnSize"] = 0; + row["CreateFormat"] = "BIGINT"; + row["CreateParameters"] = null; + row["DataType"] = "System.Int64"; + row["IsAutoincrementable"] = true; + row["IsBestMatch"] = true; + row["IsCaseSensitive"] = false; + row["IsFixedLength"] = true; + row["IsFixedPrecisionScale"] = true; + row["IsLong"] = false; + row["IsNullable"] = true; + row["IsSearchable"] = true; + row["IsSearchableWithLike"] = false; + row["IsUnsigned"] = false; + row["MaximumScale"] = 0; + row["MinimumScale"] = 0; + row["IsConcurrencyType"] = DBNull.Value; + row["IsLiteralSupported"] = false; + row["LiteralPrefix"] = null; + row["LiteralSuffix"] = null; + row["NativeDataType"] = null; + } + } +} diff --git a/MySQL.Data/src/Types/MySqlSingle.cs b/MySQL.Data/src/Types/MySqlSingle.cs index 1cb2d544c..5973d4542 100644 --- a/MySQL.Data/src/Types/MySqlSingle.cs +++ b/MySQL.Data/src/Types/MySqlSingle.cs @@ -1,130 +1,130 @@ -// Copyright (c) 2004, 2022, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data.MySqlClient; -using System; -using System.Globalization; -using System.Threading.Tasks; - -namespace MySql.Data.Types -{ - internal struct MySqlSingle : IMySqlValue - { - public MySqlSingle(bool isNull) - { - IsNull = isNull; - Value = 0.0f; - } - - public MySqlSingle(float val) - { - IsNull = false; - Value = val; - } - - #region IMySqlValue Members - - public bool IsNull { get; } - - MySqlDbType IMySqlValue.MySqlDbType => MySqlDbType.Float; - - object IMySqlValue.Value => Value; - - public float Value { get; } - - Type IMySqlValue.SystemType => typeof(float); - - string IMySqlValue.MySqlTypeName - { - get { return "FLOAT"; } - } - - async Task IMySqlValue.WriteValueAsync(MySqlPacket packet, bool binary, object val, int length, bool execAsync) - { - Single v = val as Single? ?? Convert.ToSingle(val); - if (binary) - await packet.WriteAsync(BitConverter.GetBytes(v), execAsync).ConfigureAwait(false); - else - await packet.WriteStringNoNullAsync(v.ToString("R", CultureInfo.InvariantCulture), execAsync).ConfigureAwait(false); - } - - async Task IMySqlValue.ReadValueAsync(MySqlPacket packet, long length, bool nullVal, bool execAsync) - { - if (nullVal) - return new MySqlSingle(true); - - if (length == -1) - { - byte[] b = new byte[4]; - await packet.ReadAsync(b, 0, 4, execAsync).ConfigureAwait(false); - return new MySqlSingle(BitConverter.ToSingle(b, 0)); - } - - return new MySqlSingle(Single.Parse(await packet.ReadStringAsync(length, execAsync).ConfigureAwait(false), - CultureInfo.InvariantCulture)); - } - - void IMySqlValue.SkipValue(MySqlPacket packet) - { - packet.Position += 4; - } - - #endregion - - internal static void SetDSInfo(MySqlSchemaCollection sc) - { - // we use name indexing because this method will only be called - // when GetSchema is called for the DataSourceInformation - // collection and then it wil be cached. - MySqlSchemaRow row = sc.AddRow(); - row["TypeName"] = "FLOAT"; - row["ProviderDbType"] = MySqlDbType.Float; - row["ColumnSize"] = 0; - row["CreateFormat"] = "FLOAT"; - row["CreateParameters"] = null; - row["DataType"] = "System.Single"; - row["IsAutoincrementable"] = false; - row["IsBestMatch"] = true; - row["IsCaseSensitive"] = false; - row["IsFixedLength"] = true; - row["IsFixedPrecisionScale"] = true; - row["IsLong"] = false; - row["IsNullable"] = true; - row["IsSearchable"] = true; - row["IsSearchableWithLike"] = false; - row["IsUnsigned"] = false; - row["MaximumScale"] = 0; - row["MinimumScale"] = 0; - row["IsConcurrencyType"] = DBNull.Value; - row["IsLiteralSupported"] = false; - row["LiteralPrefix"] = null; - row["LiteralSuffix"] = null; - row["NativeDataType"] = null; - } - } -} \ No newline at end of file +// Copyright © 2004, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data.MySqlClient; +using System; +using System.Globalization; +using System.Threading.Tasks; + +namespace MySql.Data.Types +{ + internal struct MySqlSingle : IMySqlValue + { + public MySqlSingle(bool isNull) + { + IsNull = isNull; + Value = 0.0f; + } + + public MySqlSingle(float val) + { + IsNull = false; + Value = val; + } + + #region IMySqlValue Members + + public bool IsNull { get; } + + MySqlDbType IMySqlValue.MySqlDbType => MySqlDbType.Float; + + object IMySqlValue.Value => Value; + + public float Value { get; } + + Type IMySqlValue.SystemType => typeof(float); + + string IMySqlValue.MySqlTypeName + { + get { return "FLOAT"; } + } + + async Task IMySqlValue.WriteValueAsync(MySqlPacket packet, bool binary, object val, int length, bool execAsync) + { + Single v = val as Single? ?? Convert.ToSingle(val); + if (binary) + await packet.WriteAsync(PacketBitConverter.GetBytes(v), execAsync).ConfigureAwait(false); + else + await packet.WriteStringNoNullAsync(v.ToString("R", CultureInfo.InvariantCulture), execAsync).ConfigureAwait(false); + } + + async Task IMySqlValue.ReadValueAsync(MySqlPacket packet, long length, bool nullVal, bool execAsync) + { + if (nullVal) + return new MySqlSingle(true); + + if (length == -1) + { + byte[] b = new byte[4]; + await packet.ReadAsync(b, 0, 4, execAsync).ConfigureAwait(false); + return new MySqlSingle(PacketBitConverter.ToSingle(b, 0)); + } + + return new MySqlSingle(Single.Parse(await packet.ReadStringAsync(length, execAsync).ConfigureAwait(false), + CultureInfo.InvariantCulture)); + } + + void IMySqlValue.SkipValue(MySqlPacket packet) + { + packet.Position += 4; + } + + #endregion + + internal static void SetDSInfo(MySqlSchemaCollection sc) + { + // we use name indexing because this method will only be called + // when GetSchema is called for the DataSourceInformation + // collection and then it wil be cached. + MySqlSchemaRow row = sc.AddRow(); + row["TypeName"] = "FLOAT"; + row["ProviderDbType"] = MySqlDbType.Float; + row["ColumnSize"] = 0; + row["CreateFormat"] = "FLOAT"; + row["CreateParameters"] = null; + row["DataType"] = "System.Single"; + row["IsAutoincrementable"] = false; + row["IsBestMatch"] = true; + row["IsCaseSensitive"] = false; + row["IsFixedLength"] = true; + row["IsFixedPrecisionScale"] = true; + row["IsLong"] = false; + row["IsNullable"] = true; + row["IsSearchable"] = true; + row["IsSearchableWithLike"] = false; + row["IsUnsigned"] = false; + row["MaximumScale"] = 0; + row["MinimumScale"] = 0; + row["IsConcurrencyType"] = DBNull.Value; + row["IsLiteralSupported"] = false; + row["LiteralPrefix"] = null; + row["LiteralSuffix"] = null; + row["NativeDataType"] = null; + } + } +} diff --git a/MySQL.Data/src/Types/MySqlString.cs b/MySQL.Data/src/Types/MySqlString.cs index a442a4256..d7b2a8b2b 100644 --- a/MySQL.Data/src/Types/MySqlString.cs +++ b/MySQL.Data/src/Types/MySqlString.cs @@ -1,145 +1,145 @@ -// Copyright (c) 2004, 2022, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data.MySqlClient; -using System; -using System.Threading.Tasks; - -namespace MySql.Data.Types -{ - internal struct MySqlString : IMySqlValue - { - private readonly MySqlDbType _type; - - public MySqlString(MySqlDbType type, bool isNull) - { - _type = type; - IsNull = isNull; - Value = String.Empty; - } - - public MySqlString(MySqlDbType type, string val) - { - _type = type; - IsNull = false; - Value = val; - } - - #region IMySqlValue Members - - public bool IsNull { get; } - - MySqlDbType IMySqlValue.MySqlDbType => _type; - - object IMySqlValue.Value => Value; - - public string Value { get; } - - Type IMySqlValue.SystemType => typeof(string); - - string IMySqlValue.MySqlTypeName => _type == MySqlDbType.Set ? "SET" : _type == MySqlDbType.Enum ? "ENUM" : "VARCHAR"; - - async Task IMySqlValue.WriteValueAsync(MySqlPacket packet, bool binary, object val, int length, bool execAsync) - { - string v = val.ToString(); - if (length > 0) - { - length = Math.Min(length, v.Length); - v = v.Substring(0, length); - } - - if (binary) - await packet.WriteLenStringAsync(v, execAsync).ConfigureAwait(false); - else - await packet.WriteStringNoNullAsync("'" + MySqlHelper.EscapeString(v) + "'", execAsync).ConfigureAwait(false); - } - - async Task IMySqlValue.ReadValueAsync(MySqlPacket packet, long length, bool nullVal, bool execAsync) - { - if (nullVal) - return new MySqlString(_type, true); - - string s = String.Empty; - if (length == -1) - s = await packet.ReadLenStringAsync(execAsync).ConfigureAwait(false); - else - s = await packet.ReadStringAsync(length, execAsync).ConfigureAwait(false); - MySqlString str = new MySqlString(_type, s); - return str; - } - - void IMySqlValue.SkipValue(MySqlPacket packet) - { - int len = (int)packet.ReadFieldLength(); - packet.Position += len; - } - - #endregion - - internal static void SetDSInfo(MySqlSchemaCollection sc) - { - string[] types = new string[] { "CHAR", "NCHAR", "VARCHAR", "NVARCHAR", "SET", - "ENUM", "TINYTEXT", "TEXT", "MEDIUMTEXT", "LONGTEXT" }; - MySqlDbType[] dbtype = new MySqlDbType[] { MySqlDbType.String, MySqlDbType.String, - MySqlDbType.VarChar, MySqlDbType.VarChar, MySqlDbType.Set, MySqlDbType.Enum, - MySqlDbType.TinyText, MySqlDbType.Text, MySqlDbType.MediumText, - MySqlDbType.LongText }; - - // we use name indexing because this method will only be called - // when GetSchema is called for the DataSourceInformation - // collection and then it wil be cached. - for (int x = 0; x < types.Length; x++) - { - MySqlSchemaRow row = sc.AddRow(); - row["TypeName"] = types[x]; - row["ProviderDbType"] = dbtype[x]; - row["ColumnSize"] = 0; - row["CreateFormat"] = x < 4 ? types[x] + "({0})" : types[x]; - row["CreateParameters"] = x < 4 ? "size" : null; - row["DataType"] = "System.String"; - row["IsAutoincrementable"] = false; - row["IsBestMatch"] = true; - row["IsCaseSensitive"] = false; - row["IsFixedLength"] = false; - row["IsFixedPrecisionScale"] = true; - row["IsLong"] = false; - row["IsNullable"] = true; - row["IsSearchable"] = true; - row["IsSearchableWithLike"] = true; - row["IsUnsigned"] = false; - row["MaximumScale"] = 0; - row["MinimumScale"] = 0; - row["IsConcurrencyType"] = DBNull.Value; - row["IsLiteralSupported"] = false; - row["LiteralPrefix"] = null; - row["LiteralSuffix"] = null; - row["NativeDataType"] = null; - } - } - } -} \ No newline at end of file +// Copyright © 2004, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data.MySqlClient; +using System; +using System.Threading.Tasks; + +namespace MySql.Data.Types +{ + internal struct MySqlString : IMySqlValue + { + private readonly MySqlDbType _type; + + public MySqlString(MySqlDbType type, bool isNull) + { + _type = type; + IsNull = isNull; + Value = String.Empty; + } + + public MySqlString(MySqlDbType type, string val) + { + _type = type; + IsNull = false; + Value = val; + } + + #region IMySqlValue Members + + public bool IsNull { get; } + + MySqlDbType IMySqlValue.MySqlDbType => _type; + + object IMySqlValue.Value => Value; + + public string Value { get; } + + Type IMySqlValue.SystemType => typeof(string); + + string IMySqlValue.MySqlTypeName => _type == MySqlDbType.Set ? "SET" : _type == MySqlDbType.Enum ? "ENUM" : "VARCHAR"; + + async Task IMySqlValue.WriteValueAsync(MySqlPacket packet, bool binary, object val, int length, bool execAsync) + { + string v = val.ToString(); + if (length > 0) + { + length = Math.Min(length, v.Length); + v = v.Substring(0, length); + } + + if (binary) + await packet.WriteLenStringAsync(v, execAsync).ConfigureAwait(false); + else + await packet.WriteStringNoNullAsync("'" + MySqlHelper.EscapeString(v) + "'", execAsync).ConfigureAwait(false); + } + + async Task IMySqlValue.ReadValueAsync(MySqlPacket packet, long length, bool nullVal, bool execAsync) + { + if (nullVal) + return new MySqlString(_type, true); + + string s = String.Empty; + if (length == -1) + s = await packet.ReadLenStringAsync(execAsync).ConfigureAwait(false); + else + s = await packet.ReadStringAsync(length, execAsync).ConfigureAwait(false); + MySqlString str = new MySqlString(_type, s); + return str; + } + + void IMySqlValue.SkipValue(MySqlPacket packet) + { + int len = (int)packet.ReadFieldLength(); + packet.Position += len; + } + + #endregion + + internal static void SetDSInfo(MySqlSchemaCollection sc) + { + string[] types = new string[] { "CHAR", "NCHAR", "VARCHAR", "NVARCHAR", "SET", + "ENUM", "TINYTEXT", "TEXT", "MEDIUMTEXT", "LONGTEXT" }; + MySqlDbType[] dbtype = new MySqlDbType[] { MySqlDbType.String, MySqlDbType.String, + MySqlDbType.VarChar, MySqlDbType.VarChar, MySqlDbType.Set, MySqlDbType.Enum, + MySqlDbType.TinyText, MySqlDbType.Text, MySqlDbType.MediumText, + MySqlDbType.LongText }; + + // we use name indexing because this method will only be called + // when GetSchema is called for the DataSourceInformation + // collection and then it wil be cached. + for (int x = 0; x < types.Length; x++) + { + MySqlSchemaRow row = sc.AddRow(); + row["TypeName"] = types[x]; + row["ProviderDbType"] = dbtype[x]; + row["ColumnSize"] = 0; + row["CreateFormat"] = x < 4 ? types[x] + "({0})" : types[x]; + row["CreateParameters"] = x < 4 ? "size" : null; + row["DataType"] = "System.String"; + row["IsAutoincrementable"] = false; + row["IsBestMatch"] = true; + row["IsCaseSensitive"] = false; + row["IsFixedLength"] = false; + row["IsFixedPrecisionScale"] = true; + row["IsLong"] = false; + row["IsNullable"] = true; + row["IsSearchable"] = true; + row["IsSearchableWithLike"] = true; + row["IsUnsigned"] = false; + row["MaximumScale"] = 0; + row["MinimumScale"] = 0; + row["IsConcurrencyType"] = DBNull.Value; + row["IsLiteralSupported"] = false; + row["LiteralPrefix"] = null; + row["LiteralSuffix"] = null; + row["NativeDataType"] = null; + } + } + } +} diff --git a/MySQL.Data/src/Types/MySqlTime.cs b/MySQL.Data/src/Types/MySqlTime.cs index 4df93332f..bd0969023 100644 --- a/MySQL.Data/src/Types/MySqlTime.cs +++ b/MySQL.Data/src/Types/MySqlTime.cs @@ -1,218 +1,218 @@ -// Copyright (c) 2004, 2022, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data.MySqlClient; -using System; -using System.Globalization; -using System.Threading.Tasks; - -namespace MySql.Data.Types -{ - internal struct MySqlTimeSpan : IMySqlValue - { - public MySqlTimeSpan(bool isNull) - { - IsNull = isNull; - Value = TimeSpan.MinValue; - } - - public MySqlTimeSpan(TimeSpan val) - { - IsNull = false; - Value = val; - } - - #region IMySqlValue Members - - public bool IsNull { get; private set; } - - MySqlDbType IMySqlValue.MySqlDbType => MySqlDbType.Time; - - object IMySqlValue.Value => Value; - - public TimeSpan Value { get; private set; } - - Type IMySqlValue.SystemType => typeof(TimeSpan); - - string IMySqlValue.MySqlTypeName => "TIME"; - - async Task IMySqlValue.WriteValueAsync(MySqlPacket packet, bool binary, object val, int length, bool execAsync) - { -#if NET6_0_OR_GREATER - if (val is TimeOnly) - val = ((TimeOnly)val).ToTimeSpan(); -#endif - if (!(val is TimeSpan)) - throw new MySqlException("Only TimeSpan objects can be serialized by MySqlTimeSpan"); - - TimeSpan ts = (TimeSpan)val; - bool negative = ts.TotalMilliseconds < 0; - ts = ts.Duration(); - - if (binary) - { - if (ts.Milliseconds > 0) - packet.WriteByte(12); - else - packet.WriteByte(8); - - packet.WriteByte((byte)(negative ? 1 : 0)); - await packet.WriteIntegerAsync(ts.Days, 4, execAsync).ConfigureAwait(false); - packet.WriteByte((byte)ts.Hours); - packet.WriteByte((byte)ts.Minutes); - packet.WriteByte((byte)ts.Seconds); - var microseconds = (int)(ts.Ticks % 10_000_000) / 10; - - if (microseconds != 0) - await packet.WriteIntegerAsync(microseconds, 4, execAsync).ConfigureAwait(false); - } - else - { - String s = $"'{(negative ? "-" : "")}{ts.Days} {ts.Hours:00}:{ts.Minutes:00}:{ts.Seconds:00}.{ts.Ticks % 10000000 / 10:000000}'"; - - await packet.WriteStringNoNullAsync(s, execAsync).ConfigureAwait(false); - } - } - - - async Task IMySqlValue.ReadValueAsync(MySqlPacket packet, long length, bool nullVal, bool execAsync) - { - if (nullVal) return new MySqlTimeSpan(true); - - if (length >= 0) - { - string value = await packet.ReadStringAsync(length, execAsync).ConfigureAwait(false); - ParseMySql(value); - return this; - } - - long bufLength = packet.ReadByte(); - int negate = 0; - if (bufLength > 0) - negate = packet.ReadByte(); - - IsNull = false; - if (bufLength == 0) - { - IsNull = true; - Value = new MySqlTimeSpan().Value; - } - else if (bufLength == 5) - Value = new TimeSpan(packet.ReadInteger(4), 0, 0, 0); - else if (bufLength == 8) - Value = new TimeSpan(packet.ReadInteger(4), - packet.ReadByte(), packet.ReadByte(), packet.ReadByte()); - else - { - var days = (int)packet.ReadInteger(4); - var hours = (int)packet.ReadByte(); - var minutes = (int)packet.ReadByte(); - var seconds = (int)packet.ReadByte(); - var microseconds = (int)packet.ReadInteger(4); - Value = new TimeSpan(days, hours, minutes, seconds) + TimeSpan.FromTicks(microseconds * 10); - } - - if (negate == 1) - Value = Value.Negate(); - return this; - } - - void IMySqlValue.SkipValue(MySqlPacket packet) - { - int len = packet.ReadByte(); - packet.Position += len; - } - - #endregion - - internal static void SetDSInfo(MySqlSchemaCollection sc) - { - // we use name indexing because this method will only be called - // when GetSchema is called for the DataSourceInformation - // collection and then it wil be cached. - MySqlSchemaRow row = sc.AddRow(); - row["TypeName"] = "TIME"; - row["ProviderDbType"] = MySqlDbType.Time; - row["ColumnSize"] = 0; - row["CreateFormat"] = "TIME"; - row["CreateParameters"] = null; - row["DataType"] = "System.TimeSpan"; - row["IsAutoincrementable"] = false; - row["IsBestMatch"] = true; - row["IsCaseSensitive"] = false; - row["IsFixedLength"] = true; - row["IsFixedPrecisionScale"] = true; - row["IsLong"] = false; - row["IsNullable"] = true; - row["IsSearchable"] = true; - row["IsSearchableWithLike"] = false; - row["IsUnsigned"] = false; - row["MaximumScale"] = 0; - row["MinimumScale"] = 0; - row["IsConcurrencyType"] = DBNull.Value; - row["IsLiteralSupported"] = false; - row["LiteralPrefix"] = null; - row["LiteralSuffix"] = null; - row["NativeDataType"] = null; - } - - public override string ToString() - { - return $"{Value.Days} {Value.Hours:00}:{Value.Minutes:00}:{Value.Seconds:00}"; - } - - private void ParseMySql(string s) - { - - string[] parts = s.Split(':', '.'); - int hours = Int32.Parse(parts[0], CultureInfo.InvariantCulture); - int mins = Int32.Parse(parts[1], CultureInfo.InvariantCulture); - int secs = Int32.Parse(parts[2], CultureInfo.InvariantCulture); - int nanoseconds = 0; - - if (parts.Length > 3) - { - //if the data is saved in MySql as Time(3) the division by 1000 always returns 0, but handling the data as Time(6) the result is the expected - parts[3] = parts[3].PadRight(7, '0'); - nanoseconds = int.Parse(parts[3], CultureInfo.InvariantCulture); - } - - - if (hours < 0 || parts[0].StartsWith("-", StringComparison.Ordinal)) - { - mins *= -1; - secs *= -1; - nanoseconds *= -1; - } - int days = hours / 24; - hours = hours - (days * 24); - Value = new TimeSpan(days, hours, mins, secs).Add(new TimeSpan(nanoseconds)); - IsNull = false; - } - } -} +// Copyright © 2004, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data.MySqlClient; +using System; +using System.Globalization; +using System.Threading.Tasks; + +namespace MySql.Data.Types +{ + internal struct MySqlTimeSpan : IMySqlValue + { + public MySqlTimeSpan(bool isNull) + { + IsNull = isNull; + Value = TimeSpan.MinValue; + } + + public MySqlTimeSpan(TimeSpan val) + { + IsNull = false; + Value = val; + } + + #region IMySqlValue Members + + public bool IsNull { get; private set; } + + MySqlDbType IMySqlValue.MySqlDbType => MySqlDbType.Time; + + object IMySqlValue.Value => Value; + + public TimeSpan Value { get; private set; } + + Type IMySqlValue.SystemType => typeof(TimeSpan); + + string IMySqlValue.MySqlTypeName => "TIME"; + + async Task IMySqlValue.WriteValueAsync(MySqlPacket packet, bool binary, object val, int length, bool execAsync) + { +#if NET6_0_OR_GREATER + if (val is TimeOnly) + val = ((TimeOnly)val).ToTimeSpan(); +#endif + if (!(val is TimeSpan)) + throw new MySqlException("Only TimeSpan objects can be serialized by MySqlTimeSpan"); + + TimeSpan ts = (TimeSpan)val; + bool negative = ts.TotalMilliseconds < 0; + ts = ts.Duration(); + + if (binary) + { + if (ts.Milliseconds > 0) + packet.WriteByte(12); + else + packet.WriteByte(8); + + packet.WriteByte((byte)(negative ? 1 : 0)); + await packet.WriteIntegerAsync(ts.Days, 4, execAsync).ConfigureAwait(false); + packet.WriteByte((byte)ts.Hours); + packet.WriteByte((byte)ts.Minutes); + packet.WriteByte((byte)ts.Seconds); + var microseconds = (int)(ts.Ticks % 10_000_000) / 10; + + if (microseconds != 0) + await packet.WriteIntegerAsync(microseconds, 4, execAsync).ConfigureAwait(false); + } + else + { + String s = $"'{(negative ? "-" : "")}{ts.Days} {ts.Hours:00}:{ts.Minutes:00}:{ts.Seconds:00}.{ts.Ticks % 10000000 / 10:000000}'"; + + await packet.WriteStringNoNullAsync(s, execAsync).ConfigureAwait(false); + } + } + + + async Task IMySqlValue.ReadValueAsync(MySqlPacket packet, long length, bool nullVal, bool execAsync) + { + if (nullVal) return new MySqlTimeSpan(true); + + if (length >= 0) + { + string value = await packet.ReadStringAsync(length, execAsync).ConfigureAwait(false); + ParseMySql(value); + return this; + } + + long bufLength = packet.ReadByte(); + int negate = 0; + if (bufLength > 0) + negate = packet.ReadByte(); + + IsNull = false; + if (bufLength == 0) + { + IsNull = true; + Value = new MySqlTimeSpan().Value; + } + else if (bufLength == 5) + Value = new TimeSpan(packet.ReadInteger(4), 0, 0, 0); + else if (bufLength == 8) + Value = new TimeSpan(packet.ReadInteger(4), + packet.ReadByte(), packet.ReadByte(), packet.ReadByte()); + else + { + var days = (int)packet.ReadInteger(4); + var hours = (int)packet.ReadByte(); + var minutes = (int)packet.ReadByte(); + var seconds = (int)packet.ReadByte(); + var microseconds = (int)packet.ReadInteger(4); + Value = new TimeSpan(days, hours, minutes, seconds) + TimeSpan.FromTicks(microseconds * 10); + } + + if (negate == 1) + Value = Value.Negate(); + return this; + } + + void IMySqlValue.SkipValue(MySqlPacket packet) + { + int len = packet.ReadByte(); + packet.Position += len; + } + + #endregion + + internal static void SetDSInfo(MySqlSchemaCollection sc) + { + // we use name indexing because this method will only be called + // when GetSchema is called for the DataSourceInformation + // collection and then it wil be cached. + MySqlSchemaRow row = sc.AddRow(); + row["TypeName"] = "TIME"; + row["ProviderDbType"] = MySqlDbType.Time; + row["ColumnSize"] = 0; + row["CreateFormat"] = "TIME"; + row["CreateParameters"] = null; + row["DataType"] = "System.TimeSpan"; + row["IsAutoincrementable"] = false; + row["IsBestMatch"] = true; + row["IsCaseSensitive"] = false; + row["IsFixedLength"] = true; + row["IsFixedPrecisionScale"] = true; + row["IsLong"] = false; + row["IsNullable"] = true; + row["IsSearchable"] = true; + row["IsSearchableWithLike"] = false; + row["IsUnsigned"] = false; + row["MaximumScale"] = 0; + row["MinimumScale"] = 0; + row["IsConcurrencyType"] = DBNull.Value; + row["IsLiteralSupported"] = false; + row["LiteralPrefix"] = null; + row["LiteralSuffix"] = null; + row["NativeDataType"] = null; + } + + public override string ToString() + { + return $"{Value.Days} {Value.Hours:00}:{Value.Minutes:00}:{Value.Seconds:00}"; + } + + private void ParseMySql(string s) + { + + string[] parts = s.Split(':', '.'); + int hours = Int32.Parse(parts[0], CultureInfo.InvariantCulture); + int mins = Int32.Parse(parts[1], CultureInfo.InvariantCulture); + int secs = Int32.Parse(parts[2], CultureInfo.InvariantCulture); + int nanoseconds = 0; + + if (parts.Length > 3) + { + //if the data is saved in MySql as Time(3) the division by 1000 always returns 0, but handling the data as Time(6) the result is the expected + parts[3] = parts[3].PadRight(7, '0'); + nanoseconds = int.Parse(parts[3], CultureInfo.InvariantCulture); + } + + + if (hours < 0 || parts[0].StartsWith("-", StringComparison.Ordinal)) + { + mins *= -1; + secs *= -1; + nanoseconds *= -1; + } + int days = hours / 24; + hours = hours - (days * 24); + Value = new TimeSpan(days, hours, mins, secs).Add(new TimeSpan(nanoseconds)); + IsNull = false; + } + } +} diff --git a/MySQL.Data/src/Types/MySqlUByte.cs b/MySQL.Data/src/Types/MySqlUByte.cs index 30022d805..5db414eed 100644 --- a/MySQL.Data/src/Types/MySqlUByte.cs +++ b/MySQL.Data/src/Types/MySqlUByte.cs @@ -1,122 +1,122 @@ -// Copyright (c) 2004, 2022, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data.MySqlClient; -using System; -using System.Globalization; -using System.Threading.Tasks; - -namespace MySql.Data.Types -{ - internal struct MySqlUByte : IMySqlValue - { - public MySqlUByte(bool isNull) - { - IsNull = isNull; - Value = 0; - } - - public MySqlUByte(byte val) - { - IsNull = false; - Value = val; - } - - #region IMySqlValue Members - - public bool IsNull { get; } - - MySqlDbType IMySqlValue.MySqlDbType => MySqlDbType.UByte; - - object IMySqlValue.Value => Value; - - public byte Value { get; } - - Type IMySqlValue.SystemType => typeof(byte); - - string IMySqlValue.MySqlTypeName => "TINYINT"; - - async Task IMySqlValue.WriteValueAsync(MySqlPacket packet, bool binary, object val, int length, bool execAsync) - { - byte v = val as byte? ?? Convert.ToByte(val); - if (binary) - packet.WriteByte(v); - else - await packet.WriteStringNoNullAsync(v.ToString(CultureInfo.InvariantCulture), execAsync).ConfigureAwait(false); - } - - async Task IMySqlValue.ReadValueAsync(MySqlPacket packet, long length, bool nullVal, bool execAsync) - { - if (nullVal) - return new MySqlUByte(true); - - if (length == -1) - return new MySqlUByte((byte)packet.ReadByte()); - else - return new MySqlUByte(Byte.Parse(await packet.ReadStringAsync(length, execAsync).ConfigureAwait(false), CultureInfo.InvariantCulture)); - } - - void IMySqlValue.SkipValue(MySqlPacket packet) - { - packet.ReadByte(); - } - - #endregion - - internal static void SetDSInfo(MySqlSchemaCollection sc) - { - // we use name indexing because this method will only be called - // when GetSchema is called for the DataSourceInformation - // collection and then it wil be cached. - MySqlSchemaRow row = sc.AddRow(); - row["TypeName"] = "TINYINT"; - row["ProviderDbType"] = MySqlDbType.UByte; - row["ColumnSize"] = 0; - row["CreateFormat"] = "TINYINT UNSIGNED"; - row["CreateParameters"] = null; - row["DataType"] = "System.Byte"; - row["IsAutoincrementable"] = true; - row["IsBestMatch"] = true; - row["IsCaseSensitive"] = false; - row["IsFixedLength"] = true; - row["IsFixedPrecisionScale"] = true; - row["IsLong"] = false; - row["IsNullable"] = true; - row["IsSearchable"] = true; - row["IsSearchableWithLike"] = false; - row["IsUnsigned"] = true; - row["MaximumScale"] = 0; - row["MinimumScale"] = 0; - row["IsConcurrencyType"] = DBNull.Value; - row["IsLiteralSupported"] = false; - row["LiteralPrefix"] = null; - row["LiteralSuffix"] = null; - row["NativeDataType"] = null; - } - } -} +// Copyright © 2004, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data.MySqlClient; +using System; +using System.Globalization; +using System.Threading.Tasks; + +namespace MySql.Data.Types +{ + internal struct MySqlUByte : IMySqlValue + { + public MySqlUByte(bool isNull) + { + IsNull = isNull; + Value = 0; + } + + public MySqlUByte(byte val) + { + IsNull = false; + Value = val; + } + + #region IMySqlValue Members + + public bool IsNull { get; } + + MySqlDbType IMySqlValue.MySqlDbType => MySqlDbType.UByte; + + object IMySqlValue.Value => Value; + + public byte Value { get; } + + Type IMySqlValue.SystemType => typeof(byte); + + string IMySqlValue.MySqlTypeName => "TINYINT"; + + async Task IMySqlValue.WriteValueAsync(MySqlPacket packet, bool binary, object val, int length, bool execAsync) + { + byte v = val as byte? ?? Convert.ToByte(val); + if (binary) + packet.WriteByte(v); + else + await packet.WriteStringNoNullAsync(v.ToString(CultureInfo.InvariantCulture), execAsync).ConfigureAwait(false); + } + + async Task IMySqlValue.ReadValueAsync(MySqlPacket packet, long length, bool nullVal, bool execAsync) + { + if (nullVal) + return new MySqlUByte(true); + + if (length == -1) + return new MySqlUByte((byte)packet.ReadByte()); + else + return new MySqlUByte(Byte.Parse(await packet.ReadStringAsync(length, execAsync).ConfigureAwait(false), CultureInfo.InvariantCulture)); + } + + void IMySqlValue.SkipValue(MySqlPacket packet) + { + packet.ReadByte(); + } + + #endregion + + internal static void SetDSInfo(MySqlSchemaCollection sc) + { + // we use name indexing because this method will only be called + // when GetSchema is called for the DataSourceInformation + // collection and then it wil be cached. + MySqlSchemaRow row = sc.AddRow(); + row["TypeName"] = "TINYINT"; + row["ProviderDbType"] = MySqlDbType.UByte; + row["ColumnSize"] = 0; + row["CreateFormat"] = "TINYINT UNSIGNED"; + row["CreateParameters"] = null; + row["DataType"] = "System.Byte"; + row["IsAutoincrementable"] = true; + row["IsBestMatch"] = true; + row["IsCaseSensitive"] = false; + row["IsFixedLength"] = true; + row["IsFixedPrecisionScale"] = true; + row["IsLong"] = false; + row["IsNullable"] = true; + row["IsSearchable"] = true; + row["IsSearchableWithLike"] = false; + row["IsUnsigned"] = true; + row["MaximumScale"] = 0; + row["MinimumScale"] = 0; + row["IsConcurrencyType"] = DBNull.Value; + row["IsLiteralSupported"] = false; + row["LiteralPrefix"] = null; + row["LiteralSuffix"] = null; + row["NativeDataType"] = null; + } + } +} diff --git a/MySQL.Data/src/Types/MySqlUInt16.cs b/MySQL.Data/src/Types/MySqlUInt16.cs index e0a344f2c..183b66f77 100644 --- a/MySQL.Data/src/Types/MySqlUInt16.cs +++ b/MySQL.Data/src/Types/MySqlUInt16.cs @@ -1,122 +1,122 @@ -// Copyright (c) 2004, 2022, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data.MySqlClient; -using System; -using System.Globalization; -using System.Threading.Tasks; - -namespace MySql.Data.Types -{ - internal struct MySqlUInt16 : IMySqlValue - { - public MySqlUInt16(bool isNull) - { - IsNull = isNull; - Value = 0; - } - - public MySqlUInt16(ushort val) - { - IsNull = false; - Value = val; - } - - #region IMySqlValue Members - - public bool IsNull { get; } - - MySqlDbType IMySqlValue.MySqlDbType => MySqlDbType.UInt16; - - object IMySqlValue.Value => Value; - - public ushort Value { get; } - - Type IMySqlValue.SystemType => typeof(ushort); - - string IMySqlValue.MySqlTypeName => "SMALLINT"; - - async Task IMySqlValue.WriteValueAsync(MySqlPacket packet, bool binary, object val, int length, bool execAsync) - { - int v = (val is UInt16) ? (UInt16)val : Convert.ToUInt16(val); - if (binary) - await packet.WriteIntegerAsync(v, 2, execAsync).ConfigureAwait(false); - else - await packet.WriteStringNoNullAsync(v.ToString(CultureInfo.InvariantCulture), execAsync).ConfigureAwait(false); - } - - async Task IMySqlValue.ReadValueAsync(MySqlPacket packet, long length, bool nullVal, bool execAsync) - { - if (nullVal) - return new MySqlUInt16(true); - - if (length == -1) - return new MySqlUInt16((ushort)packet.ReadInteger(2)); - else - return new MySqlUInt16(UInt16.Parse(await packet.ReadStringAsync(length, execAsync).ConfigureAwait(false), CultureInfo.InvariantCulture)); - } - - void IMySqlValue.SkipValue(MySqlPacket packet) - { - packet.Position += 2; - } - - #endregion - - internal static void SetDSInfo(MySqlSchemaCollection sc) - { - // we use name indexing because this method will only be called - // when GetSchema is called for the DataSourceInformation - // collection and then it wil be cached. - MySqlSchemaRow row = sc.AddRow(); - row["TypeName"] = "SMALLINT"; - row["ProviderDbType"] = MySqlDbType.UInt16; - row["ColumnSize"] = 0; - row["CreateFormat"] = "SMALLINT UNSIGNED"; - row["CreateParameters"] = null; - row["DataType"] = "System.UInt16"; - row["IsAutoincrementable"] = true; - row["IsBestMatch"] = true; - row["IsCaseSensitive"] = false; - row["IsFixedLength"] = true; - row["IsFixedPrecisionScale"] = true; - row["IsLong"] = false; - row["IsNullable"] = true; - row["IsSearchable"] = true; - row["IsSearchableWithLike"] = false; - row["IsUnsigned"] = true; - row["MaximumScale"] = 0; - row["MinimumScale"] = 0; - row["IsConcurrencyType"] = DBNull.Value; - row["IsLiteralSupported"] = false; - row["LiteralPrefix"] = null; - row["LiteralSuffix"] = null; - row["NativeDataType"] = null; - } - } -} +// Copyright © 2004, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data.MySqlClient; +using System; +using System.Globalization; +using System.Threading.Tasks; + +namespace MySql.Data.Types +{ + internal struct MySqlUInt16 : IMySqlValue + { + public MySqlUInt16(bool isNull) + { + IsNull = isNull; + Value = 0; + } + + public MySqlUInt16(ushort val) + { + IsNull = false; + Value = val; + } + + #region IMySqlValue Members + + public bool IsNull { get; } + + MySqlDbType IMySqlValue.MySqlDbType => MySqlDbType.UInt16; + + object IMySqlValue.Value => Value; + + public ushort Value { get; } + + Type IMySqlValue.SystemType => typeof(ushort); + + string IMySqlValue.MySqlTypeName => "SMALLINT"; + + async Task IMySqlValue.WriteValueAsync(MySqlPacket packet, bool binary, object val, int length, bool execAsync) + { + int v = (val is UInt16) ? (UInt16)val : Convert.ToUInt16(val); + if (binary) + await packet.WriteIntegerAsync(v, 2, execAsync).ConfigureAwait(false); + else + await packet.WriteStringNoNullAsync(v.ToString(CultureInfo.InvariantCulture), execAsync).ConfigureAwait(false); + } + + async Task IMySqlValue.ReadValueAsync(MySqlPacket packet, long length, bool nullVal, bool execAsync) + { + if (nullVal) + return new MySqlUInt16(true); + + if (length == -1) + return new MySqlUInt16((ushort)packet.ReadInteger(2)); + else + return new MySqlUInt16(UInt16.Parse(await packet.ReadStringAsync(length, execAsync).ConfigureAwait(false), CultureInfo.InvariantCulture)); + } + + void IMySqlValue.SkipValue(MySqlPacket packet) + { + packet.Position += 2; + } + + #endregion + + internal static void SetDSInfo(MySqlSchemaCollection sc) + { + // we use name indexing because this method will only be called + // when GetSchema is called for the DataSourceInformation + // collection and then it wil be cached. + MySqlSchemaRow row = sc.AddRow(); + row["TypeName"] = "SMALLINT"; + row["ProviderDbType"] = MySqlDbType.UInt16; + row["ColumnSize"] = 0; + row["CreateFormat"] = "SMALLINT UNSIGNED"; + row["CreateParameters"] = null; + row["DataType"] = "System.UInt16"; + row["IsAutoincrementable"] = true; + row["IsBestMatch"] = true; + row["IsCaseSensitive"] = false; + row["IsFixedLength"] = true; + row["IsFixedPrecisionScale"] = true; + row["IsLong"] = false; + row["IsNullable"] = true; + row["IsSearchable"] = true; + row["IsSearchableWithLike"] = false; + row["IsUnsigned"] = true; + row["MaximumScale"] = 0; + row["MinimumScale"] = 0; + row["IsConcurrencyType"] = DBNull.Value; + row["IsLiteralSupported"] = false; + row["LiteralPrefix"] = null; + row["LiteralSuffix"] = null; + row["NativeDataType"] = null; + } + } +} diff --git a/MySQL.Data/src/Types/MySqlUInt32.cs b/MySQL.Data/src/Types/MySqlUInt32.cs index af0b147c8..a5d9af68d 100644 --- a/MySQL.Data/src/Types/MySqlUInt32.cs +++ b/MySQL.Data/src/Types/MySqlUInt32.cs @@ -1,144 +1,144 @@ -// Copyright (c) 2004, 2022, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data.MySqlClient; -using System; -using System.Globalization; -using System.Threading.Tasks; - -namespace MySql.Data.Types -{ - internal struct MySqlUInt32 : IMySqlValue - { - private readonly bool _is24Bit; - - private MySqlUInt32(MySqlDbType type) - { - _is24Bit = type == MySqlDbType.UInt24; - IsNull = true; - Value = 0; - } - - public MySqlUInt32(MySqlDbType type, bool isNull) - : this(type) - { - IsNull = isNull; - } - - public MySqlUInt32(MySqlDbType type, uint val) - : this(type) - { - IsNull = false; - Value = val; - } - - #region IMySqlValue Members - - public bool IsNull { get; } - - MySqlDbType IMySqlValue.MySqlDbType => MySqlDbType.UInt32; - - object IMySqlValue.Value => Value; - - public uint Value { get; } - - Type IMySqlValue.SystemType => typeof(UInt32); - - string IMySqlValue.MySqlTypeName - { - get { return _is24Bit ? "MEDIUMINT" : "INT"; } - } - - async Task IMySqlValue.WriteValueAsync(MySqlPacket packet, bool binary, object v, int length, bool execAsync) - { - uint val = v as uint? ?? Convert.ToUInt32(v); - if (binary) - await packet.WriteIntegerAsync((long)val, 4, execAsync).ConfigureAwait(false); - else - await packet.WriteStringNoNullAsync(val.ToString(CultureInfo.InvariantCulture), execAsync).ConfigureAwait(false); - } - - async Task IMySqlValue.ReadValueAsync(MySqlPacket packet, long length, bool nullVal, bool execAsync) - { - if (nullVal) - return new MySqlUInt32((this as IMySqlValue).MySqlDbType, true); - - if (length == -1) - return new MySqlUInt32((this as IMySqlValue).MySqlDbType, - (uint)packet.ReadInteger(4)); - else - return new MySqlUInt32((this as IMySqlValue).MySqlDbType, - UInt32.Parse(await packet.ReadStringAsync(length, execAsync).ConfigureAwait(false), NumberStyles.Any, CultureInfo.InvariantCulture)); - } - - void IMySqlValue.SkipValue(MySqlPacket packet) - { - packet.Position += 4; - } - - #endregion - - internal static void SetDSInfo(MySqlSchemaCollection sc) - { - string[] types = new string[] { "MEDIUMINT", "INT" }; - MySqlDbType[] dbtype = new MySqlDbType[] { MySqlDbType.UInt24, - MySqlDbType.UInt32 }; - - // we use name indexing because this method will only be called - // when GetSchema is called for the DataSourceInformation - // collection and then it will be cached. - for (int x = 0; x < types.Length; x++) - { - MySqlSchemaRow row = sc.AddRow(); - row["TypeName"] = types[x]; - row["ProviderDbType"] = dbtype[x]; - row["ColumnSize"] = 0; - row["CreateFormat"] = types[x] + " UNSIGNED"; - row["CreateParameters"] = null; - row["DataType"] = "System.UInt32"; - row["IsAutoincrementable"] = true; - row["IsBestMatch"] = true; - row["IsCaseSensitive"] = false; - row["IsFixedLength"] = true; - row["IsFixedPrecisionScale"] = true; - row["IsLong"] = false; - row["IsNullable"] = true; - row["IsSearchable"] = true; - row["IsSearchableWithLike"] = false; - row["IsUnsigned"] = true; - row["MaximumScale"] = 0; - row["MinimumScale"] = 0; - row["IsConcurrencyType"] = DBNull.Value; - row["IsLiteralSupported"] = false; - row["LiteralPrefix"] = null; - row["LiteralSuffix"] = null; - row["NativeDataType"] = null; - } - } - } -} +// Copyright © 2004, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data.MySqlClient; +using System; +using System.Globalization; +using System.Threading.Tasks; + +namespace MySql.Data.Types +{ + internal struct MySqlUInt32 : IMySqlValue + { + private readonly bool _is24Bit; + + private MySqlUInt32(MySqlDbType type) + { + _is24Bit = type == MySqlDbType.UInt24; + IsNull = true; + Value = 0; + } + + public MySqlUInt32(MySqlDbType type, bool isNull) + : this(type) + { + IsNull = isNull; + } + + public MySqlUInt32(MySqlDbType type, uint val) + : this(type) + { + IsNull = false; + Value = val; + } + + #region IMySqlValue Members + + public bool IsNull { get; } + + MySqlDbType IMySqlValue.MySqlDbType => MySqlDbType.UInt32; + + object IMySqlValue.Value => Value; + + public uint Value { get; } + + Type IMySqlValue.SystemType => typeof(UInt32); + + string IMySqlValue.MySqlTypeName + { + get { return _is24Bit ? "MEDIUMINT" : "INT"; } + } + + async Task IMySqlValue.WriteValueAsync(MySqlPacket packet, bool binary, object v, int length, bool execAsync) + { + uint val = v as uint? ?? Convert.ToUInt32(v); + if (binary) + await packet.WriteIntegerAsync((long)val, 4, execAsync).ConfigureAwait(false); + else + await packet.WriteStringNoNullAsync(val.ToString(CultureInfo.InvariantCulture), execAsync).ConfigureAwait(false); + } + + async Task IMySqlValue.ReadValueAsync(MySqlPacket packet, long length, bool nullVal, bool execAsync) + { + if (nullVal) + return new MySqlUInt32((this as IMySqlValue).MySqlDbType, true); + + if (length == -1) + return new MySqlUInt32((this as IMySqlValue).MySqlDbType, + (uint)packet.ReadInteger(4)); + else + return new MySqlUInt32((this as IMySqlValue).MySqlDbType, + UInt32.Parse(await packet.ReadStringAsync(length, execAsync).ConfigureAwait(false), NumberStyles.Any, CultureInfo.InvariantCulture)); + } + + void IMySqlValue.SkipValue(MySqlPacket packet) + { + packet.Position += 4; + } + + #endregion + + internal static void SetDSInfo(MySqlSchemaCollection sc) + { + string[] types = new string[] { "MEDIUMINT", "INT" }; + MySqlDbType[] dbtype = new MySqlDbType[] { MySqlDbType.UInt24, + MySqlDbType.UInt32 }; + + // we use name indexing because this method will only be called + // when GetSchema is called for the DataSourceInformation + // collection and then it will be cached. + for (int x = 0; x < types.Length; x++) + { + MySqlSchemaRow row = sc.AddRow(); + row["TypeName"] = types[x]; + row["ProviderDbType"] = dbtype[x]; + row["ColumnSize"] = 0; + row["CreateFormat"] = types[x] + " UNSIGNED"; + row["CreateParameters"] = null; + row["DataType"] = "System.UInt32"; + row["IsAutoincrementable"] = true; + row["IsBestMatch"] = true; + row["IsCaseSensitive"] = false; + row["IsFixedLength"] = true; + row["IsFixedPrecisionScale"] = true; + row["IsLong"] = false; + row["IsNullable"] = true; + row["IsSearchable"] = true; + row["IsSearchableWithLike"] = false; + row["IsUnsigned"] = true; + row["MaximumScale"] = 0; + row["MinimumScale"] = 0; + row["IsConcurrencyType"] = DBNull.Value; + row["IsLiteralSupported"] = false; + row["LiteralPrefix"] = null; + row["LiteralSuffix"] = null; + row["NativeDataType"] = null; + } + } + } +} diff --git a/MySQL.Data/src/Types/MySqlUInt64.cs b/MySQL.Data/src/Types/MySqlUInt64.cs index 0b7375571..d19033180 100644 --- a/MySQL.Data/src/Types/MySqlUInt64.cs +++ b/MySQL.Data/src/Types/MySqlUInt64.cs @@ -1,125 +1,125 @@ -// Copyright (c) 2004, 2022, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data.MySqlClient; -using System; -using System.Globalization; -using System.Threading.Tasks; - -namespace MySql.Data.Types -{ - internal struct MySqlUInt64 : IMySqlValue - { - public MySqlUInt64(bool isNull) - { - IsNull = isNull; - Value = 0; - } - - public MySqlUInt64(ulong val) - { - IsNull = false; - Value = val; - } - - #region IMySqlValue Members - - public bool IsNull { get; } - - MySqlDbType IMySqlValue.MySqlDbType => MySqlDbType.UInt64; - - object IMySqlValue.Value => Value; - - public ulong Value { get; } - - Type IMySqlValue.SystemType => typeof(ulong); - - string IMySqlValue.MySqlTypeName - { - get { return "BIGINT"; } - } - - async Task IMySqlValue.WriteValueAsync(MySqlPacket packet, bool binary, object val, int length, bool execAsync) - { - ulong v = val as ulong? ?? Convert.ToUInt64(val); - if (binary) - await packet.WriteIntegerAsync((long)v, 8, execAsync).ConfigureAwait(false); - else - await packet.WriteStringNoNullAsync(v.ToString(CultureInfo.InvariantCulture), execAsync).ConfigureAwait(false); - } - - async Task IMySqlValue.ReadValueAsync(MySqlPacket packet, long length, bool nullVal, bool execAsync) - { - if (nullVal) - return new MySqlUInt64(true); - - if (length == -1) - return new MySqlUInt64(packet.ReadULong(8)); - else - return new MySqlUInt64(UInt64.Parse(await packet.ReadStringAsync(length, execAsync).ConfigureAwait(false), CultureInfo.InvariantCulture)); - } - - void IMySqlValue.SkipValue(MySqlPacket packet) - { - packet.Position += 8; - } - - #endregion - - internal static void SetDSInfo(MySqlSchemaCollection sc) - { - // we use name indexing because this method will only be called - // when GetSchema is called for the DataSourceInformation - // collection and then it wil be cached. - MySqlSchemaRow row = sc.AddRow(); - row["TypeName"] = "BIGINT"; - row["ProviderDbType"] = MySqlDbType.UInt64; - row["ColumnSize"] = 0; - row["CreateFormat"] = "BIGINT UNSIGNED"; - row["CreateParameters"] = null; - row["DataType"] = "System.UInt64"; - row["IsAutoincrementable"] = true; - row["IsBestMatch"] = true; - row["IsCaseSensitive"] = false; - row["IsFixedLength"] = true; - row["IsFixedPrecisionScale"] = true; - row["IsLong"] = false; - row["IsNullable"] = true; - row["IsSearchable"] = true; - row["IsSearchableWithLike"] = false; - row["IsUnsigned"] = true; - row["MaximumScale"] = 0; - row["MinimumScale"] = 0; - row["IsConcurrencyType"] = DBNull.Value; - row["IsLiteralSupported"] = false; - row["LiteralPrefix"] = null; - row["LiteralSuffix"] = null; - row["NativeDataType"] = null; - } - } -} +// Copyright © 2004, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data.MySqlClient; +using System; +using System.Globalization; +using System.Threading.Tasks; + +namespace MySql.Data.Types +{ + internal struct MySqlUInt64 : IMySqlValue + { + public MySqlUInt64(bool isNull) + { + IsNull = isNull; + Value = 0; + } + + public MySqlUInt64(ulong val) + { + IsNull = false; + Value = val; + } + + #region IMySqlValue Members + + public bool IsNull { get; } + + MySqlDbType IMySqlValue.MySqlDbType => MySqlDbType.UInt64; + + object IMySqlValue.Value => Value; + + public ulong Value { get; } + + Type IMySqlValue.SystemType => typeof(ulong); + + string IMySqlValue.MySqlTypeName + { + get { return "BIGINT"; } + } + + async Task IMySqlValue.WriteValueAsync(MySqlPacket packet, bool binary, object val, int length, bool execAsync) + { + ulong v = val as ulong? ?? Convert.ToUInt64(val); + if (binary) + await packet.WriteIntegerAsync((long)v, 8, execAsync).ConfigureAwait(false); + else + await packet.WriteStringNoNullAsync(v.ToString(CultureInfo.InvariantCulture), execAsync).ConfigureAwait(false); + } + + async Task IMySqlValue.ReadValueAsync(MySqlPacket packet, long length, bool nullVal, bool execAsync) + { + if (nullVal) + return new MySqlUInt64(true); + + if (length == -1) + return new MySqlUInt64(packet.ReadULong(8)); + else + return new MySqlUInt64(UInt64.Parse(await packet.ReadStringAsync(length, execAsync).ConfigureAwait(false), CultureInfo.InvariantCulture)); + } + + void IMySqlValue.SkipValue(MySqlPacket packet) + { + packet.Position += 8; + } + + #endregion + + internal static void SetDSInfo(MySqlSchemaCollection sc) + { + // we use name indexing because this method will only be called + // when GetSchema is called for the DataSourceInformation + // collection and then it wil be cached. + MySqlSchemaRow row = sc.AddRow(); + row["TypeName"] = "BIGINT"; + row["ProviderDbType"] = MySqlDbType.UInt64; + row["ColumnSize"] = 0; + row["CreateFormat"] = "BIGINT UNSIGNED"; + row["CreateParameters"] = null; + row["DataType"] = "System.UInt64"; + row["IsAutoincrementable"] = true; + row["IsBestMatch"] = true; + row["IsCaseSensitive"] = false; + row["IsFixedLength"] = true; + row["IsFixedPrecisionScale"] = true; + row["IsLong"] = false; + row["IsNullable"] = true; + row["IsSearchable"] = true; + row["IsSearchableWithLike"] = false; + row["IsUnsigned"] = true; + row["MaximumScale"] = 0; + row["MinimumScale"] = 0; + row["IsConcurrencyType"] = DBNull.Value; + row["IsLiteralSupported"] = false; + row["LiteralPrefix"] = null; + row["LiteralSuffix"] = null; + row["NativeDataType"] = null; + } + } +} diff --git a/MySQL.Data/src/Utils.cs b/MySQL.Data/src/Utils.cs index 2ba51d04d..329c3a3f7 100644 --- a/MySQL.Data/src/Utils.cs +++ b/MySQL.Data/src/Utils.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2004, 2023, Oracle and/or its affiliates. +// Copyright © 2004, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/X/Authentication/ExternalAuthenticationPlugin.cs b/MySQL.Data/src/X/Authentication/ExternalAuthenticationPlugin.cs index 33dec2cfb..6417a9ad2 100644 --- a/MySQL.Data/src/X/Authentication/ExternalAuthenticationPlugin.cs +++ b/MySQL.Data/src/X/Authentication/ExternalAuthenticationPlugin.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2017, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -61,4 +61,4 @@ public string AuthName } } } -} \ No newline at end of file +} diff --git a/MySQL.Data/src/X/Authentication/MySQL41AuthenticationPlugin.cs b/MySQL.Data/src/X/Authentication/MySQL41AuthenticationPlugin.cs index b42fae652..c4ef053d3 100644 --- a/MySQL.Data/src/X/Authentication/MySQL41AuthenticationPlugin.cs +++ b/MySQL.Data/src/X/Authentication/MySQL41AuthenticationPlugin.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2015, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -90,4 +90,4 @@ public byte[] Continue(byte[] salt) return response; } } -} \ No newline at end of file +} diff --git a/MySQL.Data/src/X/Authentication/PlainAuthenticationPlugin.cs b/MySQL.Data/src/X/Authentication/PlainAuthenticationPlugin.cs index b318a48fd..824768ec1 100644 --- a/MySQL.Data/src/X/Authentication/PlainAuthenticationPlugin.cs +++ b/MySQL.Data/src/X/Authentication/PlainAuthenticationPlugin.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2017, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -70,4 +70,4 @@ public byte[] GetAuthData() )); } } -} \ No newline at end of file +} diff --git a/MySQL.Data/src/X/Common/Tools.cs b/MySQL.Data/src/X/Common/Tools.cs index 7e962eccc..814b5ab18 100644 --- a/MySQL.Data/src/X/Common/Tools.cs +++ b/MySQL.Data/src/X/Common/Tools.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2014, 2020 Oracle and/or its affiliates. +// Copyright © 2014, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/X/Common/UnmanagedLibraryLoader.cs b/MySQL.Data/src/X/Common/UnmanagedLibraryLoader.cs index 10e6829e6..a15352bee 100644 --- a/MySQL.Data/src/X/Common/UnmanagedLibraryLoader.cs +++ b/MySQL.Data/src/X/Common/UnmanagedLibraryLoader.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2020 Oracle and/or its affiliates. +// Copyright © 2022, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/X/Communication/CommunicationPacket.cs b/MySQL.Data/src/X/Communication/CommunicationPacket.cs index 63c612636..76ab9ef25 100644 --- a/MySQL.Data/src/X/Communication/CommunicationPacket.cs +++ b/MySQL.Data/src/X/Communication/CommunicationPacket.cs @@ -1,96 +1,96 @@ -// Copyright © 2015, 2019, Oracle and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -namespace MySqlX.Communication -{ - internal class CommunicationPacket - { - - public CommunicationPacket(int messageType, int length, byte[] data) - { - MessageType = messageType; - Length = length; - Buffer = data; - } - - public byte[] Buffer; - public int MessageType; - public int Length; - } - - internal enum ClientMessageId - { - CON_CAPABILITIES_GET = 1, - CON_CAPABILITIES_SET = 2, - CON_CLOSE = 3, - - SESS_AUTHENTICATE_START = 4, - SESS_AUTHENTICATE_CONTINUE = 5, - SESS_RESET = 6, - SESS_CLOSE = 7, - - SQL_STMT_EXECUTE = 12, - - CRUD_FIND = 17, - CRUD_INSERT = 18, - CRUD_UPDATE = 19, - CRUD_DELETE = 20, - - EXPECT_OPEN = 24, - EXPECT_CLOSE = 25, - - COMPRESSION = 46 - } - - - internal enum ServerMessageId - { - OK = 0, - ERROR = 1, - - CONN_CAPABILITIES = 2, - - SESS_AUTHENTICATE_CONTINUE = 3, - SESS_AUTHENTICATE_OK = 4, - - // NOTICE has to stay at 11 forever - NOTICE = 11, - - RESULTSET_COLUMN_META_DATA = 12, - RESULTSET_ROW = 13, - RESULTSET_FETCH_DONE = 14, - RESULTSET_FETCH_SUSPENDED = 15, - RESULTSET_FETCH_DONE_MORE_RESULTSETS = 16, - - SQL_STMT_EXECUTE_OK = 17, - RESULTSET_FETCH_DONE_MORE_OUT_PARAMS = 18, - - COMPRESSION = 19 - } - -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +namespace MySqlX.Communication +{ + internal class CommunicationPacket + { + + public CommunicationPacket(int messageType, int length, byte[] data) + { + MessageType = messageType; + Length = length; + Buffer = data; + } + + public byte[] Buffer; + public int MessageType; + public int Length; + } + + internal enum ClientMessageId + { + CON_CAPABILITIES_GET = 1, + CON_CAPABILITIES_SET = 2, + CON_CLOSE = 3, + + SESS_AUTHENTICATE_START = 4, + SESS_AUTHENTICATE_CONTINUE = 5, + SESS_RESET = 6, + SESS_CLOSE = 7, + + SQL_STMT_EXECUTE = 12, + + CRUD_FIND = 17, + CRUD_INSERT = 18, + CRUD_UPDATE = 19, + CRUD_DELETE = 20, + + EXPECT_OPEN = 24, + EXPECT_CLOSE = 25, + + COMPRESSION = 46 + } + + + internal enum ServerMessageId + { + OK = 0, + ERROR = 1, + + CONN_CAPABILITIES = 2, + + SESS_AUTHENTICATE_CONTINUE = 3, + SESS_AUTHENTICATE_OK = 4, + + // NOTICE has to stay at 11 forever + NOTICE = 11, + + RESULTSET_COLUMN_META_DATA = 12, + RESULTSET_ROW = 13, + RESULTSET_FETCH_DONE = 14, + RESULTSET_FETCH_SUSPENDED = 15, + RESULTSET_FETCH_DONE_MORE_RESULTSETS = 16, + + SQL_STMT_EXECUTE_OK = 17, + RESULTSET_FETCH_DONE_MORE_OUT_PARAMS = 18, + + COMPRESSION = 19 + } + +} diff --git a/MySQL.Data/src/X/Communication/XCompressionController.cs b/MySQL.Data/src/X/Communication/XCompressionController.cs index 8701b0262..7dc6485f0 100644 --- a/MySQL.Data/src/X/Communication/XCompressionController.cs +++ b/MySQL.Data/src/X/Communication/XCompressionController.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2019, 2023, Oracle and/or its affiliates. +// Copyright © 2019, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/X/Communication/XPacketProcessor.cs b/MySQL.Data/src/X/Communication/XPacketProcessor.cs index 9d19da8a8..4da0c79e3 100644 --- a/MySQL.Data/src/X/Communication/XPacketProcessor.cs +++ b/MySQL.Data/src/X/Communication/XPacketProcessor.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2023, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/X/Communication/XPacketReaderWriter.cs b/MySQL.Data/src/X/Communication/XPacketReaderWriter.cs index b962a7b6f..a9ead2a58 100644 --- a/MySQL.Data/src/X/Communication/XPacketReaderWriter.cs +++ b/MySQL.Data/src/X/Communication/XPacketReaderWriter.cs @@ -1,151 +1,151 @@ -// Copyright (c) 2015, 2023, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using Google.Protobuf; -using MySql.Data.Common; -using MySql.Data.X.Communication; -using Mysqlx; -using Mysqlx.Connection; -using System; -using System.IO; -using System.Net.Sockets; - -namespace MySqlX.Communication -{ - internal class XPacketReaderWriter - { - private Stream _stream; - private Socket _socket; - private XPacketProcessor _packetProcessor; - - /// - /// Constructor that sets the stream used to read or write data. - /// - /// The stream used to read or write data. - /// The socket to use. - public XPacketReaderWriter(Stream stream, Socket socket) - { - _stream = stream; - _socket = socket; - _packetProcessor = new XPacketProcessor(stream); - } - - /// - /// Constructor that sets the stream used to read or write data and the compression controller. - /// - /// The stream used to read or write data. - /// The compression controller for reading. - /// The compression controller for writing. - /// The socket to use. - public XPacketReaderWriter(Stream stream, XCompressionController compressionReadController, XCompressionController compressionWriteController, Socket socket) - { - _stream = stream; - _socket = socket; - CompressionReadController = compressionReadController; - CompressionWriteController = compressionWriteController; - _packetProcessor = new XPacketProcessor(stream, CompressionReadController); - } - - /// - /// Gets or sets the compression controller uses to manage compression operations. - /// - public XCompressionController CompressionReadController { get; private set; } - public XCompressionController CompressionWriteController { get; private set; } - - /// - /// Writes X Protocol frames to the X Plugin. - /// - /// The integer representation of the client message identifier used for the message. - /// The message to include in the X Protocol frame. - public void Write(int id, IMessage message) - { - var messageSize = message.CalculateSize(); - _packetProcessor.ProcessPendingPackets(_socket); - if (CompressionWriteController != null - && CompressionWriteController.IsCompressionEnabled - && messageSize > XCompressionController.COMPRESSION_THRESHOLD - && CompressionWriteController.ClientSupportedCompressedMessages.Contains((ClientMessageId)id) - ) - { - // Build the compression protobuf message. - var messageHeader = new byte[5]; - var messageBytes = message.ToByteArray(); - byte[] payload = new byte[messageHeader.Length + messageBytes.Length]; - var sizeArray = BitConverter.GetBytes(messageSize + 1); - Buffer.BlockCopy(sizeArray, 0, messageHeader, 0, sizeArray.Length); - messageHeader[4] = (byte)id; - Buffer.BlockCopy(messageHeader, 0, payload, 0, messageHeader.Length); - Buffer.BlockCopy(messageBytes, 0, payload, messageHeader.Length, messageBytes.Length); - - var compression = new Compression(); - compression.UncompressedSize = (ulong)(messageSize + messageHeader.Length); - compression.ClientMessages = (ClientMessages.Types.Type)id; - compression.Payload = ByteString.CopyFrom(CompressionWriteController.Compress(payload)); - - // Build the X Protocol frame. - _stream.Write(BitConverter.GetBytes(compression.CalculateSize() + 1), 0, 4); - _stream.WriteByte((byte)(ClientMessageId.COMPRESSION)); - if (messageSize > 0) - { - compression.WriteTo(_stream); - } - } - else - { - _stream.Write(BitConverter.GetBytes(messageSize + 1), 0, 4); - _stream.WriteByte((byte)id); - if (messageSize > 0) - { - message.WriteTo(_stream); - } - } - - _stream.Flush(); - } - - /// - /// Writes X Protocol frames to the X Plugin. - /// - /// The client message identifier used for the message. - /// The message to include in the X Protocol frame. - public void Write(ClientMessageId id, IMessage message) - { - Write((int)id, message); - } - - /// - /// Reads X Protocol frames incoming from the X Plugin. - /// - /// A instance representing the X Protocol frame that was read. - public CommunicationPacket Read() - { - return _packetProcessor.GetPacketFromNetworkStream(true); - } - - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using Google.Protobuf; +using MySql.Data.Common; +using MySql.Data.X.Communication; +using Mysqlx; +using Mysqlx.Connection; +using System; +using System.IO; +using System.Net.Sockets; + +namespace MySqlX.Communication +{ + internal class XPacketReaderWriter + { + private Stream _stream; + private Socket _socket; + private XPacketProcessor _packetProcessor; + + /// + /// Constructor that sets the stream used to read or write data. + /// + /// The stream used to read or write data. + /// The socket to use. + public XPacketReaderWriter(Stream stream, Socket socket) + { + _stream = stream; + _socket = socket; + _packetProcessor = new XPacketProcessor(stream); + } + + /// + /// Constructor that sets the stream used to read or write data and the compression controller. + /// + /// The stream used to read or write data. + /// The compression controller for reading. + /// The compression controller for writing. + /// The socket to use. + public XPacketReaderWriter(Stream stream, XCompressionController compressionReadController, XCompressionController compressionWriteController, Socket socket) + { + _stream = stream; + _socket = socket; + CompressionReadController = compressionReadController; + CompressionWriteController = compressionWriteController; + _packetProcessor = new XPacketProcessor(stream, CompressionReadController); + } + + /// + /// Gets or sets the compression controller uses to manage compression operations. + /// + public XCompressionController CompressionReadController { get; private set; } + public XCompressionController CompressionWriteController { get; private set; } + + /// + /// Writes X Protocol frames to the X Plugin. + /// + /// The integer representation of the client message identifier used for the message. + /// The message to include in the X Protocol frame. + public void Write(int id, IMessage message) + { + var messageSize = message.CalculateSize(); + _packetProcessor.ProcessPendingPackets(_socket); + if (CompressionWriteController != null + && CompressionWriteController.IsCompressionEnabled + && messageSize > XCompressionController.COMPRESSION_THRESHOLD + && CompressionWriteController.ClientSupportedCompressedMessages.Contains((ClientMessageId)id) + ) + { + // Build the compression protobuf message. + var messageHeader = new byte[5]; + var messageBytes = message.ToByteArray(); + byte[] payload = new byte[messageHeader.Length + messageBytes.Length]; + var sizeArray = BitConverter.GetBytes(messageSize + 1); + Buffer.BlockCopy(sizeArray, 0, messageHeader, 0, sizeArray.Length); + messageHeader[4] = (byte)id; + Buffer.BlockCopy(messageHeader, 0, payload, 0, messageHeader.Length); + Buffer.BlockCopy(messageBytes, 0, payload, messageHeader.Length, messageBytes.Length); + + var compression = new Compression(); + compression.UncompressedSize = (ulong)(messageSize + messageHeader.Length); + compression.ClientMessages = (ClientMessages.Types.Type)id; + compression.Payload = ByteString.CopyFrom(CompressionWriteController.Compress(payload)); + + // Build the X Protocol frame. + _stream.Write(BitConverter.GetBytes(compression.CalculateSize() + 1), 0, 4); + _stream.WriteByte((byte)(ClientMessageId.COMPRESSION)); + if (messageSize > 0) + { + compression.WriteTo(_stream); + } + } + else + { + _stream.Write(BitConverter.GetBytes(messageSize + 1), 0, 4); + _stream.WriteByte((byte)id); + if (messageSize > 0) + { + message.WriteTo(_stream); + } + } + + _stream.Flush(); + } + + /// + /// Writes X Protocol frames to the X Plugin. + /// + /// The client message identifier used for the message. + /// The message to include in the X Protocol frame. + public void Write(ClientMessageId id, IMessage message) + { + Write((int)id, message); + } + + /// + /// Reads X Protocol frames incoming from the X Plugin. + /// + /// A instance representing the X Protocol frame that was read. + public CommunicationPacket Read() + { + return _packetProcessor.GetPacketFromNetworkStream(true); + } + + } +} diff --git a/MySQL.Data/src/X/Data/CollationMap.cs b/MySQL.Data/src/X/Data/CollationMap.cs index 6b8330115..11b694d94 100644 --- a/MySQL.Data/src/X/Data/CollationMap.cs +++ b/MySQL.Data/src/X/Data/CollationMap.cs @@ -1,342 +1,342 @@ -// Copyright © 2016, 2019, Oracle and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data; -using System; -using System.Collections.Generic; - -namespace MySqlX.Data -{ - internal class CollationMap - { - private static Dictionary collations = new Dictionary(); - - static CollationMap() - { - Load(); - } - - public static string GetCollationName(int collation) - { - if (!collations.ContainsKey(collation)) - throw new KeyNotFoundException(String.Format(ResourcesX.InvalidCollationId, collation)); - return collations[collation]; - } - - private static void Load() - { - collations.Add(0, "utf8mb3_general_ci"); - collations.Add(1, "big5_chinese_ci"); - collations.Add(2, "latin2_czech_cs"); - collations.Add(3, "dec8_swedish_ci"); - collations.Add(4, "cp850_general_ci"); - collations.Add(5, "latin1_german1_ci"); - collations.Add(6, "hp8_english_ci"); - collations.Add(7, "koi8r_general_ci"); - collations.Add(8, "latin1_swedish_ci"); - collations.Add(9, "latin2_general_ci"); - collations.Add(10, "swe7_swedish_ci"); - collations.Add(11, "ascii_general_ci"); - collations.Add(12, "ujis_japanese_ci"); - collations.Add(13, "sjis_japanese_ci"); - collations.Add(14, "cp1251_bulgarian_ci"); - collations.Add(15, "latin1_danish_ci"); - collations.Add(16, "hebrew_general_ci"); - collations.Add(18, "tis620_thai_ci"); - collations.Add(19, "euckr_korean_ci"); - collations.Add(20, "latin7_estonian_cs"); - collations.Add(21, "latin2_hungarian_ci"); - collations.Add(22, "koi8u_general_ci"); - collations.Add(23, "cp1251_ukrainian_ci"); - collations.Add(24, "gb2312_chinese_ci"); - collations.Add(25, "greek_general_ci"); - collations.Add(26, "cp1250_general_ci"); - collations.Add(27, "latin2_croatian_ci"); - collations.Add(28, "gbk_chinese_ci"); - collations.Add(29, "cp1257_lithuanian_ci"); - collations.Add(30, "latin5_turkish_ci"); - collations.Add(31, "latin1_german2_ci"); - collations.Add(32, "armscii8_general_ci"); - collations.Add(33, "utf8mb3_general_ci"); - collations.Add(34, "cp1250_czech_cs"); - collations.Add(35, "ucs2_general_ci"); - collations.Add(36, "cp866_general_ci"); - collations.Add(37, "keybcs2_general_ci"); - collations.Add(38, "macce_general_ci"); - collations.Add(39, "macroman_general_ci"); - collations.Add(40, "cp852_general_ci"); - collations.Add(41, "latin7_general_ci"); - collations.Add(42, "latin7_general_cs"); - collations.Add(43, "macce_bin"); - collations.Add(44, "cp1250_croatian_ci"); - collations.Add(45, "utf8mb4_general_ci"); - collations.Add(46, "utf8mb4_bin"); - collations.Add(47, "latin1_bin"); - collations.Add(48, "latin1_general_ci"); - collations.Add(49, "latin1_general_cs"); - collations.Add(50, "cp1251_bin"); - collations.Add(51, "cp1251_general_ci"); - collations.Add(52, "cp1251_general_cs"); - collations.Add(53, "macroman_bin"); - collations.Add(54, "utf16_general_ci"); - collations.Add(55, "utf16_bin"); - collations.Add(56, "utf16le_general_ci"); - collations.Add(57, "cp1256_general_ci"); - collations.Add(58, "cp1257_bin"); - collations.Add(59, "cp1257_general_ci"); - collations.Add(60, "utf32_general_ci"); - collations.Add(61, "utf32_bin"); - collations.Add(62, "utf16le_bin"); - collations.Add(63, "binary"); - collations.Add(64, "armscii8_bin"); - collations.Add(65, "ascii_bin"); - collations.Add(66, "cp1250_bin"); - collations.Add(67, "cp1256_bin"); - collations.Add(68, "cp866_bin"); - collations.Add(69, "dec8_bin"); - collations.Add(70, "greek_bin"); - collations.Add(71, "hebrew_bin"); - collations.Add(72, "hp8_bin"); - collations.Add(73, "keybcs2_bin"); - collations.Add(74, "koi8r_bin"); - collations.Add(75, "koi8u_bin"); - collations.Add(76, "utf8mb3_tolower_ci"); - collations.Add(77, "latin2_bin"); - collations.Add(78, "latin5_bin"); - collations.Add(79, "latin7_bin"); - collations.Add(80, "cp850_bin"); - collations.Add(81, "cp852_bin"); - collations.Add(82, "swe7_bin"); - collations.Add(83, "utf8mb3_bin"); - collations.Add(84, "big5_bin"); - collations.Add(85, "euckr_bin"); - collations.Add(86, "gb2312_bin"); - collations.Add(87, "gbk_bin"); - collations.Add(88, "sjis_bin"); - collations.Add(89, "tis620_bin"); - collations.Add(90, "ucs2_bin"); - collations.Add(91, "ujis_bin"); - collations.Add(92, "geostd8_general_ci"); - collations.Add(93, "geostd8_bin"); - collations.Add(94, "latin1_spanish_ci"); - collations.Add(95, "cp932_japanese_ci"); - collations.Add(96, "cp932_bin"); - collations.Add(97, "eucjpms_japanese_ci"); - collations.Add(98, "eucjpms_bin"); - collations.Add(99, "cp1250_polish_ci"); - collations.Add(101, "utf16_unicode_ci"); - collations.Add(102, "utf16_icelandic_ci"); - collations.Add(103, "utf16_latvian_ci"); - collations.Add(104, "utf16_romanian_ci"); - collations.Add(105, "utf16_slovenian_ci"); - collations.Add(106, "utf16_polish_ci"); - collations.Add(107, "utf16_estonian_ci"); - collations.Add(108, "utf16_spanish_ci"); - collations.Add(109, "utf16_swedish_ci"); - collations.Add(110, "utf16_turkish_ci"); - collations.Add(111, "utf16_czech_ci"); - collations.Add(112, "utf16_danish_ci"); - collations.Add(113, "utf16_lithuanian_ci"); - collations.Add(114, "utf16_slovak_ci"); - collations.Add(115, "utf16_spanish2_ci"); - collations.Add(116, "utf16_roman_ci"); - collations.Add(117, "utf16_persian_ci"); - collations.Add(118, "utf16_esperanto_ci"); - collations.Add(119, "utf16_hungarian_ci"); - collations.Add(120, "utf16_sinhala_ci"); - collations.Add(121, "utf16_german2_ci"); - collations.Add(122, "utf16_croatian_ci"); - collations.Add(123, "utf16_unicode_520_ci"); - collations.Add(124, "utf16_vietnamese_ci"); - collations.Add(128, "ucs2_unicode_ci"); - collations.Add(129, "ucs2_icelandic_ci"); - collations.Add(130, "ucs2_latvian_ci"); - collations.Add(131, "ucs2_romanian_ci"); - collations.Add(132, "ucs2_slovenian_ci"); - collations.Add(133, "ucs2_polish_ci"); - collations.Add(134, "ucs2_estonian_ci"); - collations.Add(135, "ucs2_spanish_ci"); - collations.Add(136, "ucs2_swedish_ci"); - collations.Add(137, "ucs2_turkish_ci"); - collations.Add(138, "ucs2_czech_ci"); - collations.Add(139, "ucs2_danish_ci"); - collations.Add(140, "ucs2_lithuanian_ci"); - collations.Add(141, "ucs2_slovak_ci"); - collations.Add(142, "ucs2_spanish2_ci"); - collations.Add(143, "ucs2_roman_ci"); - collations.Add(144, "ucs2_persian_ci"); - collations.Add(145, "ucs2_esperanto_ci"); - collations.Add(146, "ucs2_hungarian_ci"); - collations.Add(147, "ucs2_sinhala_ci"); - collations.Add(148, "ucs2_german2_ci"); - collations.Add(149, "ucs2_croatian_ci"); - collations.Add(150, "ucs2_unicode_520_ci"); - collations.Add(151, "ucs2_vietnamese_ci"); - collations.Add(159, "ucs2_general_mysql500_ci"); - collations.Add(160, "utf32_unicode_ci"); - collations.Add(161, "utf32_icelandic_ci"); - collations.Add(162, "utf32_latvian_ci"); - collations.Add(163, "utf32_romanian_ci"); - collations.Add(164, "utf32_slovenian_ci"); - collations.Add(165, "utf32_polish_ci"); - collations.Add(166, "utf32_estonian_ci"); - collations.Add(167, "utf32_spanish_ci"); - collations.Add(168, "utf32_swedish_ci"); - collations.Add(169, "utf32_turkish_ci"); - collations.Add(170, "utf32_czech_ci"); - collations.Add(171, "utf32_danish_ci"); - collations.Add(172, "utf32_lithuanian_ci"); - collations.Add(173, "utf32_slovak_ci"); - collations.Add(174, "utf32_spanish2_ci"); - collations.Add(175, "utf32_roman_ci"); - collations.Add(176, "utf32_persian_ci"); - collations.Add(177, "utf32_esperanto_ci"); - collations.Add(178, "utf32_hungarian_ci"); - collations.Add(179, "utf32_sinhala_ci"); - collations.Add(180, "utf32_german2_ci"); - collations.Add(181, "utf32_croatian_ci"); - collations.Add(182, "utf32_unicode_520_ci"); - collations.Add(183, "utf32_vietnamese_ci"); - collations.Add(192, "utf8mb3_unicode_ci"); - collations.Add(193, "utf8mb3_icelandic_ci"); - collations.Add(194, "utf8mb3_latvian_ci"); - collations.Add(195, "utf8mb3_romanian_ci"); - collations.Add(196, "utf8mb3_slovenian_ci"); - collations.Add(197, "utf8mb3_polish_ci"); - collations.Add(198, "utf8mb3_estonian_ci"); - collations.Add(199, "utf8mb3_spanish_ci"); - collations.Add(200, "utf8mb3_swedish_ci"); - collations.Add(201, "utf8mb3_turkish_ci"); - collations.Add(202, "utf8mb3_czech_ci"); - collations.Add(203, "utf8mb3_danish_ci"); - collations.Add(204, "utf8mb3_lithuanian_ci"); - collations.Add(205, "utf8mb3_slovak_ci"); - collations.Add(206, "utf8mb3_spanish2_ci"); - collations.Add(207, "utf8mb3_roman_ci"); - collations.Add(208, "utf8mb3_persian_ci"); - collations.Add(209, "utf8mb3_esperanto_ci"); - collations.Add(210, "utf8mb3_hungarian_ci"); - collations.Add(211, "utf8mb3_sinhala_ci"); - collations.Add(212, "utf8mb3_german2_ci"); - collations.Add(213, "utf8mb3_croatian_ci"); - collations.Add(214, "utf8mb3_unicode_520_ci"); - collations.Add(215, "utf8mb3_vietnamese_ci"); - collations.Add(223, "utf8mb3_general_mysql500_ci"); - collations.Add(224, "utf8mb4_unicode_ci"); - collations.Add(225, "utf8mb4_icelandic_ci"); - collations.Add(226, "utf8mb4_latvian_ci"); - collations.Add(227, "utf8mb4_romanian_ci"); - collations.Add(228, "utf8mb4_slovenian_ci"); - collations.Add(229, "utf8mb4_polish_ci"); - collations.Add(230, "utf8mb4_estonian_ci"); - collations.Add(231, "utf8mb4_spanish_ci"); - collations.Add(232, "utf8mb4_swedish_ci"); - collations.Add(233, "utf8mb4_turkish_ci"); - collations.Add(234, "utf8mb4_czech_ci"); - collations.Add(235, "utf8mb4_danish_ci"); - collations.Add(236, "utf8mb4_lithuanian_ci"); - collations.Add(237, "utf8mb4_slovak_ci"); - collations.Add(238, "utf8mb4_spanish2_ci"); - collations.Add(239, "utf8mb4_roman_ci"); - collations.Add(240, "utf8mb4_persian_ci"); - collations.Add(241, "utf8mb4_esperanto_ci"); - collations.Add(242, "utf8mb4_hungarian_ci"); - collations.Add(243, "utf8mb4_sinhala_ci"); - collations.Add(244, "utf8mb4_german2_ci"); - collations.Add(245, "utf8mb4_croatian_ci"); - collations.Add(246, "utf8mb4_unicode_520_ci"); - collations.Add(247, "utf8mb4_vietnamese_ci"); - collations.Add(248, "gb18030_chinese_ci"); - collations.Add(249, "gb18030_bin"); - collations.Add(250, "gb18030_unicode_520_ci"); - collations.Add(255, "utf8mb4_0900_ai_ci"); - collations.Add(256, "utf8mb4_de_pb_0900_ai_ci"); - collations.Add(257, "utf8mb4_is_0900_ai_ci"); - collations.Add(258, "utf8mb4_lv_0900_ai_ci"); - collations.Add(259, "utf8mb4_ro_0900_ai_ci"); - collations.Add(260, "utf8mb4_sl_0900_ai_ci"); - collations.Add(261, "utf8mb4_pl_0900_ai_ci"); - collations.Add(262, "utf8mb4_et_0900_ai_ci"); - collations.Add(263, "utf8mb4_es_0900_ai_ci"); - collations.Add(264, "utf8mb4_sv_0900_ai_ci"); - collations.Add(265, "utf8mb4_tr_0900_ai_ci"); - collations.Add(266, "utf8mb4_cs_0900_ai_ci"); - collations.Add(267, "utf8mb4_da_0900_ai_ci"); - collations.Add(268, "utf8mb4_lt_0900_ai_ci"); - collations.Add(269, "utf8mb4_sk_0900_ai_ci"); - collations.Add(270, "utf8mb4_es_trad_0900_ai_ci"); - collations.Add(271, "utf8mb4_la_0900_ai_ci"); - collations.Add(273, "utf8mb4_eo_0900_ai_ci"); - collations.Add(274, "utf8mb4_hu_0900_ai_ci"); - collations.Add(275, "utf8mb4_hr_0900_ai_ci"); - collations.Add(277, "utf8mb4_vi_0900_ai_ci"); - collations.Add(278, "utf8mb4_0900_as_cs"); - collations.Add(279, "utf8mb4_de_pb_0900_as_cs"); - collations.Add(280, "utf8mb4_is_0900_as_cs"); - collations.Add(281, "utf8mb4_lv_0900_as_cs"); - collations.Add(282, "utf8mb4_ro_0900_as_cs"); - collations.Add(283, "utf8mb4_sl_0900_as_cs"); - collations.Add(284, "utf8mb4_pl_0900_as_cs"); - collations.Add(285, "utf8mb4_et_0900_as_cs"); - collations.Add(286, "utf8mb4_es_0900_as_cs"); - collations.Add(287, "utf8mb4_sv_0900_as_cs"); - collations.Add(288, "utf8mb4_tr_0900_as_cs"); - collations.Add(289, "utf8mb4_cs_0900_as_cs"); - collations.Add(290, "utf8mb4_da_0900_as_cs"); - collations.Add(291, "utf8mb4_lt_0900_as_cs"); - collations.Add(292, "utf8mb4_sk_0900_as_cs"); - collations.Add(293, "utf8mb4_es_trad_0900_as_cs"); - collations.Add(294, "utf8mb4_la_0900_as_cs"); - collations.Add(296, "utf8mb4_eo_0900_as_cs"); - collations.Add(297, "utf8mb4_hu_0900_as_cs"); - collations.Add(298, "utf8mb4_hr_0900_as_cs"); - collations.Add(300, "utf8mb4_vi_0900_as_cs"); - collations.Add(303, "utf8mb4_ja_0900_as_cs"); - collations.Add(304, "utf8mb4_ja_0900_as_cs_ks"); - collations.Add(305, "utf8mb4_0900_as_ci"); - collations.Add(306, "utf8mb4_ru_0900_ai_ci"); - collations.Add(307, "utf8mb4_ru_0900_as_cs"); - collations.Add(308, "utf8mb4_zh_0900_as_cs"); - collations.Add(309, "utf8mb4_0900_bin"); - collations.Add(310, "utf8mb4_nb_0900_ai_ci"); - collations.Add(311, "utf8mb4_nb_0900_as_cs"); - collations.Add(312, "utf8mb4_nn_0900_ai_ci"); - collations.Add(313, "utf8mb4_nn_0900_as_cs"); - collations.Add(314, "utf8mb4_sr_latn_0900_ai_ci"); - collations.Add(315, "utf8mb4_sr_latn_0900_as_cs"); - collations.Add(316, "utf8mb4_bs_0900_ai_ci"); - collations.Add(317, "utf8mb4_bs_0900_as_cs"); - collations.Add(318, "utf8mb4_bg_0900_ai_ci"); - collations.Add(319, "utf8mb4_bg_0900_as_cs"); - collations.Add(320, "utf8mb4_gl_0900_ai_ci"); - collations.Add(321, "utf8mb4_gl_0900_as_cs"); - collations.Add(322, "utf8mb4_mn_cyrl_0900_ai_ci"); - collations.Add(323, "utf8mb4_mn_cyrl_0900_as_cs"); - } - } -} +// Copyright © 2016, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data; +using System; +using System.Collections.Generic; + +namespace MySqlX.Data +{ + internal class CollationMap + { + private static Dictionary collations = new Dictionary(); + + static CollationMap() + { + Load(); + } + + public static string GetCollationName(int collation) + { + if (!collations.ContainsKey(collation)) + throw new KeyNotFoundException(String.Format(ResourcesX.InvalidCollationId, collation)); + return collations[collation]; + } + + private static void Load() + { + collations.Add(0, "utf8mb3_general_ci"); + collations.Add(1, "big5_chinese_ci"); + collations.Add(2, "latin2_czech_cs"); + collations.Add(3, "dec8_swedish_ci"); + collations.Add(4, "cp850_general_ci"); + collations.Add(5, "latin1_german1_ci"); + collations.Add(6, "hp8_english_ci"); + collations.Add(7, "koi8r_general_ci"); + collations.Add(8, "latin1_swedish_ci"); + collations.Add(9, "latin2_general_ci"); + collations.Add(10, "swe7_swedish_ci"); + collations.Add(11, "ascii_general_ci"); + collations.Add(12, "ujis_japanese_ci"); + collations.Add(13, "sjis_japanese_ci"); + collations.Add(14, "cp1251_bulgarian_ci"); + collations.Add(15, "latin1_danish_ci"); + collations.Add(16, "hebrew_general_ci"); + collations.Add(18, "tis620_thai_ci"); + collations.Add(19, "euckr_korean_ci"); + collations.Add(20, "latin7_estonian_cs"); + collations.Add(21, "latin2_hungarian_ci"); + collations.Add(22, "koi8u_general_ci"); + collations.Add(23, "cp1251_ukrainian_ci"); + collations.Add(24, "gb2312_chinese_ci"); + collations.Add(25, "greek_general_ci"); + collations.Add(26, "cp1250_general_ci"); + collations.Add(27, "latin2_croatian_ci"); + collations.Add(28, "gbk_chinese_ci"); + collations.Add(29, "cp1257_lithuanian_ci"); + collations.Add(30, "latin5_turkish_ci"); + collations.Add(31, "latin1_german2_ci"); + collations.Add(32, "armscii8_general_ci"); + collations.Add(33, "utf8mb3_general_ci"); + collations.Add(34, "cp1250_czech_cs"); + collations.Add(35, "ucs2_general_ci"); + collations.Add(36, "cp866_general_ci"); + collations.Add(37, "keybcs2_general_ci"); + collations.Add(38, "macce_general_ci"); + collations.Add(39, "macroman_general_ci"); + collations.Add(40, "cp852_general_ci"); + collations.Add(41, "latin7_general_ci"); + collations.Add(42, "latin7_general_cs"); + collations.Add(43, "macce_bin"); + collations.Add(44, "cp1250_croatian_ci"); + collations.Add(45, "utf8mb4_general_ci"); + collations.Add(46, "utf8mb4_bin"); + collations.Add(47, "latin1_bin"); + collations.Add(48, "latin1_general_ci"); + collations.Add(49, "latin1_general_cs"); + collations.Add(50, "cp1251_bin"); + collations.Add(51, "cp1251_general_ci"); + collations.Add(52, "cp1251_general_cs"); + collations.Add(53, "macroman_bin"); + collations.Add(54, "utf16_general_ci"); + collations.Add(55, "utf16_bin"); + collations.Add(56, "utf16le_general_ci"); + collations.Add(57, "cp1256_general_ci"); + collations.Add(58, "cp1257_bin"); + collations.Add(59, "cp1257_general_ci"); + collations.Add(60, "utf32_general_ci"); + collations.Add(61, "utf32_bin"); + collations.Add(62, "utf16le_bin"); + collations.Add(63, "binary"); + collations.Add(64, "armscii8_bin"); + collations.Add(65, "ascii_bin"); + collations.Add(66, "cp1250_bin"); + collations.Add(67, "cp1256_bin"); + collations.Add(68, "cp866_bin"); + collations.Add(69, "dec8_bin"); + collations.Add(70, "greek_bin"); + collations.Add(71, "hebrew_bin"); + collations.Add(72, "hp8_bin"); + collations.Add(73, "keybcs2_bin"); + collations.Add(74, "koi8r_bin"); + collations.Add(75, "koi8u_bin"); + collations.Add(76, "utf8mb3_tolower_ci"); + collations.Add(77, "latin2_bin"); + collations.Add(78, "latin5_bin"); + collations.Add(79, "latin7_bin"); + collations.Add(80, "cp850_bin"); + collations.Add(81, "cp852_bin"); + collations.Add(82, "swe7_bin"); + collations.Add(83, "utf8mb3_bin"); + collations.Add(84, "big5_bin"); + collations.Add(85, "euckr_bin"); + collations.Add(86, "gb2312_bin"); + collations.Add(87, "gbk_bin"); + collations.Add(88, "sjis_bin"); + collations.Add(89, "tis620_bin"); + collations.Add(90, "ucs2_bin"); + collations.Add(91, "ujis_bin"); + collations.Add(92, "geostd8_general_ci"); + collations.Add(93, "geostd8_bin"); + collations.Add(94, "latin1_spanish_ci"); + collations.Add(95, "cp932_japanese_ci"); + collations.Add(96, "cp932_bin"); + collations.Add(97, "eucjpms_japanese_ci"); + collations.Add(98, "eucjpms_bin"); + collations.Add(99, "cp1250_polish_ci"); + collations.Add(101, "utf16_unicode_ci"); + collations.Add(102, "utf16_icelandic_ci"); + collations.Add(103, "utf16_latvian_ci"); + collations.Add(104, "utf16_romanian_ci"); + collations.Add(105, "utf16_slovenian_ci"); + collations.Add(106, "utf16_polish_ci"); + collations.Add(107, "utf16_estonian_ci"); + collations.Add(108, "utf16_spanish_ci"); + collations.Add(109, "utf16_swedish_ci"); + collations.Add(110, "utf16_turkish_ci"); + collations.Add(111, "utf16_czech_ci"); + collations.Add(112, "utf16_danish_ci"); + collations.Add(113, "utf16_lithuanian_ci"); + collations.Add(114, "utf16_slovak_ci"); + collations.Add(115, "utf16_spanish2_ci"); + collations.Add(116, "utf16_roman_ci"); + collations.Add(117, "utf16_persian_ci"); + collations.Add(118, "utf16_esperanto_ci"); + collations.Add(119, "utf16_hungarian_ci"); + collations.Add(120, "utf16_sinhala_ci"); + collations.Add(121, "utf16_german2_ci"); + collations.Add(122, "utf16_croatian_ci"); + collations.Add(123, "utf16_unicode_520_ci"); + collations.Add(124, "utf16_vietnamese_ci"); + collations.Add(128, "ucs2_unicode_ci"); + collations.Add(129, "ucs2_icelandic_ci"); + collations.Add(130, "ucs2_latvian_ci"); + collations.Add(131, "ucs2_romanian_ci"); + collations.Add(132, "ucs2_slovenian_ci"); + collations.Add(133, "ucs2_polish_ci"); + collations.Add(134, "ucs2_estonian_ci"); + collations.Add(135, "ucs2_spanish_ci"); + collations.Add(136, "ucs2_swedish_ci"); + collations.Add(137, "ucs2_turkish_ci"); + collations.Add(138, "ucs2_czech_ci"); + collations.Add(139, "ucs2_danish_ci"); + collations.Add(140, "ucs2_lithuanian_ci"); + collations.Add(141, "ucs2_slovak_ci"); + collations.Add(142, "ucs2_spanish2_ci"); + collations.Add(143, "ucs2_roman_ci"); + collations.Add(144, "ucs2_persian_ci"); + collations.Add(145, "ucs2_esperanto_ci"); + collations.Add(146, "ucs2_hungarian_ci"); + collations.Add(147, "ucs2_sinhala_ci"); + collations.Add(148, "ucs2_german2_ci"); + collations.Add(149, "ucs2_croatian_ci"); + collations.Add(150, "ucs2_unicode_520_ci"); + collations.Add(151, "ucs2_vietnamese_ci"); + collations.Add(159, "ucs2_general_mysql500_ci"); + collations.Add(160, "utf32_unicode_ci"); + collations.Add(161, "utf32_icelandic_ci"); + collations.Add(162, "utf32_latvian_ci"); + collations.Add(163, "utf32_romanian_ci"); + collations.Add(164, "utf32_slovenian_ci"); + collations.Add(165, "utf32_polish_ci"); + collations.Add(166, "utf32_estonian_ci"); + collations.Add(167, "utf32_spanish_ci"); + collations.Add(168, "utf32_swedish_ci"); + collations.Add(169, "utf32_turkish_ci"); + collations.Add(170, "utf32_czech_ci"); + collations.Add(171, "utf32_danish_ci"); + collations.Add(172, "utf32_lithuanian_ci"); + collations.Add(173, "utf32_slovak_ci"); + collations.Add(174, "utf32_spanish2_ci"); + collations.Add(175, "utf32_roman_ci"); + collations.Add(176, "utf32_persian_ci"); + collations.Add(177, "utf32_esperanto_ci"); + collations.Add(178, "utf32_hungarian_ci"); + collations.Add(179, "utf32_sinhala_ci"); + collations.Add(180, "utf32_german2_ci"); + collations.Add(181, "utf32_croatian_ci"); + collations.Add(182, "utf32_unicode_520_ci"); + collations.Add(183, "utf32_vietnamese_ci"); + collations.Add(192, "utf8mb3_unicode_ci"); + collations.Add(193, "utf8mb3_icelandic_ci"); + collations.Add(194, "utf8mb3_latvian_ci"); + collations.Add(195, "utf8mb3_romanian_ci"); + collations.Add(196, "utf8mb3_slovenian_ci"); + collations.Add(197, "utf8mb3_polish_ci"); + collations.Add(198, "utf8mb3_estonian_ci"); + collations.Add(199, "utf8mb3_spanish_ci"); + collations.Add(200, "utf8mb3_swedish_ci"); + collations.Add(201, "utf8mb3_turkish_ci"); + collations.Add(202, "utf8mb3_czech_ci"); + collations.Add(203, "utf8mb3_danish_ci"); + collations.Add(204, "utf8mb3_lithuanian_ci"); + collations.Add(205, "utf8mb3_slovak_ci"); + collations.Add(206, "utf8mb3_spanish2_ci"); + collations.Add(207, "utf8mb3_roman_ci"); + collations.Add(208, "utf8mb3_persian_ci"); + collations.Add(209, "utf8mb3_esperanto_ci"); + collations.Add(210, "utf8mb3_hungarian_ci"); + collations.Add(211, "utf8mb3_sinhala_ci"); + collations.Add(212, "utf8mb3_german2_ci"); + collations.Add(213, "utf8mb3_croatian_ci"); + collations.Add(214, "utf8mb3_unicode_520_ci"); + collations.Add(215, "utf8mb3_vietnamese_ci"); + collations.Add(223, "utf8mb3_general_mysql500_ci"); + collations.Add(224, "utf8mb4_unicode_ci"); + collations.Add(225, "utf8mb4_icelandic_ci"); + collations.Add(226, "utf8mb4_latvian_ci"); + collations.Add(227, "utf8mb4_romanian_ci"); + collations.Add(228, "utf8mb4_slovenian_ci"); + collations.Add(229, "utf8mb4_polish_ci"); + collations.Add(230, "utf8mb4_estonian_ci"); + collations.Add(231, "utf8mb4_spanish_ci"); + collations.Add(232, "utf8mb4_swedish_ci"); + collations.Add(233, "utf8mb4_turkish_ci"); + collations.Add(234, "utf8mb4_czech_ci"); + collations.Add(235, "utf8mb4_danish_ci"); + collations.Add(236, "utf8mb4_lithuanian_ci"); + collations.Add(237, "utf8mb4_slovak_ci"); + collations.Add(238, "utf8mb4_spanish2_ci"); + collations.Add(239, "utf8mb4_roman_ci"); + collations.Add(240, "utf8mb4_persian_ci"); + collations.Add(241, "utf8mb4_esperanto_ci"); + collations.Add(242, "utf8mb4_hungarian_ci"); + collations.Add(243, "utf8mb4_sinhala_ci"); + collations.Add(244, "utf8mb4_german2_ci"); + collations.Add(245, "utf8mb4_croatian_ci"); + collations.Add(246, "utf8mb4_unicode_520_ci"); + collations.Add(247, "utf8mb4_vietnamese_ci"); + collations.Add(248, "gb18030_chinese_ci"); + collations.Add(249, "gb18030_bin"); + collations.Add(250, "gb18030_unicode_520_ci"); + collations.Add(255, "utf8mb4_0900_ai_ci"); + collations.Add(256, "utf8mb4_de_pb_0900_ai_ci"); + collations.Add(257, "utf8mb4_is_0900_ai_ci"); + collations.Add(258, "utf8mb4_lv_0900_ai_ci"); + collations.Add(259, "utf8mb4_ro_0900_ai_ci"); + collations.Add(260, "utf8mb4_sl_0900_ai_ci"); + collations.Add(261, "utf8mb4_pl_0900_ai_ci"); + collations.Add(262, "utf8mb4_et_0900_ai_ci"); + collations.Add(263, "utf8mb4_es_0900_ai_ci"); + collations.Add(264, "utf8mb4_sv_0900_ai_ci"); + collations.Add(265, "utf8mb4_tr_0900_ai_ci"); + collations.Add(266, "utf8mb4_cs_0900_ai_ci"); + collations.Add(267, "utf8mb4_da_0900_ai_ci"); + collations.Add(268, "utf8mb4_lt_0900_ai_ci"); + collations.Add(269, "utf8mb4_sk_0900_ai_ci"); + collations.Add(270, "utf8mb4_es_trad_0900_ai_ci"); + collations.Add(271, "utf8mb4_la_0900_ai_ci"); + collations.Add(273, "utf8mb4_eo_0900_ai_ci"); + collations.Add(274, "utf8mb4_hu_0900_ai_ci"); + collations.Add(275, "utf8mb4_hr_0900_ai_ci"); + collations.Add(277, "utf8mb4_vi_0900_ai_ci"); + collations.Add(278, "utf8mb4_0900_as_cs"); + collations.Add(279, "utf8mb4_de_pb_0900_as_cs"); + collations.Add(280, "utf8mb4_is_0900_as_cs"); + collations.Add(281, "utf8mb4_lv_0900_as_cs"); + collations.Add(282, "utf8mb4_ro_0900_as_cs"); + collations.Add(283, "utf8mb4_sl_0900_as_cs"); + collations.Add(284, "utf8mb4_pl_0900_as_cs"); + collations.Add(285, "utf8mb4_et_0900_as_cs"); + collations.Add(286, "utf8mb4_es_0900_as_cs"); + collations.Add(287, "utf8mb4_sv_0900_as_cs"); + collations.Add(288, "utf8mb4_tr_0900_as_cs"); + collations.Add(289, "utf8mb4_cs_0900_as_cs"); + collations.Add(290, "utf8mb4_da_0900_as_cs"); + collations.Add(291, "utf8mb4_lt_0900_as_cs"); + collations.Add(292, "utf8mb4_sk_0900_as_cs"); + collations.Add(293, "utf8mb4_es_trad_0900_as_cs"); + collations.Add(294, "utf8mb4_la_0900_as_cs"); + collations.Add(296, "utf8mb4_eo_0900_as_cs"); + collations.Add(297, "utf8mb4_hu_0900_as_cs"); + collations.Add(298, "utf8mb4_hr_0900_as_cs"); + collations.Add(300, "utf8mb4_vi_0900_as_cs"); + collations.Add(303, "utf8mb4_ja_0900_as_cs"); + collations.Add(304, "utf8mb4_ja_0900_as_cs_ks"); + collations.Add(305, "utf8mb4_0900_as_ci"); + collations.Add(306, "utf8mb4_ru_0900_ai_ci"); + collations.Add(307, "utf8mb4_ru_0900_as_cs"); + collations.Add(308, "utf8mb4_zh_0900_as_cs"); + collations.Add(309, "utf8mb4_0900_bin"); + collations.Add(310, "utf8mb4_nb_0900_ai_ci"); + collations.Add(311, "utf8mb4_nb_0900_as_cs"); + collations.Add(312, "utf8mb4_nn_0900_ai_ci"); + collations.Add(313, "utf8mb4_nn_0900_as_cs"); + collations.Add(314, "utf8mb4_sr_latn_0900_ai_ci"); + collations.Add(315, "utf8mb4_sr_latn_0900_as_cs"); + collations.Add(316, "utf8mb4_bs_0900_ai_ci"); + collations.Add(317, "utf8mb4_bs_0900_as_cs"); + collations.Add(318, "utf8mb4_bg_0900_ai_ci"); + collations.Add(319, "utf8mb4_bg_0900_as_cs"); + collations.Add(320, "utf8mb4_gl_0900_ai_ci"); + collations.Add(321, "utf8mb4_gl_0900_as_cs"); + collations.Add(322, "utf8mb4_mn_cyrl_0900_ai_ci"); + collations.Add(323, "utf8mb4_mn_cyrl_0900_as_cs"); + } + } +} diff --git a/MySQL.Data/src/X/Data/Enums.cs b/MySQL.Data/src/X/Data/Enums.cs index 3cc4a1727..7eea5cfee 100644 --- a/MySQL.Data/src/X/Data/Enums.cs +++ b/MySQL.Data/src/X/Data/Enums.cs @@ -1,16 +1,16 @@ -// Copyright © 2015, 2018, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2015, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/X/Protocol/ProtocolBase.cs b/MySQL.Data/src/X/Protocol/ProtocolBase.cs index c06aaef83..e8e469313 100644 --- a/MySQL.Data/src/X/Protocol/ProtocolBase.cs +++ b/MySQL.Data/src/X/Protocol/ProtocolBase.cs @@ -1,53 +1,53 @@ -// Copyright © 2015, 2016, Oracle and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - - -using System.Collections.Generic; -using MySqlX.XDevAPI; -using MySqlX.XDevAPI.Common; -using MySqlX.XDevAPI.Relational; - -namespace MySqlX.Protocol -{ - - /// - /// Abstract class for the protocol base operations in client/server communication. - /// - /// - public abstract class ProtocolBase - { - public abstract List ReadRow(BaseResult rs); - public abstract void SendSQL(string sql, params object[] args); - - public abstract bool HasData(BaseResult rs); - - public abstract List LoadColumnMetadata(); - - public abstract void CloseResult(BaseResult rs); - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +using System.Collections.Generic; +using MySqlX.XDevAPI; +using MySqlX.XDevAPI.Common; +using MySqlX.XDevAPI.Relational; + +namespace MySqlX.Protocol +{ + + /// + /// Abstract class for the protocol base operations in client/server communication. + /// + /// + public abstract class ProtocolBase + { + public abstract List ReadRow(BaseResult rs); + public abstract void SendSQL(string sql, params object[] args); + + public abstract bool HasData(BaseResult rs); + + public abstract List LoadColumnMetadata(); + + public abstract void CloseResult(BaseResult rs); + } +} diff --git a/MySQL.Data/src/X/Protocol/ValueDecoder.cs b/MySQL.Data/src/X/Protocol/ValueDecoder.cs index 1dc1a07aa..5ec439f9f 100644 --- a/MySQL.Data/src/X/Protocol/ValueDecoder.cs +++ b/MySQL.Data/src/X/Protocol/ValueDecoder.cs @@ -1,48 +1,48 @@ -// Copyright © 2015, 2016, Oracle and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySqlX.XDevAPI; -using MySqlX.XDevAPI.Relational; - -namespace MySqlX.Protocol -{ - internal abstract class ValueDecoder - { - - public delegate object ClrDecoderDelegate(byte[] bytes); - - - public Column Column { get; set; } - - public uint Flags { get; set; } - public uint ContentType { get; set; } - - public abstract void SetMetadata(); - public ClrDecoderDelegate ClrValueDecoder; - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySqlX.XDevAPI; +using MySqlX.XDevAPI.Relational; + +namespace MySqlX.Protocol +{ + internal abstract class ValueDecoder + { + + public delegate object ClrDecoderDelegate(byte[] bytes); + + + public Column Column { get; set; } + + public uint Flags { get; set; } + public uint ContentType { get; set; } + + public abstract void SetMetadata(); + public ClrDecoderDelegate ClrValueDecoder; + } +} diff --git a/MySQL.Data/src/X/Protocol/X/BitDecoder.cs b/MySQL.Data/src/X/Protocol/X/BitDecoder.cs index 0651f99d4..cc8971581 100644 --- a/MySQL.Data/src/X/Protocol/X/BitDecoder.cs +++ b/MySQL.Data/src/X/Protocol/X/BitDecoder.cs @@ -1,16 +1,16 @@ -// Copyright © 2016, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2016, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -52,4 +52,4 @@ private object BitValueDecoder(byte[] bytes) return ReadUInt(bytes); } } -} \ No newline at end of file +} diff --git a/MySQL.Data/src/X/Protocol/X/ByteDecoder.cs b/MySQL.Data/src/X/Protocol/X/ByteDecoder.cs index af93900d1..af7e0f8ba 100644 --- a/MySQL.Data/src/X/Protocol/X/ByteDecoder.cs +++ b/MySQL.Data/src/X/Protocol/X/ByteDecoder.cs @@ -1,100 +1,100 @@ -// Copyright (c) 2015, 2022, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data.MySqlClient; -using MySql.Data.MySqlClient.X.XDevAPI.Common; -using System; -using System.Text; - -namespace MySqlX.Protocol.X -{ - internal class ByteDecoder : ValueDecoder - { - private Encoding _encoding; - private bool _isEnum; - - public ByteDecoder(bool isEnum) - { - _isEnum = isEnum; - } - - public override void SetMetadata() - { - Column.Type = GetDbType(); - Column.ClrType = GetClrType(Column.Type); - Column.IsPadded = (Flags & 1) != 0; - ClrValueDecoder = GetClrValueDecoder(); - } - - private ColumnType GetDbType() - { - if (_isEnum) - return ColumnType.Enum; - if (ContentType == (uint)ColumnContentType.Geometry) - return ColumnType.Geometry; - if (ContentType == (uint)ColumnContentType.Json) - return ColumnType.Json; - if ((Column.CollationName ?? "").Equals("binary", StringComparison.OrdinalIgnoreCase)) - return ColumnType.Bytes; - return ColumnType.String; - } - - private Type GetClrType(ColumnType dbType) - { - if (dbType == ColumnType.String || dbType == ColumnType.Json - || dbType == ColumnType.Enum) - return typeof(string); - return typeof(byte[]); - } - - private ClrDecoderDelegate GetClrValueDecoder() - { - if (Column.ClrType == typeof(String)) return StringValueDecoder; - return ByteValueDecoder; - } - - private object StringValueDecoder(byte[] bytes) - { - if (bytes.Length == 0) return null; - - if (_encoding == null) - { - string charset = Column.CharacterSetName ?? string.Empty; - _encoding = CharSetMap.GetEncoding(charset); - } - return _encoding.GetString(bytes, 0, bytes.Length - 1); - } - - private object ByteValueDecoder(byte[] bytes) - { - byte[] newValue = new byte[bytes.Length - 1]; - Array.Copy(bytes, newValue, newValue.Length); - return newValue; - } - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data.MySqlClient; +using MySql.Data.MySqlClient.X.XDevAPI.Common; +using System; +using System.Text; + +namespace MySqlX.Protocol.X +{ + internal class ByteDecoder : ValueDecoder + { + private Encoding _encoding; + private bool _isEnum; + + public ByteDecoder(bool isEnum) + { + _isEnum = isEnum; + } + + public override void SetMetadata() + { + Column.Type = GetDbType(); + Column.ClrType = GetClrType(Column.Type); + Column.IsPadded = (Flags & 1) != 0; + ClrValueDecoder = GetClrValueDecoder(); + } + + private ColumnType GetDbType() + { + if (_isEnum) + return ColumnType.Enum; + if (ContentType == (uint)ColumnContentType.Geometry) + return ColumnType.Geometry; + if (ContentType == (uint)ColumnContentType.Json) + return ColumnType.Json; + if ((Column.CollationName ?? "").Equals("binary", StringComparison.OrdinalIgnoreCase)) + return ColumnType.Bytes; + return ColumnType.String; + } + + private Type GetClrType(ColumnType dbType) + { + if (dbType == ColumnType.String || dbType == ColumnType.Json + || dbType == ColumnType.Enum) + return typeof(string); + return typeof(byte[]); + } + + private ClrDecoderDelegate GetClrValueDecoder() + { + if (Column.ClrType == typeof(String)) return StringValueDecoder; + return ByteValueDecoder; + } + + private object StringValueDecoder(byte[] bytes) + { + if (bytes.Length == 0) return null; + + if (_encoding == null) + { + string charset = Column.CharacterSetName ?? string.Empty; + _encoding = CharSetMap.GetEncoding(charset); + } + return _encoding.GetString(bytes, 0, bytes.Length - 1); + } + + private object ByteValueDecoder(byte[] bytes) + { + byte[] newValue = new byte[bytes.Length - 1]; + Array.Copy(bytes, newValue, newValue.Length); + return newValue; + } + } +} diff --git a/MySQL.Data/src/X/Protocol/X/DecimalDecoder.cs b/MySQL.Data/src/X/Protocol/X/DecimalDecoder.cs index 850cdb6f2..1b4360db5 100644 --- a/MySQL.Data/src/X/Protocol/X/DecimalDecoder.cs +++ b/MySQL.Data/src/X/Protocol/X/DecimalDecoder.cs @@ -1,35 +1,35 @@ -// Copyright © 2016, Oracle and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - +// Copyright © 2016, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + using MySql.Data; using MySql.Data.MySqlClient.X.XDevAPI.Common; -using MySqlX.Data; +using MySqlX.Data; using System; namespace MySqlX.Protocol.X @@ -78,4 +78,4 @@ private object DecimalValueDecoder(byte[] bytes) return Decimal.Parse(stringValue); } } -} \ No newline at end of file +} diff --git a/MySQL.Data/src/X/Protocol/X/Enum.cs b/MySQL.Data/src/X/Protocol/X/Enum.cs index 94a88b741..371c10f38 100644 --- a/MySQL.Data/src/X/Protocol/X/Enum.cs +++ b/MySQL.Data/src/X/Protocol/X/Enum.cs @@ -1,68 +1,68 @@ -// Copyright © 2015, 2019, Oracle and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace MySqlX.Protocol.X -{ - internal enum NoticeType : int - { - Warning = 1, - SessionVariableChanged = 2, - SessionStateChanged = 3, - } - - internal enum RowLock : int - { - SharedLock = 1, - ExclusiveLock = 2 - } - - internal static class XpluginStatementCommand - { - public static readonly string XPLUGIN_STMT_CREATE_COLLECTION = "create_collection"; - public static readonly string XPLUGIN_STMT_CREATE_COLLECTION_INDEX = "create_collection_index"; - public static readonly string XPLUGIN_STMT_DROP_COLLECTION = - "drop_collection"; - //Added to support schema validation, store the name of the command used by MySQL Server to modify collections - public static readonly string XPLUGIN_STMT_MODIFY_COLLECTION = "modify_collection_options"; - - public static readonly string XPLUGIN_STMT_DROP_COLLECTION_INDEX = "drop_collection_index"; - public static readonly string XPLUGIN_STMT_PING = "ping"; - public static readonly string XPLUGIN_STMT_LIST_OBJECTS = - "list_objects"; - public static readonly string XPLUGIN_STMT_ENABLE_NOTICES = "enable_notices"; - public static readonly string XPLUGIN_STMT_DISABLE_NOTICES = "disable_notices"; - public static readonly string XPLUGIN_STMT_LIST_NOTICES = - "list_notices"; - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MySqlX.Protocol.X +{ + internal enum NoticeType : int + { + Warning = 1, + SessionVariableChanged = 2, + SessionStateChanged = 3, + } + + internal enum RowLock : int + { + SharedLock = 1, + ExclusiveLock = 2 + } + + internal static class XpluginStatementCommand + { + public static readonly string XPLUGIN_STMT_CREATE_COLLECTION = "create_collection"; + public static readonly string XPLUGIN_STMT_CREATE_COLLECTION_INDEX = "create_collection_index"; + public static readonly string XPLUGIN_STMT_DROP_COLLECTION = + "drop_collection"; + //Added to support schema validation, store the name of the command used by MySQL Server to modify collections + public static readonly string XPLUGIN_STMT_MODIFY_COLLECTION = "modify_collection_options"; + + public static readonly string XPLUGIN_STMT_DROP_COLLECTION_INDEX = "drop_collection_index"; + public static readonly string XPLUGIN_STMT_PING = "ping"; + public static readonly string XPLUGIN_STMT_LIST_OBJECTS = + "list_objects"; + public static readonly string XPLUGIN_STMT_ENABLE_NOTICES = "enable_notices"; + public static readonly string XPLUGIN_STMT_DISABLE_NOTICES = "disable_notices"; + public static readonly string XPLUGIN_STMT_LIST_NOTICES = + "list_notices"; + } +} diff --git a/MySQL.Data/src/X/Protocol/X/ExpUnparser.cs b/MySQL.Data/src/X/Protocol/X/ExpUnparser.cs index 9432aea03..35d8ddac4 100644 --- a/MySQL.Data/src/X/Protocol/X/ExpUnparser.cs +++ b/MySQL.Data/src/X/Protocol/X/ExpUnparser.cs @@ -1,16 +1,16 @@ -// Copyright © 2015, 2016, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2015, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/X/Protocol/X/ExprParser.cs b/MySQL.Data/src/X/Protocol/X/ExprParser.cs index e77fc8f3c..72df42454 100644 --- a/MySQL.Data/src/X/Protocol/X/ExprParser.cs +++ b/MySQL.Data/src/X/Protocol/X/ExprParser.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2015, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/X/Protocol/X/ExprUtil.cs b/MySQL.Data/src/X/Protocol/X/ExprUtil.cs index 0c25a358e..1753cfb36 100644 --- a/MySQL.Data/src/X/Protocol/X/ExprUtil.cs +++ b/MySQL.Data/src/X/Protocol/X/ExprUtil.cs @@ -1,270 +1,270 @@ -// Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using System; -using Mysqlx.Expr; -using Mysqlx.Datatypes; -using Mysqlx.Crud; -using Google.Protobuf; -using System.Collections.Generic; -using System.Reflection; - -namespace MySqlX.Protocol.X -{ - internal class ExprUtil - { - /** - * Proto-buf helper to build a LITERAL Expr with a Scalar NULL type. - */ - public static Expr BuildLiteralNullScalar() - { - return BuildLiteralExpr(NullScalar()); - } - - /** - * Proto-buf helper to build a LITERAL Expr with a Scalar DOUBLE type (wrapped in Any). - */ - public static Expr BuildLiteralScalar(double d) - { - return BuildLiteralExpr(ScalarOf(d)); - } - - /** - * Proto-buf helper to build a LITERAL Expr with a Scalar SINT (signed int) type (wrapped in Any). - */ - public static Expr BuildLiteralScalar(long l) - { - return BuildLiteralExpr(ScalarOf(l)); - } - - /** - * Proto-buf helper to build a LITERAL Expr with a Scalar UINT (unsigned int) type (wrapped in Any). - */ - public static Expr BuildLiteralScalar(ulong l) - { - return BuildLiteralExpr(ScalarOf(l)); - } - - /** - * Proto-buf helper to build a LITERAL Expr with a Scalar STRING type (wrapped in Any). - */ - public static Expr BuildLiteralScalar(String str) - { - return BuildLiteralExpr(ScalarOf(str)); - } - - /** - * Proto-buf helper to build a LITERAL Expr with a Scalar OCTETS type (wrapped in Any). - */ - public static Expr BuildLiteralScalar(byte[] bytes) - { - return BuildLiteralExpr(ScalarOf(bytes)); - } - - /** - * Proto-buf helper to build a LITERAL Expr with a Scalar BOOL type (wrapped in Any). - */ - public static Expr BuildLiteralScalar(Boolean b) - { - return BuildLiteralExpr(ScalarOf(b)); - } - - /** - * Wrap an Any value in a LITERAL expression. - */ - public static Expr BuildLiteralExpr(Scalar scalar) - { - return new Expr() { Type = Expr.Types.Type.Literal, Literal = scalar }; - } - - public static Scalar NullScalar() - { - return new Scalar() { Type = Scalar.Types.Type.VNull }; - } - - public static Scalar ScalarOf(double d) - { - return new Scalar() { Type = Scalar.Types.Type.VDouble, VDouble = d }; - } - - public static Scalar ScalarOf(long l) - { - return new Scalar() { Type = Scalar.Types.Type.VSint, VSignedInt = l}; - } - - public static Scalar ScalarOf(ulong ul) - { - return new Scalar() { Type = Scalar.Types.Type.VUint, VUnsignedInt = ul}; - } - - public static Scalar ScalarOf(String str) - { - Scalar.Types.String strValue = new Scalar.Types.String() { Value = ByteString.CopyFromUtf8(str) }; - return new Scalar() { Type = Scalar.Types.Type.VString, VString = strValue }; - } - - public static Scalar ScalarOf(byte[] bytes) - { - return new Scalar() { Type = Scalar.Types.Type.VOctets, VOctets = new Scalar.Types.Octets() { Value = ByteString.CopyFrom(bytes) } }; - } - - public static Scalar ScalarOf(Boolean b) - { - return new Scalar() { Type = Scalar.Types.Type.VBool, VBool = b }; - } - - /** - * Build an Any with a string value. - */ - public static Any BuildAny(String str) - { - // same as Expr - Scalar.Types.String sstr = new Scalar.Types.String(); - sstr.Value = ByteString.CopyFromUtf8(str); - Scalar s = new Scalar(); - s.Type = Scalar.Types.Type.VString; - s.VString = sstr; - Any a = new Any(); - a.Type = Any.Types.Type.Scalar; - a.Scalar = s; - return a; - } - - public static Mysqlx.Datatypes.Object.Types.ObjectField BuildObject(string key, object value, bool evaluateStringExpression) - { - Mysqlx.Datatypes.Object.Types.ObjectField item = new Mysqlx.Datatypes.Object.Types.ObjectField(); - item.Key = key; - item.Value = evaluateStringExpression ? BuildAny(value) : BuildAnyWithoutEvaluationExpression(value); - return item; - } - - public static Any BuildEmptyAny(Any.Types.Type type) - { - return new Any() { Type = type, Obj = new Mysqlx.Datatypes.Object() }; - } - - public static Any BuildAny(Boolean b) - { - return new Any() { Type = Any.Types.Type.Scalar, Scalar = ScalarOf(b) }; - } - - public static Any BuildAny(object value) - { - return new Any() { Type = Any.Types.Type.Scalar, Scalar = ExprUtil.ArgObjectToScalar(value) }; - } - - public static Any BuildAnyWithoutEvaluationExpression(object value) - { - return new Any() { Type = Any.Types.Type.Scalar, Scalar = ExprUtil.ArgObjectToScalar(value, false) }; - } - - public static Collection BuildCollection(String schemaName, String collectionName) - { - return new Collection() { Schema = schemaName, Name = collectionName }; - } - - public static Scalar ArgObjectToScalar(System.Object value, Boolean evaluateStringExpression = true) - { - return ArgObjectToExpr(value, false, evaluateStringExpression).Literal; - } - - public static Expr ArgObjectToExpr(System.Object value, Boolean allowRelationalColumns, Boolean evaluateStringExpresssion = true) - { - if (value == null) - return BuildLiteralNullScalar(); - - if (value is Dictionary) - value = new XDevAPI.DbDoc(value).ToString(); - - if (value is XDevAPI.MySqlExpression) - value = (value as XDevAPI.MySqlExpression).value; - - if (value is bool) - return BuildLiteralScalar(Convert.ToBoolean(value)); - else if (value is byte || value is short || value is int || value is long) - return BuildLiteralScalar(Convert.ToInt64(value)); - else if (value is ushort || value is uint || value is ulong) - return BuildLiteralScalar(Convert.ToUInt64(value)); - else if (value is float || value is double) - return BuildLiteralScalar(Convert.ToDouble(value)); - else if (value is string) - { - try - { - // try to parse expressions - var stringValue = (string) value; - if (!evaluateStringExpresssion) return BuildLiteralScalar((string)value); - - Expr expr = new ExprParser(stringValue).Parse(); - if (expr.Identifier != null) - return BuildLiteralScalar(stringValue); - return expr; - } - catch - { - // if can't parse, returns as literal - return BuildLiteralScalar((string)value); - } - } - else if (value is XDevAPI.DbDoc) - return (BuildLiteralScalar(value.ToString())); - - throw new NotSupportedException("Value of type " + value.GetType() + " is not currently supported."); - } - - public static string JoinString(string[] values) - { - if (values == null) return string.Empty; - return string.Join(", ", values); - } - - /// - /// Parses an anonymous object into a dictionary. - /// - /// The object to parse. - /// A dictionary if the provided object is an anonymous object; otherwise, null. - public static Dictionary ParseAnonymousObject(object value) - { - if (value == null) - return null; - - Type type = value.GetType(); - if (type.Name.Contains("Anonymous")) - { - Dictionary dictionary = new Dictionary(); - PropertyInfo[] props = type.GetProperties(); - foreach (PropertyInfo prop in props) - dictionary.Add(prop.Name, prop.GetValue(value, null)); - - return dictionary; - } - - return null; - } - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using System; +using Mysqlx.Expr; +using Mysqlx.Datatypes; +using Mysqlx.Crud; +using Google.Protobuf; +using System.Collections.Generic; +using System.Reflection; + +namespace MySqlX.Protocol.X +{ + internal class ExprUtil + { + /** + * Proto-buf helper to build a LITERAL Expr with a Scalar NULL type. + */ + public static Expr BuildLiteralNullScalar() + { + return BuildLiteralExpr(NullScalar()); + } + + /** + * Proto-buf helper to build a LITERAL Expr with a Scalar DOUBLE type (wrapped in Any). + */ + public static Expr BuildLiteralScalar(double d) + { + return BuildLiteralExpr(ScalarOf(d)); + } + + /** + * Proto-buf helper to build a LITERAL Expr with a Scalar SINT (signed int) type (wrapped in Any). + */ + public static Expr BuildLiteralScalar(long l) + { + return BuildLiteralExpr(ScalarOf(l)); + } + + /** + * Proto-buf helper to build a LITERAL Expr with a Scalar UINT (unsigned int) type (wrapped in Any). + */ + public static Expr BuildLiteralScalar(ulong l) + { + return BuildLiteralExpr(ScalarOf(l)); + } + + /** + * Proto-buf helper to build a LITERAL Expr with a Scalar STRING type (wrapped in Any). + */ + public static Expr BuildLiteralScalar(String str) + { + return BuildLiteralExpr(ScalarOf(str)); + } + + /** + * Proto-buf helper to build a LITERAL Expr with a Scalar OCTETS type (wrapped in Any). + */ + public static Expr BuildLiteralScalar(byte[] bytes) + { + return BuildLiteralExpr(ScalarOf(bytes)); + } + + /** + * Proto-buf helper to build a LITERAL Expr with a Scalar BOOL type (wrapped in Any). + */ + public static Expr BuildLiteralScalar(Boolean b) + { + return BuildLiteralExpr(ScalarOf(b)); + } + + /** + * Wrap an Any value in a LITERAL expression. + */ + public static Expr BuildLiteralExpr(Scalar scalar) + { + return new Expr() { Type = Expr.Types.Type.Literal, Literal = scalar }; + } + + public static Scalar NullScalar() + { + return new Scalar() { Type = Scalar.Types.Type.VNull }; + } + + public static Scalar ScalarOf(double d) + { + return new Scalar() { Type = Scalar.Types.Type.VDouble, VDouble = d }; + } + + public static Scalar ScalarOf(long l) + { + return new Scalar() { Type = Scalar.Types.Type.VSint, VSignedInt = l}; + } + + public static Scalar ScalarOf(ulong ul) + { + return new Scalar() { Type = Scalar.Types.Type.VUint, VUnsignedInt = ul}; + } + + public static Scalar ScalarOf(String str) + { + Scalar.Types.String strValue = new Scalar.Types.String() { Value = ByteString.CopyFromUtf8(str) }; + return new Scalar() { Type = Scalar.Types.Type.VString, VString = strValue }; + } + + public static Scalar ScalarOf(byte[] bytes) + { + return new Scalar() { Type = Scalar.Types.Type.VOctets, VOctets = new Scalar.Types.Octets() { Value = ByteString.CopyFrom(bytes) } }; + } + + public static Scalar ScalarOf(Boolean b) + { + return new Scalar() { Type = Scalar.Types.Type.VBool, VBool = b }; + } + + /** + * Build an Any with a string value. + */ + public static Any BuildAny(String str) + { + // same as Expr + Scalar.Types.String sstr = new Scalar.Types.String(); + sstr.Value = ByteString.CopyFromUtf8(str); + Scalar s = new Scalar(); + s.Type = Scalar.Types.Type.VString; + s.VString = sstr; + Any a = new Any(); + a.Type = Any.Types.Type.Scalar; + a.Scalar = s; + return a; + } + + public static Mysqlx.Datatypes.Object.Types.ObjectField BuildObject(string key, object value, bool evaluateStringExpression) + { + Mysqlx.Datatypes.Object.Types.ObjectField item = new Mysqlx.Datatypes.Object.Types.ObjectField(); + item.Key = key; + item.Value = evaluateStringExpression ? BuildAny(value) : BuildAnyWithoutEvaluationExpression(value); + return item; + } + + public static Any BuildEmptyAny(Any.Types.Type type) + { + return new Any() { Type = type, Obj = new Mysqlx.Datatypes.Object() }; + } + + public static Any BuildAny(Boolean b) + { + return new Any() { Type = Any.Types.Type.Scalar, Scalar = ScalarOf(b) }; + } + + public static Any BuildAny(object value) + { + return new Any() { Type = Any.Types.Type.Scalar, Scalar = ExprUtil.ArgObjectToScalar(value) }; + } + + public static Any BuildAnyWithoutEvaluationExpression(object value) + { + return new Any() { Type = Any.Types.Type.Scalar, Scalar = ExprUtil.ArgObjectToScalar(value, false) }; + } + + public static Collection BuildCollection(String schemaName, String collectionName) + { + return new Collection() { Schema = schemaName, Name = collectionName }; + } + + public static Scalar ArgObjectToScalar(System.Object value, Boolean evaluateStringExpression = true) + { + return ArgObjectToExpr(value, false, evaluateStringExpression).Literal; + } + + public static Expr ArgObjectToExpr(System.Object value, Boolean allowRelationalColumns, Boolean evaluateStringExpresssion = true) + { + if (value == null) + return BuildLiteralNullScalar(); + + if (value is Dictionary) + value = new XDevAPI.DbDoc(value).ToString(); + + if (value is XDevAPI.MySqlExpression) + value = (value as XDevAPI.MySqlExpression).value; + + if (value is bool) + return BuildLiteralScalar(Convert.ToBoolean(value)); + else if (value is byte || value is short || value is int || value is long) + return BuildLiteralScalar(Convert.ToInt64(value)); + else if (value is ushort || value is uint || value is ulong) + return BuildLiteralScalar(Convert.ToUInt64(value)); + else if (value is float || value is double) + return BuildLiteralScalar(Convert.ToDouble(value)); + else if (value is string) + { + try + { + // try to parse expressions + var stringValue = (string) value; + if (!evaluateStringExpresssion) return BuildLiteralScalar((string)value); + + Expr expr = new ExprParser(stringValue).Parse(); + if (expr.Identifier != null) + return BuildLiteralScalar(stringValue); + return expr; + } + catch + { + // if can't parse, returns as literal + return BuildLiteralScalar((string)value); + } + } + else if (value is XDevAPI.DbDoc) + return (BuildLiteralScalar(value.ToString())); + + throw new NotSupportedException("Value of type " + value.GetType() + " is not currently supported."); + } + + public static string JoinString(string[] values) + { + if (values == null) return string.Empty; + return string.Join(", ", values); + } + + /// + /// Parses an anonymous object into a dictionary. + /// + /// The object to parse. + /// A dictionary if the provided object is an anonymous object; otherwise, null. + public static Dictionary ParseAnonymousObject(object value) + { + if (value == null) + return null; + + Type type = value.GetType(); + if (type.Name.Contains("Anonymous")) + { + Dictionary dictionary = new Dictionary(); + PropertyInfo[] props = type.GetProperties(); + foreach (PropertyInfo prop in props) + dictionary.Add(prop.Name, prop.GetValue(value, null)); + + return dictionary; + } + + return null; + } + } +} diff --git a/MySQL.Data/src/X/Protocol/X/FloatDecoder.cs b/MySQL.Data/src/X/Protocol/X/FloatDecoder.cs index efd155a0b..8c792f475 100644 --- a/MySQL.Data/src/X/Protocol/X/FloatDecoder.cs +++ b/MySQL.Data/src/X/Protocol/X/FloatDecoder.cs @@ -1,69 +1,69 @@ -// Copyright © 2015, 2016, Oracle and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - - - -using MySqlX.Data; -using MySqlX.XDevAPI; -using System; -using MySql.Data.MySqlClient; -using MySqlX; -using MySql.Data.MySqlClient.X.XDevAPI.Common; -using Google.Protobuf; - -namespace MySqlX.Protocol.X -{ - internal class FloatDecoder : ValueDecoder - { - bool _float; - - public FloatDecoder(bool isFloat) - { - _float = isFloat; - } - - public override void SetMetadata() - { - Column.Type = _float ? ColumnType.Float : ColumnType.Double; - Column.ClrType = _float ? typeof(float) : typeof(double); - ClrValueDecoder = FloatValueDecoder; - if (!_float) - ClrValueDecoder = DoubleValueDecoder; - } - - private object FloatValueDecoder(byte[] bytes) - { - return new CodedInputStream(bytes).ReadFloat(); - } - - private object DoubleValueDecoder(byte[] bytes) - { - return new CodedInputStream(bytes).ReadDouble(); - } - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + + +using MySqlX.Data; +using MySqlX.XDevAPI; +using System; +using MySql.Data.MySqlClient; +using MySqlX; +using MySql.Data.MySqlClient.X.XDevAPI.Common; +using Google.Protobuf; + +namespace MySqlX.Protocol.X +{ + internal class FloatDecoder : ValueDecoder + { + bool _float; + + public FloatDecoder(bool isFloat) + { + _float = isFloat; + } + + public override void SetMetadata() + { + Column.Type = _float ? ColumnType.Float : ColumnType.Double; + Column.ClrType = _float ? typeof(float) : typeof(double); + ClrValueDecoder = FloatValueDecoder; + if (!_float) + ClrValueDecoder = DoubleValueDecoder; + } + + private object FloatValueDecoder(byte[] bytes) + { + return new CodedInputStream(bytes).ReadFloat(); + } + + private object DoubleValueDecoder(byte[] bytes) + { + return new CodedInputStream(bytes).ReadDouble(); + } + } +} diff --git a/MySQL.Data/src/X/Protocol/X/IntegerDecoder.cs b/MySQL.Data/src/X/Protocol/X/IntegerDecoder.cs index 9bb3afb88..6ac733faf 100644 --- a/MySQL.Data/src/X/Protocol/X/IntegerDecoder.cs +++ b/MySQL.Data/src/X/Protocol/X/IntegerDecoder.cs @@ -1,158 +1,158 @@ -// Copyright © 2015, 2016, Oracle and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - - - -using Google.Protobuf; -using MySql.Data.MySqlClient; -using MySql.Data.MySqlClient.X.XDevAPI.Common; -using MySqlX.Data; -using MySqlX.XDevAPI; -using System; - -namespace MySqlX.Protocol.X -{ - internal class IntegerDecoder : ValueDecoder - { - bool _signed; - - public IntegerDecoder(bool signed) - { - _signed = signed; - } - - public override void SetMetadata() - { - Column.Type = GetDbType(); - Column.IsNumberSigned = _signed; - Column.ClrType = _signed ? GetSignedClrType() : GetUnsignedClrType(); - ClrValueDecoder = _signed ? GetSignedValueDecoder() : GetUnsignedValueDecoder(); - Column.IsPadded = _signed ? false : (Flags & 1) != 0; - } - - private ColumnType GetDbType() - { - uint len = Column.Length + (_signed ? 0u : 1u); - if (len <= 4) return ColumnType.Tinyint; - else if (len <= 6) return ColumnType.Smallint; - else if (len <= 9) return ColumnType.Mediumint; - else if (len <= 11) return ColumnType.Int; - else return ColumnType.Bigint; - } - - private Type GetSignedClrType() - { - uint len = Column.Length; - if (len <= 4) return typeof(sbyte); - else if (len <= 6) return typeof(Int16); - else if (len <= 9) return typeof(Int32); - else if (len <= 11) return typeof(Int32); - else return typeof(Int64); - } - - private Type GetUnsignedClrType() - { - uint len = Column.Length; - if (len < 4) return typeof(byte); - else if (len < 6) return typeof(UInt16); - else if (len < 9) return typeof(UInt32); - else if (len < 11) return typeof(UInt32); - else return typeof(UInt64); - } - - private ClrDecoderDelegate GetSignedValueDecoder() - { - uint len = Column.Length; - if (len <= 4) return SByteValueDecoder; - else if (len <= 6) return Int16ValueDecoder; - else if (len <= 9) return Int32ValueDecoder; - else if (len <= 11) return Int32ValueDecoder; - else return Int64ValueDecoder; - } - - private ClrDecoderDelegate GetUnsignedValueDecoder() - { - uint len = Column.Length; - if (len < 4) return ByteValueDecoder; - else if (len < 6) return UInt16ValueDecoder; - else if (len < 9) return UInt32ValueDecoder; - else if (len < 11) return UInt32ValueDecoder; - else return UInt64ValueDecoder; - } - - private Int64 ReadInt(byte[] bytes) - { - return new CodedInputStream(bytes).ReadSInt64(); - } - - private UInt64 ReadUInt(byte[] bytes) - { - return new CodedInputStream(bytes).ReadUInt64(); - } - - public object SByteValueDecoder(byte[] bytes) - { - return (sbyte)ReadInt(bytes); - } - - public object Int16ValueDecoder(byte[] bytes) - { - return (Int16)ReadInt(bytes); - } - - public object Int32ValueDecoder(byte[] bytes) - { - return (Int32)ReadInt(bytes); - } - - public object Int64ValueDecoder(byte[] bytes) - { - return ReadInt(bytes); - } - - public object ByteValueDecoder(byte[] bytes) - { - return (byte)ReadUInt(bytes); - } - - public object UInt16ValueDecoder(byte[] bytes) - { - return (UInt16)ReadUInt(bytes); - } - - public object UInt32ValueDecoder(byte[] bytes) - { - return (UInt32)ReadUInt(bytes); - } - - public object UInt64ValueDecoder(byte[] bytes) - { - return (UInt64)ReadUInt(bytes); - } - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + + +using Google.Protobuf; +using MySql.Data.MySqlClient; +using MySql.Data.MySqlClient.X.XDevAPI.Common; +using MySqlX.Data; +using MySqlX.XDevAPI; +using System; + +namespace MySqlX.Protocol.X +{ + internal class IntegerDecoder : ValueDecoder + { + bool _signed; + + public IntegerDecoder(bool signed) + { + _signed = signed; + } + + public override void SetMetadata() + { + Column.Type = GetDbType(); + Column.IsNumberSigned = _signed; + Column.ClrType = _signed ? GetSignedClrType() : GetUnsignedClrType(); + ClrValueDecoder = _signed ? GetSignedValueDecoder() : GetUnsignedValueDecoder(); + Column.IsPadded = _signed ? false : (Flags & 1) != 0; + } + + private ColumnType GetDbType() + { + uint len = Column.Length + (_signed ? 0u : 1u); + if (len <= 4) return ColumnType.Tinyint; + else if (len <= 6) return ColumnType.Smallint; + else if (len <= 9) return ColumnType.Mediumint; + else if (len <= 11) return ColumnType.Int; + else return ColumnType.Bigint; + } + + private Type GetSignedClrType() + { + uint len = Column.Length; + if (len <= 4) return typeof(sbyte); + else if (len <= 6) return typeof(Int16); + else if (len <= 9) return typeof(Int32); + else if (len <= 11) return typeof(Int32); + else return typeof(Int64); + } + + private Type GetUnsignedClrType() + { + uint len = Column.Length; + if (len < 4) return typeof(byte); + else if (len < 6) return typeof(UInt16); + else if (len < 9) return typeof(UInt32); + else if (len < 11) return typeof(UInt32); + else return typeof(UInt64); + } + + private ClrDecoderDelegate GetSignedValueDecoder() + { + uint len = Column.Length; + if (len <= 4) return SByteValueDecoder; + else if (len <= 6) return Int16ValueDecoder; + else if (len <= 9) return Int32ValueDecoder; + else if (len <= 11) return Int32ValueDecoder; + else return Int64ValueDecoder; + } + + private ClrDecoderDelegate GetUnsignedValueDecoder() + { + uint len = Column.Length; + if (len < 4) return ByteValueDecoder; + else if (len < 6) return UInt16ValueDecoder; + else if (len < 9) return UInt32ValueDecoder; + else if (len < 11) return UInt32ValueDecoder; + else return UInt64ValueDecoder; + } + + private Int64 ReadInt(byte[] bytes) + { + return new CodedInputStream(bytes).ReadSInt64(); + } + + private UInt64 ReadUInt(byte[] bytes) + { + return new CodedInputStream(bytes).ReadUInt64(); + } + + public object SByteValueDecoder(byte[] bytes) + { + return (sbyte)ReadInt(bytes); + } + + public object Int16ValueDecoder(byte[] bytes) + { + return (Int16)ReadInt(bytes); + } + + public object Int32ValueDecoder(byte[] bytes) + { + return (Int32)ReadInt(bytes); + } + + public object Int64ValueDecoder(byte[] bytes) + { + return ReadInt(bytes); + } + + public object ByteValueDecoder(byte[] bytes) + { + return (byte)ReadUInt(bytes); + } + + public object UInt16ValueDecoder(byte[] bytes) + { + return (UInt16)ReadUInt(bytes); + } + + public object UInt32ValueDecoder(byte[] bytes) + { + return (UInt32)ReadUInt(bytes); + } + + public object UInt64ValueDecoder(byte[] bytes) + { + return (UInt64)ReadUInt(bytes); + } + } +} diff --git a/MySQL.Data/src/X/Protocol/X/Protobuf/Mysqlx.cs b/MySQL.Data/src/X/Protocol/X/Protobuf/Mysqlx.cs index 09240017d..be76ea51a 100644 --- a/MySQL.Data/src/X/Protocol/X/Protobuf/Mysqlx.cs +++ b/MySQL.Data/src/X/Protocol/X/Protobuf/Mysqlx.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2022, 2023, Oracle and/or its affiliates. +// Copyright © 2022, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -37,19 +37,23 @@ using pbc = global::Google.Protobuf.Collections; using pbr = global::Google.Protobuf.Reflection; using scg = global::System.Collections.Generic; -namespace Mysqlx { +namespace Mysqlx +{ /// Holder for reflection information generated from mysqlx.proto - internal static partial class MysqlxReflection { + public static partial class MysqlxReflection + { #region Descriptor /// File descriptor for mysqlx.proto - public static pbr::FileDescriptor Descriptor { + public static pbr::FileDescriptor Descriptor + { get { return descriptor; } } private static pbr::FileDescriptor descriptor; - static MysqlxReflection() { + static MysqlxReflection() + { byte[] descriptorData = global::System.Convert.FromBase64String( string.Concat( "CgxteXNxbHgucHJvdG8SBk15c3FseBogZ29vZ2xlL3Byb3RvYnVmL2Rlc2Ny", @@ -95,11 +99,12 @@ static MysqlxReflection() { } /// Holder for extension identifiers generated from the top level of mysqlx.proto - internal static partial class MysqlxExtensions { + public static partial class MysqlxExtensions + { public static readonly pb::Extension ClientMessageId = - new pb::Extension(100001, pb::FieldCodec.ForEnum(800008, x => (int) x, x => (global::Mysqlx.ClientMessages.Types.Type) x, global::Mysqlx.ClientMessages.Types.Type.ConCapabilitiesGet)); + new pb::Extension(100001, pb::FieldCodec.ForEnum(800008, x => (int)x, x => (global::Mysqlx.ClientMessages.Types.Type)x, global::Mysqlx.ClientMessages.Types.Type.ConCapabilitiesGet)); public static readonly pb::Extension ServerMessageId = - new pb::Extension(100002, pb::FieldCodec.ForEnum(800016, x => (int) x, x => (global::Mysqlx.ServerMessages.Types.Type) x, global::Mysqlx.ServerMessages.Types.Type.Ok)); + new pb::Extension(100002, pb::FieldCodec.ForEnum(800016, x => (int)x, x => (global::Mysqlx.ServerMessages.Types.Type)x, global::Mysqlx.ServerMessages.Types.Type.Ok)); } #region Messages @@ -112,10 +117,11 @@ internal static partial class MysqlxExtensions { ///- generate constants ///- check for uniqueness /// - internal sealed partial class ClientMessages : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class ClientMessages : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ClientMessages()); private pb::UnknownFieldSet _unknownFields; @@ -125,19 +131,22 @@ internal sealed partial class ClientMessages : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.MysqlxReflection.Descriptor.MessageTypes[0]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public ClientMessages() { + public ClientMessages() + { OnConstruction(); } @@ -145,29 +154,35 @@ public ClientMessages() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public ClientMessages(ClientMessages other) : this() { + public ClientMessages(ClientMessages other) : this() + { _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public ClientMessages Clone() { + public ClientMessages Clone() + { return new ClientMessages(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as ClientMessages); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(ClientMessages other) { - if (ReferenceEquals(other, null)) { + public bool Equals(ClientMessages other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } return Equals(_unknownFields, other._unknownFields); @@ -175,9 +190,11 @@ public bool Equals(ClientMessages other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -185,37 +202,43 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (_unknownFields != null) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -223,8 +246,10 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(ClientMessages other) { - if (other == null) { + public void MergeFrom(ClientMessages other) + { + if (other == null) + { return; } _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); @@ -232,42 +257,57 @@ public void MergeFrom(ClientMessages other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; } } } - #endif +#endif #region Nested types /// Container for nested types declared in the ClientMessages message type. [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static partial class Types { - public enum Type { + public static partial class Types + { + public enum Type + { [pbr::OriginalName("CON_CAPABILITIES_GET")] ConCapabilitiesGet = 1, [pbr::OriginalName("CON_CAPABILITIES_SET")] ConCapabilitiesSet = 2, [pbr::OriginalName("CON_CLOSE")] ConClose = 3, @@ -308,10 +348,11 @@ public enum Type { ///- generate constants ///- check for uniqueness /// - internal sealed partial class ServerMessages : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class ServerMessages : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ServerMessages()); private pb::UnknownFieldSet _unknownFields; @@ -321,19 +362,22 @@ internal sealed partial class ServerMessages : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.MysqlxReflection.Descriptor.MessageTypes[1]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public ServerMessages() { + public ServerMessages() + { OnConstruction(); } @@ -341,29 +385,35 @@ public ServerMessages() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public ServerMessages(ServerMessages other) : this() { + public ServerMessages(ServerMessages other) : this() + { _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public ServerMessages Clone() { + public ServerMessages Clone() + { return new ServerMessages(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as ServerMessages); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(ServerMessages other) { - if (ReferenceEquals(other, null)) { + public bool Equals(ServerMessages other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } return Equals(_unknownFields, other._unknownFields); @@ -371,9 +421,11 @@ public bool Equals(ServerMessages other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -381,37 +433,43 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (_unknownFields != null) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -419,8 +477,10 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(ServerMessages other) { - if (other == null) { + public void MergeFrom(ServerMessages other) + { + if (other == null) + { return; } _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); @@ -428,42 +488,57 @@ public void MergeFrom(ServerMessages other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; } } } - #endif +#endif #region Nested types /// Container for nested types declared in the ServerMessages message type. [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static partial class Types { - public enum Type { + public static partial class Types + { + public enum Type + { [pbr::OriginalName("OK")] Ok = 0, [pbr::OriginalName("ERROR")] Error = 1, [pbr::OriginalName("CONN_CAPABILITIES")] ConnCapabilities = 2, @@ -488,10 +563,11 @@ public enum Type { } - internal sealed partial class Ok : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class Ok : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Ok()); private pb::UnknownFieldSet _unknownFields; @@ -501,19 +577,22 @@ internal sealed partial class Ok : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.MysqlxReflection.Descriptor.MessageTypes[2]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Ok() { + public Ok() + { OnConstruction(); } @@ -521,14 +600,16 @@ public Ok() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Ok(Ok other) : this() { + public Ok(Ok other) : this() + { msg_ = other.msg_; _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Ok Clone() { + public Ok Clone() + { return new Ok(this); } @@ -539,38 +620,46 @@ public Ok Clone() { private string msg_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public string Msg { + public string Msg + { get { return msg_ ?? MsgDefaultValue; } - set { + set + { msg_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); } } /// Gets whether the "msg" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasMsg { + public bool HasMsg + { get { return msg_ != null; } } /// Clears the value of the "msg" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearMsg() { + public void ClearMsg() + { msg_ = null; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as Ok); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(Ok other) { - if (ReferenceEquals(other, null)) { + public bool Equals(Ok other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } if (Msg != other.Msg) return false; @@ -579,10 +668,12 @@ public bool Equals(Ok other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; if (HasMsg) hash ^= Msg.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -590,16 +681,18 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (HasMsg) { output.WriteRawTag(10); output.WriteString(Msg); @@ -607,31 +700,37 @@ public void WriteTo(pb::CodedOutputStream output) { if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (HasMsg) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (HasMsg) + { output.WriteRawTag(10); output.WriteString(Msg); } - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (HasMsg) { + if (HasMsg) + { size += 1 + pb::CodedOutputStream.ComputeStringSize(Msg); } - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -639,11 +738,14 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(Ok other) { - if (other == null) { + public void MergeFrom(Ok other) + { + if (other == null) + { return; } - if (other.HasMsg) { + if (other.HasMsg) + { Msg = other.Msg; } _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); @@ -651,13 +753,18 @@ public void MergeFrom(Ok other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -667,34 +774,44 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 10: { - Msg = input.ReadString(); - break; - } + case 10: + { + Msg = input.ReadString(); + break; + } } } } - #endif +#endif } - internal sealed partial class Error : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class Error : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Error()); private pb::UnknownFieldSet _unknownFields; @@ -705,19 +822,22 @@ internal sealed partial class Error : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.MysqlxReflection.Descriptor.MessageTypes[3]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Error() { + public Error() + { OnConstruction(); } @@ -725,7 +845,8 @@ public Error() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Error(Error other) : this() { + public Error(Error other) : this() + { _hasBits0 = other._hasBits0; severity_ = other.severity_; code_ = other.code_; @@ -736,7 +857,8 @@ public Error(Error other) : this() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Error Clone() { + public Error Clone() + { return new Error(this); } @@ -750,9 +872,11 @@ public Error Clone() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Error.Types.Severity Severity { + public global::Mysqlx.Error.Types.Severity Severity + { get { if ((_hasBits0 & 1) != 0) { return severity_; } else { return SeverityDefaultValue; } } - set { + set + { _hasBits0 |= 1; severity_ = value; } @@ -760,13 +884,15 @@ public Error Clone() { /// Gets whether the "severity" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasSeverity { + public bool HasSeverity + { get { return (_hasBits0 & 1) != 0; } } /// Clears the value of the "severity" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearSeverity() { + public void ClearSeverity() + { _hasBits0 &= ~1; } @@ -780,9 +906,11 @@ public void ClearSeverity() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public uint Code { + public uint Code + { get { if ((_hasBits0 & 2) != 0) { return code_; } else { return CodeDefaultValue; } } - set { + set + { _hasBits0 |= 2; code_ = value; } @@ -790,13 +918,15 @@ public uint Code { /// Gets whether the "code" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasCode { + public bool HasCode + { get { return (_hasBits0 & 2) != 0; } } /// Clears the value of the "code" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearCode() { + public void ClearCode() + { _hasBits0 &= ~2; } @@ -810,22 +940,26 @@ public void ClearCode() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public string SqlState { + public string SqlState + { get { return sqlState_ ?? SqlStateDefaultValue; } - set { + set + { sqlState_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); } } /// Gets whether the "sql_state" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasSqlState { + public bool HasSqlState + { get { return sqlState_ != null; } } /// Clears the value of the "sql_state" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearSqlState() { + public void ClearSqlState() + { sqlState_ = null; } @@ -839,38 +973,46 @@ public void ClearSqlState() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public string Msg { + public string Msg + { get { return msg_ ?? MsgDefaultValue; } - set { + set + { msg_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); } } /// Gets whether the "msg" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasMsg { + public bool HasMsg + { get { return msg_ != null; } } /// Clears the value of the "msg" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearMsg() { + public void ClearMsg() + { msg_ = null; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as Error); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(Error other) { - if (ReferenceEquals(other, null)) { + public bool Equals(Error other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } if (Severity != other.Severity) return false; @@ -882,13 +1024,15 @@ public bool Equals(Error other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; if (HasSeverity) hash ^= Severity.GetHashCode(); if (HasCode) hash ^= Code.GetHashCode(); if (HasSqlState) hash ^= SqlState.GetHashCode(); if (HasMsg) hash ^= Msg.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -896,16 +1040,18 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (HasSeverity) { output.WriteRawTag(8); output.WriteEnum((int) Severity); @@ -925,52 +1071,64 @@ public void WriteTo(pb::CodedOutputStream output) { if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (HasSeverity) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (HasSeverity) + { output.WriteRawTag(8); - output.WriteEnum((int) Severity); + output.WriteEnum((int)Severity); } - if (HasCode) { + if (HasCode) + { output.WriteRawTag(16); output.WriteUInt32(Code); } - if (HasMsg) { + if (HasMsg) + { output.WriteRawTag(26); output.WriteString(Msg); } - if (HasSqlState) { + if (HasSqlState) + { output.WriteRawTag(34); output.WriteString(SqlState); } - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (HasSeverity) { - size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Severity); + if (HasSeverity) + { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int)Severity); } - if (HasCode) { + if (HasCode) + { size += 1 + pb::CodedOutputStream.ComputeUInt32Size(Code); } - if (HasSqlState) { + if (HasSqlState) + { size += 1 + pb::CodedOutputStream.ComputeStringSize(SqlState); } - if (HasMsg) { + if (HasMsg) + { size += 1 + pb::CodedOutputStream.ComputeStringSize(Msg); } - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -978,20 +1136,26 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(Error other) { - if (other == null) { + public void MergeFrom(Error other) + { + if (other == null) + { return; } - if (other.HasSeverity) { + if (other.HasSeverity) + { Severity = other.Severity; } - if (other.HasCode) { + if (other.HasCode) + { Code = other.Code; } - if (other.HasSqlState) { + if (other.HasSqlState) + { SqlState = other.SqlState; } - if (other.HasMsg) { + if (other.HasMsg) + { Msg = other.Msg; } _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); @@ -999,13 +1163,18 @@ public void MergeFrom(Error other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -1027,46 +1196,60 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 8: { - Severity = (global::Mysqlx.Error.Types.Severity) input.ReadEnum(); - break; - } - case 16: { - Code = input.ReadUInt32(); - break; - } - case 26: { - Msg = input.ReadString(); - break; - } - case 34: { - SqlState = input.ReadString(); - break; - } + case 8: + { + Severity = (global::Mysqlx.Error.Types.Severity)input.ReadEnum(); + break; + } + case 16: + { + Code = input.ReadUInt32(); + break; + } + case 26: + { + Msg = input.ReadString(); + break; + } + case 34: + { + SqlState = input.ReadString(); + break; + } } } } - #endif +#endif #region Nested types /// Container for nested types declared in the Error message type. [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static partial class Types { - public enum Severity { + public static partial class Types + { + public enum Severity + { [pbr::OriginalName("ERROR")] Error = 0, [pbr::OriginalName("FATAL")] Fatal = 1, } diff --git a/MySQL.Data/src/X/Protocol/X/Protobuf/MysqlxConnection.cs b/MySQL.Data/src/X/Protocol/X/Protobuf/MysqlxConnection.cs index 56fa65d62..b5f4aec39 100644 --- a/MySQL.Data/src/X/Protocol/X/Protobuf/MysqlxConnection.cs +++ b/MySQL.Data/src/X/Protocol/X/Protobuf/MysqlxConnection.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2022, 2023, Oracle and/or its affiliates. +// Copyright © 2022, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -37,19 +37,23 @@ using pbc = global::Google.Protobuf.Collections; using pbr = global::Google.Protobuf.Reflection; using scg = global::System.Collections.Generic; -namespace Mysqlx.Connection { +namespace Mysqlx.Connection +{ /// Holder for reflection information generated from mysqlx_connection.proto - internal static partial class MysqlxConnectionReflection { + public static partial class MysqlxConnectionReflection + { #region Descriptor /// File descriptor for mysqlx_connection.proto - public static pbr::FileDescriptor Descriptor { + public static pbr::FileDescriptor Descriptor + { get { return descriptor; } } private static pbr::FileDescriptor descriptor; - static MysqlxConnectionReflection() { + static MysqlxConnectionReflection() + { byte[] descriptorData = global::System.Convert.FromBase64String( string.Concat( "ChdteXNxbHhfY29ubmVjdGlvbi5wcm90bxIRTXlzcWx4LkNvbm5lY3Rpb24a", @@ -63,7 +67,7 @@ static MysqlxConnectionReflection() { "GQoRdW5jb21wcmVzc2VkX3NpemUYASABKAQSNAoPc2VydmVyX21lc3NhZ2Vz", "GAIgASgOMhsuTXlzcWx4LlNlcnZlck1lc3NhZ2VzLlR5cGUSNAoPY2xpZW50", "X21lc3NhZ2VzGAMgASgOMhsuTXlzcWx4LkNsaWVudE1lc3NhZ2VzLlR5cGUS", - "DwoHcGF5bG9hZBgEIAIoDDoIkOowE4jqMC5CGQoXY29tLm15c3FsLmNqLngu", + "DwoHcGF5bG9hZBgEIAIoDDoIiOowLpDqMBNCGQoXY29tLm15c3FsLmNqLngu", "cHJvdG9idWY=")); descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, new pbr::FileDescriptor[] { global::Mysqlx.Datatypes.MysqlxDatatypesReflection.Descriptor, global::Mysqlx.MysqlxReflection.Descriptor, }, @@ -86,10 +90,11 @@ static MysqlxConnectionReflection() { /// ///A tuple of a ``name`` and a @ref Mysqlx::Datatypes::Any /// - internal sealed partial class Capability : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class Capability : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Capability()); private pb::UnknownFieldSet _unknownFields; @@ -99,19 +104,22 @@ internal sealed partial class Capability : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Connection.MysqlxConnectionReflection.Descriptor.MessageTypes[0]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Capability() { + public Capability() + { OnConstruction(); } @@ -119,7 +127,8 @@ public Capability() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Capability(Capability other) : this() { + public Capability(Capability other) : this() + { name_ = other.name_; value_ = other.value_ != null ? other.value_.Clone() : null; _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); @@ -127,7 +136,8 @@ public Capability(Capability other) : this() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Capability Clone() { + public Capability Clone() + { return new Capability(this); } @@ -138,22 +148,26 @@ public Capability Clone() { private string name_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public string Name { + public string Name + { get { return name_ ?? NameDefaultValue; } - set { + set + { name_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); } } /// Gets whether the "name" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasName { + public bool HasName + { get { return name_ != null; } } /// Clears the value of the "name" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearName() { + public void ClearName() + { name_ = null; } @@ -162,26 +176,32 @@ public void ClearName() { private global::Mysqlx.Datatypes.Any value_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Datatypes.Any Value { + public global::Mysqlx.Datatypes.Any Value + { get { return value_; } - set { + set + { value_ = value; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as Capability); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(Capability other) { - if (ReferenceEquals(other, null)) { + public bool Equals(Capability other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } if (Name != other.Name) return false; @@ -191,11 +211,13 @@ public bool Equals(Capability other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; if (HasName) hash ^= Name.GetHashCode(); if (value_ != null) hash ^= Value.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -203,16 +225,18 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (HasName) { output.WriteRawTag(10); output.WriteString(Name); @@ -224,38 +248,46 @@ public void WriteTo(pb::CodedOutputStream output) { if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (HasName) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (HasName) + { output.WriteRawTag(10); output.WriteString(Name); } - if (value_ != null) { + if (value_ != null) + { output.WriteRawTag(18); output.WriteMessage(Value); } - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (HasName) { + if (HasName) + { size += 1 + pb::CodedOutputStream.ComputeStringSize(Name); } - if (value_ != null) { + if (value_ != null) + { size += 1 + pb::CodedOutputStream.ComputeMessageSize(Value); } - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -263,15 +295,20 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(Capability other) { - if (other == null) { + public void MergeFrom(Capability other) + { + if (other == null) + { return; } - if (other.HasName) { + if (other.HasName) + { Name = other.Name; } - if (other.value_ != null) { - if (value_ == null) { + if (other.value_ != null) + { + if (value_ == null) + { Value = new global::Mysqlx.Datatypes.Any(); } Value.MergeFrom(other.Value); @@ -281,13 +318,18 @@ public void MergeFrom(Capability other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -304,34 +346,45 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 10: { - Name = input.ReadString(); - break; - } - case 18: { - if (value_ == null) { - Value = new global::Mysqlx.Datatypes.Any(); + case 10: + { + Name = input.ReadString(); + break; + } + case 18: + { + if (value_ == null) + { + Value = new global::Mysqlx.Datatypes.Any(); + } + input.ReadMessage(Value); + break; } - input.ReadMessage(Value); - break; - } } } } - #endif +#endif } @@ -341,10 +394,11 @@ public void MergeFrom(pb::CodedInputStream input) { /// ///list of Capability /// - internal sealed partial class Capabilities : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class Capabilities : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Capabilities()); private pb::UnknownFieldSet _unknownFields; @@ -354,19 +408,22 @@ internal sealed partial class Capabilities : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Connection.MysqlxConnectionReflection.Descriptor.MessageTypes[1]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Capabilities() { + public Capabilities() + { OnConstruction(); } @@ -374,14 +431,16 @@ public Capabilities() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Capabilities(Capabilities other) : this() { + public Capabilities(Capabilities other) : this() + { capabilities_ = other.capabilities_.Clone(); _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Capabilities Clone() { + public Capabilities Clone() + { return new Capabilities(this); } @@ -392,35 +451,42 @@ public Capabilities Clone() { private readonly pbc::RepeatedField capabilities_ = new pbc::RepeatedField(); [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public pbc::RepeatedField Capabilities_ { + public pbc::RepeatedField Capabilities_ + { get { return capabilities_; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as Capabilities); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(Capabilities other) { - if (ReferenceEquals(other, null)) { + public bool Equals(Capabilities other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } - if(!capabilities_.Equals(other.capabilities_)) return false; + if (!capabilities_.Equals(other.capabilities_)) return false; return Equals(_unknownFields, other._unknownFields); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; hash ^= capabilities_.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -428,40 +494,46 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else capabilities_.WriteTo(output, _repeated_capabilities_codec); if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { capabilities_.WriteTo(ref output, _repeated_capabilities_codec); - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; size += capabilities_.CalculateSize(_repeated_capabilities_codec); - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -469,8 +541,10 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(Capabilities other) { - if (other == null) { + public void MergeFrom(Capabilities other) + { + if (other == null) + { return; } capabilities_.Add(other.capabilities_); @@ -479,13 +553,18 @@ public void MergeFrom(Capabilities other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -495,27 +574,36 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 10: { - capabilities_.AddEntriesFrom(ref input, _repeated_capabilities_codec); - break; - } + case 10: + { + capabilities_.AddEntriesFrom(ref input, _repeated_capabilities_codec); + break; + } } } } - #endif +#endif } @@ -525,10 +613,11 @@ public void MergeFrom(pb::CodedInputStream input) { /// ///@returns @ref Mysqlx::Connection::Capabilities or @ref Mysqlx::Error /// - internal sealed partial class CapabilitiesGet : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class CapabilitiesGet : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new CapabilitiesGet()); private pb::UnknownFieldSet _unknownFields; @@ -538,19 +627,22 @@ internal sealed partial class CapabilitiesGet : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Connection.MysqlxConnectionReflection.Descriptor.MessageTypes[2]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public CapabilitiesGet() { + public CapabilitiesGet() + { OnConstruction(); } @@ -558,29 +650,35 @@ public CapabilitiesGet() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public CapabilitiesGet(CapabilitiesGet other) : this() { + public CapabilitiesGet(CapabilitiesGet other) : this() + { _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public CapabilitiesGet Clone() { + public CapabilitiesGet Clone() + { return new CapabilitiesGet(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as CapabilitiesGet); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(CapabilitiesGet other) { - if (ReferenceEquals(other, null)) { + public bool Equals(CapabilitiesGet other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } return Equals(_unknownFields, other._unknownFields); @@ -588,9 +686,11 @@ public bool Equals(CapabilitiesGet other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -598,37 +698,43 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (_unknownFields != null) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -636,8 +742,10 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(CapabilitiesGet other) { - if (other == null) { + public void MergeFrom(CapabilitiesGet other) + { + if (other == null) + { return; } _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); @@ -645,35 +753,48 @@ public void MergeFrom(CapabilitiesGet other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; } } } - #endif +#endif } @@ -688,10 +809,11 @@ public void MergeFrom(pb::CodedInputStream input) { /// ///@returns @ref Mysqlx::Ok or @ref Mysqlx::Error /// - internal sealed partial class CapabilitiesSet : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class CapabilitiesSet : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new CapabilitiesSet()); private pb::UnknownFieldSet _unknownFields; @@ -701,19 +823,22 @@ internal sealed partial class CapabilitiesSet : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Connection.MysqlxConnectionReflection.Descriptor.MessageTypes[3]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public CapabilitiesSet() { + public CapabilitiesSet() + { OnConstruction(); } @@ -721,14 +846,16 @@ public CapabilitiesSet() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public CapabilitiesSet(CapabilitiesSet other) : this() { + public CapabilitiesSet(CapabilitiesSet other) : this() + { capabilities_ = other.capabilities_ != null ? other.capabilities_.Clone() : null; _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public CapabilitiesSet Clone() { + public CapabilitiesSet Clone() + { return new CapabilitiesSet(this); } @@ -737,26 +864,32 @@ public CapabilitiesSet Clone() { private global::Mysqlx.Connection.Capabilities capabilities_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Connection.Capabilities Capabilities { + public global::Mysqlx.Connection.Capabilities Capabilities + { get { return capabilities_; } - set { + set + { capabilities_ = value; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as CapabilitiesSet); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(CapabilitiesSet other) { - if (ReferenceEquals(other, null)) { + public bool Equals(CapabilitiesSet other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } if (!object.Equals(Capabilities, other.Capabilities)) return false; @@ -765,10 +898,12 @@ public bool Equals(CapabilitiesSet other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; if (capabilities_ != null) hash ^= Capabilities.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -776,16 +911,18 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (capabilities_ != null) { output.WriteRawTag(10); output.WriteMessage(Capabilities); @@ -793,31 +930,37 @@ public void WriteTo(pb::CodedOutputStream output) { if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (capabilities_ != null) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (capabilities_ != null) + { output.WriteRawTag(10); output.WriteMessage(Capabilities); } - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (capabilities_ != null) { + if (capabilities_ != null) + { size += 1 + pb::CodedOutputStream.ComputeMessageSize(Capabilities); } - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -825,12 +968,16 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(CapabilitiesSet other) { - if (other == null) { + public void MergeFrom(CapabilitiesSet other) + { + if (other == null) + { return; } - if (other.capabilities_ != null) { - if (capabilities_ == null) { + if (other.capabilities_ != null) + { + if (capabilities_ == null) + { Capabilities = new global::Mysqlx.Connection.Capabilities(); } Capabilities.MergeFrom(other.Capabilities); @@ -840,13 +987,18 @@ public void MergeFrom(CapabilitiesSet other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -859,30 +1011,40 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 10: { - if (capabilities_ == null) { - Capabilities = new global::Mysqlx.Connection.Capabilities(); + case 10: + { + if (capabilities_ == null) + { + Capabilities = new global::Mysqlx.Connection.Capabilities(); + } + input.ReadMessage(Capabilities); + break; } - input.ReadMessage(Capabilities); - break; - } } } } - #endif +#endif } @@ -894,10 +1056,11 @@ public void MergeFrom(pb::CodedInputStream input) { /// ///@returns @ref Mysqlx::Ok /// - internal sealed partial class Close : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class Close : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Close()); private pb::UnknownFieldSet _unknownFields; @@ -907,19 +1070,22 @@ internal sealed partial class Close : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Connection.MysqlxConnectionReflection.Descriptor.MessageTypes[4]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Close() { + public Close() + { OnConstruction(); } @@ -927,29 +1093,35 @@ public Close() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Close(Close other) : this() { + public Close(Close other) : this() + { _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Close Clone() { + public Close Clone() + { return new Close(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as Close); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(Close other) { - if (ReferenceEquals(other, null)) { + public bool Equals(Close other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } return Equals(_unknownFields, other._unknownFields); @@ -957,9 +1129,11 @@ public bool Equals(Close other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -967,37 +1141,43 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (_unknownFields != null) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -1005,8 +1185,10 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(Close other) { - if (other == null) { + public void MergeFrom(Close other) + { + if (other == null) + { return; } _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); @@ -1014,42 +1196,56 @@ public void MergeFrom(Close other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; } } } - #endif +#endif } - internal sealed partial class Compression : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class Compression : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Compression()); private pb::UnknownFieldSet _unknownFields; @@ -1060,19 +1256,22 @@ internal sealed partial class Compression : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Connection.MysqlxConnectionReflection.Descriptor.MessageTypes[5]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Compression() { + public Compression() + { OnConstruction(); } @@ -1080,7 +1279,8 @@ public Compression() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Compression(Compression other) : this() { + public Compression(Compression other) : this() + { _hasBits0 = other._hasBits0; uncompressedSize_ = other.uncompressedSize_; serverMessages_ = other.serverMessages_; @@ -1091,7 +1291,8 @@ public Compression(Compression other) : this() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Compression Clone() { + public Compression Clone() + { return new Compression(this); } @@ -1102,9 +1303,11 @@ public Compression Clone() { private ulong uncompressedSize_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public ulong UncompressedSize { + public ulong UncompressedSize + { get { if ((_hasBits0 & 1) != 0) { return uncompressedSize_; } else { return UncompressedSizeDefaultValue; } } - set { + set + { _hasBits0 |= 1; uncompressedSize_ = value; } @@ -1112,13 +1315,15 @@ public ulong UncompressedSize { /// Gets whether the "uncompressed_size" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasUncompressedSize { + public bool HasUncompressedSize + { get { return (_hasBits0 & 1) != 0; } } /// Clears the value of the "uncompressed_size" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearUncompressedSize() { + public void ClearUncompressedSize() + { _hasBits0 &= ~1; } @@ -1129,9 +1334,11 @@ public void ClearUncompressedSize() { private global::Mysqlx.ServerMessages.Types.Type serverMessages_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.ServerMessages.Types.Type ServerMessages { + public global::Mysqlx.ServerMessages.Types.Type ServerMessages + { get { if ((_hasBits0 & 2) != 0) { return serverMessages_; } else { return ServerMessagesDefaultValue; } } - set { + set + { _hasBits0 |= 2; serverMessages_ = value; } @@ -1139,13 +1346,15 @@ public void ClearUncompressedSize() { /// Gets whether the "server_messages" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasServerMessages { + public bool HasServerMessages + { get { return (_hasBits0 & 2) != 0; } } /// Clears the value of the "server_messages" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearServerMessages() { + public void ClearServerMessages() + { _hasBits0 &= ~2; } @@ -1156,9 +1365,11 @@ public void ClearServerMessages() { private global::Mysqlx.ClientMessages.Types.Type clientMessages_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.ClientMessages.Types.Type ClientMessages { + public global::Mysqlx.ClientMessages.Types.Type ClientMessages + { get { if ((_hasBits0 & 4) != 0) { return clientMessages_; } else { return ClientMessagesDefaultValue; } } - set { + set + { _hasBits0 |= 4; clientMessages_ = value; } @@ -1166,13 +1377,15 @@ public void ClearServerMessages() { /// Gets whether the "client_messages" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasClientMessages { + public bool HasClientMessages + { get { return (_hasBits0 & 4) != 0; } } /// Clears the value of the "client_messages" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearClientMessages() { + public void ClearClientMessages() + { _hasBits0 &= ~4; } @@ -1183,38 +1396,46 @@ public void ClearClientMessages() { private pb::ByteString payload_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public pb::ByteString Payload { + public pb::ByteString Payload + { get { return payload_ ?? PayloadDefaultValue; } - set { + set + { payload_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); } } /// Gets whether the "payload" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasPayload { + public bool HasPayload + { get { return payload_ != null; } } /// Clears the value of the "payload" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearPayload() { + public void ClearPayload() + { payload_ = null; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as Compression); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(Compression other) { - if (ReferenceEquals(other, null)) { + public bool Equals(Compression other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } if (UncompressedSize != other.UncompressedSize) return false; @@ -1226,13 +1447,15 @@ public bool Equals(Compression other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; if (HasUncompressedSize) hash ^= UncompressedSize.GetHashCode(); if (HasServerMessages) hash ^= ServerMessages.GetHashCode(); if (HasClientMessages) hash ^= ClientMessages.GetHashCode(); if (HasPayload) hash ^= Payload.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -1240,16 +1463,18 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (HasUncompressedSize) { output.WriteRawTag(8); output.WriteUInt64(UncompressedSize); @@ -1269,52 +1494,64 @@ public void WriteTo(pb::CodedOutputStream output) { if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (HasUncompressedSize) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (HasUncompressedSize) + { output.WriteRawTag(8); output.WriteUInt64(UncompressedSize); } - if (HasServerMessages) { + if (HasServerMessages) + { output.WriteRawTag(16); - output.WriteEnum((int) ServerMessages); + output.WriteEnum((int)ServerMessages); } - if (HasClientMessages) { + if (HasClientMessages) + { output.WriteRawTag(24); - output.WriteEnum((int) ClientMessages); + output.WriteEnum((int)ClientMessages); } - if (HasPayload) { + if (HasPayload) + { output.WriteRawTag(34); output.WriteBytes(Payload); } - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (HasUncompressedSize) { + if (HasUncompressedSize) + { size += 1 + pb::CodedOutputStream.ComputeUInt64Size(UncompressedSize); } - if (HasServerMessages) { - size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) ServerMessages); + if (HasServerMessages) + { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int)ServerMessages); } - if (HasClientMessages) { - size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) ClientMessages); + if (HasClientMessages) + { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int)ClientMessages); } - if (HasPayload) { + if (HasPayload) + { size += 1 + pb::CodedOutputStream.ComputeBytesSize(Payload); } - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -1322,20 +1559,26 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(Compression other) { - if (other == null) { + public void MergeFrom(Compression other) + { + if (other == null) + { return; } - if (other.HasUncompressedSize) { + if (other.HasUncompressedSize) + { UncompressedSize = other.UncompressedSize; } - if (other.HasServerMessages) { + if (other.HasServerMessages) + { ServerMessages = other.ServerMessages; } - if (other.HasClientMessages) { + if (other.HasClientMessages) + { ClientMessages = other.ClientMessages; } - if (other.HasPayload) { + if (other.HasPayload) + { Payload = other.Payload; } _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); @@ -1343,13 +1586,18 @@ public void MergeFrom(Compression other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -1371,39 +1619,51 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 8: { - UncompressedSize = input.ReadUInt64(); - break; - } - case 16: { - ServerMessages = (global::Mysqlx.ServerMessages.Types.Type) input.ReadEnum(); - break; - } - case 24: { - ClientMessages = (global::Mysqlx.ClientMessages.Types.Type) input.ReadEnum(); - break; - } - case 34: { - Payload = input.ReadBytes(); - break; - } + case 8: + { + UncompressedSize = input.ReadUInt64(); + break; + } + case 16: + { + ServerMessages = (global::Mysqlx.ServerMessages.Types.Type)input.ReadEnum(); + break; + } + case 24: + { + ClientMessages = (global::Mysqlx.ClientMessages.Types.Type)input.ReadEnum(); + break; + } + case 34: + { + Payload = input.ReadBytes(); + break; + } } } } - #endif +#endif } @@ -1412,3 +1672,4 @@ public void MergeFrom(pb::CodedInputStream input) { } #endregion Designer generated code + diff --git a/MySQL.Data/src/X/Protocol/X/Protobuf/MysqlxCrud.cs b/MySQL.Data/src/X/Protocol/X/Protobuf/MysqlxCrud.cs index bef4f3ff2..75e212cd8 100644 --- a/MySQL.Data/src/X/Protocol/X/Protobuf/MysqlxCrud.cs +++ b/MySQL.Data/src/X/Protocol/X/Protobuf/MysqlxCrud.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2022, 2023, Oracle and/or its affiliates. +// Copyright © 2022, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -37,19 +37,23 @@ using pbc = global::Google.Protobuf.Collections; using pbr = global::Google.Protobuf.Reflection; using scg = global::System.Collections.Generic; -namespace Mysqlx.Crud { +namespace Mysqlx.Crud +{ /// Holder for reflection information generated from mysqlx_crud.proto - internal static partial class MysqlxCrudReflection { + public static partial class MysqlxCrudReflection + { #region Descriptor /// File descriptor for mysqlx_crud.proto - public static pbr::FileDescriptor Descriptor { + public static pbr::FileDescriptor Descriptor + { get { return descriptor; } } private static pbr::FileDescriptor descriptor; - static MysqlxCrudReflection() { + static MysqlxCrudReflection() + { byte[] descriptorData = global::System.Convert.FromBase64String( string.Concat( "ChFteXNxbHhfY3J1ZC5wcm90bxILTXlzcWx4LkNydWQaDG15c3FseC5wcm90", @@ -128,7 +132,7 @@ static MysqlxCrudReflection() { "QhkKF2NvbS5teXNxbC5jai54LnByb3RvYnVm")); descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, new pbr::FileDescriptor[] { global::Mysqlx.MysqlxReflection.Descriptor, global::Mysqlx.Expr.MysqlxExprReflection.Descriptor, global::Mysqlx.Datatypes.MysqlxDatatypesReflection.Descriptor, }, - new pbr::GeneratedClrTypeInfo(new[] {typeof(global::Mysqlx.Crud.DataModel), typeof(global::Mysqlx.Crud.ViewAlgorithm), typeof(global::Mysqlx.Crud.ViewSqlSecurity), typeof(global::Mysqlx.Crud.ViewCheckOption), }, null, new pbr::GeneratedClrTypeInfo[] { + new pbr::GeneratedClrTypeInfo(new[] { typeof(global::Mysqlx.Crud.DataModel), typeof(global::Mysqlx.Crud.ViewAlgorithm), typeof(global::Mysqlx.Crud.ViewSqlSecurity), typeof(global::Mysqlx.Crud.ViewCheckOption), }, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::Mysqlx.Crud.Column), global::Mysqlx.Crud.Column.Parser, new[]{ "Name", "Alias", "DocumentPath" }, null, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Mysqlx.Crud.Projection), global::Mysqlx.Crud.Projection.Parser, new[]{ "Source", "Alias" }, null, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Mysqlx.Crud.Collection), global::Mysqlx.Crud.Collection.Parser, new[]{ "Name", "Schema" }, null, null, null, null), @@ -153,7 +157,8 @@ static MysqlxCrudReflection() { ///* ///DataModel to use for filters, names, ... /// - internal enum DataModel { + public enum DataModel + { [pbr::OriginalName("DOCUMENT")] Document = 1, [pbr::OriginalName("TABLE")] Table = 2, } @@ -162,7 +167,8 @@ internal enum DataModel { ///* ///ViewAlgorithm defines how MySQL Server processes the view /// - internal enum ViewAlgorithm { + public enum ViewAlgorithm + { /// ///* MySQL chooses which algorithm to use /// @@ -184,7 +190,8 @@ internal enum ViewAlgorithm { ///executed; this means that VIEW can be executed with current user permissions or ///with permissions of the user who defined the VIEW /// - internal enum ViewSqlSecurity { + public enum ViewSqlSecurity + { /// ///* use current user permissions /// @@ -200,7 +207,8 @@ internal enum ViewSqlSecurity { ///ViewCheckOption limits the write operations done on a `VIEW` ///(`INSERT`, `UPDATE`, `DELETE`) to rows in which the `WHERE` clause is `TRUE` /// - internal enum ViewCheckOption { + public enum ViewCheckOption + { /// ///* the view WHERE clause is checked, but no underlying views are checked /// @@ -215,10 +223,11 @@ internal enum ViewCheckOption { #endregion #region Messages - internal sealed partial class Column : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class Column : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Column()); private pb::UnknownFieldSet _unknownFields; @@ -228,19 +237,22 @@ internal sealed partial class Column : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Crud.MysqlxCrudReflection.Descriptor.MessageTypes[0]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Column() { + public Column() + { OnConstruction(); } @@ -248,7 +260,8 @@ public Column() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Column(Column other) : this() { + public Column(Column other) : this() + { name_ = other.name_; alias_ = other.alias_; documentPath_ = other.documentPath_.Clone(); @@ -257,7 +270,8 @@ public Column(Column other) : this() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Column Clone() { + public Column Clone() + { return new Column(this); } @@ -268,22 +282,26 @@ public Column Clone() { private string name_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public string Name { + public string Name + { get { return name_ ?? NameDefaultValue; } - set { + set + { name_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); } } /// Gets whether the "name" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasName { + public bool HasName + { get { return name_ != null; } } /// Clears the value of the "name" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearName() { + public void ClearName() + { name_ = null; } @@ -294,22 +312,26 @@ public void ClearName() { private string alias_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public string Alias { + public string Alias + { get { return alias_ ?? AliasDefaultValue; } - set { + set + { alias_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); } } /// Gets whether the "alias" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasAlias { + public bool HasAlias + { get { return alias_ != null; } } /// Clears the value of the "alias" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearAlias() { + public void ClearAlias() + { alias_ = null; } @@ -320,39 +342,46 @@ public void ClearAlias() { private readonly pbc::RepeatedField documentPath_ = new pbc::RepeatedField(); [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public pbc::RepeatedField DocumentPath { + public pbc::RepeatedField DocumentPath + { get { return documentPath_; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as Column); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(Column other) { - if (ReferenceEquals(other, null)) { + public bool Equals(Column other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } if (Name != other.Name) return false; if (Alias != other.Alias) return false; - if(!documentPath_.Equals(other.documentPath_)) return false; + if (!documentPath_.Equals(other.documentPath_)) return false; return Equals(_unknownFields, other._unknownFields); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; if (HasName) hash ^= Name.GetHashCode(); if (HasAlias) hash ^= Alias.GetHashCode(); hash ^= documentPath_.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -360,16 +389,18 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (HasName) { output.WriteRawTag(10); output.WriteString(Name); @@ -382,40 +413,48 @@ public void WriteTo(pb::CodedOutputStream output) { if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (HasName) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (HasName) + { output.WriteRawTag(10); output.WriteString(Name); } - if (HasAlias) { + if (HasAlias) + { output.WriteRawTag(18); output.WriteString(Alias); } documentPath_.WriteTo(ref output, _repeated_documentPath_codec); - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (HasName) { + if (HasName) + { size += 1 + pb::CodedOutputStream.ComputeStringSize(Name); } - if (HasAlias) { + if (HasAlias) + { size += 1 + pb::CodedOutputStream.ComputeStringSize(Alias); } size += documentPath_.CalculateSize(_repeated_documentPath_codec); - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -423,14 +462,18 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(Column other) { - if (other == null) { + public void MergeFrom(Column other) + { + if (other == null) + { return; } - if (other.HasName) { + if (other.HasName) + { Name = other.Name; } - if (other.HasAlias) { + if (other.HasAlias) + { Alias = other.Alias; } documentPath_.Add(other.documentPath_); @@ -439,13 +482,18 @@ public void MergeFrom(Column other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -463,42 +511,54 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 10: { - Name = input.ReadString(); - break; - } - case 18: { - Alias = input.ReadString(); - break; - } - case 26: { - documentPath_.AddEntriesFrom(ref input, _repeated_documentPath_codec); - break; - } + case 10: + { + Name = input.ReadString(); + break; + } + case 18: + { + Alias = input.ReadString(); + break; + } + case 26: + { + documentPath_.AddEntriesFrom(ref input, _repeated_documentPath_codec); + break; + } } } } - #endif +#endif } - internal sealed partial class Projection : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class Projection : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Projection()); private pb::UnknownFieldSet _unknownFields; @@ -508,19 +568,22 @@ internal sealed partial class Projection : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Crud.MysqlxCrudReflection.Descriptor.MessageTypes[1]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Projection() { + public Projection() + { OnConstruction(); } @@ -528,7 +591,8 @@ public Projection() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Projection(Projection other) : this() { + public Projection(Projection other) : this() + { source_ = other.source_ != null ? other.source_.Clone() : null; alias_ = other.alias_; _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); @@ -536,7 +600,8 @@ public Projection(Projection other) : this() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Projection Clone() { + public Projection Clone() + { return new Projection(this); } @@ -549,9 +614,11 @@ public Projection Clone() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Expr.Expr Source { + public global::Mysqlx.Expr.Expr Source + { get { return source_; } - set { + set + { source_ = value; } } @@ -567,38 +634,46 @@ public Projection Clone() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public string Alias { + public string Alias + { get { return alias_ ?? AliasDefaultValue; } - set { + set + { alias_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); } } /// Gets whether the "alias" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasAlias { + public bool HasAlias + { get { return alias_ != null; } } /// Clears the value of the "alias" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearAlias() { + public void ClearAlias() + { alias_ = null; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as Projection); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(Projection other) { - if (ReferenceEquals(other, null)) { + public bool Equals(Projection other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } if (!object.Equals(Source, other.Source)) return false; @@ -608,11 +683,13 @@ public bool Equals(Projection other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; if (source_ != null) hash ^= Source.GetHashCode(); if (HasAlias) hash ^= Alias.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -620,16 +697,18 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (source_ != null) { output.WriteRawTag(10); output.WriteMessage(Source); @@ -641,38 +720,46 @@ public void WriteTo(pb::CodedOutputStream output) { if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (source_ != null) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (source_ != null) + { output.WriteRawTag(10); output.WriteMessage(Source); } - if (HasAlias) { + if (HasAlias) + { output.WriteRawTag(18); output.WriteString(Alias); } - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (source_ != null) { + if (source_ != null) + { size += 1 + pb::CodedOutputStream.ComputeMessageSize(Source); } - if (HasAlias) { + if (HasAlias) + { size += 1 + pb::CodedOutputStream.ComputeStringSize(Alias); } - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -680,17 +767,22 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(Projection other) { - if (other == null) { + public void MergeFrom(Projection other) + { + if (other == null) + { return; } - if (other.source_ != null) { - if (source_ == null) { + if (other.source_ != null) + { + if (source_ == null) + { Source = new global::Mysqlx.Expr.Expr(); } Source.MergeFrom(other.Source); } - if (other.HasAlias) { + if (other.HasAlias) + { Alias = other.Alias; } _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); @@ -698,13 +790,18 @@ public void MergeFrom(Projection other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -721,41 +818,53 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 10: { - if (source_ == null) { - Source = new global::Mysqlx.Expr.Expr(); + case 10: + { + if (source_ == null) + { + Source = new global::Mysqlx.Expr.Expr(); + } + input.ReadMessage(Source); + break; + } + case 18: + { + Alias = input.ReadString(); + break; } - input.ReadMessage(Source); - break; - } - case 18: { - Alias = input.ReadString(); - break; - } } } } - #endif +#endif } - internal sealed partial class Collection : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class Collection : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Collection()); private pb::UnknownFieldSet _unknownFields; @@ -765,19 +874,22 @@ internal sealed partial class Collection : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Crud.MysqlxCrudReflection.Descriptor.MessageTypes[2]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Collection() { + public Collection() + { OnConstruction(); } @@ -785,7 +897,8 @@ public Collection() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Collection(Collection other) : this() { + public Collection(Collection other) : this() + { name_ = other.name_; schema_ = other.schema_; _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); @@ -793,7 +906,8 @@ public Collection(Collection other) : this() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Collection Clone() { + public Collection Clone() + { return new Collection(this); } @@ -804,22 +918,26 @@ public Collection Clone() { private string name_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public string Name { + public string Name + { get { return name_ ?? NameDefaultValue; } - set { + set + { name_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); } } /// Gets whether the "name" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasName { + public bool HasName + { get { return name_ != null; } } /// Clears the value of the "name" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearName() { + public void ClearName() + { name_ = null; } @@ -830,38 +948,46 @@ public void ClearName() { private string schema_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public string Schema { + public string Schema + { get { return schema_ ?? SchemaDefaultValue; } - set { + set + { schema_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); } } /// Gets whether the "schema" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasSchema { + public bool HasSchema + { get { return schema_ != null; } } /// Clears the value of the "schema" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearSchema() { + public void ClearSchema() + { schema_ = null; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as Collection); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(Collection other) { - if (ReferenceEquals(other, null)) { + public bool Equals(Collection other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } if (Name != other.Name) return false; @@ -871,11 +997,13 @@ public bool Equals(Collection other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; if (HasName) hash ^= Name.GetHashCode(); if (HasSchema) hash ^= Schema.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -883,16 +1011,18 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (HasName) { output.WriteRawTag(10); output.WriteString(Name); @@ -904,38 +1034,46 @@ public void WriteTo(pb::CodedOutputStream output) { if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (HasName) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (HasName) + { output.WriteRawTag(10); output.WriteString(Name); } - if (HasSchema) { + if (HasSchema) + { output.WriteRawTag(18); output.WriteString(Schema); } - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (HasName) { + if (HasName) + { size += 1 + pb::CodedOutputStream.ComputeStringSize(Name); } - if (HasSchema) { + if (HasSchema) + { size += 1 + pb::CodedOutputStream.ComputeStringSize(Schema); } - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -943,14 +1081,18 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(Collection other) { - if (other == null) { + public void MergeFrom(Collection other) + { + if (other == null) + { return; } - if (other.HasName) { + if (other.HasName) + { Name = other.Name; } - if (other.HasSchema) { + if (other.HasSchema) + { Schema = other.Schema; } _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); @@ -958,13 +1100,18 @@ public void MergeFrom(Collection other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -978,38 +1125,49 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 10: { - Name = input.ReadString(); - break; - } - case 18: { - Schema = input.ReadString(); - break; - } + case 10: + { + Name = input.ReadString(); + break; + } + case 18: + { + Schema = input.ReadString(); + break; + } } } } - #endif +#endif } - internal sealed partial class Limit : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class Limit : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Limit()); private pb::UnknownFieldSet _unknownFields; @@ -1020,19 +1178,22 @@ internal sealed partial class Limit : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Crud.MysqlxCrudReflection.Descriptor.MessageTypes[3]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Limit() { + public Limit() + { OnConstruction(); } @@ -1040,7 +1201,8 @@ public Limit() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Limit(Limit other) : this() { + public Limit(Limit other) : this() + { _hasBits0 = other._hasBits0; rowCount_ = other.rowCount_; offset_ = other.offset_; @@ -1049,7 +1211,8 @@ public Limit(Limit other) : this() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Limit Clone() { + public Limit Clone() + { return new Limit(this); } @@ -1063,9 +1226,11 @@ public Limit Clone() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public ulong RowCount { + public ulong RowCount + { get { if ((_hasBits0 & 1) != 0) { return rowCount_; } else { return RowCountDefaultValue; } } - set { + set + { _hasBits0 |= 1; rowCount_ = value; } @@ -1073,13 +1238,15 @@ public ulong RowCount { /// Gets whether the "row_count" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasRowCount { + public bool HasRowCount + { get { return (_hasBits0 & 1) != 0; } } /// Clears the value of the "row_count" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearRowCount() { + public void ClearRowCount() + { _hasBits0 &= ~1; } @@ -1093,9 +1260,11 @@ public void ClearRowCount() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public ulong Offset { + public ulong Offset + { get { if ((_hasBits0 & 2) != 0) { return offset_; } else { return OffsetDefaultValue; } } - set { + set + { _hasBits0 |= 2; offset_ = value; } @@ -1103,29 +1272,35 @@ public ulong Offset { /// Gets whether the "offset" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasOffset { + public bool HasOffset + { get { return (_hasBits0 & 2) != 0; } } /// Clears the value of the "offset" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearOffset() { + public void ClearOffset() + { _hasBits0 &= ~2; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as Limit); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(Limit other) { - if (ReferenceEquals(other, null)) { + public bool Equals(Limit other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } if (RowCount != other.RowCount) return false; @@ -1135,11 +1310,13 @@ public bool Equals(Limit other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; if (HasRowCount) hash ^= RowCount.GetHashCode(); if (HasOffset) hash ^= Offset.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -1147,16 +1324,18 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (HasRowCount) { output.WriteRawTag(8); output.WriteUInt64(RowCount); @@ -1168,38 +1347,46 @@ public void WriteTo(pb::CodedOutputStream output) { if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (HasRowCount) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (HasRowCount) + { output.WriteRawTag(8); output.WriteUInt64(RowCount); } - if (HasOffset) { + if (HasOffset) + { output.WriteRawTag(16); output.WriteUInt64(Offset); } - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (HasRowCount) { + if (HasRowCount) + { size += 1 + pb::CodedOutputStream.ComputeUInt64Size(RowCount); } - if (HasOffset) { + if (HasOffset) + { size += 1 + pb::CodedOutputStream.ComputeUInt64Size(Offset); } - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -1207,14 +1394,18 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(Limit other) { - if (other == null) { + public void MergeFrom(Limit other) + { + if (other == null) + { return; } - if (other.HasRowCount) { + if (other.HasRowCount) + { RowCount = other.RowCount; } - if (other.HasOffset) { + if (other.HasOffset) + { Offset = other.Offset; } _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); @@ -1222,13 +1413,18 @@ public void MergeFrom(Limit other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -1242,31 +1438,41 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 8: { - RowCount = input.ReadUInt64(); - break; - } - case 16: { - Offset = input.ReadUInt64(); - break; - } + case 8: + { + RowCount = input.ReadUInt64(); + break; + } + case 16: + { + Offset = input.ReadUInt64(); + break; + } } } } - #endif +#endif } @@ -1277,10 +1483,11 @@ public void MergeFrom(pb::CodedInputStream input) { ///This message support expressions of following types Expr/literal/UINT, ///Expr/PLACEHOLDER. /// - internal sealed partial class LimitExpr : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class LimitExpr : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new LimitExpr()); private pb::UnknownFieldSet _unknownFields; @@ -1290,19 +1497,22 @@ internal sealed partial class LimitExpr : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Crud.MysqlxCrudReflection.Descriptor.MessageTypes[4]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public LimitExpr() { + public LimitExpr() + { OnConstruction(); } @@ -1310,7 +1520,8 @@ public LimitExpr() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public LimitExpr(LimitExpr other) : this() { + public LimitExpr(LimitExpr other) : this() + { rowCount_ = other.rowCount_ != null ? other.rowCount_.Clone() : null; offset_ = other.offset_ != null ? other.offset_.Clone() : null; _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); @@ -1318,7 +1529,8 @@ public LimitExpr(LimitExpr other) : this() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public LimitExpr Clone() { + public LimitExpr Clone() + { return new LimitExpr(this); } @@ -1330,9 +1542,11 @@ public LimitExpr Clone() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Expr.Expr RowCount { + public global::Mysqlx.Expr.Expr RowCount + { get { return rowCount_; } - set { + set + { rowCount_ = value; } } @@ -1345,26 +1559,32 @@ public LimitExpr Clone() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Expr.Expr Offset { + public global::Mysqlx.Expr.Expr Offset + { get { return offset_; } - set { + set + { offset_ = value; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as LimitExpr); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(LimitExpr other) { - if (ReferenceEquals(other, null)) { + public bool Equals(LimitExpr other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } if (!object.Equals(RowCount, other.RowCount)) return false; @@ -1374,11 +1594,13 @@ public bool Equals(LimitExpr other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; if (rowCount_ != null) hash ^= RowCount.GetHashCode(); if (offset_ != null) hash ^= Offset.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -1386,16 +1608,18 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (rowCount_ != null) { output.WriteRawTag(10); output.WriteMessage(RowCount); @@ -1407,38 +1631,46 @@ public void WriteTo(pb::CodedOutputStream output) { if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (rowCount_ != null) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (rowCount_ != null) + { output.WriteRawTag(10); output.WriteMessage(RowCount); } - if (offset_ != null) { + if (offset_ != null) + { output.WriteRawTag(18); output.WriteMessage(Offset); } - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (rowCount_ != null) { + if (rowCount_ != null) + { size += 1 + pb::CodedOutputStream.ComputeMessageSize(RowCount); } - if (offset_ != null) { + if (offset_ != null) + { size += 1 + pb::CodedOutputStream.ComputeMessageSize(Offset); } - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -1446,18 +1678,24 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(LimitExpr other) { - if (other == null) { + public void MergeFrom(LimitExpr other) + { + if (other == null) + { return; } - if (other.rowCount_ != null) { - if (rowCount_ == null) { + if (other.rowCount_ != null) + { + if (rowCount_ == null) + { RowCount = new global::Mysqlx.Expr.Expr(); } RowCount.MergeFrom(other.RowCount); } - if (other.offset_ != null) { - if (offset_ == null) { + if (other.offset_ != null) + { + if (offset_ == null) + { Offset = new global::Mysqlx.Expr.Expr(); } Offset.MergeFrom(other.Offset); @@ -1467,13 +1705,18 @@ public void MergeFrom(LimitExpr other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -1493,37 +1736,49 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 10: { - if (rowCount_ == null) { - RowCount = new global::Mysqlx.Expr.Expr(); + case 10: + { + if (rowCount_ == null) + { + RowCount = new global::Mysqlx.Expr.Expr(); + } + input.ReadMessage(RowCount); + break; } - input.ReadMessage(RowCount); - break; - } - case 18: { - if (offset_ == null) { - Offset = new global::Mysqlx.Expr.Expr(); + case 18: + { + if (offset_ == null) + { + Offset = new global::Mysqlx.Expr.Expr(); + } + input.ReadMessage(Offset); + break; } - input.ReadMessage(Offset); - break; - } } } } - #endif +#endif } @@ -1531,10 +1786,11 @@ public void MergeFrom(pb::CodedInputStream input) { ///* ///Sort order /// - internal sealed partial class Order : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class Order : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Order()); private pb::UnknownFieldSet _unknownFields; @@ -1545,19 +1801,22 @@ internal sealed partial class Order : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Crud.MysqlxCrudReflection.Descriptor.MessageTypes[5]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Order() { + public Order() + { OnConstruction(); } @@ -1565,7 +1824,8 @@ public Order() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Order(Order other) : this() { + public Order(Order other) : this() + { _hasBits0 = other._hasBits0; expr_ = other.expr_ != null ? other.expr_.Clone() : null; direction_ = other.direction_; @@ -1574,7 +1834,8 @@ public Order(Order other) : this() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Order Clone() { + public Order Clone() + { return new Order(this); } @@ -1583,9 +1844,11 @@ public Order Clone() { private global::Mysqlx.Expr.Expr expr_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Expr.Expr Expr { + public global::Mysqlx.Expr.Expr Expr + { get { return expr_; } - set { + set + { expr_ = value; } } @@ -1597,9 +1860,11 @@ public Order Clone() { private global::Mysqlx.Crud.Order.Types.Direction direction_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Crud.Order.Types.Direction Direction { + public global::Mysqlx.Crud.Order.Types.Direction Direction + { get { if ((_hasBits0 & 1) != 0) { return direction_; } else { return DirectionDefaultValue; } } - set { + set + { _hasBits0 |= 1; direction_ = value; } @@ -1607,29 +1872,35 @@ public Order Clone() { /// Gets whether the "direction" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasDirection { + public bool HasDirection + { get { return (_hasBits0 & 1) != 0; } } /// Clears the value of the "direction" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearDirection() { + public void ClearDirection() + { _hasBits0 &= ~1; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as Order); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(Order other) { - if (ReferenceEquals(other, null)) { + public bool Equals(Order other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } if (!object.Equals(Expr, other.Expr)) return false; @@ -1639,11 +1910,13 @@ public bool Equals(Order other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; if (expr_ != null) hash ^= Expr.GetHashCode(); if (HasDirection) hash ^= Direction.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -1651,16 +1924,18 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (expr_ != null) { output.WriteRawTag(10); output.WriteMessage(Expr); @@ -1672,38 +1947,46 @@ public void WriteTo(pb::CodedOutputStream output) { if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (expr_ != null) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (expr_ != null) + { output.WriteRawTag(10); output.WriteMessage(Expr); } - if (HasDirection) { + if (HasDirection) + { output.WriteRawTag(16); - output.WriteEnum((int) Direction); + output.WriteEnum((int)Direction); } - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (expr_ != null) { + if (expr_ != null) + { size += 1 + pb::CodedOutputStream.ComputeMessageSize(Expr); } - if (HasDirection) { - size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Direction); + if (HasDirection) + { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int)Direction); } - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -1711,17 +1994,22 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(Order other) { - if (other == null) { + public void MergeFrom(Order other) + { + if (other == null) + { return; } - if (other.expr_ != null) { - if (expr_ == null) { + if (other.expr_ != null) + { + if (expr_ == null) + { Expr = new global::Mysqlx.Expr.Expr(); } Expr.MergeFrom(other.Expr); } - if (other.HasDirection) { + if (other.HasDirection) + { Direction = other.Direction; } _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); @@ -1729,13 +2017,18 @@ public void MergeFrom(Order other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -1752,41 +2045,54 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 10: { - if (expr_ == null) { - Expr = new global::Mysqlx.Expr.Expr(); + case 10: + { + if (expr_ == null) + { + Expr = new global::Mysqlx.Expr.Expr(); + } + input.ReadMessage(Expr); + break; + } + case 16: + { + Direction = (global::Mysqlx.Crud.Order.Types.Direction)input.ReadEnum(); + break; } - input.ReadMessage(Expr); - break; - } - case 16: { - Direction = (global::Mysqlx.Crud.Order.Types.Direction) input.ReadEnum(); - break; - } } } } - #endif +#endif #region Nested types /// Container for nested types declared in the Order message type. [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static partial class Types { - public enum Direction { + public static partial class Types + { + public enum Direction + { [pbr::OriginalName("ASC")] Asc = 1, [pbr::OriginalName("DESC")] Desc = 2, } @@ -1796,10 +2102,11 @@ public enum Direction { } - internal sealed partial class UpdateOperation : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class UpdateOperation : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new UpdateOperation()); private pb::UnknownFieldSet _unknownFields; @@ -1810,19 +2117,22 @@ internal sealed partial class UpdateOperation : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Crud.MysqlxCrudReflection.Descriptor.MessageTypes[6]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public UpdateOperation() { + public UpdateOperation() + { OnConstruction(); } @@ -1830,7 +2140,8 @@ public UpdateOperation() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public UpdateOperation(UpdateOperation other) : this() { + public UpdateOperation(UpdateOperation other) : this() + { _hasBits0 = other._hasBits0; source_ = other.source_ != null ? other.source_.Clone() : null; operation_ = other.operation_; @@ -1840,7 +2151,8 @@ public UpdateOperation(UpdateOperation other) : this() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public UpdateOperation Clone() { + public UpdateOperation Clone() + { return new UpdateOperation(this); } @@ -1857,9 +2169,11 @@ public UpdateOperation Clone() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Expr.ColumnIdentifier Source { + public global::Mysqlx.Expr.ColumnIdentifier Source + { get { return source_; } - set { + set + { source_ = value; } } @@ -1874,9 +2188,11 @@ public UpdateOperation Clone() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Crud.UpdateOperation.Types.UpdateType Operation { + public global::Mysqlx.Crud.UpdateOperation.Types.UpdateType Operation + { get { if ((_hasBits0 & 1) != 0) { return operation_; } else { return OperationDefaultValue; } } - set { + set + { _hasBits0 |= 1; operation_ = value; } @@ -1884,13 +2200,15 @@ public UpdateOperation Clone() { /// Gets whether the "operation" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasOperation { + public bool HasOperation + { get { return (_hasBits0 & 1) != 0; } } /// Clears the value of the "operation" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearOperation() { + public void ClearOperation() + { _hasBits0 &= ~1; } @@ -1902,26 +2220,32 @@ public void ClearOperation() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Expr.Expr Value { + public global::Mysqlx.Expr.Expr Value + { get { return value_; } - set { + set + { value_ = value; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as UpdateOperation); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(UpdateOperation other) { - if (ReferenceEquals(other, null)) { + public bool Equals(UpdateOperation other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } if (!object.Equals(Source, other.Source)) return false; @@ -1932,12 +2256,14 @@ public bool Equals(UpdateOperation other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; if (source_ != null) hash ^= Source.GetHashCode(); if (HasOperation) hash ^= Operation.GetHashCode(); if (value_ != null) hash ^= Value.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -1945,16 +2271,18 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (source_ != null) { output.WriteRawTag(10); output.WriteMessage(Source); @@ -1970,45 +2298,55 @@ public void WriteTo(pb::CodedOutputStream output) { if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (source_ != null) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (source_ != null) + { output.WriteRawTag(10); output.WriteMessage(Source); } - if (HasOperation) { + if (HasOperation) + { output.WriteRawTag(16); - output.WriteEnum((int) Operation); + output.WriteEnum((int)Operation); } - if (value_ != null) { + if (value_ != null) + { output.WriteRawTag(26); output.WriteMessage(Value); } - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (source_ != null) { + if (source_ != null) + { size += 1 + pb::CodedOutputStream.ComputeMessageSize(Source); } - if (HasOperation) { - size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Operation); + if (HasOperation) + { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int)Operation); } - if (value_ != null) { + if (value_ != null) + { size += 1 + pb::CodedOutputStream.ComputeMessageSize(Value); } - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -2016,21 +2354,28 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(UpdateOperation other) { - if (other == null) { + public void MergeFrom(UpdateOperation other) + { + if (other == null) + { return; } - if (other.source_ != null) { - if (source_ == null) { + if (other.source_ != null) + { + if (source_ == null) + { Source = new global::Mysqlx.Expr.ColumnIdentifier(); } Source.MergeFrom(other.Source); } - if (other.HasOperation) { + if (other.HasOperation) + { Operation = other.Operation; } - if (other.value_ != null) { - if (value_ == null) { + if (other.value_ != null) + { + if (value_ == null) + { Value = new global::Mysqlx.Expr.Expr(); } Value.MergeFrom(other.Value); @@ -2040,13 +2385,18 @@ public void MergeFrom(UpdateOperation other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -2070,48 +2420,63 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 10: { - if (source_ == null) { - Source = new global::Mysqlx.Expr.ColumnIdentifier(); + case 10: + { + if (source_ == null) + { + Source = new global::Mysqlx.Expr.ColumnIdentifier(); + } + input.ReadMessage(Source); + break; } - input.ReadMessage(Source); - break; - } - case 16: { - Operation = (global::Mysqlx.Crud.UpdateOperation.Types.UpdateType) input.ReadEnum(); - break; - } - case 26: { - if (value_ == null) { - Value = new global::Mysqlx.Expr.Expr(); + case 16: + { + Operation = (global::Mysqlx.Crud.UpdateOperation.Types.UpdateType)input.ReadEnum(); + break; + } + case 26: + { + if (value_ == null) + { + Value = new global::Mysqlx.Expr.Expr(); + } + input.ReadMessage(Value); + break; } - input.ReadMessage(Value); - break; - } } } } - #endif +#endif #region Nested types /// Container for nested types declared in the UpdateOperation message type. [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static partial class Types { - public enum UpdateType { + public static partial class Types + { + public enum UpdateType + { /// ///* only allowed for TABLE /// @@ -2162,10 +2527,11 @@ public enum UpdateType { /// ///@returns @ref Mysqlx::Resultset /// - internal sealed partial class Find : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class Find : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Find()); private pb::UnknownFieldSet _unknownFields; @@ -2176,19 +2542,22 @@ internal sealed partial class Find : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Crud.MysqlxCrudReflection.Descriptor.MessageTypes[7]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Find() { + public Find() + { OnConstruction(); } @@ -2196,7 +2565,8 @@ public Find() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Find(Find other) : this() { + public Find(Find other) : this() + { _hasBits0 = other._hasBits0; collection_ = other.collection_ != null ? other.collection_.Clone() : null; dataModel_ = other.dataModel_; @@ -2215,7 +2585,8 @@ public Find(Find other) : this() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Find Clone() { + public Find Clone() + { return new Find(this); } @@ -2227,9 +2598,11 @@ public Find Clone() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Crud.Collection Collection { + public global::Mysqlx.Crud.Collection Collection + { get { return collection_; } - set { + set + { collection_ = value; } } @@ -2244,9 +2617,11 @@ public Find Clone() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Crud.DataModel DataModel { + public global::Mysqlx.Crud.DataModel DataModel + { get { if ((_hasBits0 & 1) != 0) { return dataModel_; } else { return DataModelDefaultValue; } } - set { + set + { _hasBits0 |= 1; dataModel_ = value; } @@ -2254,13 +2629,15 @@ public Find Clone() { /// Gets whether the "data_model" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasDataModel { + public bool HasDataModel + { get { return (_hasBits0 & 1) != 0; } } /// Clears the value of the "data_model" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearDataModel() { + public void ClearDataModel() + { _hasBits0 &= ~1; } @@ -2274,7 +2651,8 @@ public void ClearDataModel() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public pbc::RepeatedField Projection { + public pbc::RepeatedField Projection + { get { return projection_; } } @@ -2288,7 +2666,8 @@ public void ClearDataModel() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public pbc::RepeatedField Args { + public pbc::RepeatedField Args + { get { return args_; } } @@ -2300,9 +2679,11 @@ public void ClearDataModel() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Expr.Expr Criteria { + public global::Mysqlx.Expr.Expr Criteria + { get { return criteria_; } - set { + set + { criteria_ = value; } } @@ -2316,9 +2697,11 @@ public void ClearDataModel() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Crud.Limit Limit { + public global::Mysqlx.Crud.Limit Limit + { get { return limit_; } - set { + set + { limit_ = value; } } @@ -2333,7 +2716,8 @@ public void ClearDataModel() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public pbc::RepeatedField Order { + public pbc::RepeatedField Order + { get { return order_; } } @@ -2347,7 +2731,8 @@ public void ClearDataModel() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public pbc::RepeatedField Grouping { + public pbc::RepeatedField Grouping + { get { return grouping_; } } @@ -2359,9 +2744,11 @@ public void ClearDataModel() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Expr.Expr GroupingCriteria { + public global::Mysqlx.Expr.Expr GroupingCriteria + { get { return groupingCriteria_; } - set { + set + { groupingCriteria_ = value; } } @@ -2376,9 +2763,11 @@ public void ClearDataModel() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Crud.Find.Types.RowLock Locking { + public global::Mysqlx.Crud.Find.Types.RowLock Locking + { get { if ((_hasBits0 & 2) != 0) { return locking_; } else { return LockingDefaultValue; } } - set { + set + { _hasBits0 |= 2; locking_ = value; } @@ -2386,13 +2775,15 @@ public void ClearDataModel() { /// Gets whether the "locking" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasLocking { + public bool HasLocking + { get { return (_hasBits0 & 2) != 0; } } /// Clears the value of the "locking" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearLocking() { + public void ClearLocking() + { _hasBits0 &= ~2; } @@ -2406,9 +2797,11 @@ public void ClearLocking() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Crud.Find.Types.RowLockOptions LockingOptions { + public global::Mysqlx.Crud.Find.Types.RowLockOptions LockingOptions + { get { if ((_hasBits0 & 4) != 0) { return lockingOptions_; } else { return LockingOptionsDefaultValue; } } - set { + set + { _hasBits0 |= 4; lockingOptions_ = value; } @@ -2416,13 +2809,15 @@ public void ClearLocking() { /// Gets whether the "locking_options" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasLockingOptions { + public bool HasLockingOptions + { get { return (_hasBits0 & 4) != 0; } } /// Clears the value of the "locking_options" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearLockingOptions() { + public void ClearLockingOptions() + { _hasBits0 &= ~4; } @@ -2435,36 +2830,42 @@ public void ClearLockingOptions() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Crud.LimitExpr LimitExpr { + public global::Mysqlx.Crud.LimitExpr LimitExpr + { get { return limitExpr_; } - set { + set + { limitExpr_ = value; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as Find); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(Find other) { - if (ReferenceEquals(other, null)) { + public bool Equals(Find other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } if (!object.Equals(Collection, other.Collection)) return false; if (DataModel != other.DataModel) return false; - if(!projection_.Equals(other.projection_)) return false; - if(!args_.Equals(other.args_)) return false; + if (!projection_.Equals(other.projection_)) return false; + if (!args_.Equals(other.args_)) return false; if (!object.Equals(Criteria, other.Criteria)) return false; if (!object.Equals(Limit, other.Limit)) return false; - if(!order_.Equals(other.order_)) return false; - if(!grouping_.Equals(other.grouping_)) return false; + if (!order_.Equals(other.order_)) return false; + if (!grouping_.Equals(other.grouping_)) return false; if (!object.Equals(GroupingCriteria, other.GroupingCriteria)) return false; if (Locking != other.Locking) return false; if (LockingOptions != other.LockingOptions) return false; @@ -2474,7 +2875,8 @@ public bool Equals(Find other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; if (collection_ != null) hash ^= Collection.GetHashCode(); if (HasDataModel) hash ^= DataModel.GetHashCode(); @@ -2488,7 +2890,8 @@ public override int GetHashCode() { if (HasLocking) hash ^= Locking.GetHashCode(); if (HasLockingOptions) hash ^= LockingOptions.GetHashCode(); if (limitExpr_ != null) hash ^= LimitExpr.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -2496,16 +2899,18 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (collection_ != null) { output.WriteRawTag(18); output.WriteMessage(Collection); @@ -2545,88 +2950,108 @@ public void WriteTo(pb::CodedOutputStream output) { if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (collection_ != null) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (collection_ != null) + { output.WriteRawTag(18); output.WriteMessage(Collection); } - if (HasDataModel) { + if (HasDataModel) + { output.WriteRawTag(24); - output.WriteEnum((int) DataModel); + output.WriteEnum((int)DataModel); } projection_.WriteTo(ref output, _repeated_projection_codec); - if (criteria_ != null) { + if (criteria_ != null) + { output.WriteRawTag(42); output.WriteMessage(Criteria); } - if (limit_ != null) { + if (limit_ != null) + { output.WriteRawTag(50); output.WriteMessage(Limit); } order_.WriteTo(ref output, _repeated_order_codec); grouping_.WriteTo(ref output, _repeated_grouping_codec); - if (groupingCriteria_ != null) { + if (groupingCriteria_ != null) + { output.WriteRawTag(74); output.WriteMessage(GroupingCriteria); } args_.WriteTo(ref output, _repeated_args_codec); - if (HasLocking) { + if (HasLocking) + { output.WriteRawTag(96); - output.WriteEnum((int) Locking); + output.WriteEnum((int)Locking); } - if (HasLockingOptions) { + if (HasLockingOptions) + { output.WriteRawTag(104); - output.WriteEnum((int) LockingOptions); + output.WriteEnum((int)LockingOptions); } - if (limitExpr_ != null) { + if (limitExpr_ != null) + { output.WriteRawTag(114); output.WriteMessage(LimitExpr); } - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (collection_ != null) { + if (collection_ != null) + { size += 1 + pb::CodedOutputStream.ComputeMessageSize(Collection); } - if (HasDataModel) { - size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) DataModel); + if (HasDataModel) + { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int)DataModel); } size += projection_.CalculateSize(_repeated_projection_codec); size += args_.CalculateSize(_repeated_args_codec); - if (criteria_ != null) { + if (criteria_ != null) + { size += 1 + pb::CodedOutputStream.ComputeMessageSize(Criteria); } - if (limit_ != null) { + if (limit_ != null) + { size += 1 + pb::CodedOutputStream.ComputeMessageSize(Limit); } size += order_.CalculateSize(_repeated_order_codec); size += grouping_.CalculateSize(_repeated_grouping_codec); - if (groupingCriteria_ != null) { + if (groupingCriteria_ != null) + { size += 1 + pb::CodedOutputStream.ComputeMessageSize(GroupingCriteria); } - if (HasLocking) { - size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Locking); + if (HasLocking) + { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int)Locking); } - if (HasLockingOptions) { - size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) LockingOptions); + if (HasLockingOptions) + { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int)LockingOptions); } - if (limitExpr_ != null) { + if (limitExpr_ != null) + { size += 1 + pb::CodedOutputStream.ComputeMessageSize(LimitExpr); } - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -2634,49 +3059,64 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(Find other) { - if (other == null) { + public void MergeFrom(Find other) + { + if (other == null) + { return; } - if (other.collection_ != null) { - if (collection_ == null) { + if (other.collection_ != null) + { + if (collection_ == null) + { Collection = new global::Mysqlx.Crud.Collection(); } Collection.MergeFrom(other.Collection); } - if (other.HasDataModel) { + if (other.HasDataModel) + { DataModel = other.DataModel; } projection_.Add(other.projection_); args_.Add(other.args_); - if (other.criteria_ != null) { - if (criteria_ == null) { + if (other.criteria_ != null) + { + if (criteria_ == null) + { Criteria = new global::Mysqlx.Expr.Expr(); } Criteria.MergeFrom(other.Criteria); } - if (other.limit_ != null) { - if (limit_ == null) { + if (other.limit_ != null) + { + if (limit_ == null) + { Limit = new global::Mysqlx.Crud.Limit(); } Limit.MergeFrom(other.Limit); } order_.Add(other.order_); grouping_.Add(other.grouping_); - if (other.groupingCriteria_ != null) { - if (groupingCriteria_ == null) { + if (other.groupingCriteria_ != null) + { + if (groupingCriteria_ == null) + { GroupingCriteria = new global::Mysqlx.Expr.Expr(); } GroupingCriteria.MergeFrom(other.GroupingCriteria); } - if (other.HasLocking) { + if (other.HasLocking) + { Locking = other.Locking; } - if (other.HasLockingOptions) { + if (other.HasLockingOptions) + { LockingOptions = other.LockingOptions; } - if (other.limitExpr_ != null) { - if (limitExpr_ == null) { + if (other.limitExpr_ != null) + { + if (limitExpr_ == null) + { LimitExpr = new global::Mysqlx.Crud.LimitExpr(); } LimitExpr.MergeFrom(other.LimitExpr); @@ -2686,13 +3126,18 @@ public void MergeFrom(Find other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -2761,93 +3206,120 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 18: { - if (collection_ == null) { - Collection = new global::Mysqlx.Crud.Collection(); + case 18: + { + if (collection_ == null) + { + Collection = new global::Mysqlx.Crud.Collection(); + } + input.ReadMessage(Collection); + break; } - input.ReadMessage(Collection); - break; - } - case 24: { - DataModel = (global::Mysqlx.Crud.DataModel) input.ReadEnum(); - break; - } - case 34: { - projection_.AddEntriesFrom(ref input, _repeated_projection_codec); - break; - } - case 42: { - if (criteria_ == null) { - Criteria = new global::Mysqlx.Expr.Expr(); + case 24: + { + DataModel = (global::Mysqlx.Crud.DataModel)input.ReadEnum(); + break; } - input.ReadMessage(Criteria); - break; - } - case 50: { - if (limit_ == null) { - Limit = new global::Mysqlx.Crud.Limit(); + case 34: + { + projection_.AddEntriesFrom(ref input, _repeated_projection_codec); + break; } - input.ReadMessage(Limit); - break; - } - case 58: { - order_.AddEntriesFrom(ref input, _repeated_order_codec); - break; - } - case 66: { - grouping_.AddEntriesFrom(ref input, _repeated_grouping_codec); - break; - } - case 74: { - if (groupingCriteria_ == null) { - GroupingCriteria = new global::Mysqlx.Expr.Expr(); + case 42: + { + if (criteria_ == null) + { + Criteria = new global::Mysqlx.Expr.Expr(); + } + input.ReadMessage(Criteria); + break; } - input.ReadMessage(GroupingCriteria); - break; - } - case 90: { - args_.AddEntriesFrom(ref input, _repeated_args_codec); - break; - } - case 96: { - Locking = (global::Mysqlx.Crud.Find.Types.RowLock) input.ReadEnum(); - break; - } - case 104: { - LockingOptions = (global::Mysqlx.Crud.Find.Types.RowLockOptions) input.ReadEnum(); - break; - } - case 114: { - if (limitExpr_ == null) { - LimitExpr = new global::Mysqlx.Crud.LimitExpr(); + case 50: + { + if (limit_ == null) + { + Limit = new global::Mysqlx.Crud.Limit(); + } + input.ReadMessage(Limit); + break; + } + case 58: + { + order_.AddEntriesFrom(ref input, _repeated_order_codec); + break; + } + case 66: + { + grouping_.AddEntriesFrom(ref input, _repeated_grouping_codec); + break; + } + case 74: + { + if (groupingCriteria_ == null) + { + GroupingCriteria = new global::Mysqlx.Expr.Expr(); + } + input.ReadMessage(GroupingCriteria); + break; + } + case 90: + { + args_.AddEntriesFrom(ref input, _repeated_args_codec); + break; + } + case 96: + { + Locking = (global::Mysqlx.Crud.Find.Types.RowLock)input.ReadEnum(); + break; + } + case 104: + { + LockingOptions = (global::Mysqlx.Crud.Find.Types.RowLockOptions)input.ReadEnum(); + break; + } + case 114: + { + if (limitExpr_ == null) + { + LimitExpr = new global::Mysqlx.Crud.LimitExpr(); + } + input.ReadMessage(LimitExpr); + break; } - input.ReadMessage(LimitExpr); - break; - } } } } - #endif +#endif #region Nested types /// Container for nested types declared in the Find message type. [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static partial class Types { - public enum RowLock { + public static partial class Types + { + public enum RowLock + { /// ///* Lock matching rows against updates /// @@ -2858,7 +3330,8 @@ public enum RowLock { [pbr::OriginalName("EXCLUSIVE_LOCK")] ExclusiveLock = 2, } - public enum RowLockOptions { + public enum RowLockOptions + { /// ///* Do not wait to acquire row lock, fail with an error ///if a requested row is locked @@ -2882,10 +3355,11 @@ public enum RowLockOptions { /// ///@returns @ref Mysqlx::Resultset /// - internal sealed partial class Insert : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class Insert : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Insert()); private pb::UnknownFieldSet _unknownFields; @@ -2896,19 +3370,22 @@ internal sealed partial class Insert : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Crud.MysqlxCrudReflection.Descriptor.MessageTypes[8]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Insert() { + public Insert() + { OnConstruction(); } @@ -2916,7 +3393,8 @@ public Insert() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Insert(Insert other) : this() { + public Insert(Insert other) : this() + { _hasBits0 = other._hasBits0; collection_ = other.collection_ != null ? other.collection_.Clone() : null; dataModel_ = other.dataModel_; @@ -2929,7 +3407,8 @@ public Insert(Insert other) : this() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Insert Clone() { + public Insert Clone() + { return new Insert(this); } @@ -2941,9 +3420,11 @@ public Insert Clone() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Crud.Collection Collection { + public global::Mysqlx.Crud.Collection Collection + { get { return collection_; } - set { + set + { collection_ = value; } } @@ -2958,9 +3439,11 @@ public Insert Clone() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Crud.DataModel DataModel { + public global::Mysqlx.Crud.DataModel DataModel + { get { if ((_hasBits0 & 1) != 0) { return dataModel_; } else { return DataModelDefaultValue; } } - set { + set + { _hasBits0 |= 1; dataModel_ = value; } @@ -2968,13 +3451,15 @@ public Insert Clone() { /// Gets whether the "data_model" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasDataModel { + public bool HasDataModel + { get { return (_hasBits0 & 1) != 0; } } /// Clears the value of the "data_model" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearDataModel() { + public void ClearDataModel() + { _hasBits0 &= ~1; } @@ -2989,7 +3474,8 @@ public void ClearDataModel() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public pbc::RepeatedField Projection { + public pbc::RepeatedField Projection + { get { return projection_; } } @@ -3004,7 +3490,8 @@ public void ClearDataModel() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public pbc::RepeatedField Row { + public pbc::RepeatedField Row + { get { return row_; } } @@ -3018,7 +3505,8 @@ public void ClearDataModel() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public pbc::RepeatedField Args { + public pbc::RepeatedField Args + { get { return args_; } } @@ -3033,9 +3521,11 @@ public void ClearDataModel() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Upsert { + public bool Upsert + { get { if ((_hasBits0 & 2) != 0) { return upsert_; } else { return UpsertDefaultValue; } } - set { + set + { _hasBits0 |= 2; upsert_ = value; } @@ -3043,43 +3533,50 @@ public bool Upsert { /// Gets whether the "upsert" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasUpsert { + public bool HasUpsert + { get { return (_hasBits0 & 2) != 0; } } /// Clears the value of the "upsert" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearUpsert() { + public void ClearUpsert() + { _hasBits0 &= ~2; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as Insert); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(Insert other) { - if (ReferenceEquals(other, null)) { + public bool Equals(Insert other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } if (!object.Equals(Collection, other.Collection)) return false; if (DataModel != other.DataModel) return false; - if(!projection_.Equals(other.projection_)) return false; - if(!row_.Equals(other.row_)) return false; - if(!args_.Equals(other.args_)) return false; + if (!projection_.Equals(other.projection_)) return false; + if (!row_.Equals(other.row_)) return false; + if (!args_.Equals(other.args_)) return false; if (Upsert != other.Upsert) return false; return Equals(_unknownFields, other._unknownFields); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; if (collection_ != null) hash ^= Collection.GetHashCode(); if (HasDataModel) hash ^= DataModel.GetHashCode(); @@ -3087,7 +3584,8 @@ public override int GetHashCode() { hash ^= row_.GetHashCode(); hash ^= args_.GetHashCode(); if (HasUpsert) hash ^= Upsert.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -3095,16 +3593,18 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (collection_ != null) { output.WriteRawTag(10); output.WriteMessage(Collection); @@ -3123,51 +3623,61 @@ public void WriteTo(pb::CodedOutputStream output) { if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (collection_ != null) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (collection_ != null) + { output.WriteRawTag(10); output.WriteMessage(Collection); } - if (HasDataModel) { + if (HasDataModel) + { output.WriteRawTag(16); - output.WriteEnum((int) DataModel); + output.WriteEnum((int)DataModel); } projection_.WriteTo(ref output, _repeated_projection_codec); row_.WriteTo(ref output, _repeated_row_codec); args_.WriteTo(ref output, _repeated_args_codec); - if (HasUpsert) { + if (HasUpsert) + { output.WriteRawTag(48); output.WriteBool(Upsert); } - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (collection_ != null) { + if (collection_ != null) + { size += 1 + pb::CodedOutputStream.ComputeMessageSize(Collection); } - if (HasDataModel) { - size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) DataModel); + if (HasDataModel) + { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int)DataModel); } size += projection_.CalculateSize(_repeated_projection_codec); size += row_.CalculateSize(_repeated_row_codec); size += args_.CalculateSize(_repeated_args_codec); - if (HasUpsert) { + if (HasUpsert) + { size += 1 + 1; } - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -3175,23 +3685,29 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(Insert other) { - if (other == null) { + public void MergeFrom(Insert other) + { + if (other == null) + { return; } - if (other.collection_ != null) { - if (collection_ == null) { + if (other.collection_ != null) + { + if (collection_ == null) + { Collection = new global::Mysqlx.Crud.Collection(); } Collection.MergeFrom(other.Collection); } - if (other.HasDataModel) { + if (other.HasDataModel) + { DataModel = other.DataModel; } projection_.Add(other.projection_); row_.Add(other.row_); args_.Add(other.args_); - if (other.HasUpsert) { + if (other.HasUpsert) + { Upsert = other.Upsert; } _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); @@ -3199,13 +3715,18 @@ public void MergeFrom(Insert other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -3238,63 +3759,80 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 10: { - if (collection_ == null) { - Collection = new global::Mysqlx.Crud.Collection(); + case 10: + { + if (collection_ == null) + { + Collection = new global::Mysqlx.Crud.Collection(); + } + input.ReadMessage(Collection); + break; + } + case 16: + { + DataModel = (global::Mysqlx.Crud.DataModel)input.ReadEnum(); + break; + } + case 26: + { + projection_.AddEntriesFrom(ref input, _repeated_projection_codec); + break; + } + case 34: + { + row_.AddEntriesFrom(ref input, _repeated_row_codec); + break; + } + case 42: + { + args_.AddEntriesFrom(ref input, _repeated_args_codec); + break; + } + case 48: + { + Upsert = input.ReadBool(); + break; } - input.ReadMessage(Collection); - break; - } - case 16: { - DataModel = (global::Mysqlx.Crud.DataModel) input.ReadEnum(); - break; - } - case 26: { - projection_.AddEntriesFrom(ref input, _repeated_projection_codec); - break; - } - case 34: { - row_.AddEntriesFrom(ref input, _repeated_row_codec); - break; - } - case 42: { - args_.AddEntriesFrom(ref input, _repeated_args_codec); - break; - } - case 48: { - Upsert = input.ReadBool(); - break; - } } } } - #endif +#endif #region Nested types /// Container for nested types declared in the Insert message type. [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static partial class Types { + public static partial class Types + { /// ///* set of fields to insert as a one row /// + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] public sealed partial class TypedRow : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new TypedRow()); private pb::UnknownFieldSet _unknownFields; @@ -3304,19 +3842,22 @@ public sealed partial class TypedRow : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Crud.Insert.Descriptor.NestedTypes[0]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public TypedRow() { + public TypedRow() + { OnConstruction(); } @@ -3324,14 +3865,16 @@ public TypedRow() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public TypedRow(TypedRow other) : this() { + public TypedRow(TypedRow other) : this() + { field_ = other.field_.Clone(); _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public TypedRow Clone() { + public TypedRow Clone() + { return new TypedRow(this); } @@ -3342,35 +3885,42 @@ public TypedRow Clone() { private readonly pbc::RepeatedField field_ = new pbc::RepeatedField(); [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public pbc::RepeatedField Field { + public pbc::RepeatedField Field + { get { return field_; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as TypedRow); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(TypedRow other) { - if (ReferenceEquals(other, null)) { + public bool Equals(TypedRow other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } - if(!field_.Equals(other.field_)) return false; + if (!field_.Equals(other.field_)) return false; return Equals(_unknownFields, other._unknownFields); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; hash ^= field_.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -3378,40 +3928,46 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else field_.WriteTo(output, _repeated_field_codec); if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { field_.WriteTo(ref output, _repeated_field_codec); - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; size += field_.CalculateSize(_repeated_field_codec); - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -3419,8 +3975,10 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(TypedRow other) { - if (other == null) { + public void MergeFrom(TypedRow other) + { + if (other == null) + { return; } field_.Add(other.field_); @@ -3429,13 +3987,18 @@ public void MergeFrom(TypedRow other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -3445,27 +4008,36 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 10: { - field_.AddEntriesFrom(ref input, _repeated_field_codec); - break; - } + case 10: + { + field_.AddEntriesFrom(ref input, _repeated_field_codec); + break; + } } } } - #endif +#endif } @@ -3480,10 +4052,11 @@ public void MergeFrom(pb::CodedInputStream input) { /// ///@returns @ref Mysqlx::Resultset /// - internal sealed partial class Update : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class Update : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Update()); private pb::UnknownFieldSet _unknownFields; @@ -3494,19 +4067,22 @@ internal sealed partial class Update : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Crud.MysqlxCrudReflection.Descriptor.MessageTypes[9]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Update() { + public Update() + { OnConstruction(); } @@ -3514,7 +4090,8 @@ public Update() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Update(Update other) : this() { + public Update(Update other) : this() + { _hasBits0 = other._hasBits0; collection_ = other.collection_ != null ? other.collection_.Clone() : null; dataModel_ = other.dataModel_; @@ -3529,7 +4106,8 @@ public Update(Update other) : this() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Update Clone() { + public Update Clone() + { return new Update(this); } @@ -3541,9 +4119,11 @@ public Update Clone() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Crud.Collection Collection { + public global::Mysqlx.Crud.Collection Collection + { get { return collection_; } - set { + set + { collection_ = value; } } @@ -3558,9 +4138,11 @@ public Update Clone() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Crud.DataModel DataModel { + public global::Mysqlx.Crud.DataModel DataModel + { get { if ((_hasBits0 & 1) != 0) { return dataModel_; } else { return DataModelDefaultValue; } } - set { + set + { _hasBits0 |= 1; dataModel_ = value; } @@ -3568,13 +4150,15 @@ public Update Clone() { /// Gets whether the "data_model" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasDataModel { + public bool HasDataModel + { get { return (_hasBits0 & 1) != 0; } } /// Clears the value of the "data_model" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearDataModel() { + public void ClearDataModel() + { _hasBits0 &= ~1; } @@ -3586,9 +4170,11 @@ public void ClearDataModel() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Expr.Expr Criteria { + public global::Mysqlx.Expr.Expr Criteria + { get { return criteria_; } - set { + set + { criteria_ = value; } } @@ -3602,9 +4188,11 @@ public void ClearDataModel() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Crud.Limit Limit { + public global::Mysqlx.Crud.Limit Limit + { get { return limit_; } - set { + set + { limit_ = value; } } @@ -3619,7 +4207,8 @@ public void ClearDataModel() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public pbc::RepeatedField Order { + public pbc::RepeatedField Order + { get { return order_; } } @@ -3634,7 +4223,8 @@ public void ClearDataModel() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public pbc::RepeatedField Operation { + public pbc::RepeatedField Operation + { get { return operation_; } } @@ -3648,7 +4238,8 @@ public void ClearDataModel() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public pbc::RepeatedField Args { + public pbc::RepeatedField Args + { get { return args_; } } @@ -3661,42 +4252,49 @@ public void ClearDataModel() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Crud.LimitExpr LimitExpr { + public global::Mysqlx.Crud.LimitExpr LimitExpr + { get { return limitExpr_; } - set { + set + { limitExpr_ = value; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as Update); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(Update other) { - if (ReferenceEquals(other, null)) { + public bool Equals(Update other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } if (!object.Equals(Collection, other.Collection)) return false; if (DataModel != other.DataModel) return false; if (!object.Equals(Criteria, other.Criteria)) return false; if (!object.Equals(Limit, other.Limit)) return false; - if(!order_.Equals(other.order_)) return false; - if(!operation_.Equals(other.operation_)) return false; - if(!args_.Equals(other.args_)) return false; + if (!order_.Equals(other.order_)) return false; + if (!operation_.Equals(other.operation_)) return false; + if (!args_.Equals(other.args_)) return false; if (!object.Equals(LimitExpr, other.LimitExpr)) return false; return Equals(_unknownFields, other._unknownFields); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; if (collection_ != null) hash ^= Collection.GetHashCode(); if (HasDataModel) hash ^= DataModel.GetHashCode(); @@ -3706,7 +4304,8 @@ public override int GetHashCode() { hash ^= operation_.GetHashCode(); hash ^= args_.GetHashCode(); if (limitExpr_ != null) hash ^= LimitExpr.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -3714,16 +4313,18 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (collection_ != null) { output.WriteRawTag(18); output.WriteMessage(Collection); @@ -3750,65 +4351,79 @@ public void WriteTo(pb::CodedOutputStream output) { if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (collection_ != null) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (collection_ != null) + { output.WriteRawTag(18); output.WriteMessage(Collection); } - if (HasDataModel) { + if (HasDataModel) + { output.WriteRawTag(24); - output.WriteEnum((int) DataModel); + output.WriteEnum((int)DataModel); } - if (criteria_ != null) { + if (criteria_ != null) + { output.WriteRawTag(34); output.WriteMessage(Criteria); } - if (limit_ != null) { + if (limit_ != null) + { output.WriteRawTag(42); output.WriteMessage(Limit); } order_.WriteTo(ref output, _repeated_order_codec); operation_.WriteTo(ref output, _repeated_operation_codec); args_.WriteTo(ref output, _repeated_args_codec); - if (limitExpr_ != null) { + if (limitExpr_ != null) + { output.WriteRawTag(74); output.WriteMessage(LimitExpr); } - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (collection_ != null) { + if (collection_ != null) + { size += 1 + pb::CodedOutputStream.ComputeMessageSize(Collection); } - if (HasDataModel) { - size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) DataModel); + if (HasDataModel) + { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int)DataModel); } - if (criteria_ != null) { + if (criteria_ != null) + { size += 1 + pb::CodedOutputStream.ComputeMessageSize(Criteria); } - if (limit_ != null) { + if (limit_ != null) + { size += 1 + pb::CodedOutputStream.ComputeMessageSize(Limit); } size += order_.CalculateSize(_repeated_order_codec); size += operation_.CalculateSize(_repeated_operation_codec); size += args_.CalculateSize(_repeated_args_codec); - if (limitExpr_ != null) { + if (limitExpr_ != null) + { size += 1 + pb::CodedOutputStream.ComputeMessageSize(LimitExpr); } - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -3816,27 +4431,36 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(Update other) { - if (other == null) { + public void MergeFrom(Update other) + { + if (other == null) + { return; } - if (other.collection_ != null) { - if (collection_ == null) { + if (other.collection_ != null) + { + if (collection_ == null) + { Collection = new global::Mysqlx.Crud.Collection(); } Collection.MergeFrom(other.Collection); } - if (other.HasDataModel) { + if (other.HasDataModel) + { DataModel = other.DataModel; } - if (other.criteria_ != null) { - if (criteria_ == null) { + if (other.criteria_ != null) + { + if (criteria_ == null) + { Criteria = new global::Mysqlx.Expr.Expr(); } Criteria.MergeFrom(other.Criteria); } - if (other.limit_ != null) { - if (limit_ == null) { + if (other.limit_ != null) + { + if (limit_ == null) + { Limit = new global::Mysqlx.Crud.Limit(); } Limit.MergeFrom(other.Limit); @@ -3844,8 +4468,10 @@ public void MergeFrom(Update other) { order_.Add(other.order_); operation_.Add(other.operation_); args_.Add(other.args_); - if (other.limitExpr_ != null) { - if (limitExpr_ == null) { + if (other.limitExpr_ != null) + { + if (limitExpr_ == null) + { LimitExpr = new global::Mysqlx.Crud.LimitExpr(); } LimitExpr.MergeFrom(other.LimitExpr); @@ -3855,13 +4481,18 @@ public void MergeFrom(Update other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -3911,67 +4542,87 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 18: { - if (collection_ == null) { - Collection = new global::Mysqlx.Crud.Collection(); + case 18: + { + if (collection_ == null) + { + Collection = new global::Mysqlx.Crud.Collection(); + } + input.ReadMessage(Collection); + break; } - input.ReadMessage(Collection); - break; - } - case 24: { - DataModel = (global::Mysqlx.Crud.DataModel) input.ReadEnum(); - break; - } - case 34: { - if (criteria_ == null) { - Criteria = new global::Mysqlx.Expr.Expr(); + case 24: + { + DataModel = (global::Mysqlx.Crud.DataModel)input.ReadEnum(); + break; } - input.ReadMessage(Criteria); - break; - } - case 42: { - if (limit_ == null) { - Limit = new global::Mysqlx.Crud.Limit(); + case 34: + { + if (criteria_ == null) + { + Criteria = new global::Mysqlx.Expr.Expr(); + } + input.ReadMessage(Criteria); + break; } - input.ReadMessage(Limit); - break; - } - case 50: { - order_.AddEntriesFrom(ref input, _repeated_order_codec); - break; - } - case 58: { - operation_.AddEntriesFrom(ref input, _repeated_operation_codec); - break; - } - case 66: { - args_.AddEntriesFrom(ref input, _repeated_args_codec); - break; - } - case 74: { - if (limitExpr_ == null) { - LimitExpr = new global::Mysqlx.Crud.LimitExpr(); + case 42: + { + if (limit_ == null) + { + Limit = new global::Mysqlx.Crud.Limit(); + } + input.ReadMessage(Limit); + break; + } + case 50: + { + order_.AddEntriesFrom(ref input, _repeated_order_codec); + break; + } + case 58: + { + operation_.AddEntriesFrom(ref input, _repeated_operation_codec); + break; + } + case 66: + { + args_.AddEntriesFrom(ref input, _repeated_args_codec); + break; + } + case 74: + { + if (limitExpr_ == null) + { + LimitExpr = new global::Mysqlx.Crud.LimitExpr(); + } + input.ReadMessage(LimitExpr); + break; } - input.ReadMessage(LimitExpr); - break; - } } } } - #endif +#endif } @@ -3981,10 +4632,11 @@ public void MergeFrom(pb::CodedInputStream input) { /// ///@returns @ref Mysqlx::Resultset /// - internal sealed partial class Delete : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class Delete : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Delete()); private pb::UnknownFieldSet _unknownFields; @@ -3995,19 +4647,22 @@ internal sealed partial class Delete : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Crud.MysqlxCrudReflection.Descriptor.MessageTypes[10]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Delete() { + public Delete() + { OnConstruction(); } @@ -4015,7 +4670,8 @@ public Delete() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Delete(Delete other) : this() { + public Delete(Delete other) : this() + { _hasBits0 = other._hasBits0; collection_ = other.collection_ != null ? other.collection_.Clone() : null; dataModel_ = other.dataModel_; @@ -4029,7 +4685,8 @@ public Delete(Delete other) : this() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Delete Clone() { + public Delete Clone() + { return new Delete(this); } @@ -4041,9 +4698,11 @@ public Delete Clone() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Crud.Collection Collection { + public global::Mysqlx.Crud.Collection Collection + { get { return collection_; } - set { + set + { collection_ = value; } } @@ -4058,9 +4717,11 @@ public Delete Clone() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Crud.DataModel DataModel { + public global::Mysqlx.Crud.DataModel DataModel + { get { if ((_hasBits0 & 1) != 0) { return dataModel_; } else { return DataModelDefaultValue; } } - set { + set + { _hasBits0 |= 1; dataModel_ = value; } @@ -4068,13 +4729,15 @@ public Delete Clone() { /// Gets whether the "data_model" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasDataModel { + public bool HasDataModel + { get { return (_hasBits0 & 1) != 0; } } /// Clears the value of the "data_model" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearDataModel() { + public void ClearDataModel() + { _hasBits0 &= ~1; } @@ -4086,9 +4749,11 @@ public void ClearDataModel() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Expr.Expr Criteria { + public global::Mysqlx.Expr.Expr Criteria + { get { return criteria_; } - set { + set + { criteria_ = value; } } @@ -4102,9 +4767,11 @@ public void ClearDataModel() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Crud.Limit Limit { + public global::Mysqlx.Crud.Limit Limit + { get { return limit_; } - set { + set + { limit_ = value; } } @@ -4119,7 +4786,8 @@ public void ClearDataModel() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public pbc::RepeatedField Order { + public pbc::RepeatedField Order + { get { return order_; } } @@ -4133,7 +4801,8 @@ public void ClearDataModel() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public pbc::RepeatedField Args { + public pbc::RepeatedField Args + { get { return args_; } } @@ -4146,41 +4815,48 @@ public void ClearDataModel() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Crud.LimitExpr LimitExpr { + public global::Mysqlx.Crud.LimitExpr LimitExpr + { get { return limitExpr_; } - set { + set + { limitExpr_ = value; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as Delete); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(Delete other) { - if (ReferenceEquals(other, null)) { + public bool Equals(Delete other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } if (!object.Equals(Collection, other.Collection)) return false; if (DataModel != other.DataModel) return false; if (!object.Equals(Criteria, other.Criteria)) return false; if (!object.Equals(Limit, other.Limit)) return false; - if(!order_.Equals(other.order_)) return false; - if(!args_.Equals(other.args_)) return false; + if (!order_.Equals(other.order_)) return false; + if (!args_.Equals(other.args_)) return false; if (!object.Equals(LimitExpr, other.LimitExpr)) return false; return Equals(_unknownFields, other._unknownFields); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; if (collection_ != null) hash ^= Collection.GetHashCode(); if (HasDataModel) hash ^= DataModel.GetHashCode(); @@ -4189,7 +4865,8 @@ public override int GetHashCode() { hash ^= order_.GetHashCode(); hash ^= args_.GetHashCode(); if (limitExpr_ != null) hash ^= LimitExpr.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -4197,16 +4874,18 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (collection_ != null) { output.WriteRawTag(10); output.WriteMessage(Collection); @@ -4232,63 +4911,77 @@ public void WriteTo(pb::CodedOutputStream output) { if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (collection_ != null) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (collection_ != null) + { output.WriteRawTag(10); output.WriteMessage(Collection); } - if (HasDataModel) { + if (HasDataModel) + { output.WriteRawTag(16); - output.WriteEnum((int) DataModel); + output.WriteEnum((int)DataModel); } - if (criteria_ != null) { + if (criteria_ != null) + { output.WriteRawTag(26); output.WriteMessage(Criteria); } - if (limit_ != null) { + if (limit_ != null) + { output.WriteRawTag(34); output.WriteMessage(Limit); } order_.WriteTo(ref output, _repeated_order_codec); args_.WriteTo(ref output, _repeated_args_codec); - if (limitExpr_ != null) { + if (limitExpr_ != null) + { output.WriteRawTag(58); output.WriteMessage(LimitExpr); } - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (collection_ != null) { + if (collection_ != null) + { size += 1 + pb::CodedOutputStream.ComputeMessageSize(Collection); } - if (HasDataModel) { - size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) DataModel); + if (HasDataModel) + { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int)DataModel); } - if (criteria_ != null) { + if (criteria_ != null) + { size += 1 + pb::CodedOutputStream.ComputeMessageSize(Criteria); } - if (limit_ != null) { + if (limit_ != null) + { size += 1 + pb::CodedOutputStream.ComputeMessageSize(Limit); } size += order_.CalculateSize(_repeated_order_codec); size += args_.CalculateSize(_repeated_args_codec); - if (limitExpr_ != null) { + if (limitExpr_ != null) + { size += 1 + pb::CodedOutputStream.ComputeMessageSize(LimitExpr); } - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -4296,35 +4989,46 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(Delete other) { - if (other == null) { + public void MergeFrom(Delete other) + { + if (other == null) + { return; } - if (other.collection_ != null) { - if (collection_ == null) { + if (other.collection_ != null) + { + if (collection_ == null) + { Collection = new global::Mysqlx.Crud.Collection(); } Collection.MergeFrom(other.Collection); } - if (other.HasDataModel) { + if (other.HasDataModel) + { DataModel = other.DataModel; } - if (other.criteria_ != null) { - if (criteria_ == null) { + if (other.criteria_ != null) + { + if (criteria_ == null) + { Criteria = new global::Mysqlx.Expr.Expr(); } Criteria.MergeFrom(other.Criteria); } - if (other.limit_ != null) { - if (limit_ == null) { + if (other.limit_ != null) + { + if (limit_ == null) + { Limit = new global::Mysqlx.Crud.Limit(); } Limit.MergeFrom(other.Limit); } order_.Add(other.order_); args_.Add(other.args_); - if (other.limitExpr_ != null) { - if (limitExpr_ == null) { + if (other.limitExpr_ != null) + { + if (limitExpr_ == null) + { LimitExpr = new global::Mysqlx.Crud.LimitExpr(); } LimitExpr.MergeFrom(other.LimitExpr); @@ -4334,13 +5038,18 @@ public void MergeFrom(Delete other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -4386,63 +5095,82 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 10: { - if (collection_ == null) { - Collection = new global::Mysqlx.Crud.Collection(); + case 10: + { + if (collection_ == null) + { + Collection = new global::Mysqlx.Crud.Collection(); + } + input.ReadMessage(Collection); + break; } - input.ReadMessage(Collection); - break; - } - case 16: { - DataModel = (global::Mysqlx.Crud.DataModel) input.ReadEnum(); - break; - } - case 26: { - if (criteria_ == null) { - Criteria = new global::Mysqlx.Expr.Expr(); + case 16: + { + DataModel = (global::Mysqlx.Crud.DataModel)input.ReadEnum(); + break; } - input.ReadMessage(Criteria); - break; - } - case 34: { - if (limit_ == null) { - Limit = new global::Mysqlx.Crud.Limit(); + case 26: + { + if (criteria_ == null) + { + Criteria = new global::Mysqlx.Expr.Expr(); + } + input.ReadMessage(Criteria); + break; } - input.ReadMessage(Limit); - break; - } - case 42: { - order_.AddEntriesFrom(ref input, _repeated_order_codec); - break; - } - case 50: { - args_.AddEntriesFrom(ref input, _repeated_args_codec); - break; - } - case 58: { - if (limitExpr_ == null) { - LimitExpr = new global::Mysqlx.Crud.LimitExpr(); + case 34: + { + if (limit_ == null) + { + Limit = new global::Mysqlx.Crud.Limit(); + } + input.ReadMessage(Limit); + break; + } + case 42: + { + order_.AddEntriesFrom(ref input, _repeated_order_codec); + break; + } + case 50: + { + args_.AddEntriesFrom(ref input, _repeated_args_codec); + break; + } + case 58: + { + if (limitExpr_ == null) + { + LimitExpr = new global::Mysqlx.Crud.LimitExpr(); + } + input.ReadMessage(LimitExpr); + break; } - input.ReadMessage(LimitExpr); - break; - } } } } - #endif +#endif } @@ -4450,10 +5178,11 @@ public void MergeFrom(pb::CodedInputStream input) { ///* ///CreateView create view based on indicated @ref Mysqlx::Crud::Find message /// - internal sealed partial class CreateView : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class CreateView : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new CreateView()); private pb::UnknownFieldSet _unknownFields; @@ -4464,19 +5193,22 @@ internal sealed partial class CreateView : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Crud.MysqlxCrudReflection.Descriptor.MessageTypes[11]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public CreateView() { + public CreateView() + { OnConstruction(); } @@ -4484,7 +5216,8 @@ public CreateView() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public CreateView(CreateView other) : this() { + public CreateView(CreateView other) : this() + { _hasBits0 = other._hasBits0; collection_ = other.collection_ != null ? other.collection_.Clone() : null; definer_ = other.definer_; @@ -4499,7 +5232,8 @@ public CreateView(CreateView other) : this() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public CreateView Clone() { + public CreateView Clone() + { return new CreateView(this); } @@ -4511,9 +5245,11 @@ public CreateView Clone() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Crud.Collection Collection { + public global::Mysqlx.Crud.Collection Collection + { get { return collection_; } - set { + set + { collection_ = value; } } @@ -4529,22 +5265,26 @@ public CreateView Clone() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public string Definer { + public string Definer + { get { return definer_ ?? DefinerDefaultValue; } - set { + set + { definer_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); } } /// Gets whether the "definer" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasDefiner { + public bool HasDefiner + { get { return definer_ != null; } } /// Clears the value of the "definer" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearDefiner() { + public void ClearDefiner() + { definer_ = null; } @@ -4558,9 +5298,11 @@ public void ClearDefiner() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Crud.ViewAlgorithm Algorithm { + public global::Mysqlx.Crud.ViewAlgorithm Algorithm + { get { if ((_hasBits0 & 1) != 0) { return algorithm_; } else { return AlgorithmDefaultValue; } } - set { + set + { _hasBits0 |= 1; algorithm_ = value; } @@ -4568,13 +5310,15 @@ public void ClearDefiner() { /// Gets whether the "algorithm" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasAlgorithm { + public bool HasAlgorithm + { get { return (_hasBits0 & 1) != 0; } } /// Clears the value of the "algorithm" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearAlgorithm() { + public void ClearAlgorithm() + { _hasBits0 &= ~1; } @@ -4588,9 +5332,11 @@ public void ClearAlgorithm() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Crud.ViewSqlSecurity Security { + public global::Mysqlx.Crud.ViewSqlSecurity Security + { get { if ((_hasBits0 & 2) != 0) { return security_; } else { return SecurityDefaultValue; } } - set { + set + { _hasBits0 |= 2; security_ = value; } @@ -4598,13 +5344,15 @@ public void ClearAlgorithm() { /// Gets whether the "security" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasSecurity { + public bool HasSecurity + { get { return (_hasBits0 & 2) != 0; } } /// Clears the value of the "security" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearSecurity() { + public void ClearSecurity() + { _hasBits0 &= ~2; } @@ -4618,9 +5366,11 @@ public void ClearSecurity() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Crud.ViewCheckOption Check { + public global::Mysqlx.Crud.ViewCheckOption Check + { get { if ((_hasBits0 & 4) != 0) { return check_; } else { return CheckDefaultValue; } } - set { + set + { _hasBits0 |= 4; check_ = value; } @@ -4628,13 +5378,15 @@ public void ClearSecurity() { /// Gets whether the "check" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasCheck { + public bool HasCheck + { get { return (_hasBits0 & 4) != 0; } } /// Clears the value of the "check" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearCheck() { + public void ClearCheck() + { _hasBits0 &= ~4; } @@ -4648,7 +5400,8 @@ public void ClearCheck() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public pbc::RepeatedField Column { + public pbc::RepeatedField Column + { get { return column_; } } @@ -4661,9 +5414,11 @@ public void ClearCheck() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Crud.Find Stmt { + public global::Mysqlx.Crud.Find Stmt + { get { return stmt_; } - set { + set + { stmt_ = value; } } @@ -4679,9 +5434,11 @@ public void ClearCheck() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool ReplaceExisting { + public bool ReplaceExisting + { get { if ((_hasBits0 & 8) != 0) { return replaceExisting_; } else { return ReplaceExistingDefaultValue; } } - set { + set + { _hasBits0 |= 8; replaceExisting_ = value; } @@ -4689,29 +5446,35 @@ public bool ReplaceExisting { /// Gets whether the "replace_existing" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasReplaceExisting { + public bool HasReplaceExisting + { get { return (_hasBits0 & 8) != 0; } } /// Clears the value of the "replace_existing" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearReplaceExisting() { + public void ClearReplaceExisting() + { _hasBits0 &= ~8; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as CreateView); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(CreateView other) { - if (ReferenceEquals(other, null)) { + public bool Equals(CreateView other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } if (!object.Equals(Collection, other.Collection)) return false; @@ -4719,7 +5482,7 @@ public bool Equals(CreateView other) { if (Algorithm != other.Algorithm) return false; if (Security != other.Security) return false; if (Check != other.Check) return false; - if(!column_.Equals(other.column_)) return false; + if (!column_.Equals(other.column_)) return false; if (!object.Equals(Stmt, other.Stmt)) return false; if (ReplaceExisting != other.ReplaceExisting) return false; return Equals(_unknownFields, other._unknownFields); @@ -4727,7 +5490,8 @@ public bool Equals(CreateView other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; if (collection_ != null) hash ^= Collection.GetHashCode(); if (HasDefiner) hash ^= Definer.GetHashCode(); @@ -4737,7 +5501,8 @@ public override int GetHashCode() { hash ^= column_.GetHashCode(); if (stmt_ != null) hash ^= Stmt.GetHashCode(); if (HasReplaceExisting) hash ^= ReplaceExisting.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -4745,16 +5510,18 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (collection_ != null) { output.WriteRawTag(10); output.WriteMessage(Collection); @@ -4787,75 +5554,93 @@ public void WriteTo(pb::CodedOutputStream output) { if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (collection_ != null) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (collection_ != null) + { output.WriteRawTag(10); output.WriteMessage(Collection); } - if (HasDefiner) { + if (HasDefiner) + { output.WriteRawTag(18); output.WriteString(Definer); } - if (HasAlgorithm) { + if (HasAlgorithm) + { output.WriteRawTag(24); - output.WriteEnum((int) Algorithm); + output.WriteEnum((int)Algorithm); } - if (HasSecurity) { + if (HasSecurity) + { output.WriteRawTag(32); - output.WriteEnum((int) Security); + output.WriteEnum((int)Security); } - if (HasCheck) { + if (HasCheck) + { output.WriteRawTag(40); - output.WriteEnum((int) Check); + output.WriteEnum((int)Check); } column_.WriteTo(ref output, _repeated_column_codec); - if (stmt_ != null) { + if (stmt_ != null) + { output.WriteRawTag(58); output.WriteMessage(Stmt); } - if (HasReplaceExisting) { + if (HasReplaceExisting) + { output.WriteRawTag(64); output.WriteBool(ReplaceExisting); } - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (collection_ != null) { + if (collection_ != null) + { size += 1 + pb::CodedOutputStream.ComputeMessageSize(Collection); } - if (HasDefiner) { + if (HasDefiner) + { size += 1 + pb::CodedOutputStream.ComputeStringSize(Definer); } - if (HasAlgorithm) { - size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Algorithm); + if (HasAlgorithm) + { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int)Algorithm); } - if (HasSecurity) { - size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Security); + if (HasSecurity) + { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int)Security); } - if (HasCheck) { - size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Check); + if (HasCheck) + { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int)Check); } size += column_.CalculateSize(_repeated_column_codec); - if (stmt_ != null) { + if (stmt_ != null) + { size += 1 + pb::CodedOutputStream.ComputeMessageSize(Stmt); } - if (HasReplaceExisting) { + if (HasReplaceExisting) + { size += 1 + 1; } - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -4863,36 +5648,47 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(CreateView other) { - if (other == null) { + public void MergeFrom(CreateView other) + { + if (other == null) + { return; } - if (other.collection_ != null) { - if (collection_ == null) { + if (other.collection_ != null) + { + if (collection_ == null) + { Collection = new global::Mysqlx.Crud.Collection(); } Collection.MergeFrom(other.Collection); } - if (other.HasDefiner) { + if (other.HasDefiner) + { Definer = other.Definer; } - if (other.HasAlgorithm) { + if (other.HasAlgorithm) + { Algorithm = other.Algorithm; } - if (other.HasSecurity) { + if (other.HasSecurity) + { Security = other.Security; } - if (other.HasCheck) { + if (other.HasCheck) + { Check = other.Check; } column_.Add(other.column_); - if (other.stmt_ != null) { - if (stmt_ == null) { + if (other.stmt_ != null) + { + if (stmt_ == null) + { Stmt = new global::Mysqlx.Crud.Find(); } Stmt.MergeFrom(other.Stmt); } - if (other.HasReplaceExisting) { + if (other.HasReplaceExisting) + { ReplaceExisting = other.ReplaceExisting; } _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); @@ -4900,13 +5696,18 @@ public void MergeFrom(CreateView other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -4950,61 +5751,79 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 10: { - if (collection_ == null) { - Collection = new global::Mysqlx.Crud.Collection(); + case 10: + { + if (collection_ == null) + { + Collection = new global::Mysqlx.Crud.Collection(); + } + input.ReadMessage(Collection); + break; } - input.ReadMessage(Collection); - break; - } - case 18: { - Definer = input.ReadString(); - break; - } - case 24: { - Algorithm = (global::Mysqlx.Crud.ViewAlgorithm) input.ReadEnum(); - break; - } - case 32: { - Security = (global::Mysqlx.Crud.ViewSqlSecurity) input.ReadEnum(); - break; - } - case 40: { - Check = (global::Mysqlx.Crud.ViewCheckOption) input.ReadEnum(); - break; - } - case 50: { - column_.AddEntriesFrom(ref input, _repeated_column_codec); - break; - } - case 58: { - if (stmt_ == null) { - Stmt = new global::Mysqlx.Crud.Find(); + case 18: + { + Definer = input.ReadString(); + break; + } + case 24: + { + Algorithm = (global::Mysqlx.Crud.ViewAlgorithm)input.ReadEnum(); + break; + } + case 32: + { + Security = (global::Mysqlx.Crud.ViewSqlSecurity)input.ReadEnum(); + break; + } + case 40: + { + Check = (global::Mysqlx.Crud.ViewCheckOption)input.ReadEnum(); + break; + } + case 50: + { + column_.AddEntriesFrom(ref input, _repeated_column_codec); + break; + } + case 58: + { + if (stmt_ == null) + { + Stmt = new global::Mysqlx.Crud.Find(); + } + input.ReadMessage(Stmt); + break; + } + case 64: + { + ReplaceExisting = input.ReadBool(); + break; } - input.ReadMessage(Stmt); - break; - } - case 64: { - ReplaceExisting = input.ReadBool(); - break; - } } } } - #endif +#endif } @@ -5013,10 +5832,11 @@ public void MergeFrom(pb::CodedInputStream input) { ///ModifyView modify existing view based on indicated ///@ref Mysqlx::Crud::Find message /// - internal sealed partial class ModifyView : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class ModifyView : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ModifyView()); private pb::UnknownFieldSet _unknownFields; @@ -5027,19 +5847,22 @@ internal sealed partial class ModifyView : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Crud.MysqlxCrudReflection.Descriptor.MessageTypes[12]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public ModifyView() { + public ModifyView() + { OnConstruction(); } @@ -5047,7 +5870,8 @@ public ModifyView() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public ModifyView(ModifyView other) : this() { + public ModifyView(ModifyView other) : this() + { _hasBits0 = other._hasBits0; collection_ = other.collection_ != null ? other.collection_.Clone() : null; definer_ = other.definer_; @@ -5061,7 +5885,8 @@ public ModifyView(ModifyView other) : this() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public ModifyView Clone() { + public ModifyView Clone() + { return new ModifyView(this); } @@ -5073,9 +5898,11 @@ public ModifyView Clone() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Crud.Collection Collection { + public global::Mysqlx.Crud.Collection Collection + { get { return collection_; } - set { + set + { collection_ = value; } } @@ -5091,22 +5918,26 @@ public ModifyView Clone() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public string Definer { + public string Definer + { get { return definer_ ?? DefinerDefaultValue; } - set { + set + { definer_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); } } /// Gets whether the "definer" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasDefiner { + public bool HasDefiner + { get { return definer_ != null; } } /// Clears the value of the "definer" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearDefiner() { + public void ClearDefiner() + { definer_ = null; } @@ -5120,9 +5951,11 @@ public void ClearDefiner() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Crud.ViewAlgorithm Algorithm { + public global::Mysqlx.Crud.ViewAlgorithm Algorithm + { get { if ((_hasBits0 & 1) != 0) { return algorithm_; } else { return AlgorithmDefaultValue; } } - set { + set + { _hasBits0 |= 1; algorithm_ = value; } @@ -5130,13 +5963,15 @@ public void ClearDefiner() { /// Gets whether the "algorithm" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasAlgorithm { + public bool HasAlgorithm + { get { return (_hasBits0 & 1) != 0; } } /// Clears the value of the "algorithm" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearAlgorithm() { + public void ClearAlgorithm() + { _hasBits0 &= ~1; } @@ -5150,9 +5985,11 @@ public void ClearAlgorithm() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Crud.ViewSqlSecurity Security { + public global::Mysqlx.Crud.ViewSqlSecurity Security + { get { if ((_hasBits0 & 2) != 0) { return security_; } else { return SecurityDefaultValue; } } - set { + set + { _hasBits0 |= 2; security_ = value; } @@ -5160,13 +5997,15 @@ public void ClearAlgorithm() { /// Gets whether the "security" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasSecurity { + public bool HasSecurity + { get { return (_hasBits0 & 2) != 0; } } /// Clears the value of the "security" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearSecurity() { + public void ClearSecurity() + { _hasBits0 &= ~2; } @@ -5180,9 +6019,11 @@ public void ClearSecurity() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Crud.ViewCheckOption Check { + public global::Mysqlx.Crud.ViewCheckOption Check + { get { if ((_hasBits0 & 4) != 0) { return check_; } else { return CheckDefaultValue; } } - set { + set + { _hasBits0 |= 4; check_ = value; } @@ -5190,13 +6031,15 @@ public void ClearSecurity() { /// Gets whether the "check" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasCheck { + public bool HasCheck + { get { return (_hasBits0 & 4) != 0; } } /// Clears the value of the "check" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearCheck() { + public void ClearCheck() + { _hasBits0 &= ~4; } @@ -5210,7 +6053,8 @@ public void ClearCheck() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public pbc::RepeatedField Column { + public pbc::RepeatedField Column + { get { return column_; } } @@ -5223,26 +6067,32 @@ public void ClearCheck() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Crud.Find Stmt { + public global::Mysqlx.Crud.Find Stmt + { get { return stmt_; } - set { + set + { stmt_ = value; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as ModifyView); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(ModifyView other) { - if (ReferenceEquals(other, null)) { + public bool Equals(ModifyView other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } if (!object.Equals(Collection, other.Collection)) return false; @@ -5250,14 +6100,15 @@ public bool Equals(ModifyView other) { if (Algorithm != other.Algorithm) return false; if (Security != other.Security) return false; if (Check != other.Check) return false; - if(!column_.Equals(other.column_)) return false; + if (!column_.Equals(other.column_)) return false; if (!object.Equals(Stmt, other.Stmt)) return false; return Equals(_unknownFields, other._unknownFields); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; if (collection_ != null) hash ^= Collection.GetHashCode(); if (HasDefiner) hash ^= Definer.GetHashCode(); @@ -5266,7 +6117,8 @@ public override int GetHashCode() { if (HasCheck) hash ^= Check.GetHashCode(); hash ^= column_.GetHashCode(); if (stmt_ != null) hash ^= Stmt.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -5274,16 +6126,18 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (collection_ != null) { output.WriteRawTag(10); output.WriteMessage(Collection); @@ -5312,68 +6166,84 @@ public void WriteTo(pb::CodedOutputStream output) { if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (collection_ != null) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (collection_ != null) + { output.WriteRawTag(10); output.WriteMessage(Collection); } - if (HasDefiner) { + if (HasDefiner) + { output.WriteRawTag(18); output.WriteString(Definer); } - if (HasAlgorithm) { + if (HasAlgorithm) + { output.WriteRawTag(24); - output.WriteEnum((int) Algorithm); + output.WriteEnum((int)Algorithm); } - if (HasSecurity) { + if (HasSecurity) + { output.WriteRawTag(32); - output.WriteEnum((int) Security); + output.WriteEnum((int)Security); } - if (HasCheck) { + if (HasCheck) + { output.WriteRawTag(40); - output.WriteEnum((int) Check); + output.WriteEnum((int)Check); } column_.WriteTo(ref output, _repeated_column_codec); - if (stmt_ != null) { + if (stmt_ != null) + { output.WriteRawTag(58); output.WriteMessage(Stmt); } - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (collection_ != null) { + if (collection_ != null) + { size += 1 + pb::CodedOutputStream.ComputeMessageSize(Collection); } - if (HasDefiner) { + if (HasDefiner) + { size += 1 + pb::CodedOutputStream.ComputeStringSize(Definer); } - if (HasAlgorithm) { - size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Algorithm); + if (HasAlgorithm) + { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int)Algorithm); } - if (HasSecurity) { - size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Security); + if (HasSecurity) + { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int)Security); } - if (HasCheck) { - size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Check); + if (HasCheck) + { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int)Check); } size += column_.CalculateSize(_repeated_column_codec); - if (stmt_ != null) { + if (stmt_ != null) + { size += 1 + pb::CodedOutputStream.ComputeMessageSize(Stmt); } - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -5381,31 +6251,41 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(ModifyView other) { - if (other == null) { + public void MergeFrom(ModifyView other) + { + if (other == null) + { return; } - if (other.collection_ != null) { - if (collection_ == null) { + if (other.collection_ != null) + { + if (collection_ == null) + { Collection = new global::Mysqlx.Crud.Collection(); } Collection.MergeFrom(other.Collection); } - if (other.HasDefiner) { + if (other.HasDefiner) + { Definer = other.Definer; } - if (other.HasAlgorithm) { + if (other.HasAlgorithm) + { Algorithm = other.Algorithm; } - if (other.HasSecurity) { + if (other.HasSecurity) + { Security = other.Security; } - if (other.HasCheck) { + if (other.HasCheck) + { Check = other.Check; } column_.Add(other.column_); - if (other.stmt_ != null) { - if (stmt_ == null) { + if (other.stmt_ != null) + { + if (stmt_ == null) + { Stmt = new global::Mysqlx.Crud.Find(); } Stmt.MergeFrom(other.Stmt); @@ -5415,13 +6295,18 @@ public void MergeFrom(ModifyView other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -5461,57 +6346,74 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 10: { - if (collection_ == null) { - Collection = new global::Mysqlx.Crud.Collection(); + case 10: + { + if (collection_ == null) + { + Collection = new global::Mysqlx.Crud.Collection(); + } + input.ReadMessage(Collection); + break; } - input.ReadMessage(Collection); - break; - } - case 18: { - Definer = input.ReadString(); - break; - } - case 24: { - Algorithm = (global::Mysqlx.Crud.ViewAlgorithm) input.ReadEnum(); - break; - } - case 32: { - Security = (global::Mysqlx.Crud.ViewSqlSecurity) input.ReadEnum(); - break; - } - case 40: { - Check = (global::Mysqlx.Crud.ViewCheckOption) input.ReadEnum(); - break; - } - case 50: { - column_.AddEntriesFrom(ref input, _repeated_column_codec); - break; - } - case 58: { - if (stmt_ == null) { - Stmt = new global::Mysqlx.Crud.Find(); + case 18: + { + Definer = input.ReadString(); + break; + } + case 24: + { + Algorithm = (global::Mysqlx.Crud.ViewAlgorithm)input.ReadEnum(); + break; + } + case 32: + { + Security = (global::Mysqlx.Crud.ViewSqlSecurity)input.ReadEnum(); + break; + } + case 40: + { + Check = (global::Mysqlx.Crud.ViewCheckOption)input.ReadEnum(); + break; + } + case 50: + { + column_.AddEntriesFrom(ref input, _repeated_column_codec); + break; + } + case 58: + { + if (stmt_ == null) + { + Stmt = new global::Mysqlx.Crud.Find(); + } + input.ReadMessage(Stmt); + break; } - input.ReadMessage(Stmt); - break; - } } } } - #endif +#endif } @@ -5519,10 +6421,11 @@ public void MergeFrom(pb::CodedInputStream input) { ///* ///DropView removing existing view /// - internal sealed partial class DropView : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class DropView : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new DropView()); private pb::UnknownFieldSet _unknownFields; @@ -5533,19 +6436,22 @@ internal sealed partial class DropView : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Crud.MysqlxCrudReflection.Descriptor.MessageTypes[13]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public DropView() { + public DropView() + { OnConstruction(); } @@ -5553,7 +6459,8 @@ public DropView() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public DropView(DropView other) : this() { + public DropView(DropView other) : this() + { _hasBits0 = other._hasBits0; collection_ = other.collection_ != null ? other.collection_.Clone() : null; ifExists_ = other.ifExists_; @@ -5562,7 +6469,8 @@ public DropView(DropView other) : this() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public DropView Clone() { + public DropView Clone() + { return new DropView(this); } @@ -5574,9 +6482,11 @@ public DropView Clone() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Crud.Collection Collection { + public global::Mysqlx.Crud.Collection Collection + { get { return collection_; } - set { + set + { collection_ = value; } } @@ -5591,9 +6501,11 @@ public DropView Clone() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool IfExists { + public bool IfExists + { get { if ((_hasBits0 & 1) != 0) { return ifExists_; } else { return IfExistsDefaultValue; } } - set { + set + { _hasBits0 |= 1; ifExists_ = value; } @@ -5601,29 +6513,35 @@ public bool IfExists { /// Gets whether the "if_exists" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasIfExists { + public bool HasIfExists + { get { return (_hasBits0 & 1) != 0; } } /// Clears the value of the "if_exists" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearIfExists() { + public void ClearIfExists() + { _hasBits0 &= ~1; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as DropView); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(DropView other) { - if (ReferenceEquals(other, null)) { + public bool Equals(DropView other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } if (!object.Equals(Collection, other.Collection)) return false; @@ -5633,11 +6551,13 @@ public bool Equals(DropView other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; if (collection_ != null) hash ^= Collection.GetHashCode(); if (HasIfExists) hash ^= IfExists.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -5645,16 +6565,18 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (collection_ != null) { output.WriteRawTag(10); output.WriteMessage(Collection); @@ -5666,38 +6588,46 @@ public void WriteTo(pb::CodedOutputStream output) { if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (collection_ != null) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (collection_ != null) + { output.WriteRawTag(10); output.WriteMessage(Collection); } - if (HasIfExists) { + if (HasIfExists) + { output.WriteRawTag(16); output.WriteBool(IfExists); } - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (collection_ != null) { + if (collection_ != null) + { size += 1 + pb::CodedOutputStream.ComputeMessageSize(Collection); } - if (HasIfExists) { + if (HasIfExists) + { size += 1 + 1; } - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -5705,17 +6635,22 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(DropView other) { - if (other == null) { + public void MergeFrom(DropView other) + { + if (other == null) + { return; } - if (other.collection_ != null) { - if (collection_ == null) { + if (other.collection_ != null) + { + if (collection_ == null) + { Collection = new global::Mysqlx.Crud.Collection(); } Collection.MergeFrom(other.Collection); } - if (other.HasIfExists) { + if (other.HasIfExists) + { IfExists = other.IfExists; } _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); @@ -5723,13 +6658,18 @@ public void MergeFrom(DropView other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -5746,34 +6686,45 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 10: { - if (collection_ == null) { - Collection = new global::Mysqlx.Crud.Collection(); + case 10: + { + if (collection_ == null) + { + Collection = new global::Mysqlx.Crud.Collection(); + } + input.ReadMessage(Collection); + break; + } + case 16: + { + IfExists = input.ReadBool(); + break; } - input.ReadMessage(Collection); - break; - } - case 16: { - IfExists = input.ReadBool(); - break; - } } } } - #endif +#endif } @@ -5782,3 +6733,4 @@ public void MergeFrom(pb::CodedInputStream input) { } #endregion Designer generated code + diff --git a/MySQL.Data/src/X/Protocol/X/Protobuf/MysqlxCursor.cs b/MySQL.Data/src/X/Protocol/X/Protobuf/MysqlxCursor.cs index 2faf288d0..235ec14bb 100644 --- a/MySQL.Data/src/X/Protocol/X/Protobuf/MysqlxCursor.cs +++ b/MySQL.Data/src/X/Protocol/X/Protobuf/MysqlxCursor.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2022, 2023, Oracle and/or its affiliates. +// Copyright © 2022, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -37,19 +37,23 @@ using pbc = global::Google.Protobuf.Collections; using pbr = global::Google.Protobuf.Reflection; using scg = global::System.Collections.Generic; -namespace Mysqlx.Cursor { +namespace Mysqlx.Cursor +{ /// Holder for reflection information generated from mysqlx_cursor.proto - internal static partial class MysqlxCursorReflection { + public static partial class MysqlxCursorReflection + { #region Descriptor /// File descriptor for mysqlx_cursor.proto - public static pbr::FileDescriptor Descriptor { + public static pbr::FileDescriptor Descriptor + { get { return descriptor; } } private static pbr::FileDescriptor descriptor; - static MysqlxCursorReflection() { + static MysqlxCursorReflection() + { byte[] descriptorData = global::System.Convert.FromBase64String( string.Concat( "ChNteXNxbHhfY3Vyc29yLnByb3RvEg1NeXNxbHguQ3Vyc29yGgxteXNxbHgu", @@ -90,10 +94,11 @@ static MysqlxCursorReflection() { /// ///@returns @ref Mysqlx::Ok /// - internal sealed partial class Open : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class Open : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Open()); private pb::UnknownFieldSet _unknownFields; @@ -104,19 +109,22 @@ internal sealed partial class Open : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Cursor.MysqlxCursorReflection.Descriptor.MessageTypes[0]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Open() { + public Open() + { OnConstruction(); } @@ -124,7 +132,8 @@ public Open() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Open(Open other) : this() { + public Open(Open other) : this() + { _hasBits0 = other._hasBits0; cursorId_ = other.cursorId_; stmt_ = other.stmt_ != null ? other.stmt_.Clone() : null; @@ -134,7 +143,8 @@ public Open(Open other) : this() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Open Clone() { + public Open Clone() + { return new Open(this); } @@ -149,9 +159,11 @@ public Open Clone() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public uint CursorId { + public uint CursorId + { get { if ((_hasBits0 & 1) != 0) { return cursorId_; } else { return CursorIdDefaultValue; } } - set { + set + { _hasBits0 |= 1; cursorId_ = value; } @@ -159,13 +171,15 @@ public uint CursorId { /// Gets whether the "cursor_id" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasCursorId { + public bool HasCursorId + { get { return (_hasBits0 & 1) != 0; } } /// Clears the value of the "cursor_id" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearCursorId() { + public void ClearCursorId() + { _hasBits0 &= ~1; } @@ -177,9 +191,11 @@ public void ClearCursorId() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Cursor.Open.Types.OneOfMessage Stmt { + public global::Mysqlx.Cursor.Open.Types.OneOfMessage Stmt + { get { return stmt_; } - set { + set + { stmt_ = value; } } @@ -194,9 +210,11 @@ public void ClearCursorId() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public ulong FetchRows { + public ulong FetchRows + { get { if ((_hasBits0 & 2) != 0) { return fetchRows_; } else { return FetchRowsDefaultValue; } } - set { + set + { _hasBits0 |= 2; fetchRows_ = value; } @@ -204,29 +222,35 @@ public ulong FetchRows { /// Gets whether the "fetch_rows" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasFetchRows { + public bool HasFetchRows + { get { return (_hasBits0 & 2) != 0; } } /// Clears the value of the "fetch_rows" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearFetchRows() { + public void ClearFetchRows() + { _hasBits0 &= ~2; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as Open); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(Open other) { - if (ReferenceEquals(other, null)) { + public bool Equals(Open other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } if (CursorId != other.CursorId) return false; @@ -237,12 +261,14 @@ public bool Equals(Open other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; if (HasCursorId) hash ^= CursorId.GetHashCode(); if (stmt_ != null) hash ^= Stmt.GetHashCode(); if (HasFetchRows) hash ^= FetchRows.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -250,16 +276,18 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (HasCursorId) { output.WriteRawTag(8); output.WriteUInt32(CursorId); @@ -275,45 +303,55 @@ public void WriteTo(pb::CodedOutputStream output) { if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (HasCursorId) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (HasCursorId) + { output.WriteRawTag(8); output.WriteUInt32(CursorId); } - if (stmt_ != null) { + if (stmt_ != null) + { output.WriteRawTag(34); output.WriteMessage(Stmt); } - if (HasFetchRows) { + if (HasFetchRows) + { output.WriteRawTag(40); output.WriteUInt64(FetchRows); } - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (HasCursorId) { + if (HasCursorId) + { size += 1 + pb::CodedOutputStream.ComputeUInt32Size(CursorId); } - if (stmt_ != null) { + if (stmt_ != null) + { size += 1 + pb::CodedOutputStream.ComputeMessageSize(Stmt); } - if (HasFetchRows) { + if (HasFetchRows) + { size += 1 + pb::CodedOutputStream.ComputeUInt64Size(FetchRows); } - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -321,20 +359,26 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(Open other) { - if (other == null) { + public void MergeFrom(Open other) + { + if (other == null) + { return; } - if (other.HasCursorId) { + if (other.HasCursorId) + { CursorId = other.CursorId; } - if (other.stmt_ != null) { - if (stmt_ == null) { + if (other.stmt_ != null) + { + if (stmt_ == null) + { Stmt = new global::Mysqlx.Cursor.Open.Types.OneOfMessage(); } Stmt.MergeFrom(other.Stmt); } - if (other.HasFetchRows) { + if (other.HasFetchRows) + { FetchRows = other.FetchRows; } _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); @@ -342,13 +386,18 @@ public void MergeFrom(Open other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -369,48 +418,62 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 8: { - CursorId = input.ReadUInt32(); - break; - } - case 34: { - if (stmt_ == null) { - Stmt = new global::Mysqlx.Cursor.Open.Types.OneOfMessage(); + case 8: + { + CursorId = input.ReadUInt32(); + break; + } + case 34: + { + if (stmt_ == null) + { + Stmt = new global::Mysqlx.Cursor.Open.Types.OneOfMessage(); + } + input.ReadMessage(Stmt); + break; + } + case 40: + { + FetchRows = input.ReadUInt64(); + break; } - input.ReadMessage(Stmt); - break; - } - case 40: { - FetchRows = input.ReadUInt64(); - break; - } } } } - #endif +#endif #region Nested types /// Container for nested types declared in the Open message type. [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static partial class Types { + public static partial class Types + { + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] public sealed partial class OneOfMessage : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new OneOfMessage()); private pb::UnknownFieldSet _unknownFields; @@ -421,19 +484,22 @@ public sealed partial class OneOfMessage : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Cursor.Open.Descriptor.NestedTypes[0]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public OneOfMessage() { + public OneOfMessage() + { OnConstruction(); } @@ -441,7 +507,8 @@ public OneOfMessage() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public OneOfMessage(OneOfMessage other) : this() { + public OneOfMessage(OneOfMessage other) : this() + { _hasBits0 = other._hasBits0; type_ = other.type_; prepareExecute_ = other.prepareExecute_ != null ? other.prepareExecute_.Clone() : null; @@ -450,7 +517,8 @@ public OneOfMessage(OneOfMessage other) : this() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public OneOfMessage Clone() { + public OneOfMessage Clone() + { return new OneOfMessage(this); } @@ -461,9 +529,11 @@ public OneOfMessage Clone() { private global::Mysqlx.Cursor.Open.Types.OneOfMessage.Types.Type type_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Cursor.Open.Types.OneOfMessage.Types.Type Type { + public global::Mysqlx.Cursor.Open.Types.OneOfMessage.Types.Type Type + { get { if ((_hasBits0 & 1) != 0) { return type_; } else { return TypeDefaultValue; } } - set { + set + { _hasBits0 |= 1; type_ = value; } @@ -471,13 +541,15 @@ public OneOfMessage Clone() { /// Gets whether the "type" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasType { + public bool HasType + { get { return (_hasBits0 & 1) != 0; } } /// Clears the value of the "type" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearType() { + public void ClearType() + { _hasBits0 &= ~1; } @@ -486,26 +558,32 @@ public void ClearType() { private global::Mysqlx.Prepare.Execute prepareExecute_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Prepare.Execute PrepareExecute { + public global::Mysqlx.Prepare.Execute PrepareExecute + { get { return prepareExecute_; } - set { + set + { prepareExecute_ = value; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as OneOfMessage); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(OneOfMessage other) { - if (ReferenceEquals(other, null)) { + public bool Equals(OneOfMessage other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } if (Type != other.Type) return false; @@ -515,11 +593,13 @@ public bool Equals(OneOfMessage other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; if (HasType) hash ^= Type.GetHashCode(); if (prepareExecute_ != null) hash ^= PrepareExecute.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -527,16 +607,18 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (HasType) { output.WriteRawTag(8); output.WriteEnum((int) Type); @@ -548,38 +630,46 @@ public void WriteTo(pb::CodedOutputStream output) { if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (HasType) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (HasType) + { output.WriteRawTag(8); - output.WriteEnum((int) Type); + output.WriteEnum((int)Type); } - if (prepareExecute_ != null) { + if (prepareExecute_ != null) + { output.WriteRawTag(18); output.WriteMessage(PrepareExecute); } - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (HasType) { - size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Type); + if (HasType) + { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int)Type); } - if (prepareExecute_ != null) { + if (prepareExecute_ != null) + { size += 1 + pb::CodedOutputStream.ComputeMessageSize(PrepareExecute); } - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -587,15 +677,20 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(OneOfMessage other) { - if (other == null) { + public void MergeFrom(OneOfMessage other) + { + if (other == null) + { return; } - if (other.HasType) { + if (other.HasType) + { Type = other.Type; } - if (other.prepareExecute_ != null) { - if (prepareExecute_ == null) { + if (other.prepareExecute_ != null) + { + if (prepareExecute_ == null) + { PrepareExecute = new global::Mysqlx.Prepare.Execute(); } PrepareExecute.MergeFrom(other.PrepareExecute); @@ -605,13 +700,18 @@ public void MergeFrom(OneOfMessage other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -628,41 +728,54 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 8: { - Type = (global::Mysqlx.Cursor.Open.Types.OneOfMessage.Types.Type) input.ReadEnum(); - break; - } - case 18: { - if (prepareExecute_ == null) { - PrepareExecute = new global::Mysqlx.Prepare.Execute(); + case 8: + { + Type = (global::Mysqlx.Cursor.Open.Types.OneOfMessage.Types.Type)input.ReadEnum(); + break; + } + case 18: + { + if (prepareExecute_ == null) + { + PrepareExecute = new global::Mysqlx.Prepare.Execute(); + } + input.ReadMessage(PrepareExecute); + break; } - input.ReadMessage(PrepareExecute); - break; - } } } } - #endif +#endif #region Nested types /// Container for nested types declared in the OneOfMessage message type. [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static partial class Types { - public enum Type { + public static partial class Types + { + public enum Type + { [pbr::OriginalName("PREPARE_EXECUTE")] PrepareExecute = 0, } @@ -690,10 +803,11 @@ public enum Type { ///end ///@enduml /// - internal sealed partial class Fetch : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class Fetch : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Fetch()); private pb::UnknownFieldSet _unknownFields; @@ -704,19 +818,22 @@ internal sealed partial class Fetch : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Cursor.MysqlxCursorReflection.Descriptor.MessageTypes[1]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Fetch() { + public Fetch() + { OnConstruction(); } @@ -724,7 +841,8 @@ public Fetch() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Fetch(Fetch other) : this() { + public Fetch(Fetch other) : this() + { _hasBits0 = other._hasBits0; cursorId_ = other.cursorId_; fetchRows_ = other.fetchRows_; @@ -733,7 +851,8 @@ public Fetch(Fetch other) : this() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Fetch Clone() { + public Fetch Clone() + { return new Fetch(this); } @@ -747,9 +866,11 @@ public Fetch Clone() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public uint CursorId { + public uint CursorId + { get { if ((_hasBits0 & 1) != 0) { return cursorId_; } else { return CursorIdDefaultValue; } } - set { + set + { _hasBits0 |= 1; cursorId_ = value; } @@ -757,13 +878,15 @@ public uint CursorId { /// Gets whether the "cursor_id" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasCursorId { + public bool HasCursorId + { get { return (_hasBits0 & 1) != 0; } } /// Clears the value of the "cursor_id" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearCursorId() { + public void ClearCursorId() + { _hasBits0 &= ~1; } @@ -777,9 +900,11 @@ public void ClearCursorId() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public ulong FetchRows { + public ulong FetchRows + { get { if ((_hasBits0 & 2) != 0) { return fetchRows_; } else { return FetchRowsDefaultValue; } } - set { + set + { _hasBits0 |= 2; fetchRows_ = value; } @@ -787,29 +912,35 @@ public ulong FetchRows { /// Gets whether the "fetch_rows" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasFetchRows { + public bool HasFetchRows + { get { return (_hasBits0 & 2) != 0; } } /// Clears the value of the "fetch_rows" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearFetchRows() { + public void ClearFetchRows() + { _hasBits0 &= ~2; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as Fetch); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(Fetch other) { - if (ReferenceEquals(other, null)) { + public bool Equals(Fetch other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } if (CursorId != other.CursorId) return false; @@ -819,11 +950,13 @@ public bool Equals(Fetch other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; if (HasCursorId) hash ^= CursorId.GetHashCode(); if (HasFetchRows) hash ^= FetchRows.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -831,16 +964,18 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (HasCursorId) { output.WriteRawTag(8); output.WriteUInt32(CursorId); @@ -852,38 +987,46 @@ public void WriteTo(pb::CodedOutputStream output) { if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (HasCursorId) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (HasCursorId) + { output.WriteRawTag(8); output.WriteUInt32(CursorId); } - if (HasFetchRows) { + if (HasFetchRows) + { output.WriteRawTag(40); output.WriteUInt64(FetchRows); } - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (HasCursorId) { + if (HasCursorId) + { size += 1 + pb::CodedOutputStream.ComputeUInt32Size(CursorId); } - if (HasFetchRows) { + if (HasFetchRows) + { size += 1 + pb::CodedOutputStream.ComputeUInt64Size(FetchRows); } - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -891,14 +1034,18 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(Fetch other) { - if (other == null) { + public void MergeFrom(Fetch other) + { + if (other == null) + { return; } - if (other.HasCursorId) { + if (other.HasCursorId) + { CursorId = other.CursorId; } - if (other.HasFetchRows) { + if (other.HasFetchRows) + { FetchRows = other.FetchRows; } _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); @@ -906,13 +1053,18 @@ public void MergeFrom(Fetch other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -926,31 +1078,41 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 8: { - CursorId = input.ReadUInt32(); - break; - } - case 40: { - FetchRows = input.ReadUInt64(); - break; - } + case 8: + { + CursorId = input.ReadUInt32(); + break; + } + case 40: + { + FetchRows = input.ReadUInt64(); + break; + } } } } - #endif +#endif } @@ -969,10 +1131,11 @@ public void MergeFrom(pb::CodedInputStream input) { /// ///@returns @ref Mysqlx::Ok or @ref Mysqlx::Error /// - internal sealed partial class Close : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class Close : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Close()); private pb::UnknownFieldSet _unknownFields; @@ -983,19 +1146,22 @@ internal sealed partial class Close : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Cursor.MysqlxCursorReflection.Descriptor.MessageTypes[2]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Close() { + public Close() + { OnConstruction(); } @@ -1003,7 +1169,8 @@ public Close() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Close(Close other) : this() { + public Close(Close other) : this() + { _hasBits0 = other._hasBits0; cursorId_ = other.cursorId_; _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); @@ -1011,7 +1178,8 @@ public Close(Close other) : this() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Close Clone() { + public Close Clone() + { return new Close(this); } @@ -1025,9 +1193,11 @@ public Close Clone() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public uint CursorId { + public uint CursorId + { get { if ((_hasBits0 & 1) != 0) { return cursorId_; } else { return CursorIdDefaultValue; } } - set { + set + { _hasBits0 |= 1; cursorId_ = value; } @@ -1035,29 +1205,35 @@ public uint CursorId { /// Gets whether the "cursor_id" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasCursorId { + public bool HasCursorId + { get { return (_hasBits0 & 1) != 0; } } /// Clears the value of the "cursor_id" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearCursorId() { + public void ClearCursorId() + { _hasBits0 &= ~1; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as Close); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(Close other) { - if (ReferenceEquals(other, null)) { + public bool Equals(Close other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } if (CursorId != other.CursorId) return false; @@ -1066,10 +1242,12 @@ public bool Equals(Close other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; if (HasCursorId) hash ^= CursorId.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -1077,16 +1255,18 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (HasCursorId) { output.WriteRawTag(8); output.WriteUInt32(CursorId); @@ -1094,31 +1274,37 @@ public void WriteTo(pb::CodedOutputStream output) { if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (HasCursorId) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (HasCursorId) + { output.WriteRawTag(8); output.WriteUInt32(CursorId); } - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (HasCursorId) { + if (HasCursorId) + { size += 1 + pb::CodedOutputStream.ComputeUInt32Size(CursorId); } - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -1126,11 +1312,14 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(Close other) { - if (other == null) { + public void MergeFrom(Close other) + { + if (other == null) + { return; } - if (other.HasCursorId) { + if (other.HasCursorId) + { CursorId = other.CursorId; } _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); @@ -1138,13 +1327,18 @@ public void MergeFrom(Close other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -1154,27 +1348,36 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 8: { - CursorId = input.ReadUInt32(); - break; - } + case 8: + { + CursorId = input.ReadUInt32(); + break; + } } } } - #endif +#endif } @@ -1183,3 +1386,4 @@ public void MergeFrom(pb::CodedInputStream input) { } #endregion Designer generated code + diff --git a/MySQL.Data/src/X/Protocol/X/Protobuf/MysqlxDatatypes.cs b/MySQL.Data/src/X/Protocol/X/Protobuf/MysqlxDatatypes.cs index 75d44e306..bdf38ad39 100644 --- a/MySQL.Data/src/X/Protocol/X/Protobuf/MysqlxDatatypes.cs +++ b/MySQL.Data/src/X/Protocol/X/Protobuf/MysqlxDatatypes.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2022, 2023, Oracle and/or its affiliates. +// Copyright © 2022, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -37,19 +37,23 @@ using pbc = global::Google.Protobuf.Collections; using pbr = global::Google.Protobuf.Reflection; using scg = global::System.Collections.Generic; -namespace Mysqlx.Datatypes { +namespace Mysqlx.Datatypes +{ /// Holder for reflection information generated from mysqlx_datatypes.proto - internal static partial class MysqlxDatatypesReflection { + public static partial class MysqlxDatatypesReflection + { #region Descriptor /// File descriptor for mysqlx_datatypes.proto - internal static pbr::FileDescriptor Descriptor { + public static pbr::FileDescriptor Descriptor + { get { return descriptor; } } private static pbr::FileDescriptor descriptor; - static MysqlxDatatypesReflection() { + static MysqlxDatatypesReflection() + { byte[] descriptorData = global::System.Convert.FromBase64String( string.Concat( "ChZteXNxbHhfZGF0YXR5cGVzLnByb3RvEhBNeXNxbHguRGF0YXR5cGVzIsYD", @@ -90,10 +94,11 @@ static MysqlxDatatypesReflection() { /// /// a scalar /// - internal sealed partial class Scalar : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class Scalar : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Scalar()); private pb::UnknownFieldSet _unknownFields; @@ -104,19 +109,22 @@ internal sealed partial class Scalar : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Datatypes.MysqlxDatatypesReflection.Descriptor.MessageTypes[0]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Scalar() { + public Scalar() + { OnConstruction(); } @@ -124,7 +132,8 @@ public Scalar() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Scalar(Scalar other) : this() { + public Scalar(Scalar other) : this() + { _hasBits0 = other._hasBits0; type_ = other.type_; vSignedInt_ = other.vSignedInt_; @@ -139,7 +148,8 @@ public Scalar(Scalar other) : this() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Scalar Clone() { + public Scalar Clone() + { return new Scalar(this); } @@ -150,9 +160,11 @@ public Scalar Clone() { private global::Mysqlx.Datatypes.Scalar.Types.Type type_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Datatypes.Scalar.Types.Type Type { + public global::Mysqlx.Datatypes.Scalar.Types.Type Type + { get { if ((_hasBits0 & 1) != 0) { return type_; } else { return TypeDefaultValue; } } - set { + set + { _hasBits0 |= 1; type_ = value; } @@ -160,13 +172,15 @@ public Scalar Clone() { /// Gets whether the "type" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasType { + public bool HasType + { get { return (_hasBits0 & 1) != 0; } } /// Clears the value of the "type" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearType() { + public void ClearType() + { _hasBits0 &= ~1; } @@ -177,9 +191,11 @@ public void ClearType() { private long vSignedInt_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public long VSignedInt { + public long VSignedInt + { get { if ((_hasBits0 & 2) != 0) { return vSignedInt_; } else { return VSignedIntDefaultValue; } } - set { + set + { _hasBits0 |= 2; vSignedInt_ = value; } @@ -187,13 +203,15 @@ public long VSignedInt { /// Gets whether the "v_signed_int" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasVSignedInt { + public bool HasVSignedInt + { get { return (_hasBits0 & 2) != 0; } } /// Clears the value of the "v_signed_int" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearVSignedInt() { + public void ClearVSignedInt() + { _hasBits0 &= ~2; } @@ -204,9 +222,11 @@ public void ClearVSignedInt() { private ulong vUnsignedInt_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public ulong VUnsignedInt { + public ulong VUnsignedInt + { get { if ((_hasBits0 & 4) != 0) { return vUnsignedInt_; } else { return VUnsignedIntDefaultValue; } } - set { + set + { _hasBits0 |= 4; vUnsignedInt_ = value; } @@ -214,13 +234,15 @@ public ulong VUnsignedInt { /// Gets whether the "v_unsigned_int" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasVUnsignedInt { + public bool HasVUnsignedInt + { get { return (_hasBits0 & 4) != 0; } } /// Clears the value of the "v_unsigned_int" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearVUnsignedInt() { + public void ClearVUnsignedInt() + { _hasBits0 &= ~4; } @@ -232,9 +254,11 @@ public void ClearVUnsignedInt() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Datatypes.Scalar.Types.Octets VOctets { + public global::Mysqlx.Datatypes.Scalar.Types.Octets VOctets + { get { return vOctets_; } - set { + set + { vOctets_ = value; } } @@ -246,9 +270,11 @@ public void ClearVUnsignedInt() { private double vDouble_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public double VDouble { + public double VDouble + { get { if ((_hasBits0 & 8) != 0) { return vDouble_; } else { return VDoubleDefaultValue; } } - set { + set + { _hasBits0 |= 8; vDouble_ = value; } @@ -256,13 +282,15 @@ public double VDouble { /// Gets whether the "v_double" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasVDouble { + public bool HasVDouble + { get { return (_hasBits0 & 8) != 0; } } /// Clears the value of the "v_double" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearVDouble() { + public void ClearVDouble() + { _hasBits0 &= ~8; } @@ -273,9 +301,11 @@ public void ClearVDouble() { private float vFloat_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public float VFloat { + public float VFloat + { get { if ((_hasBits0 & 16) != 0) { return vFloat_; } else { return VFloatDefaultValue; } } - set { + set + { _hasBits0 |= 16; vFloat_ = value; } @@ -283,13 +313,15 @@ public float VFloat { /// Gets whether the "v_float" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasVFloat { + public bool HasVFloat + { get { return (_hasBits0 & 16) != 0; } } /// Clears the value of the "v_float" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearVFloat() { + public void ClearVFloat() + { _hasBits0 &= ~16; } @@ -300,9 +332,11 @@ public void ClearVFloat() { private bool vBool_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool VBool { + public bool VBool + { get { if ((_hasBits0 & 32) != 0) { return vBool_; } else { return VBoolDefaultValue; } } - set { + set + { _hasBits0 |= 32; vBool_ = value; } @@ -310,13 +344,15 @@ public bool VBool { /// Gets whether the "v_bool" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasVBool { + public bool HasVBool + { get { return (_hasBits0 & 32) != 0; } } /// Clears the value of the "v_bool" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearVBool() { + public void ClearVBool() + { _hasBits0 &= ~32; } @@ -325,26 +361,32 @@ public void ClearVBool() { private global::Mysqlx.Datatypes.Scalar.Types.String vString_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Datatypes.Scalar.Types.String VString { + public global::Mysqlx.Datatypes.Scalar.Types.String VString + { get { return vString_; } - set { + set + { vString_ = value; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as Scalar); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(Scalar other) { - if (ReferenceEquals(other, null)) { + public bool Equals(Scalar other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } if (Type != other.Type) return false; @@ -360,7 +402,8 @@ public bool Equals(Scalar other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; if (HasType) hash ^= Type.GetHashCode(); if (HasVSignedInt) hash ^= VSignedInt.GetHashCode(); @@ -370,7 +413,8 @@ public override int GetHashCode() { if (HasVFloat) hash ^= pbc::ProtobufEqualityComparers.BitwiseSingleEqualityComparer.GetHashCode(VFloat); if (HasVBool) hash ^= VBool.GetHashCode(); if (vString_ != null) hash ^= VString.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -378,16 +422,18 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (HasType) { output.WriteRawTag(8); output.WriteEnum((int) Type); @@ -423,80 +469,100 @@ public void WriteTo(pb::CodedOutputStream output) { if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (HasType) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (HasType) + { output.WriteRawTag(8); - output.WriteEnum((int) Type); + output.WriteEnum((int)Type); } - if (HasVSignedInt) { + if (HasVSignedInt) + { output.WriteRawTag(16); output.WriteSInt64(VSignedInt); } - if (HasVUnsignedInt) { + if (HasVUnsignedInt) + { output.WriteRawTag(24); output.WriteUInt64(VUnsignedInt); } - if (vOctets_ != null) { + if (vOctets_ != null) + { output.WriteRawTag(42); output.WriteMessage(VOctets); } - if (HasVDouble) { + if (HasVDouble) + { output.WriteRawTag(49); output.WriteDouble(VDouble); } - if (HasVFloat) { + if (HasVFloat) + { output.WriteRawTag(61); output.WriteFloat(VFloat); } - if (HasVBool) { + if (HasVBool) + { output.WriteRawTag(64); output.WriteBool(VBool); } - if (vString_ != null) { + if (vString_ != null) + { output.WriteRawTag(74); output.WriteMessage(VString); } - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (HasType) { - size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Type); + if (HasType) + { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int)Type); } - if (HasVSignedInt) { + if (HasVSignedInt) + { size += 1 + pb::CodedOutputStream.ComputeSInt64Size(VSignedInt); } - if (HasVUnsignedInt) { + if (HasVUnsignedInt) + { size += 1 + pb::CodedOutputStream.ComputeUInt64Size(VUnsignedInt); } - if (vOctets_ != null) { + if (vOctets_ != null) + { size += 1 + pb::CodedOutputStream.ComputeMessageSize(VOctets); } - if (HasVDouble) { + if (HasVDouble) + { size += 1 + 8; } - if (HasVFloat) { + if (HasVFloat) + { size += 1 + 4; } - if (HasVBool) { + if (HasVBool) + { size += 1 + 1; } - if (vString_ != null) { + if (vString_ != null) + { size += 1 + pb::CodedOutputStream.ComputeMessageSize(VString); } - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -504,36 +570,48 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(Scalar other) { - if (other == null) { + public void MergeFrom(Scalar other) + { + if (other == null) + { return; } - if (other.HasType) { + if (other.HasType) + { Type = other.Type; } - if (other.HasVSignedInt) { + if (other.HasVSignedInt) + { VSignedInt = other.VSignedInt; } - if (other.HasVUnsignedInt) { + if (other.HasVUnsignedInt) + { VUnsignedInt = other.VUnsignedInt; } - if (other.vOctets_ != null) { - if (vOctets_ == null) { + if (other.vOctets_ != null) + { + if (vOctets_ == null) + { VOctets = new global::Mysqlx.Datatypes.Scalar.Types.Octets(); } VOctets.MergeFrom(other.VOctets); } - if (other.HasVDouble) { + if (other.HasVDouble) + { VDouble = other.VDouble; } - if (other.HasVFloat) { + if (other.HasVFloat) + { VFloat = other.VFloat; } - if (other.HasVBool) { + if (other.HasVBool) + { VBool = other.VBool; } - if (other.vString_ != null) { - if (vString_ == null) { + if (other.vString_ != null) + { + if (vString_ == null) + { VString = new global::Mysqlx.Datatypes.Scalar.Types.String(); } VString.MergeFrom(other.VString); @@ -543,13 +621,18 @@ public void MergeFrom(Scalar other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -593,68 +676,88 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 8: { - Type = (global::Mysqlx.Datatypes.Scalar.Types.Type) input.ReadEnum(); - break; - } - case 16: { - VSignedInt = input.ReadSInt64(); - break; - } - case 24: { - VUnsignedInt = input.ReadUInt64(); - break; - } - case 42: { - if (vOctets_ == null) { - VOctets = new global::Mysqlx.Datatypes.Scalar.Types.Octets(); + case 8: + { + Type = (global::Mysqlx.Datatypes.Scalar.Types.Type)input.ReadEnum(); + break; } - input.ReadMessage(VOctets); - break; - } - case 49: { - VDouble = input.ReadDouble(); - break; - } - case 61: { - VFloat = input.ReadFloat(); - break; - } - case 64: { - VBool = input.ReadBool(); - break; - } - case 74: { - if (vString_ == null) { - VString = new global::Mysqlx.Datatypes.Scalar.Types.String(); + case 16: + { + VSignedInt = input.ReadSInt64(); + break; + } + case 24: + { + VUnsignedInt = input.ReadUInt64(); + break; + } + case 42: + { + if (vOctets_ == null) + { + VOctets = new global::Mysqlx.Datatypes.Scalar.Types.Octets(); + } + input.ReadMessage(VOctets); + break; + } + case 49: + { + VDouble = input.ReadDouble(); + break; + } + case 61: + { + VFloat = input.ReadFloat(); + break; + } + case 64: + { + VBool = input.ReadBool(); + break; + } + case 74: + { + if (vString_ == null) + { + VString = new global::Mysqlx.Datatypes.Scalar.Types.String(); + } + input.ReadMessage(VString); + break; } - input.ReadMessage(VString); - break; - } } } } - #endif +#endif #region Nested types /// Container for nested types declared in the Scalar message type. [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static partial class Types { - public enum Type { + public static partial class Types + { + public enum Type + { [pbr::OriginalName("V_SINT")] VSint = 1, [pbr::OriginalName("V_UINT")] VUint = 2, [pbr::OriginalName("V_NULL")] VNull = 3, @@ -668,10 +771,11 @@ public enum Type { /// ///* a string with a charset/collation /// + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] public sealed partial class String : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new String()); private pb::UnknownFieldSet _unknownFields; @@ -682,19 +786,22 @@ public sealed partial class String : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Datatypes.Scalar.Descriptor.NestedTypes[0]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public String() { + public String() + { OnConstruction(); } @@ -702,7 +809,8 @@ public String() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public String(String other) : this() { + public String(String other) : this() + { _hasBits0 = other._hasBits0; value_ = other.value_; collation_ = other.collation_; @@ -711,7 +819,8 @@ public String(String other) : this() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public String Clone() { + public String Clone() + { return new String(this); } @@ -722,22 +831,26 @@ public String Clone() { private pb::ByteString value_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public pb::ByteString Value { + public pb::ByteString Value + { get { return value_ ?? ValueDefaultValue; } - set { + set + { value_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); } } /// Gets whether the "value" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasValue { + public bool HasValue + { get { return value_ != null; } } /// Clears the value of the "value" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearValue() { + public void ClearValue() + { value_ = null; } @@ -748,9 +861,11 @@ public void ClearValue() { private ulong collation_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public ulong Collation { + public ulong Collation + { get { if ((_hasBits0 & 1) != 0) { return collation_; } else { return CollationDefaultValue; } } - set { + set + { _hasBits0 |= 1; collation_ = value; } @@ -758,29 +873,35 @@ public ulong Collation { /// Gets whether the "collation" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasCollation { + public bool HasCollation + { get { return (_hasBits0 & 1) != 0; } } /// Clears the value of the "collation" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearCollation() { + public void ClearCollation() + { _hasBits0 &= ~1; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as String); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(String other) { - if (ReferenceEquals(other, null)) { + public bool Equals(String other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } if (Value != other.Value) return false; @@ -790,11 +911,13 @@ public bool Equals(String other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; if (HasValue) hash ^= Value.GetHashCode(); if (HasCollation) hash ^= Collation.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -802,16 +925,18 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (HasValue) { output.WriteRawTag(10); output.WriteBytes(Value); @@ -823,38 +948,46 @@ public void WriteTo(pb::CodedOutputStream output) { if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (HasValue) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (HasValue) + { output.WriteRawTag(10); output.WriteBytes(Value); } - if (HasCollation) { + if (HasCollation) + { output.WriteRawTag(16); output.WriteUInt64(Collation); } - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (HasValue) { + if (HasValue) + { size += 1 + pb::CodedOutputStream.ComputeBytesSize(Value); } - if (HasCollation) { + if (HasCollation) + { size += 1 + pb::CodedOutputStream.ComputeUInt64Size(Collation); } - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -862,14 +995,18 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(String other) { - if (other == null) { + public void MergeFrom(String other) + { + if (other == null) + { return; } - if (other.HasValue) { + if (other.HasValue) + { Value = other.Value; } - if (other.HasCollation) { + if (other.HasCollation) + { Collation = other.Collation; } _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); @@ -877,13 +1014,18 @@ public void MergeFrom(String other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -897,31 +1039,41 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 10: { - Value = input.ReadBytes(); - break; - } - case 16: { - Collation = input.ReadUInt64(); - break; - } + case 10: + { + Value = input.ReadBytes(); + break; + } + case 16: + { + Collation = input.ReadUInt64(); + break; + } } } } - #endif +#endif } @@ -929,10 +1081,11 @@ public void MergeFrom(pb::CodedInputStream input) { ///* an opaque octet sequence, with an optional content_type ///See @ref Mysqlx::Resultset::ContentType_BYTES for list of known values. /// + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] public sealed partial class Octets : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Octets()); private pb::UnknownFieldSet _unknownFields; @@ -943,19 +1096,22 @@ public sealed partial class Octets : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Datatypes.Scalar.Descriptor.NestedTypes[1]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Octets() { + public Octets() + { OnConstruction(); } @@ -963,7 +1119,8 @@ public Octets() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Octets(Octets other) : this() { + public Octets(Octets other) : this() + { _hasBits0 = other._hasBits0; value_ = other.value_; contentType_ = other.contentType_; @@ -972,7 +1129,8 @@ public Octets(Octets other) : this() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Octets Clone() { + public Octets Clone() + { return new Octets(this); } @@ -983,22 +1141,26 @@ public Octets Clone() { private pb::ByteString value_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public pb::ByteString Value { + public pb::ByteString Value + { get { return value_ ?? ValueDefaultValue; } - set { + set + { value_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); } } /// Gets whether the "value" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasValue { + public bool HasValue + { get { return value_ != null; } } /// Clears the value of the "value" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearValue() { + public void ClearValue() + { value_ = null; } @@ -1009,9 +1171,11 @@ public void ClearValue() { private uint contentType_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public uint ContentType { + public uint ContentType + { get { if ((_hasBits0 & 1) != 0) { return contentType_; } else { return ContentTypeDefaultValue; } } - set { + set + { _hasBits0 |= 1; contentType_ = value; } @@ -1019,29 +1183,35 @@ public uint ContentType { /// Gets whether the "content_type" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasContentType { + public bool HasContentType + { get { return (_hasBits0 & 1) != 0; } } /// Clears the value of the "content_type" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearContentType() { + public void ClearContentType() + { _hasBits0 &= ~1; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as Octets); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(Octets other) { - if (ReferenceEquals(other, null)) { + public bool Equals(Octets other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } if (Value != other.Value) return false; @@ -1051,11 +1221,13 @@ public bool Equals(Octets other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; if (HasValue) hash ^= Value.GetHashCode(); if (HasContentType) hash ^= ContentType.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -1063,16 +1235,18 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (HasValue) { output.WriteRawTag(10); output.WriteBytes(Value); @@ -1084,38 +1258,46 @@ public void WriteTo(pb::CodedOutputStream output) { if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (HasValue) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (HasValue) + { output.WriteRawTag(10); output.WriteBytes(Value); } - if (HasContentType) { + if (HasContentType) + { output.WriteRawTag(16); output.WriteUInt32(ContentType); } - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (HasValue) { + if (HasValue) + { size += 1 + pb::CodedOutputStream.ComputeBytesSize(Value); } - if (HasContentType) { + if (HasContentType) + { size += 1 + pb::CodedOutputStream.ComputeUInt32Size(ContentType); } - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -1123,14 +1305,18 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(Octets other) { - if (other == null) { + public void MergeFrom(Octets other) + { + if (other == null) + { return; } - if (other.HasValue) { + if (other.HasValue) + { Value = other.Value; } - if (other.HasContentType) { + if (other.HasContentType) + { ContentType = other.ContentType; } _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); @@ -1138,13 +1324,18 @@ public void MergeFrom(Octets other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -1158,31 +1349,41 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 10: { - Value = input.ReadBytes(); - break; - } - case 16: { - ContentType = input.ReadUInt32(); - break; - } + case 10: + { + Value = input.ReadBytes(); + break; + } + case 16: + { + ContentType = input.ReadUInt32(); + break; + } } } } - #endif +#endif } @@ -1195,10 +1396,11 @@ public void MergeFrom(pb::CodedInputStream input) { ///* ///An object /// - internal sealed partial class Object : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class Object : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Object()); private pb::UnknownFieldSet _unknownFields; @@ -1208,19 +1410,22 @@ internal sealed partial class Object : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Datatypes.MysqlxDatatypesReflection.Descriptor.MessageTypes[1]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Object() { + public Object() + { OnConstruction(); } @@ -1228,14 +1433,16 @@ public Object() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Object(Object other) : this() { + public Object(Object other) : this() + { fld_ = other.fld_.Clone(); _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Object Clone() { + public Object Clone() + { return new Object(this); } @@ -1246,35 +1453,42 @@ public Object Clone() { private readonly pbc::RepeatedField fld_ = new pbc::RepeatedField(); [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public pbc::RepeatedField Fld { + public pbc::RepeatedField Fld + { get { return fld_; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as Object); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(Object other) { - if (ReferenceEquals(other, null)) { + public bool Equals(Object other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } - if(!fld_.Equals(other.fld_)) return false; + if (!fld_.Equals(other.fld_)) return false; return Equals(_unknownFields, other._unknownFields); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; hash ^= fld_.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -1282,40 +1496,46 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else fld_.WriteTo(output, _repeated_fld_codec); if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { fld_.WriteTo(ref output, _repeated_fld_codec); - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; size += fld_.CalculateSize(_repeated_fld_codec); - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -1323,8 +1543,10 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(Object other) { - if (other == null) { + public void MergeFrom(Object other) + { + if (other == null) + { return; } fld_.Add(other.fld_); @@ -1333,13 +1555,18 @@ public void MergeFrom(Object other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -1349,37 +1576,48 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 10: { - fld_.AddEntriesFrom(ref input, _repeated_fld_codec); - break; - } + case 10: + { + fld_.AddEntriesFrom(ref input, _repeated_fld_codec); + break; + } } } } - #endif +#endif #region Nested types /// Container for nested types declared in the Object message type. [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static partial class Types { + public static partial class Types + { + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] public sealed partial class ObjectField : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ObjectField()); private pb::UnknownFieldSet _unknownFields; @@ -1389,19 +1627,22 @@ public sealed partial class ObjectField : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Datatypes.Object.Descriptor.NestedTypes[0]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public ObjectField() { + public ObjectField() + { OnConstruction(); } @@ -1409,7 +1650,8 @@ public ObjectField() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public ObjectField(ObjectField other) : this() { + public ObjectField(ObjectField other) : this() + { key_ = other.key_; value_ = other.value_ != null ? other.value_.Clone() : null; _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); @@ -1417,7 +1659,8 @@ public ObjectField(ObjectField other) : this() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public ObjectField Clone() { + public ObjectField Clone() + { return new ObjectField(this); } @@ -1428,22 +1671,26 @@ public ObjectField Clone() { private string key_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public string Key { + public string Key + { get { return key_ ?? KeyDefaultValue; } - set { + set + { key_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); } } /// Gets whether the "key" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasKey { + public bool HasKey + { get { return key_ != null; } } /// Clears the value of the "key" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearKey() { + public void ClearKey() + { key_ = null; } @@ -1452,26 +1699,32 @@ public void ClearKey() { private global::Mysqlx.Datatypes.Any value_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Datatypes.Any Value { + public global::Mysqlx.Datatypes.Any Value + { get { return value_; } - set { + set + { value_ = value; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as ObjectField); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(ObjectField other) { - if (ReferenceEquals(other, null)) { + public bool Equals(ObjectField other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } if (Key != other.Key) return false; @@ -1481,11 +1734,13 @@ public bool Equals(ObjectField other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; if (HasKey) hash ^= Key.GetHashCode(); if (value_ != null) hash ^= Value.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -1493,16 +1748,18 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (HasKey) { output.WriteRawTag(10); output.WriteString(Key); @@ -1514,38 +1771,46 @@ public void WriteTo(pb::CodedOutputStream output) { if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (HasKey) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (HasKey) + { output.WriteRawTag(10); output.WriteString(Key); } - if (value_ != null) { + if (value_ != null) + { output.WriteRawTag(18); output.WriteMessage(Value); } - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (HasKey) { + if (HasKey) + { size += 1 + pb::CodedOutputStream.ComputeStringSize(Key); } - if (value_ != null) { + if (value_ != null) + { size += 1 + pb::CodedOutputStream.ComputeMessageSize(Value); } - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -1553,15 +1818,20 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(ObjectField other) { - if (other == null) { + public void MergeFrom(ObjectField other) + { + if (other == null) + { return; } - if (other.HasKey) { + if (other.HasKey) + { Key = other.Key; } - if (other.value_ != null) { - if (value_ == null) { + if (other.value_ != null) + { + if (value_ == null) + { Value = new global::Mysqlx.Datatypes.Any(); } Value.MergeFrom(other.Value); @@ -1571,13 +1841,18 @@ public void MergeFrom(ObjectField other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -1594,34 +1869,45 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 10: { - Key = input.ReadString(); - break; - } - case 18: { - if (value_ == null) { - Value = new global::Mysqlx.Datatypes.Any(); + case 10: + { + Key = input.ReadString(); + break; + } + case 18: + { + if (value_ == null) + { + Value = new global::Mysqlx.Datatypes.Any(); + } + input.ReadMessage(Value); + break; } - input.ReadMessage(Value); - break; - } } } } - #endif +#endif } @@ -1634,10 +1920,11 @@ public void MergeFrom(pb::CodedInputStream input) { ///* ///An Array /// - internal sealed partial class Array : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class Array : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Array()); private pb::UnknownFieldSet _unknownFields; @@ -1647,19 +1934,22 @@ internal sealed partial class Array : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Datatypes.MysqlxDatatypesReflection.Descriptor.MessageTypes[2]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Array() { + public Array() + { OnConstruction(); } @@ -1667,14 +1957,16 @@ public Array() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Array(Array other) : this() { + public Array(Array other) : this() + { value_ = other.value_.Clone(); _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Array Clone() { + public Array Clone() + { return new Array(this); } @@ -1685,35 +1977,42 @@ public Array Clone() { private readonly pbc::RepeatedField value_ = new pbc::RepeatedField(); [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public pbc::RepeatedField Value { + public pbc::RepeatedField Value + { get { return value_; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as Array); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(Array other) { - if (ReferenceEquals(other, null)) { + public bool Equals(Array other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } - if(!value_.Equals(other.value_)) return false; + if (!value_.Equals(other.value_)) return false; return Equals(_unknownFields, other._unknownFields); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; hash ^= value_.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -1721,40 +2020,46 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else value_.WriteTo(output, _repeated_value_codec); if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { value_.WriteTo(ref output, _repeated_value_codec); - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; size += value_.CalculateSize(_repeated_value_codec); - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -1762,8 +2067,10 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(Array other) { - if (other == null) { + public void MergeFrom(Array other) + { + if (other == null) + { return; } value_.Add(other.value_); @@ -1772,13 +2079,18 @@ public void MergeFrom(Array other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -1788,27 +2100,36 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 10: { - value_.AddEntriesFrom(ref input, _repeated_value_codec); - break; - } + case 10: + { + value_.AddEntriesFrom(ref input, _repeated_value_codec); + break; + } } } } - #endif +#endif } @@ -1816,10 +2137,11 @@ public void MergeFrom(pb::CodedInputStream input) { ///* ///A helper to allow all field types /// - internal sealed partial class Any : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class Any : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Any()); private pb::UnknownFieldSet _unknownFields; @@ -1830,19 +2152,22 @@ internal sealed partial class Any : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Datatypes.MysqlxDatatypesReflection.Descriptor.MessageTypes[3]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Any() { + public Any() + { OnConstruction(); } @@ -1850,7 +2175,8 @@ public Any() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Any(Any other) : this() { + public Any(Any other) : this() + { _hasBits0 = other._hasBits0; type_ = other.type_; scalar_ = other.scalar_ != null ? other.scalar_.Clone() : null; @@ -1861,7 +2187,8 @@ public Any(Any other) : this() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Any Clone() { + public Any Clone() + { return new Any(this); } @@ -1872,9 +2199,11 @@ public Any Clone() { private global::Mysqlx.Datatypes.Any.Types.Type type_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Datatypes.Any.Types.Type Type { + public global::Mysqlx.Datatypes.Any.Types.Type Type + { get { if ((_hasBits0 & 1) != 0) { return type_; } else { return TypeDefaultValue; } } - set { + set + { _hasBits0 |= 1; type_ = value; } @@ -1882,13 +2211,15 @@ public Any Clone() { /// Gets whether the "type" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasType { + public bool HasType + { get { return (_hasBits0 & 1) != 0; } } /// Clears the value of the "type" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearType() { + public void ClearType() + { _hasBits0 &= ~1; } @@ -1897,9 +2228,11 @@ public void ClearType() { private global::Mysqlx.Datatypes.Scalar scalar_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Datatypes.Scalar Scalar { + public global::Mysqlx.Datatypes.Scalar Scalar + { get { return scalar_; } - set { + set + { scalar_ = value; } } @@ -1909,9 +2242,11 @@ public void ClearType() { private global::Mysqlx.Datatypes.Object obj_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Datatypes.Object Obj { + public global::Mysqlx.Datatypes.Object Obj + { get { return obj_; } - set { + set + { obj_ = value; } } @@ -1921,26 +2256,32 @@ public void ClearType() { private global::Mysqlx.Datatypes.Array array_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Datatypes.Array Array { + public global::Mysqlx.Datatypes.Array Array + { get { return array_; } - set { + set + { array_ = value; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as Any); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(Any other) { - if (ReferenceEquals(other, null)) { + public bool Equals(Any other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } if (Type != other.Type) return false; @@ -1952,13 +2293,15 @@ public bool Equals(Any other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; if (HasType) hash ^= Type.GetHashCode(); if (scalar_ != null) hash ^= Scalar.GetHashCode(); if (obj_ != null) hash ^= Obj.GetHashCode(); if (array_ != null) hash ^= Array.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -1966,16 +2309,18 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (HasType) { output.WriteRawTag(8); output.WriteEnum((int) Type); @@ -1995,52 +2340,64 @@ public void WriteTo(pb::CodedOutputStream output) { if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (HasType) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (HasType) + { output.WriteRawTag(8); - output.WriteEnum((int) Type); + output.WriteEnum((int)Type); } - if (scalar_ != null) { + if (scalar_ != null) + { output.WriteRawTag(18); output.WriteMessage(Scalar); } - if (obj_ != null) { + if (obj_ != null) + { output.WriteRawTag(26); output.WriteMessage(Obj); } - if (array_ != null) { + if (array_ != null) + { output.WriteRawTag(34); output.WriteMessage(Array); } - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (HasType) { - size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Type); + if (HasType) + { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int)Type); } - if (scalar_ != null) { + if (scalar_ != null) + { size += 1 + pb::CodedOutputStream.ComputeMessageSize(Scalar); } - if (obj_ != null) { + if (obj_ != null) + { size += 1 + pb::CodedOutputStream.ComputeMessageSize(Obj); } - if (array_ != null) { + if (array_ != null) + { size += 1 + pb::CodedOutputStream.ComputeMessageSize(Array); } - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -2048,27 +2405,36 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(Any other) { - if (other == null) { + public void MergeFrom(Any other) + { + if (other == null) + { return; } - if (other.HasType) { + if (other.HasType) + { Type = other.Type; } - if (other.scalar_ != null) { - if (scalar_ == null) { + if (other.scalar_ != null) + { + if (scalar_ == null) + { Scalar = new global::Mysqlx.Datatypes.Scalar(); } Scalar.MergeFrom(other.Scalar); } - if (other.obj_ != null) { - if (obj_ == null) { + if (other.obj_ != null) + { + if (obj_ == null) + { Obj = new global::Mysqlx.Datatypes.Object(); } Obj.MergeFrom(other.Obj); } - if (other.array_ != null) { - if (array_ == null) { + if (other.array_ != null) + { + if (array_ == null) + { Array = new global::Mysqlx.Datatypes.Array(); } Array.MergeFrom(other.Array); @@ -2078,13 +2444,18 @@ public void MergeFrom(Any other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -2115,55 +2486,72 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 8: { - Type = (global::Mysqlx.Datatypes.Any.Types.Type) input.ReadEnum(); - break; - } - case 18: { - if (scalar_ == null) { - Scalar = new global::Mysqlx.Datatypes.Scalar(); + case 8: + { + Type = (global::Mysqlx.Datatypes.Any.Types.Type)input.ReadEnum(); + break; } - input.ReadMessage(Scalar); - break; - } - case 26: { - if (obj_ == null) { - Obj = new global::Mysqlx.Datatypes.Object(); + case 18: + { + if (scalar_ == null) + { + Scalar = new global::Mysqlx.Datatypes.Scalar(); + } + input.ReadMessage(Scalar); + break; } - input.ReadMessage(Obj); - break; - } - case 34: { - if (array_ == null) { - Array = new global::Mysqlx.Datatypes.Array(); + case 26: + { + if (obj_ == null) + { + Obj = new global::Mysqlx.Datatypes.Object(); + } + input.ReadMessage(Obj); + break; + } + case 34: + { + if (array_ == null) + { + Array = new global::Mysqlx.Datatypes.Array(); + } + input.ReadMessage(Array); + break; } - input.ReadMessage(Array); - break; - } } } } - #endif +#endif #region Nested types /// Container for nested types declared in the Any message type. [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static partial class Types { - public enum Type { + public static partial class Types + { + public enum Type + { [pbr::OriginalName("SCALAR")] Scalar = 1, [pbr::OriginalName("OBJECT")] Object = 2, [pbr::OriginalName("ARRAY")] Array = 3, @@ -2179,3 +2567,4 @@ public enum Type { } #endregion Designer generated code + diff --git a/MySQL.Data/src/X/Protocol/X/Protobuf/MysqlxExpect.cs b/MySQL.Data/src/X/Protocol/X/Protobuf/MysqlxExpect.cs index 4e994c039..0c92b140e 100644 --- a/MySQL.Data/src/X/Protocol/X/Protobuf/MysqlxExpect.cs +++ b/MySQL.Data/src/X/Protocol/X/Protobuf/MysqlxExpect.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2022, 2023, Oracle and/or its affiliates. +// Copyright © 2022, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -37,19 +37,23 @@ using pbc = global::Google.Protobuf.Collections; using pbr = global::Google.Protobuf.Reflection; using scg = global::System.Collections.Generic; -namespace Mysqlx.Expect { +namespace Mysqlx.Expect +{ /// Holder for reflection information generated from mysqlx_expect.proto - internal static partial class MysqlxExpectReflection { + public static partial class MysqlxExpectReflection + { #region Descriptor /// File descriptor for mysqlx_expect.proto - internal static pbr::FileDescriptor Descriptor { + public static pbr::FileDescriptor Descriptor + { get { return descriptor; } } private static pbr::FileDescriptor descriptor; - static MysqlxExpectReflection() { + static MysqlxExpectReflection() + { byte[] descriptorData = global::System.Convert.FromBase64String( string.Concat( "ChNteXNxbHhfZXhwZWN0LnByb3RvEg1NeXNxbHguRXhwZWN0GgxteXNxbHgu", @@ -86,10 +90,11 @@ static MysqlxExpectReflection() { /// ///@returns @ref Mysqlx::Ok on success, @ref Mysqlx::Error on error /// - internal sealed partial class Open : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class Open : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Open()); private pb::UnknownFieldSet _unknownFields; @@ -100,19 +105,22 @@ internal sealed partial class Open : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Expect.MysqlxExpectReflection.Descriptor.MessageTypes[0]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Open() { + public Open() + { OnConstruction(); } @@ -120,7 +128,8 @@ public Open() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Open(Open other) : this() { + public Open(Open other) : this() + { _hasBits0 = other._hasBits0; op_ = other.op_; cond_ = other.cond_.Clone(); @@ -129,7 +138,8 @@ public Open(Open other) : this() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Open Clone() { + public Open Clone() + { return new Open(this); } @@ -140,9 +150,11 @@ public Open Clone() { private global::Mysqlx.Expect.Open.Types.CtxOperation op_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Expect.Open.Types.CtxOperation Op { + public global::Mysqlx.Expect.Open.Types.CtxOperation Op + { get { if ((_hasBits0 & 1) != 0) { return op_; } else { return OpDefaultValue; } } - set { + set + { _hasBits0 |= 1; op_ = value; } @@ -150,13 +162,15 @@ public Open Clone() { /// Gets whether the "op" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasOp { + public bool HasOp + { get { return (_hasBits0 & 1) != 0; } } /// Clears the value of the "op" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearOp() { + public void ClearOp() + { _hasBits0 &= ~1; } @@ -167,37 +181,44 @@ public void ClearOp() { private readonly pbc::RepeatedField cond_ = new pbc::RepeatedField(); [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public pbc::RepeatedField Cond { + public pbc::RepeatedField Cond + { get { return cond_; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as Open); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(Open other) { - if (ReferenceEquals(other, null)) { + public bool Equals(Open other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } if (Op != other.Op) return false; - if(!cond_.Equals(other.cond_)) return false; + if (!cond_.Equals(other.cond_)) return false; return Equals(_unknownFields, other._unknownFields); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; if (HasOp) hash ^= Op.GetHashCode(); hash ^= cond_.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -205,16 +226,18 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (HasOp) { output.WriteRawTag(8); output.WriteEnum((int) Op); @@ -223,33 +246,39 @@ public void WriteTo(pb::CodedOutputStream output) { if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (HasOp) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (HasOp) + { output.WriteRawTag(8); - output.WriteEnum((int) Op); + output.WriteEnum((int)Op); } cond_.WriteTo(ref output, _repeated_cond_codec); - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (HasOp) { - size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Op); + if (HasOp) + { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int)Op); } size += cond_.CalculateSize(_repeated_cond_codec); - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -257,11 +286,14 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(Open other) { - if (other == null) { + public void MergeFrom(Open other) + { + if (other == null) + { return; } - if (other.HasOp) { + if (other.HasOp) + { Op = other.Op; } cond_.Add(other.cond_); @@ -270,13 +302,18 @@ public void MergeFrom(Open other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -290,38 +327,50 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 8: { - Op = (global::Mysqlx.Expect.Open.Types.CtxOperation) input.ReadEnum(); - break; - } - case 18: { - cond_.AddEntriesFrom(ref input, _repeated_cond_codec); - break; - } + case 8: + { + Op = (global::Mysqlx.Expect.Open.Types.CtxOperation)input.ReadEnum(); + break; + } + case 18: + { + cond_.AddEntriesFrom(ref input, _repeated_cond_codec); + break; + } } } } - #endif +#endif #region Nested types /// Container for nested types declared in the Open message type. [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static partial class Types { - public enum CtxOperation { + public static partial class Types + { + public enum CtxOperation + { /// ///* copy the operations from the parent Expect-block /// @@ -332,10 +381,11 @@ public enum CtxOperation { [pbr::OriginalName("EXPECT_CTX_EMPTY")] ExpectCtxEmpty = 1, } + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] public sealed partial class Condition : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Condition()); private pb::UnknownFieldSet _unknownFields; @@ -346,19 +396,22 @@ public sealed partial class Condition : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Expect.Open.Descriptor.NestedTypes[0]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Condition() { + public Condition() + { OnConstruction(); } @@ -366,7 +419,8 @@ public Condition() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Condition(Condition other) : this() { + public Condition(Condition other) : this() + { _hasBits0 = other._hasBits0; conditionKey_ = other.conditionKey_; conditionValue_ = other.conditionValue_; @@ -376,7 +430,8 @@ public Condition(Condition other) : this() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Condition Clone() { + public Condition Clone() + { return new Condition(this); } @@ -387,9 +442,11 @@ public Condition Clone() { private uint conditionKey_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public uint ConditionKey { + public uint ConditionKey + { get { if ((_hasBits0 & 1) != 0) { return conditionKey_; } else { return ConditionKeyDefaultValue; } } - set { + set + { _hasBits0 |= 1; conditionKey_ = value; } @@ -397,13 +454,15 @@ public uint ConditionKey { /// Gets whether the "condition_key" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasConditionKey { + public bool HasConditionKey + { get { return (_hasBits0 & 1) != 0; } } /// Clears the value of the "condition_key" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearConditionKey() { + public void ClearConditionKey() + { _hasBits0 &= ~1; } @@ -414,22 +473,26 @@ public void ClearConditionKey() { private pb::ByteString conditionValue_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public pb::ByteString ConditionValue { + public pb::ByteString ConditionValue + { get { return conditionValue_ ?? ConditionValueDefaultValue; } - set { + set + { conditionValue_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); } } /// Gets whether the "condition_value" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasConditionValue { + public bool HasConditionValue + { get { return conditionValue_ != null; } } /// Clears the value of the "condition_value" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearConditionValue() { + public void ClearConditionValue() + { conditionValue_ = null; } @@ -440,9 +503,11 @@ public void ClearConditionValue() { private global::Mysqlx.Expect.Open.Types.Condition.Types.ConditionOperation op_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Expect.Open.Types.Condition.Types.ConditionOperation Op { + public global::Mysqlx.Expect.Open.Types.Condition.Types.ConditionOperation Op + { get { if ((_hasBits0 & 2) != 0) { return op_; } else { return OpDefaultValue; } } - set { + set + { _hasBits0 |= 2; op_ = value; } @@ -450,29 +515,35 @@ public void ClearConditionValue() { /// Gets whether the "op" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasOp { + public bool HasOp + { get { return (_hasBits0 & 2) != 0; } } /// Clears the value of the "op" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearOp() { + public void ClearOp() + { _hasBits0 &= ~2; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as Condition); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(Condition other) { - if (ReferenceEquals(other, null)) { + public bool Equals(Condition other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } if (ConditionKey != other.ConditionKey) return false; @@ -483,12 +554,14 @@ public bool Equals(Condition other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; if (HasConditionKey) hash ^= ConditionKey.GetHashCode(); if (HasConditionValue) hash ^= ConditionValue.GetHashCode(); if (HasOp) hash ^= Op.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -496,16 +569,18 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (HasConditionKey) { output.WriteRawTag(8); output.WriteUInt32(ConditionKey); @@ -521,45 +596,55 @@ public void WriteTo(pb::CodedOutputStream output) { if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (HasConditionKey) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (HasConditionKey) + { output.WriteRawTag(8); output.WriteUInt32(ConditionKey); } - if (HasConditionValue) { + if (HasConditionValue) + { output.WriteRawTag(18); output.WriteBytes(ConditionValue); } - if (HasOp) { + if (HasOp) + { output.WriteRawTag(24); - output.WriteEnum((int) Op); + output.WriteEnum((int)Op); } - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (HasConditionKey) { + if (HasConditionKey) + { size += 1 + pb::CodedOutputStream.ComputeUInt32Size(ConditionKey); } - if (HasConditionValue) { + if (HasConditionValue) + { size += 1 + pb::CodedOutputStream.ComputeBytesSize(ConditionValue); } - if (HasOp) { - size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Op); + if (HasOp) + { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int)Op); } - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -567,17 +652,22 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(Condition other) { - if (other == null) { + public void MergeFrom(Condition other) + { + if (other == null) + { return; } - if (other.HasConditionKey) { + if (other.HasConditionKey) + { ConditionKey = other.ConditionKey; } - if (other.HasConditionValue) { + if (other.HasConditionValue) + { ConditionValue = other.ConditionValue; } - if (other.HasOp) { + if (other.HasOp) + { Op = other.Op; } _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); @@ -585,13 +675,18 @@ public void MergeFrom(Condition other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -609,42 +704,55 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 8: { - ConditionKey = input.ReadUInt32(); - break; - } - case 18: { - ConditionValue = input.ReadBytes(); - break; - } - case 24: { - Op = (global::Mysqlx.Expect.Open.Types.Condition.Types.ConditionOperation) input.ReadEnum(); - break; - } + case 8: + { + ConditionKey = input.ReadUInt32(); + break; + } + case 18: + { + ConditionValue = input.ReadBytes(); + break; + } + case 24: + { + Op = (global::Mysqlx.Expect.Open.Types.Condition.Types.ConditionOperation)input.ReadEnum(); + break; + } } } } - #endif +#endif #region Nested types /// Container for nested types declared in the Condition message type. [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static partial class Types { - public enum Key { + public static partial class Types + { + public enum Key + { /// ///* Change error propagation behaviour /// @@ -659,7 +767,8 @@ public enum Key { [pbr::OriginalName("EXPECT_DOCID_GENERATED")] ExpectDocidGenerated = 3, } - public enum ConditionOperation { + public enum ConditionOperation + { /// ///* set the condition; set, if not set; overwrite, if set /// @@ -689,10 +798,11 @@ public enum ConditionOperation { /// ///@returns @ref Mysqlx::Ok on success, @ref Mysqlx::Error on error /// - internal sealed partial class Close : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class Close : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Close()); private pb::UnknownFieldSet _unknownFields; @@ -702,19 +812,22 @@ internal sealed partial class Close : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Expect.MysqlxExpectReflection.Descriptor.MessageTypes[1]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Close() { + public Close() + { OnConstruction(); } @@ -722,29 +835,35 @@ public Close() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Close(Close other) : this() { + public Close(Close other) : this() + { _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Close Clone() { + public Close Clone() + { return new Close(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as Close); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(Close other) { - if (ReferenceEquals(other, null)) { + public bool Equals(Close other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } return Equals(_unknownFields, other._unknownFields); @@ -752,9 +871,11 @@ public bool Equals(Close other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -762,37 +883,43 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (_unknownFields != null) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -800,8 +927,10 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(Close other) { - if (other == null) { + public void MergeFrom(Close other) + { + if (other == null) + { return; } _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); @@ -809,35 +938,48 @@ public void MergeFrom(Close other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; } } } - #endif +#endif } @@ -846,3 +988,4 @@ public void MergeFrom(pb::CodedInputStream input) { } #endregion Designer generated code + diff --git a/MySQL.Data/src/X/Protocol/X/Protobuf/MysqlxExpr.cs b/MySQL.Data/src/X/Protocol/X/Protobuf/MysqlxExpr.cs index 3714a77d2..dcb51f823 100644 --- a/MySQL.Data/src/X/Protocol/X/Protobuf/MysqlxExpr.cs +++ b/MySQL.Data/src/X/Protocol/X/Protobuf/MysqlxExpr.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2022, 2023, Oracle and/or its affiliates. +// Copyright © 2022, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -37,19 +37,23 @@ using pbc = global::Google.Protobuf.Collections; using pbr = global::Google.Protobuf.Reflection; using scg = global::System.Collections.Generic; -namespace Mysqlx.Expr { +namespace Mysqlx.Expr +{ /// Holder for reflection information generated from mysqlx_expr.proto - internal static partial class MysqlxExprReflection { + public static partial class MysqlxExprReflection + { #region Descriptor /// File descriptor for mysqlx_expr.proto - internal static pbr::FileDescriptor Descriptor { + public static pbr::FileDescriptor Descriptor + { get { return descriptor; } } private static pbr::FileDescriptor descriptor; - static MysqlxExprReflection() { + static MysqlxExprReflection() + { byte[] descriptorData = global::System.Convert.FromBase64String( string.Concat( "ChFteXNxbHhfZXhwci5wcm90bxILTXlzcWx4LkV4cHIaFm15c3FseF9kYXRh", @@ -119,10 +123,11 @@ static MysqlxExprReflection() { ///: placeholder ///@endcode /// - internal sealed partial class Expr : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class Expr : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Expr()); private pb::UnknownFieldSet _unknownFields; @@ -133,19 +138,22 @@ internal sealed partial class Expr : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Expr.MysqlxExprReflection.Descriptor.MessageTypes[0]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Expr() { + public Expr() + { OnConstruction(); } @@ -153,7 +161,8 @@ public Expr() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Expr(Expr other) : this() { + public Expr(Expr other) : this() + { _hasBits0 = other._hasBits0; type_ = other.type_; identifier_ = other.identifier_ != null ? other.identifier_.Clone() : null; @@ -169,7 +178,8 @@ public Expr(Expr other) : this() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Expr Clone() { + public Expr Clone() + { return new Expr(this); } @@ -180,9 +190,11 @@ public Expr Clone() { private global::Mysqlx.Expr.Expr.Types.Type type_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Expr.Expr.Types.Type Type { + public global::Mysqlx.Expr.Expr.Types.Type Type + { get { if ((_hasBits0 & 1) != 0) { return type_; } else { return TypeDefaultValue; } } - set { + set + { _hasBits0 |= 1; type_ = value; } @@ -190,13 +202,15 @@ public Expr Clone() { /// Gets whether the "type" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasType { + public bool HasType + { get { return (_hasBits0 & 1) != 0; } } /// Clears the value of the "type" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearType() { + public void ClearType() + { _hasBits0 &= ~1; } @@ -205,9 +219,11 @@ public void ClearType() { private global::Mysqlx.Expr.ColumnIdentifier identifier_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Expr.ColumnIdentifier Identifier { + public global::Mysqlx.Expr.ColumnIdentifier Identifier + { get { return identifier_; } - set { + set + { identifier_ = value; } } @@ -219,22 +235,26 @@ public void ClearType() { private string variable_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public string Variable { + public string Variable + { get { return variable_ ?? VariableDefaultValue; } - set { + set + { variable_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); } } /// Gets whether the "variable" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasVariable { + public bool HasVariable + { get { return variable_ != null; } } /// Clears the value of the "variable" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearVariable() { + public void ClearVariable() + { variable_ = null; } @@ -243,9 +263,11 @@ public void ClearVariable() { private global::Mysqlx.Datatypes.Scalar literal_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Datatypes.Scalar Literal { + public global::Mysqlx.Datatypes.Scalar Literal + { get { return literal_; } - set { + set + { literal_ = value; } } @@ -255,9 +277,11 @@ public void ClearVariable() { private global::Mysqlx.Expr.FunctionCall functionCall_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Expr.FunctionCall FunctionCall { + public global::Mysqlx.Expr.FunctionCall FunctionCall + { get { return functionCall_; } - set { + set + { functionCall_ = value; } } @@ -267,9 +291,11 @@ public void ClearVariable() { private global::Mysqlx.Expr.Operator operator_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Expr.Operator Operator { + public global::Mysqlx.Expr.Operator Operator + { get { return operator_; } - set { + set + { operator_ = value; } } @@ -281,9 +307,11 @@ public void ClearVariable() { private uint position_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public uint Position { + public uint Position + { get { if ((_hasBits0 & 2) != 0) { return position_; } else { return PositionDefaultValue; } } - set { + set + { _hasBits0 |= 2; position_ = value; } @@ -291,13 +319,15 @@ public uint Position { /// Gets whether the "position" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasPosition { + public bool HasPosition + { get { return (_hasBits0 & 2) != 0; } } /// Clears the value of the "position" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearPosition() { + public void ClearPosition() + { _hasBits0 &= ~2; } @@ -306,9 +336,11 @@ public void ClearPosition() { private global::Mysqlx.Expr.Object object_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Expr.Object Object { + public global::Mysqlx.Expr.Object Object + { get { return object_; } - set { + set + { object_ = value; } } @@ -318,26 +350,32 @@ public void ClearPosition() { private global::Mysqlx.Expr.Array array_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Expr.Array Array { + public global::Mysqlx.Expr.Array Array + { get { return array_; } - set { + set + { array_ = value; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as Expr); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(Expr other) { - if (ReferenceEquals(other, null)) { + public bool Equals(Expr other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } if (Type != other.Type) return false; @@ -354,7 +392,8 @@ public bool Equals(Expr other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; if (HasType) hash ^= Type.GetHashCode(); if (identifier_ != null) hash ^= Identifier.GetHashCode(); @@ -365,7 +404,8 @@ public override int GetHashCode() { if (HasPosition) hash ^= Position.GetHashCode(); if (object_ != null) hash ^= Object.GetHashCode(); if (array_ != null) hash ^= Array.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -373,16 +413,18 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (HasType) { output.WriteRawTag(8); output.WriteEnum((int) Type); @@ -422,87 +464,109 @@ public void WriteTo(pb::CodedOutputStream output) { if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (HasType) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (HasType) + { output.WriteRawTag(8); - output.WriteEnum((int) Type); + output.WriteEnum((int)Type); } - if (identifier_ != null) { + if (identifier_ != null) + { output.WriteRawTag(18); output.WriteMessage(Identifier); } - if (HasVariable) { + if (HasVariable) + { output.WriteRawTag(26); output.WriteString(Variable); } - if (literal_ != null) { + if (literal_ != null) + { output.WriteRawTag(34); output.WriteMessage(Literal); } - if (functionCall_ != null) { + if (functionCall_ != null) + { output.WriteRawTag(42); output.WriteMessage(FunctionCall); } - if (operator_ != null) { + if (operator_ != null) + { output.WriteRawTag(50); output.WriteMessage(Operator); } - if (HasPosition) { + if (HasPosition) + { output.WriteRawTag(56); output.WriteUInt32(Position); } - if (object_ != null) { + if (object_ != null) + { output.WriteRawTag(66); output.WriteMessage(Object); } - if (array_ != null) { + if (array_ != null) + { output.WriteRawTag(74); output.WriteMessage(Array); } - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (HasType) { - size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Type); + if (HasType) + { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int)Type); } - if (identifier_ != null) { + if (identifier_ != null) + { size += 1 + pb::CodedOutputStream.ComputeMessageSize(Identifier); } - if (HasVariable) { + if (HasVariable) + { size += 1 + pb::CodedOutputStream.ComputeStringSize(Variable); } - if (literal_ != null) { + if (literal_ != null) + { size += 1 + pb::CodedOutputStream.ComputeMessageSize(Literal); } - if (functionCall_ != null) { + if (functionCall_ != null) + { size += 1 + pb::CodedOutputStream.ComputeMessageSize(FunctionCall); } - if (operator_ != null) { + if (operator_ != null) + { size += 1 + pb::CodedOutputStream.ComputeMessageSize(Operator); } - if (HasPosition) { + if (HasPosition) + { size += 1 + pb::CodedOutputStream.ComputeUInt32Size(Position); } - if (object_ != null) { + if (object_ != null) + { size += 1 + pb::CodedOutputStream.ComputeMessageSize(Object); } - if (array_ != null) { + if (array_ != null) + { size += 1 + pb::CodedOutputStream.ComputeMessageSize(Array); } - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -510,51 +574,68 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(Expr other) { - if (other == null) { + public void MergeFrom(Expr other) + { + if (other == null) + { return; } - if (other.HasType) { + if (other.HasType) + { Type = other.Type; } - if (other.identifier_ != null) { - if (identifier_ == null) { + if (other.identifier_ != null) + { + if (identifier_ == null) + { Identifier = new global::Mysqlx.Expr.ColumnIdentifier(); } Identifier.MergeFrom(other.Identifier); } - if (other.HasVariable) { + if (other.HasVariable) + { Variable = other.Variable; } - if (other.literal_ != null) { - if (literal_ == null) { + if (other.literal_ != null) + { + if (literal_ == null) + { Literal = new global::Mysqlx.Datatypes.Scalar(); } Literal.MergeFrom(other.Literal); } - if (other.functionCall_ != null) { - if (functionCall_ == null) { + if (other.functionCall_ != null) + { + if (functionCall_ == null) + { FunctionCall = new global::Mysqlx.Expr.FunctionCall(); } FunctionCall.MergeFrom(other.FunctionCall); } - if (other.operator_ != null) { - if (operator_ == null) { + if (other.operator_ != null) + { + if (operator_ == null) + { Operator = new global::Mysqlx.Expr.Operator(); } Operator.MergeFrom(other.Operator); } - if (other.HasPosition) { + if (other.HasPosition) + { Position = other.Position; } - if (other.object_ != null) { - if (object_ == null) { + if (other.object_ != null) + { + if (object_ == null) + { Object = new global::Mysqlx.Expr.Object(); } Object.MergeFrom(other.Object); } - if (other.array_ != null) { - if (array_ == null) { + if (other.array_ != null) + { + if (array_ == null) + { Array = new global::Mysqlx.Expr.Array(); } Array.MergeFrom(other.Array); @@ -564,13 +645,18 @@ public void MergeFrom(Expr other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -630,84 +716,109 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 8: { - Type = (global::Mysqlx.Expr.Expr.Types.Type) input.ReadEnum(); - break; - } - case 18: { - if (identifier_ == null) { - Identifier = new global::Mysqlx.Expr.ColumnIdentifier(); + case 8: + { + Type = (global::Mysqlx.Expr.Expr.Types.Type)input.ReadEnum(); + break; } - input.ReadMessage(Identifier); - break; - } - case 26: { - Variable = input.ReadString(); - break; - } - case 34: { - if (literal_ == null) { - Literal = new global::Mysqlx.Datatypes.Scalar(); + case 18: + { + if (identifier_ == null) + { + Identifier = new global::Mysqlx.Expr.ColumnIdentifier(); + } + input.ReadMessage(Identifier); + break; } - input.ReadMessage(Literal); - break; - } - case 42: { - if (functionCall_ == null) { - FunctionCall = new global::Mysqlx.Expr.FunctionCall(); + case 26: + { + Variable = input.ReadString(); + break; } - input.ReadMessage(FunctionCall); - break; - } - case 50: { - if (operator_ == null) { - Operator = new global::Mysqlx.Expr.Operator(); + case 34: + { + if (literal_ == null) + { + Literal = new global::Mysqlx.Datatypes.Scalar(); + } + input.ReadMessage(Literal); + break; } - input.ReadMessage(Operator); - break; - } - case 56: { - Position = input.ReadUInt32(); - break; - } - case 66: { - if (object_ == null) { - Object = new global::Mysqlx.Expr.Object(); + case 42: + { + if (functionCall_ == null) + { + FunctionCall = new global::Mysqlx.Expr.FunctionCall(); + } + input.ReadMessage(FunctionCall); + break; } - input.ReadMessage(Object); - break; - } - case 74: { - if (array_ == null) { - Array = new global::Mysqlx.Expr.Array(); + case 50: + { + if (operator_ == null) + { + Operator = new global::Mysqlx.Expr.Operator(); + } + input.ReadMessage(Operator); + break; + } + case 56: + { + Position = input.ReadUInt32(); + break; + } + case 66: + { + if (object_ == null) + { + Object = new global::Mysqlx.Expr.Object(); + } + input.ReadMessage(Object); + break; + } + case 74: + { + if (array_ == null) + { + Array = new global::Mysqlx.Expr.Array(); + } + input.ReadMessage(Array); + break; } - input.ReadMessage(Array); - break; - } } } } - #endif +#endif #region Nested types /// Container for nested types declared in the Expr message type. [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static partial class Types { - public enum Type { + public static partial class Types + { + public enum Type + { [pbr::OriginalName("IDENT")] Ident = 1, [pbr::OriginalName("LITERAL")] Literal = 2, [pbr::OriginalName("VARIABLE")] Variable = 3, @@ -733,10 +844,11 @@ public enum Type { ///: string ///@endcode /// - internal sealed partial class Identifier : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class Identifier : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Identifier()); private pb::UnknownFieldSet _unknownFields; @@ -746,19 +858,22 @@ internal sealed partial class Identifier : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Expr.MysqlxExprReflection.Descriptor.MessageTypes[1]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Identifier() { + public Identifier() + { OnConstruction(); } @@ -766,7 +881,8 @@ public Identifier() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Identifier(Identifier other) : this() { + public Identifier(Identifier other) : this() + { name_ = other.name_; schemaName_ = other.schemaName_; _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); @@ -774,7 +890,8 @@ public Identifier(Identifier other) : this() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Identifier Clone() { + public Identifier Clone() + { return new Identifier(this); } @@ -785,22 +902,26 @@ public Identifier Clone() { private string name_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public string Name { + public string Name + { get { return name_ ?? NameDefaultValue; } - set { + set + { name_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); } } /// Gets whether the "name" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasName { + public bool HasName + { get { return name_ != null; } } /// Clears the value of the "name" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearName() { + public void ClearName() + { name_ = null; } @@ -811,38 +932,46 @@ public void ClearName() { private string schemaName_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public string SchemaName { + public string SchemaName + { get { return schemaName_ ?? SchemaNameDefaultValue; } - set { + set + { schemaName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); } } /// Gets whether the "schema_name" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasSchemaName { + public bool HasSchemaName + { get { return schemaName_ != null; } } /// Clears the value of the "schema_name" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearSchemaName() { + public void ClearSchemaName() + { schemaName_ = null; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as Identifier); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(Identifier other) { - if (ReferenceEquals(other, null)) { + public bool Equals(Identifier other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } if (Name != other.Name) return false; @@ -852,11 +981,13 @@ public bool Equals(Identifier other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; if (HasName) hash ^= Name.GetHashCode(); if (HasSchemaName) hash ^= SchemaName.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -864,16 +995,18 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (HasName) { output.WriteRawTag(10); output.WriteString(Name); @@ -885,38 +1018,46 @@ public void WriteTo(pb::CodedOutputStream output) { if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (HasName) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (HasName) + { output.WriteRawTag(10); output.WriteString(Name); } - if (HasSchemaName) { + if (HasSchemaName) + { output.WriteRawTag(18); output.WriteString(SchemaName); } - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (HasName) { + if (HasName) + { size += 1 + pb::CodedOutputStream.ComputeStringSize(Name); } - if (HasSchemaName) { + if (HasSchemaName) + { size += 1 + pb::CodedOutputStream.ComputeStringSize(SchemaName); } - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -924,14 +1065,18 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(Identifier other) { - if (other == null) { + public void MergeFrom(Identifier other) + { + if (other == null) + { return; } - if (other.HasName) { + if (other.HasName) + { Name = other.Name; } - if (other.HasSchemaName) { + if (other.HasSchemaName) + { SchemaName = other.SchemaName; } _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); @@ -939,13 +1084,18 @@ public void MergeFrom(Identifier other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -959,31 +1109,41 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 10: { - Name = input.ReadString(); - break; - } - case 18: { - SchemaName = input.ReadString(); - break; - } + case 10: + { + Name = input.ReadString(); + break; + } + case 18: + { + SchemaName = input.ReadString(); + break; + } } } } - #endif +#endif } @@ -999,10 +1159,11 @@ public void MergeFrom(pb::CodedInputStream input) { ///array_index : "[" number "]" | "[" "*" "]" ///@endcode /// - internal sealed partial class DocumentPathItem : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class DocumentPathItem : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new DocumentPathItem()); private pb::UnknownFieldSet _unknownFields; @@ -1013,19 +1174,22 @@ internal sealed partial class DocumentPathItem : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Expr.MysqlxExprReflection.Descriptor.MessageTypes[2]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public DocumentPathItem() { + public DocumentPathItem() + { OnConstruction(); } @@ -1033,7 +1197,8 @@ public DocumentPathItem() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public DocumentPathItem(DocumentPathItem other) : this() { + public DocumentPathItem(DocumentPathItem other) : this() + { _hasBits0 = other._hasBits0; type_ = other.type_; value_ = other.value_; @@ -1043,7 +1208,8 @@ public DocumentPathItem(DocumentPathItem other) : this() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public DocumentPathItem Clone() { + public DocumentPathItem Clone() + { return new DocumentPathItem(this); } @@ -1054,9 +1220,11 @@ public DocumentPathItem Clone() { private global::Mysqlx.Expr.DocumentPathItem.Types.Type type_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Expr.DocumentPathItem.Types.Type Type { + public global::Mysqlx.Expr.DocumentPathItem.Types.Type Type + { get { if ((_hasBits0 & 1) != 0) { return type_; } else { return TypeDefaultValue; } } - set { + set + { _hasBits0 |= 1; type_ = value; } @@ -1064,13 +1232,15 @@ public DocumentPathItem Clone() { /// Gets whether the "type" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasType { + public bool HasType + { get { return (_hasBits0 & 1) != 0; } } /// Clears the value of the "type" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearType() { + public void ClearType() + { _hasBits0 &= ~1; } @@ -1081,22 +1251,26 @@ public void ClearType() { private string value_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public string Value { + public string Value + { get { return value_ ?? ValueDefaultValue; } - set { + set + { value_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); } } /// Gets whether the "value" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasValue { + public bool HasValue + { get { return value_ != null; } } /// Clears the value of the "value" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearValue() { + public void ClearValue() + { value_ = null; } @@ -1110,9 +1284,11 @@ public void ClearValue() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public uint Index { + public uint Index + { get { if ((_hasBits0 & 2) != 0) { return index_; } else { return IndexDefaultValue; } } - set { + set + { _hasBits0 |= 2; index_ = value; } @@ -1120,29 +1296,35 @@ public uint Index { /// Gets whether the "index" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasIndex { + public bool HasIndex + { get { return (_hasBits0 & 2) != 0; } } /// Clears the value of the "index" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearIndex() { + public void ClearIndex() + { _hasBits0 &= ~2; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as DocumentPathItem); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(DocumentPathItem other) { - if (ReferenceEquals(other, null)) { + public bool Equals(DocumentPathItem other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } if (Type != other.Type) return false; @@ -1153,12 +1335,14 @@ public bool Equals(DocumentPathItem other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; if (HasType) hash ^= Type.GetHashCode(); if (HasValue) hash ^= Value.GetHashCode(); if (HasIndex) hash ^= Index.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -1166,16 +1350,18 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (HasType) { output.WriteRawTag(8); output.WriteEnum((int) Type); @@ -1191,45 +1377,55 @@ public void WriteTo(pb::CodedOutputStream output) { if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (HasType) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (HasType) + { output.WriteRawTag(8); - output.WriteEnum((int) Type); + output.WriteEnum((int)Type); } - if (HasValue) { + if (HasValue) + { output.WriteRawTag(18); output.WriteString(Value); } - if (HasIndex) { + if (HasIndex) + { output.WriteRawTag(24); output.WriteUInt32(Index); } - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (HasType) { - size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Type); + if (HasType) + { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int)Type); } - if (HasValue) { + if (HasValue) + { size += 1 + pb::CodedOutputStream.ComputeStringSize(Value); } - if (HasIndex) { + if (HasIndex) + { size += 1 + pb::CodedOutputStream.ComputeUInt32Size(Index); } - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -1237,17 +1433,22 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(DocumentPathItem other) { - if (other == null) { + public void MergeFrom(DocumentPathItem other) + { + if (other == null) + { return; } - if (other.HasType) { + if (other.HasType) + { Type = other.Type; } - if (other.HasValue) { + if (other.HasValue) + { Value = other.Value; } - if (other.HasIndex) { + if (other.HasIndex) + { Index = other.Index; } _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); @@ -1255,13 +1456,18 @@ public void MergeFrom(DocumentPathItem other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -1279,42 +1485,55 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 8: { - Type = (global::Mysqlx.Expr.DocumentPathItem.Types.Type) input.ReadEnum(); - break; - } - case 18: { - Value = input.ReadString(); - break; - } - case 24: { - Index = input.ReadUInt32(); - break; - } + case 8: + { + Type = (global::Mysqlx.Expr.DocumentPathItem.Types.Type)input.ReadEnum(); + break; + } + case 18: + { + Value = input.ReadString(); + break; + } + case 24: + { + Index = input.ReadUInt32(); + break; + } } } } - #endif +#endif #region Nested types /// Container for nested types declared in the DocumentPathItem message type. [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static partial class Types { - public enum Type { + public static partial class Types + { + public enum Type + { /// ///* .member /// @@ -1348,7 +1567,7 @@ public enum Type { /// ///for table: col\@doc_path, tbl.col\@doc_path col, tbl.col, schema.tbl.col ///for document collection: doc_path - ///// + ///// ///@par production list ///@code{unparsed} ///col_identifier: string "." string "." string | @@ -1364,10 +1583,11 @@ public enum Type { ///doubleAsterisk = "**" ///@endcode /// - internal sealed partial class ColumnIdentifier : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class ColumnIdentifier : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ColumnIdentifier()); private pb::UnknownFieldSet _unknownFields; @@ -1377,19 +1597,22 @@ internal sealed partial class ColumnIdentifier : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Expr.MysqlxExprReflection.Descriptor.MessageTypes[3]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public ColumnIdentifier() { + public ColumnIdentifier() + { OnConstruction(); } @@ -1397,7 +1620,8 @@ public ColumnIdentifier() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public ColumnIdentifier(ColumnIdentifier other) : this() { + public ColumnIdentifier(ColumnIdentifier other) : this() + { documentPath_ = other.documentPath_.Clone(); name_ = other.name_; tableName_ = other.tableName_; @@ -1407,7 +1631,8 @@ public ColumnIdentifier(ColumnIdentifier other) : this() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public ColumnIdentifier Clone() { + public ColumnIdentifier Clone() + { return new ColumnIdentifier(this); } @@ -1421,7 +1646,8 @@ public ColumnIdentifier Clone() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public pbc::RepeatedField DocumentPath { + public pbc::RepeatedField DocumentPath + { get { return documentPath_; } } @@ -1435,22 +1661,26 @@ public ColumnIdentifier Clone() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public string Name { + public string Name + { get { return name_ ?? NameDefaultValue; } - set { + set + { name_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); } } /// Gets whether the "name" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasName { + public bool HasName + { get { return name_ != null; } } /// Clears the value of the "name" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearName() { + public void ClearName() + { name_ = null; } @@ -1464,22 +1694,26 @@ public void ClearName() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public string TableName { + public string TableName + { get { return tableName_ ?? TableNameDefaultValue; } - set { + set + { tableName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); } } /// Gets whether the "table_name" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasTableName { + public bool HasTableName + { get { return tableName_ != null; } } /// Clears the value of the "table_name" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearTableName() { + public void ClearTableName() + { tableName_ = null; } @@ -1493,41 +1727,49 @@ public void ClearTableName() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public string SchemaName { + public string SchemaName + { get { return schemaName_ ?? SchemaNameDefaultValue; } - set { + set + { schemaName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); } } /// Gets whether the "schema_name" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasSchemaName { + public bool HasSchemaName + { get { return schemaName_ != null; } } /// Clears the value of the "schema_name" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearSchemaName() { + public void ClearSchemaName() + { schemaName_ = null; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as ColumnIdentifier); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(ColumnIdentifier other) { - if (ReferenceEquals(other, null)) { + public bool Equals(ColumnIdentifier other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } - if(!documentPath_.Equals(other.documentPath_)) return false; + if (!documentPath_.Equals(other.documentPath_)) return false; if (Name != other.Name) return false; if (TableName != other.TableName) return false; if (SchemaName != other.SchemaName) return false; @@ -1536,13 +1778,15 @@ public bool Equals(ColumnIdentifier other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; hash ^= documentPath_.GetHashCode(); if (HasName) hash ^= Name.GetHashCode(); if (HasTableName) hash ^= TableName.GetHashCode(); if (HasSchemaName) hash ^= SchemaName.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -1550,16 +1794,18 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else documentPath_.WriteTo(output, _repeated_documentPath_codec); if (HasName) { output.WriteRawTag(18); @@ -1576,47 +1822,57 @@ public void WriteTo(pb::CodedOutputStream output) { if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { documentPath_.WriteTo(ref output, _repeated_documentPath_codec); - if (HasName) { + if (HasName) + { output.WriteRawTag(18); output.WriteString(Name); } - if (HasTableName) { + if (HasTableName) + { output.WriteRawTag(26); output.WriteString(TableName); } - if (HasSchemaName) { + if (HasSchemaName) + { output.WriteRawTag(34); output.WriteString(SchemaName); } - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; size += documentPath_.CalculateSize(_repeated_documentPath_codec); - if (HasName) { + if (HasName) + { size += 1 + pb::CodedOutputStream.ComputeStringSize(Name); } - if (HasTableName) { + if (HasTableName) + { size += 1 + pb::CodedOutputStream.ComputeStringSize(TableName); } - if (HasSchemaName) { + if (HasSchemaName) + { size += 1 + pb::CodedOutputStream.ComputeStringSize(SchemaName); } - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -1624,18 +1880,23 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(ColumnIdentifier other) { - if (other == null) { + public void MergeFrom(ColumnIdentifier other) + { + if (other == null) + { return; } documentPath_.Add(other.documentPath_); - if (other.HasName) { + if (other.HasName) + { Name = other.Name; } - if (other.HasTableName) { + if (other.HasTableName) + { TableName = other.TableName; } - if (other.HasSchemaName) { + if (other.HasSchemaName) + { SchemaName = other.SchemaName; } _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); @@ -1643,13 +1904,18 @@ public void MergeFrom(ColumnIdentifier other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -1671,39 +1937,51 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 10: { - documentPath_.AddEntriesFrom(ref input, _repeated_documentPath_codec); - break; - } - case 18: { - Name = input.ReadString(); - break; - } - case 26: { - TableName = input.ReadString(); - break; - } - case 34: { - SchemaName = input.ReadString(); - break; - } + case 10: + { + documentPath_.AddEntriesFrom(ref input, _repeated_documentPath_codec); + break; + } + case 18: + { + Name = input.ReadString(); + break; + } + case 26: + { + TableName = input.ReadString(); + break; + } + case 34: + { + SchemaName = input.ReadString(); + break; + } } } } - #endif +#endif } @@ -1716,10 +1994,11 @@ public void MergeFrom(pb::CodedInputStream input) { ///function_call: `identifier` "(" [ `expr` ["," `expr` ]* ] ")" ///@endcode /// - internal sealed partial class FunctionCall : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class FunctionCall : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new FunctionCall()); private pb::UnknownFieldSet _unknownFields; @@ -1729,19 +2008,22 @@ internal sealed partial class FunctionCall : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Expr.MysqlxExprReflection.Descriptor.MessageTypes[4]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public FunctionCall() { + public FunctionCall() + { OnConstruction(); } @@ -1749,7 +2031,8 @@ public FunctionCall() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public FunctionCall(FunctionCall other) : this() { + public FunctionCall(FunctionCall other) : this() + { name_ = other.name_ != null ? other.name_.Clone() : null; param_ = other.param_.Clone(); _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); @@ -1757,7 +2040,8 @@ public FunctionCall(FunctionCall other) : this() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public FunctionCall Clone() { + public FunctionCall Clone() + { return new FunctionCall(this); } @@ -1769,9 +2053,11 @@ public FunctionCall Clone() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Expr.Identifier Name { + public global::Mysqlx.Expr.Identifier Name + { get { return name_; } - set { + set + { name_ = value; } } @@ -1786,37 +2072,44 @@ public FunctionCall Clone() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public pbc::RepeatedField Param { + public pbc::RepeatedField Param + { get { return param_; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as FunctionCall); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(FunctionCall other) { - if (ReferenceEquals(other, null)) { + public bool Equals(FunctionCall other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } if (!object.Equals(Name, other.Name)) return false; - if(!param_.Equals(other.param_)) return false; + if (!param_.Equals(other.param_)) return false; return Equals(_unknownFields, other._unknownFields); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; if (name_ != null) hash ^= Name.GetHashCode(); hash ^= param_.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -1824,16 +2117,18 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (name_ != null) { output.WriteRawTag(10); output.WriteMessage(Name); @@ -1842,33 +2137,39 @@ public void WriteTo(pb::CodedOutputStream output) { if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (name_ != null) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (name_ != null) + { output.WriteRawTag(10); output.WriteMessage(Name); } param_.WriteTo(ref output, _repeated_param_codec); - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (name_ != null) { + if (name_ != null) + { size += 1 + pb::CodedOutputStream.ComputeMessageSize(Name); } size += param_.CalculateSize(_repeated_param_codec); - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -1876,12 +2177,16 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(FunctionCall other) { - if (other == null) { + public void MergeFrom(FunctionCall other) + { + if (other == null) + { return; } - if (other.name_ != null) { - if (name_ == null) { + if (other.name_ != null) + { + if (name_ == null) + { Name = new global::Mysqlx.Expr.Identifier(); } Name.MergeFrom(other.Name); @@ -1892,13 +2197,18 @@ public void MergeFrom(FunctionCall other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -1915,41 +2225,53 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 10: { - if (name_ == null) { - Name = new global::Mysqlx.Expr.Identifier(); + case 10: + { + if (name_ == null) + { + Name = new global::Mysqlx.Expr.Identifier(); + } + input.ReadMessage(Name); + break; + } + case 18: + { + param_.AddEntriesFrom(ref input, _repeated_param_codec); + break; } - input.ReadMessage(Name); - break; - } - case 18: { - param_.AddEntriesFrom(ref input, _repeated_param_codec); - break; - } } } } - #endif +#endif } - internal sealed partial class Operator : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class Operator : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Operator()); private pb::UnknownFieldSet _unknownFields; @@ -1959,19 +2281,22 @@ internal sealed partial class Operator : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Expr.MysqlxExprReflection.Descriptor.MessageTypes[5]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Operator() { + public Operator() + { OnConstruction(); } @@ -1979,7 +2304,8 @@ public Operator() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Operator(Operator other) : this() { + public Operator(Operator other) : this() + { name_ = other.name_; param_ = other.param_.Clone(); _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); @@ -1987,7 +2313,8 @@ public Operator(Operator other) : this() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Operator Clone() { + public Operator Clone() + { return new Operator(this); } @@ -2001,22 +2328,26 @@ public Operator Clone() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public string Name { + public string Name + { get { return name_ ?? NameDefaultValue; } - set { + set + { name_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); } } /// Gets whether the "name" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasName { + public bool HasName + { get { return name_ != null; } } /// Clears the value of the "name" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearName() { + public void ClearName() + { name_ = null; } @@ -2030,37 +2361,44 @@ public void ClearName() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public pbc::RepeatedField Param { + public pbc::RepeatedField Param + { get { return param_; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as Operator); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(Operator other) { - if (ReferenceEquals(other, null)) { + public bool Equals(Operator other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } if (Name != other.Name) return false; - if(!param_.Equals(other.param_)) return false; + if (!param_.Equals(other.param_)) return false; return Equals(_unknownFields, other._unknownFields); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; if (HasName) hash ^= Name.GetHashCode(); hash ^= param_.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -2068,16 +2406,18 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (HasName) { output.WriteRawTag(10); output.WriteString(Name); @@ -2086,33 +2426,39 @@ public void WriteTo(pb::CodedOutputStream output) { if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (HasName) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (HasName) + { output.WriteRawTag(10); output.WriteString(Name); } param_.WriteTo(ref output, _repeated_param_codec); - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (HasName) { + if (HasName) + { size += 1 + pb::CodedOutputStream.ComputeStringSize(Name); } size += param_.CalculateSize(_repeated_param_codec); - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -2120,11 +2466,14 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(Operator other) { - if (other == null) { + public void MergeFrom(Operator other) + { + if (other == null) + { return; } - if (other.HasName) { + if (other.HasName) + { Name = other.Name; } param_.Add(other.param_); @@ -2133,13 +2482,18 @@ public void MergeFrom(Operator other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -2153,31 +2507,41 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 10: { - Name = input.ReadString(); - break; - } - case 18: { - param_.AddEntriesFrom(ref input, _repeated_param_codec); - break; - } + case 10: + { + Name = input.ReadString(); + break; + } + case 18: + { + param_.AddEntriesFrom(ref input, _repeated_param_codec); + break; + } } } } - #endif +#endif } @@ -2185,10 +2549,11 @@ public void MergeFrom(pb::CodedInputStream input) { ///* ///An object (with expression values) /// - internal sealed partial class Object : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class Object : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Object()); private pb::UnknownFieldSet _unknownFields; @@ -2198,19 +2563,22 @@ internal sealed partial class Object : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Expr.MysqlxExprReflection.Descriptor.MessageTypes[6]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Object() { + public Object() + { OnConstruction(); } @@ -2218,14 +2586,16 @@ public Object() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Object(Object other) : this() { + public Object(Object other) : this() + { fld_ = other.fld_.Clone(); _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Object Clone() { + public Object Clone() + { return new Object(this); } @@ -2239,35 +2609,42 @@ public Object Clone() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public pbc::RepeatedField Fld { + public pbc::RepeatedField Fld + { get { return fld_; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as Object); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(Object other) { - if (ReferenceEquals(other, null)) { + public bool Equals(Object other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } - if(!fld_.Equals(other.fld_)) return false; + if (!fld_.Equals(other.fld_)) return false; return Equals(_unknownFields, other._unknownFields); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; hash ^= fld_.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -2275,40 +2652,46 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else fld_.WriteTo(output, _repeated_fld_codec); if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { fld_.WriteTo(ref output, _repeated_fld_codec); - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; size += fld_.CalculateSize(_repeated_fld_codec); - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -2316,8 +2699,10 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(Object other) { - if (other == null) { + public void MergeFrom(Object other) + { + if (other == null) + { return; } fld_.Add(other.fld_); @@ -2326,13 +2711,18 @@ public void MergeFrom(Object other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -2342,37 +2732,48 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 10: { - fld_.AddEntriesFrom(ref input, _repeated_fld_codec); - break; - } + case 10: + { + fld_.AddEntriesFrom(ref input, _repeated_fld_codec); + break; + } } } } - #endif +#endif #region Nested types /// Container for nested types declared in the Object message type. [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static partial class Types { + public static partial class Types + { + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] public sealed partial class ObjectField : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ObjectField()); private pb::UnknownFieldSet _unknownFields; @@ -2382,19 +2783,22 @@ public sealed partial class ObjectField : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Expr.Object.Descriptor.NestedTypes[0]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public ObjectField() { + public ObjectField() + { OnConstruction(); } @@ -2402,7 +2806,8 @@ public ObjectField() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public ObjectField(ObjectField other) : this() { + public ObjectField(ObjectField other) : this() + { key_ = other.key_; value_ = other.value_ != null ? other.value_.Clone() : null; _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); @@ -2410,7 +2815,8 @@ public ObjectField(ObjectField other) : this() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public ObjectField Clone() { + public ObjectField Clone() + { return new ObjectField(this); } @@ -2424,22 +2830,26 @@ public ObjectField Clone() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public string Key { + public string Key + { get { return key_ ?? KeyDefaultValue; } - set { + set + { key_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); } } /// Gets whether the "key" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasKey { + public bool HasKey + { get { return key_ != null; } } /// Clears the value of the "key" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearKey() { + public void ClearKey() + { key_ = null; } @@ -2451,26 +2861,32 @@ public void ClearKey() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Expr.Expr Value { + public global::Mysqlx.Expr.Expr Value + { get { return value_; } - set { + set + { value_ = value; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as ObjectField); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(ObjectField other) { - if (ReferenceEquals(other, null)) { + public bool Equals(ObjectField other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } if (Key != other.Key) return false; @@ -2480,11 +2896,13 @@ public bool Equals(ObjectField other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; if (HasKey) hash ^= Key.GetHashCode(); if (value_ != null) hash ^= Value.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -2492,16 +2910,18 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (HasKey) { output.WriteRawTag(10); output.WriteString(Key); @@ -2513,38 +2933,46 @@ public void WriteTo(pb::CodedOutputStream output) { if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (HasKey) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (HasKey) + { output.WriteRawTag(10); output.WriteString(Key); } - if (value_ != null) { + if (value_ != null) + { output.WriteRawTag(18); output.WriteMessage(Value); } - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (HasKey) { + if (HasKey) + { size += 1 + pb::CodedOutputStream.ComputeStringSize(Key); } - if (value_ != null) { + if (value_ != null) + { size += 1 + pb::CodedOutputStream.ComputeMessageSize(Value); } - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -2552,15 +2980,20 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(ObjectField other) { - if (other == null) { + public void MergeFrom(ObjectField other) + { + if (other == null) + { return; } - if (other.HasKey) { + if (other.HasKey) + { Key = other.Key; } - if (other.value_ != null) { - if (value_ == null) { + if (other.value_ != null) + { + if (value_ == null) + { Value = new global::Mysqlx.Expr.Expr(); } Value.MergeFrom(other.Value); @@ -2570,13 +3003,18 @@ public void MergeFrom(ObjectField other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -2593,34 +3031,45 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 10: { - Key = input.ReadString(); - break; - } - case 18: { - if (value_ == null) { - Value = new global::Mysqlx.Expr.Expr(); + case 10: + { + Key = input.ReadString(); + break; + } + case 18: + { + if (value_ == null) + { + Value = new global::Mysqlx.Expr.Expr(); + } + input.ReadMessage(Value); + break; } - input.ReadMessage(Value); - break; - } } } } - #endif +#endif } @@ -2633,10 +3082,11 @@ public void MergeFrom(pb::CodedInputStream input) { ///* ///An array of expressions /// - internal sealed partial class Array : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class Array : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Array()); private pb::UnknownFieldSet _unknownFields; @@ -2646,19 +3096,22 @@ internal sealed partial class Array : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Expr.MysqlxExprReflection.Descriptor.MessageTypes[7]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Array() { + public Array() + { OnConstruction(); } @@ -2666,14 +3119,16 @@ public Array() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Array(Array other) : this() { + public Array(Array other) : this() + { value_ = other.value_.Clone(); _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Array Clone() { + public Array Clone() + { return new Array(this); } @@ -2687,35 +3142,42 @@ public Array Clone() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public pbc::RepeatedField Value { + public pbc::RepeatedField Value + { get { return value_; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as Array); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(Array other) { - if (ReferenceEquals(other, null)) { + public bool Equals(Array other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } - if(!value_.Equals(other.value_)) return false; + if (!value_.Equals(other.value_)) return false; return Equals(_unknownFields, other._unknownFields); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; hash ^= value_.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -2723,40 +3185,46 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else value_.WriteTo(output, _repeated_value_codec); if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { value_.WriteTo(ref output, _repeated_value_codec); - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; size += value_.CalculateSize(_repeated_value_codec); - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -2764,8 +3232,10 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(Array other) { - if (other == null) { + public void MergeFrom(Array other) + { + if (other == null) + { return; } value_.Add(other.value_); @@ -2774,13 +3244,18 @@ public void MergeFrom(Array other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -2790,27 +3265,36 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 10: { - value_.AddEntriesFrom(ref input, _repeated_value_codec); - break; - } + case 10: + { + value_.AddEntriesFrom(ref input, _repeated_value_codec); + break; + } } } } - #endif +#endif } @@ -2819,3 +3303,4 @@ public void MergeFrom(pb::CodedInputStream input) { } #endregion Designer generated code + diff --git a/MySQL.Data/src/X/Protocol/X/Protobuf/MysqlxNotice.cs b/MySQL.Data/src/X/Protocol/X/Protobuf/MysqlxNotice.cs index 7333d2701..39a8bdee1 100644 --- a/MySQL.Data/src/X/Protocol/X/Protobuf/MysqlxNotice.cs +++ b/MySQL.Data/src/X/Protocol/X/Protobuf/MysqlxNotice.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2022, 2023, Oracle and/or its affiliates. +// Copyright © 2022, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -37,19 +37,23 @@ using pbc = global::Google.Protobuf.Collections; using pbr = global::Google.Protobuf.Reflection; using scg = global::System.Collections.Generic; -namespace Mysqlx.Notice { +namespace Mysqlx.Notice +{ /// Holder for reflection information generated from mysqlx_notice.proto - internal static partial class MysqlxNoticeReflection { + public static partial class MysqlxNoticeReflection + { #region Descriptor /// File descriptor for mysqlx_notice.proto - public static pbr::FileDescriptor Descriptor { + public static pbr::FileDescriptor Descriptor + { get { return descriptor; } } private static pbr::FileDescriptor descriptor; - static MysqlxNoticeReflection() { + static MysqlxNoticeReflection() + { byte[] descriptorData = global::System.Convert.FromBase64String( string.Concat( "ChNteXNxbHhfbm90aWNlLnByb3RvEg1NeXNxbHguTm90aWNlGgxteXNxbHgu", @@ -105,10 +109,11 @@ static MysqlxNoticeReflection() { ///| @ref Mysqlx::Notice::GroupReplicationStateChanged | 4 | ///| @ref Mysqlx::Notice::ServerHello | 5 | /// - internal sealed partial class Frame : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class Frame : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Frame()); private pb::UnknownFieldSet _unknownFields; @@ -119,19 +124,22 @@ internal sealed partial class Frame : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Notice.MysqlxNoticeReflection.Descriptor.MessageTypes[0]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Frame() { + public Frame() + { OnConstruction(); } @@ -139,7 +147,8 @@ public Frame() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Frame(Frame other) : this() { + public Frame(Frame other) : this() + { _hasBits0 = other._hasBits0; type_ = other.type_; scope_ = other.scope_; @@ -149,7 +158,8 @@ public Frame(Frame other) : this() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Frame Clone() { + public Frame Clone() + { return new Frame(this); } @@ -163,9 +173,11 @@ public Frame Clone() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public uint Type { + public uint Type + { get { if ((_hasBits0 & 1) != 0) { return type_; } else { return TypeDefaultValue; } } - set { + set + { _hasBits0 |= 1; type_ = value; } @@ -173,13 +185,15 @@ public uint Type { /// Gets whether the "type" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasType { + public bool HasType + { get { return (_hasBits0 & 1) != 0; } } /// Clears the value of the "type" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearType() { + public void ClearType() + { _hasBits0 &= ~1; } @@ -193,9 +207,11 @@ public void ClearType() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Notice.Frame.Types.Scope Scope { + public global::Mysqlx.Notice.Frame.Types.Scope Scope + { get { if ((_hasBits0 & 2) != 0) { return scope_; } else { return ScopeDefaultValue; } } - set { + set + { _hasBits0 |= 2; scope_ = value; } @@ -203,13 +219,15 @@ public void ClearType() { /// Gets whether the "scope" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasScope { + public bool HasScope + { get { return (_hasBits0 & 2) != 0; } } /// Clears the value of the "scope" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearScope() { + public void ClearScope() + { _hasBits0 &= ~2; } @@ -223,38 +241,46 @@ public void ClearScope() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public pb::ByteString Payload { + public pb::ByteString Payload + { get { return payload_ ?? PayloadDefaultValue; } - set { + set + { payload_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); } } /// Gets whether the "payload" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasPayload { + public bool HasPayload + { get { return payload_ != null; } } /// Clears the value of the "payload" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearPayload() { + public void ClearPayload() + { payload_ = null; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as Frame); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(Frame other) { - if (ReferenceEquals(other, null)) { + public bool Equals(Frame other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } if (Type != other.Type) return false; @@ -265,12 +291,14 @@ public bool Equals(Frame other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; if (HasType) hash ^= Type.GetHashCode(); if (HasScope) hash ^= Scope.GetHashCode(); if (HasPayload) hash ^= Payload.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -278,16 +306,18 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (HasType) { output.WriteRawTag(8); output.WriteUInt32(Type); @@ -303,45 +333,55 @@ public void WriteTo(pb::CodedOutputStream output) { if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (HasType) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (HasType) + { output.WriteRawTag(8); output.WriteUInt32(Type); } - if (HasScope) { + if (HasScope) + { output.WriteRawTag(16); - output.WriteEnum((int) Scope); + output.WriteEnum((int)Scope); } - if (HasPayload) { + if (HasPayload) + { output.WriteRawTag(26); output.WriteBytes(Payload); } - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (HasType) { + if (HasType) + { size += 1 + pb::CodedOutputStream.ComputeUInt32Size(Type); } - if (HasScope) { - size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Scope); + if (HasScope) + { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int)Scope); } - if (HasPayload) { + if (HasPayload) + { size += 1 + pb::CodedOutputStream.ComputeBytesSize(Payload); } - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -349,17 +389,22 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(Frame other) { - if (other == null) { + public void MergeFrom(Frame other) + { + if (other == null) + { return; } - if (other.HasType) { + if (other.HasType) + { Type = other.Type; } - if (other.HasScope) { + if (other.HasScope) + { Scope = other.Scope; } - if (other.HasPayload) { + if (other.HasPayload) + { Payload = other.Payload; } _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); @@ -367,13 +412,18 @@ public void MergeFrom(Frame other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -391,45 +441,58 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 8: { - Type = input.ReadUInt32(); - break; - } - case 16: { - Scope = (global::Mysqlx.Notice.Frame.Types.Scope) input.ReadEnum(); - break; - } - case 26: { - Payload = input.ReadBytes(); - break; - } + case 8: + { + Type = input.ReadUInt32(); + break; + } + case 16: + { + Scope = (global::Mysqlx.Notice.Frame.Types.Scope)input.ReadEnum(); + break; + } + case 26: + { + Payload = input.ReadBytes(); + break; + } } } } - #endif +#endif #region Nested types /// Container for nested types declared in the Frame message type. [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static partial class Types { + public static partial class Types + { /// ///* scope of notice /// - public enum Scope { + public enum Scope + { [pbr::OriginalName("GLOBAL")] Global = 1, [pbr::OriginalName("LOCAL")] Local = 2, } @@ -437,7 +500,8 @@ public enum Scope { /// ///* type of notice payload /// - public enum Type { + public enum Type + { [pbr::OriginalName("WARNING")] Warning = 1, [pbr::OriginalName("SESSION_VARIABLE_CHANGED")] SessionVariableChanged = 2, [pbr::OriginalName("SESSION_STATE_CHANGED")] SessionStateChanged = 3, @@ -471,10 +535,11 @@ public enum Type { ///| ``.type`` | 1 | ///| ``.scope`` | ``local`` or ``global`` | /// - internal sealed partial class Warning : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class Warning : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Warning()); private pb::UnknownFieldSet _unknownFields; @@ -485,19 +550,22 @@ internal sealed partial class Warning : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Notice.MysqlxNoticeReflection.Descriptor.MessageTypes[1]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Warning() { + public Warning() + { OnConstruction(); } @@ -505,7 +573,8 @@ public Warning() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Warning(Warning other) : this() { + public Warning(Warning other) : this() + { _hasBits0 = other._hasBits0; level_ = other.level_; code_ = other.code_; @@ -515,7 +584,8 @@ public Warning(Warning other) : this() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Warning Clone() { + public Warning Clone() + { return new Warning(this); } @@ -529,9 +599,11 @@ public Warning Clone() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Notice.Warning.Types.Level Level { + public global::Mysqlx.Notice.Warning.Types.Level Level + { get { if ((_hasBits0 & 1) != 0) { return level_; } else { return LevelDefaultValue; } } - set { + set + { _hasBits0 |= 1; level_ = value; } @@ -539,13 +611,15 @@ public Warning Clone() { /// Gets whether the "level" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasLevel { + public bool HasLevel + { get { return (_hasBits0 & 1) != 0; } } /// Clears the value of the "level" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearLevel() { + public void ClearLevel() + { _hasBits0 &= ~1; } @@ -559,9 +633,11 @@ public void ClearLevel() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public uint Code { + public uint Code + { get { if ((_hasBits0 & 2) != 0) { return code_; } else { return CodeDefaultValue; } } - set { + set + { _hasBits0 |= 2; code_ = value; } @@ -569,13 +645,15 @@ public uint Code { /// Gets whether the "code" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasCode { + public bool HasCode + { get { return (_hasBits0 & 2) != 0; } } /// Clears the value of the "code" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearCode() { + public void ClearCode() + { _hasBits0 &= ~2; } @@ -589,38 +667,46 @@ public void ClearCode() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public string Msg { + public string Msg + { get { return msg_ ?? MsgDefaultValue; } - set { + set + { msg_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); } } /// Gets whether the "msg" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasMsg { + public bool HasMsg + { get { return msg_ != null; } } /// Clears the value of the "msg" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearMsg() { + public void ClearMsg() + { msg_ = null; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as Warning); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(Warning other) { - if (ReferenceEquals(other, null)) { + public bool Equals(Warning other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } if (Level != other.Level) return false; @@ -631,12 +717,14 @@ public bool Equals(Warning other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; if (HasLevel) hash ^= Level.GetHashCode(); if (HasCode) hash ^= Code.GetHashCode(); if (HasMsg) hash ^= Msg.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -644,16 +732,18 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (HasLevel) { output.WriteRawTag(8); output.WriteEnum((int) Level); @@ -669,45 +759,55 @@ public void WriteTo(pb::CodedOutputStream output) { if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (HasLevel) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (HasLevel) + { output.WriteRawTag(8); - output.WriteEnum((int) Level); + output.WriteEnum((int)Level); } - if (HasCode) { + if (HasCode) + { output.WriteRawTag(16); output.WriteUInt32(Code); } - if (HasMsg) { + if (HasMsg) + { output.WriteRawTag(26); output.WriteString(Msg); } - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (HasLevel) { - size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Level); + if (HasLevel) + { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int)Level); } - if (HasCode) { + if (HasCode) + { size += 1 + pb::CodedOutputStream.ComputeUInt32Size(Code); } - if (HasMsg) { + if (HasMsg) + { size += 1 + pb::CodedOutputStream.ComputeStringSize(Msg); } - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -715,17 +815,22 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(Warning other) { - if (other == null) { + public void MergeFrom(Warning other) + { + if (other == null) + { return; } - if (other.HasLevel) { + if (other.HasLevel) + { Level = other.Level; } - if (other.HasCode) { + if (other.HasCode) + { Code = other.Code; } - if (other.HasMsg) { + if (other.HasMsg) + { Msg = other.Msg; } _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); @@ -733,13 +838,18 @@ public void MergeFrom(Warning other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -757,42 +867,55 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 8: { - Level = (global::Mysqlx.Notice.Warning.Types.Level) input.ReadEnum(); - break; - } - case 16: { - Code = input.ReadUInt32(); - break; - } - case 26: { - Msg = input.ReadString(); - break; - } + case 8: + { + Level = (global::Mysqlx.Notice.Warning.Types.Level)input.ReadEnum(); + break; + } + case 16: + { + Code = input.ReadUInt32(); + break; + } + case 26: + { + Msg = input.ReadString(); + break; + } } } } - #endif +#endif #region Nested types /// Container for nested types declared in the Warning message type. [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static partial class Types { - public enum Level { + public static partial class Types + { + public enum Level + { [pbr::OriginalName("NOTE")] Note = 1, [pbr::OriginalName("WARNING")] Warning = 2, [pbr::OriginalName("ERROR")] Error = 3, @@ -818,10 +941,11 @@ public enum Level { ///| ``.type`` | 2 | ///| ``.scope`` | ``local``| /// - internal sealed partial class SessionVariableChanged : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class SessionVariableChanged : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new SessionVariableChanged()); private pb::UnknownFieldSet _unknownFields; @@ -831,19 +955,22 @@ internal sealed partial class SessionVariableChanged : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public string Param { + public string Param + { get { return param_ ?? ParamDefaultValue; } - set { + set + { param_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); } } /// Gets whether the "param" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasParam { + public bool HasParam + { get { return param_ != null; } } /// Clears the value of the "param" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearParam() { + public void ClearParam() + { param_ = null; } @@ -900,26 +1033,32 @@ public void ClearParam() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Datatypes.Scalar Value { + public global::Mysqlx.Datatypes.Scalar Value + { get { return value_; } - set { + set + { value_ = value; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as SessionVariableChanged); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(SessionVariableChanged other) { - if (ReferenceEquals(other, null)) { + public bool Equals(SessionVariableChanged other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } if (Param != other.Param) return false; @@ -929,11 +1068,13 @@ public bool Equals(SessionVariableChanged other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; if (HasParam) hash ^= Param.GetHashCode(); if (value_ != null) hash ^= Value.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -941,16 +1082,18 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (HasParam) { output.WriteRawTag(10); output.WriteString(Param); @@ -962,38 +1105,46 @@ public void WriteTo(pb::CodedOutputStream output) { if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (HasParam) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (HasParam) + { output.WriteRawTag(10); output.WriteString(Param); } - if (value_ != null) { + if (value_ != null) + { output.WriteRawTag(18); output.WriteMessage(Value); } - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (HasParam) { + if (HasParam) + { size += 1 + pb::CodedOutputStream.ComputeStringSize(Param); } - if (value_ != null) { + if (value_ != null) + { size += 1 + pb::CodedOutputStream.ComputeMessageSize(Value); } - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -1001,15 +1152,20 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(SessionVariableChanged other) { - if (other == null) { + public void MergeFrom(SessionVariableChanged other) + { + if (other == null) + { return; } - if (other.HasParam) { + if (other.HasParam) + { Param = other.Param; } - if (other.value_ != null) { - if (value_ == null) { + if (other.value_ != null) + { + if (value_ == null) + { Value = new global::Mysqlx.Datatypes.Scalar(); } Value.MergeFrom(other.Value); @@ -1019,13 +1175,18 @@ public void MergeFrom(SessionVariableChanged other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -1042,41 +1203,53 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 10: { - Param = input.ReadString(); - break; - } - case 18: { - if (value_ == null) { - Value = new global::Mysqlx.Datatypes.Scalar(); + case 10: + { + Param = input.ReadString(); + break; + } + case 18: + { + if (value_ == null) + { + Value = new global::Mysqlx.Datatypes.Scalar(); + } + input.ReadMessage(Value); + break; } - input.ReadMessage(Value); - break; - } } } } - #endif +#endif } - internal sealed partial class SessionStateChanged : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class SessionStateChanged : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new SessionStateChanged()); private pb::UnknownFieldSet _unknownFields; @@ -1087,19 +1260,22 @@ internal sealed partial class SessionStateChanged : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Notice.SessionStateChanged.Types.Parameter Param { + public global::Mysqlx.Notice.SessionStateChanged.Types.Parameter Param + { get { if ((_hasBits0 & 1) != 0) { return param_; } else { return ParamDefaultValue; } } - set { + set + { _hasBits0 |= 1; param_ = value; } @@ -1140,13 +1320,15 @@ public SessionStateChanged Clone() { /// Gets whether the "param" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasParam { + public bool HasParam + { get { return (_hasBits0 & 1) != 0; } } /// Clears the value of the "param" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearParam() { + public void ClearParam() + { _hasBits0 &= ~1; } @@ -1160,37 +1342,44 @@ public void ClearParam() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public pbc::RepeatedField Value { + public pbc::RepeatedField Value + { get { return value_; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as SessionStateChanged); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(SessionStateChanged other) { - if (ReferenceEquals(other, null)) { + public bool Equals(SessionStateChanged other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } if (Param != other.Param) return false; - if(!value_.Equals(other.value_)) return false; + if (!value_.Equals(other.value_)) return false; return Equals(_unknownFields, other._unknownFields); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; if (HasParam) hash ^= Param.GetHashCode(); hash ^= value_.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -1198,16 +1387,18 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (HasParam) { output.WriteRawTag(8); output.WriteEnum((int) Param); @@ -1216,33 +1407,39 @@ public void WriteTo(pb::CodedOutputStream output) { if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (HasParam) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (HasParam) + { output.WriteRawTag(8); - output.WriteEnum((int) Param); + output.WriteEnum((int)Param); } value_.WriteTo(ref output, _repeated_value_codec); - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (HasParam) { - size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Param); + if (HasParam) + { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int)Param); } size += value_.CalculateSize(_repeated_value_codec); - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -1250,11 +1447,14 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(SessionStateChanged other) { - if (other == null) { + public void MergeFrom(SessionStateChanged other) + { + if (other == null) + { return; } - if (other.HasParam) { + if (other.HasParam) + { Param = other.Param; } value_.Add(other.value_); @@ -1263,13 +1463,18 @@ public void MergeFrom(SessionStateChanged other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -1283,38 +1488,50 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 8: { - Param = (global::Mysqlx.Notice.SessionStateChanged.Types.Parameter) input.ReadEnum(); - break; - } - case 18: { - value_.AddEntriesFrom(ref input, _repeated_value_codec); - break; - } + case 8: + { + Param = (global::Mysqlx.Notice.SessionStateChanged.Types.Parameter)input.ReadEnum(); + break; + } + case 18: + { + value_.AddEntriesFrom(ref input, _repeated_value_codec); + break; + } } } } - #endif +#endif #region Nested types /// Container for nested types declared in the SessionStateChanged message type. [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static partial class Types { - public enum Parameter { + public static partial class Types + { + public enum Parameter + { [pbr::OriginalName("CURRENT_SCHEMA")] CurrentSchema = 1, [pbr::OriginalName("ACCOUNT_EXPIRED")] AccountExpired = 2, [pbr::OriginalName("GENERATED_INSERT_ID")] GeneratedInsertId = 3, @@ -1345,10 +1562,11 @@ public enum Parameter { ///|``.type`` | 4 | ///|``.scope`` | ``global`` | /// - internal sealed partial class GroupReplicationStateChanged : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class GroupReplicationStateChanged : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GroupReplicationStateChanged()); private pb::UnknownFieldSet _unknownFields; @@ -1359,19 +1577,22 @@ internal sealed partial class GroupReplicationStateChanged : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public uint Type { + public uint Type + { get { if ((_hasBits0 & 1) != 0) { return type_; } else { return TypeDefaultValue; } } - set { + set + { _hasBits0 |= 1; type_ = value; } @@ -1412,13 +1637,15 @@ public uint Type { /// Gets whether the "type" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasType { + public bool HasType + { get { return (_hasBits0 & 1) != 0; } } /// Clears the value of the "type" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearType() { + public void ClearType() + { _hasBits0 &= ~1; } @@ -1432,38 +1659,46 @@ public void ClearType() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public string ViewId { + public string ViewId + { get { return viewId_ ?? ViewIdDefaultValue; } - set { + set + { viewId_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); } } /// Gets whether the "view_id" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasViewId { + public bool HasViewId + { get { return viewId_ != null; } } /// Clears the value of the "view_id" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearViewId() { + public void ClearViewId() + { viewId_ = null; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as GroupReplicationStateChanged); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(GroupReplicationStateChanged other) { - if (ReferenceEquals(other, null)) { + public bool Equals(GroupReplicationStateChanged other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } if (Type != other.Type) return false; @@ -1473,11 +1708,13 @@ public bool Equals(GroupReplicationStateChanged other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; if (HasType) hash ^= Type.GetHashCode(); if (HasViewId) hash ^= ViewId.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -1485,16 +1722,18 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (HasType) { output.WriteRawTag(8); output.WriteUInt32(Type); @@ -1506,38 +1745,46 @@ public void WriteTo(pb::CodedOutputStream output) { if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (HasType) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (HasType) + { output.WriteRawTag(8); output.WriteUInt32(Type); } - if (HasViewId) { + if (HasViewId) + { output.WriteRawTag(18); output.WriteString(ViewId); } - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (HasType) { + if (HasType) + { size += 1 + pb::CodedOutputStream.ComputeUInt32Size(Type); } - if (HasViewId) { + if (HasViewId) + { size += 1 + pb::CodedOutputStream.ComputeStringSize(ViewId); } - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -1545,14 +1792,18 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(GroupReplicationStateChanged other) { - if (other == null) { + public void MergeFrom(GroupReplicationStateChanged other) + { + if (other == null) + { return; } - if (other.HasType) { + if (other.HasType) + { Type = other.Type; } - if (other.HasViewId) { + if (other.HasViewId) + { ViewId = other.ViewId; } _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); @@ -1560,13 +1811,18 @@ public void MergeFrom(GroupReplicationStateChanged other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -1580,38 +1836,50 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 8: { - Type = input.ReadUInt32(); - break; - } - case 18: { - ViewId = input.ReadString(); - break; - } + case 8: + { + Type = input.ReadUInt32(); + break; + } + case 18: + { + ViewId = input.ReadString(); + break; + } } } } - #endif +#endif #region Nested types /// Container for nested types declared in the GroupReplicationStateChanged message type. [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static partial class Types { - public enum Type { + public static partial class Types + { + public enum Type + { [pbr::OriginalName("MEMBERSHIP_QUORUM_LOSS")] MembershipQuorumLoss = 1, [pbr::OriginalName("MEMBERSHIP_VIEW_CHANGE")] MembershipViewChange = 2, [pbr::OriginalName("MEMBER_ROLE_CHANGE")] MemberRoleChange = 3, @@ -1632,10 +1900,11 @@ public enum Type { ///|``.type`` | 5 | ///|``.scope`` | ``global`` | /// - internal sealed partial class ServerHello : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class ServerHello : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ServerHello()); private pb::UnknownFieldSet _unknownFields; @@ -1645,19 +1914,22 @@ internal sealed partial class ServerHello : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Notice.MysqlxNoticeReflection.Descriptor.MessageTypes[5]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public ServerHello() { + public ServerHello() + { OnConstruction(); } @@ -1665,29 +1937,35 @@ public ServerHello() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public ServerHello(ServerHello other) : this() { + public ServerHello(ServerHello other) : this() + { _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public ServerHello Clone() { + public ServerHello Clone() + { return new ServerHello(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as ServerHello); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(ServerHello other) { - if (ReferenceEquals(other, null)) { + public bool Equals(ServerHello other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } return Equals(_unknownFields, other._unknownFields); @@ -1695,9 +1973,11 @@ public bool Equals(ServerHello other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -1705,37 +1985,43 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (_unknownFields != null) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -1743,8 +2029,10 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(ServerHello other) { - if (other == null) { + public void MergeFrom(ServerHello other) + { + if (other == null) + { return; } _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); @@ -1752,35 +2040,48 @@ public void MergeFrom(ServerHello other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; } } } - #endif +#endif } diff --git a/MySQL.Data/src/X/Protocol/X/Protobuf/MysqlxPrepare.cs b/MySQL.Data/src/X/Protocol/X/Protobuf/MysqlxPrepare.cs index 45bfa77ba..aec5a7492 100644 --- a/MySQL.Data/src/X/Protocol/X/Protobuf/MysqlxPrepare.cs +++ b/MySQL.Data/src/X/Protocol/X/Protobuf/MysqlxPrepare.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2022, 2023, Oracle and/or its affiliates. +// Copyright © 2022, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -37,19 +37,23 @@ using pbc = global::Google.Protobuf.Collections; using pbr = global::Google.Protobuf.Reflection; using scg = global::System.Collections.Generic; -namespace Mysqlx.Prepare { +namespace Mysqlx.Prepare +{ /// Holder for reflection information generated from mysqlx_prepare.proto - internal static partial class MysqlxPrepareReflection { + public static partial class MysqlxPrepareReflection + { #region Descriptor /// File descriptor for mysqlx_prepare.proto - internal static pbr::FileDescriptor Descriptor { + public static pbr::FileDescriptor Descriptor + { get { return descriptor; } } private static pbr::FileDescriptor descriptor; - static MysqlxPrepareReflection() { + static MysqlxPrepareReflection() + { byte[] descriptorData = global::System.Convert.FromBase64String( string.Concat( "ChRteXNxbHhfcHJlcGFyZS5wcm90bxIOTXlzcWx4LlByZXBhcmUaDG15c3Fs", @@ -95,10 +99,11 @@ static MysqlxPrepareReflection() { /// ///@returns @ref Mysqlx::Ok or @ref Mysqlx::Error /// - internal sealed partial class Prepare : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class Prepare : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Prepare()); private pb::UnknownFieldSet _unknownFields; @@ -109,19 +114,22 @@ internal sealed partial class Prepare : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Prepare.MysqlxPrepareReflection.Descriptor.MessageTypes[0]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Prepare() { + public Prepare() + { OnConstruction(); } @@ -129,7 +137,8 @@ public Prepare() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Prepare(Prepare other) : this() { + public Prepare(Prepare other) : this() + { _hasBits0 = other._hasBits0; stmtId_ = other.stmtId_; stmt_ = other.stmt_ != null ? other.stmt_.Clone() : null; @@ -138,7 +147,8 @@ public Prepare(Prepare other) : this() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Prepare Clone() { + public Prepare Clone() + { return new Prepare(this); } @@ -153,9 +163,11 @@ public Prepare Clone() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public uint StmtId { + public uint StmtId + { get { if ((_hasBits0 & 1) != 0) { return stmtId_; } else { return StmtIdDefaultValue; } } - set { + set + { _hasBits0 |= 1; stmtId_ = value; } @@ -163,13 +175,15 @@ public uint StmtId { /// Gets whether the "stmt_id" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasStmtId { + public bool HasStmtId + { get { return (_hasBits0 & 1) != 0; } } /// Clears the value of the "stmt_id" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearStmtId() { + public void ClearStmtId() + { _hasBits0 &= ~1; } @@ -182,26 +196,32 @@ public void ClearStmtId() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Prepare.Prepare.Types.OneOfMessage Stmt { + public global::Mysqlx.Prepare.Prepare.Types.OneOfMessage Stmt + { get { return stmt_; } - set { + set + { stmt_ = value; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as Prepare); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(Prepare other) { - if (ReferenceEquals(other, null)) { + public bool Equals(Prepare other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } if (StmtId != other.StmtId) return false; @@ -211,11 +231,13 @@ public bool Equals(Prepare other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; if (HasStmtId) hash ^= StmtId.GetHashCode(); if (stmt_ != null) hash ^= Stmt.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -223,16 +245,18 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (HasStmtId) { output.WriteRawTag(8); output.WriteUInt32(StmtId); @@ -244,38 +268,46 @@ public void WriteTo(pb::CodedOutputStream output) { if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (HasStmtId) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (HasStmtId) + { output.WriteRawTag(8); output.WriteUInt32(StmtId); } - if (stmt_ != null) { + if (stmt_ != null) + { output.WriteRawTag(18); output.WriteMessage(Stmt); } - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (HasStmtId) { + if (HasStmtId) + { size += 1 + pb::CodedOutputStream.ComputeUInt32Size(StmtId); } - if (stmt_ != null) { + if (stmt_ != null) + { size += 1 + pb::CodedOutputStream.ComputeMessageSize(Stmt); } - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -283,15 +315,20 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(Prepare other) { - if (other == null) { + public void MergeFrom(Prepare other) + { + if (other == null) + { return; } - if (other.HasStmtId) { + if (other.HasStmtId) + { StmtId = other.StmtId; } - if (other.stmt_ != null) { - if (stmt_ == null) { + if (other.stmt_ != null) + { + if (stmt_ == null) + { Stmt = new global::Mysqlx.Prepare.Prepare.Types.OneOfMessage(); } Stmt.MergeFrom(other.Stmt); @@ -301,13 +338,18 @@ public void MergeFrom(Prepare other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -324,44 +366,57 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 8: { - StmtId = input.ReadUInt32(); - break; - } - case 18: { - if (stmt_ == null) { - Stmt = new global::Mysqlx.Prepare.Prepare.Types.OneOfMessage(); + case 8: + { + StmtId = input.ReadUInt32(); + break; + } + case 18: + { + if (stmt_ == null) + { + Stmt = new global::Mysqlx.Prepare.Prepare.Types.OneOfMessage(); + } + input.ReadMessage(Stmt); + break; } - input.ReadMessage(Stmt); - break; - } } } } - #endif +#endif #region Nested types /// Container for nested types declared in the Prepare message type. [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static partial class Types { + public static partial class Types + { + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] public sealed partial class OneOfMessage : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new OneOfMessage()); private pb::UnknownFieldSet _unknownFields; @@ -372,19 +427,22 @@ public sealed partial class OneOfMessage : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Prepare.Prepare.Descriptor.NestedTypes[0]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public OneOfMessage() { + public OneOfMessage() + { OnConstruction(); } @@ -392,7 +450,8 @@ public OneOfMessage() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public OneOfMessage(OneOfMessage other) : this() { + public OneOfMessage(OneOfMessage other) : this() + { _hasBits0 = other._hasBits0; type_ = other.type_; find_ = other.find_ != null ? other.find_.Clone() : null; @@ -405,7 +464,8 @@ public OneOfMessage(OneOfMessage other) : this() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public OneOfMessage Clone() { + public OneOfMessage Clone() + { return new OneOfMessage(this); } @@ -416,9 +476,11 @@ public OneOfMessage Clone() { private global::Mysqlx.Prepare.Prepare.Types.OneOfMessage.Types.Type type_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Prepare.Prepare.Types.OneOfMessage.Types.Type Type { + public global::Mysqlx.Prepare.Prepare.Types.OneOfMessage.Types.Type Type + { get { if ((_hasBits0 & 1) != 0) { return type_; } else { return TypeDefaultValue; } } - set { + set + { _hasBits0 |= 1; type_ = value; } @@ -426,13 +488,15 @@ public OneOfMessage Clone() { /// Gets whether the "type" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasType { + public bool HasType + { get { return (_hasBits0 & 1) != 0; } } /// Clears the value of the "type" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearType() { + public void ClearType() + { _hasBits0 &= ~1; } @@ -441,9 +505,11 @@ public void ClearType() { private global::Mysqlx.Crud.Find find_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Crud.Find Find { + public global::Mysqlx.Crud.Find Find + { get { return find_; } - set { + set + { find_ = value; } } @@ -453,9 +519,11 @@ public void ClearType() { private global::Mysqlx.Crud.Insert insert_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Crud.Insert Insert { + public global::Mysqlx.Crud.Insert Insert + { get { return insert_; } - set { + set + { insert_ = value; } } @@ -465,9 +533,11 @@ public void ClearType() { private global::Mysqlx.Crud.Update update_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Crud.Update Update { + public global::Mysqlx.Crud.Update Update + { get { return update_; } - set { + set + { update_ = value; } } @@ -477,9 +547,11 @@ public void ClearType() { private global::Mysqlx.Crud.Delete delete_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Crud.Delete Delete { + public global::Mysqlx.Crud.Delete Delete + { get { return delete_; } - set { + set + { delete_ = value; } } @@ -489,26 +561,32 @@ public void ClearType() { private global::Mysqlx.Sql.StmtExecute stmtExecute_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Sql.StmtExecute StmtExecute { + public global::Mysqlx.Sql.StmtExecute StmtExecute + { get { return stmtExecute_; } - set { + set + { stmtExecute_ = value; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as OneOfMessage); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(OneOfMessage other) { - if (ReferenceEquals(other, null)) { + public bool Equals(OneOfMessage other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } if (Type != other.Type) return false; @@ -522,7 +600,8 @@ public bool Equals(OneOfMessage other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; if (HasType) hash ^= Type.GetHashCode(); if (find_ != null) hash ^= Find.GetHashCode(); @@ -530,7 +609,8 @@ public override int GetHashCode() { if (update_ != null) hash ^= Update.GetHashCode(); if (delete_ != null) hash ^= Delete.GetHashCode(); if (stmtExecute_ != null) hash ^= StmtExecute.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -538,16 +618,18 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (HasType) { output.WriteRawTag(8); output.WriteEnum((int) Type); @@ -575,66 +657,82 @@ public void WriteTo(pb::CodedOutputStream output) { if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (HasType) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (HasType) + { output.WriteRawTag(8); - output.WriteEnum((int) Type); + output.WriteEnum((int)Type); } - if (find_ != null) { + if (find_ != null) + { output.WriteRawTag(18); output.WriteMessage(Find); } - if (insert_ != null) { + if (insert_ != null) + { output.WriteRawTag(26); output.WriteMessage(Insert); } - if (update_ != null) { + if (update_ != null) + { output.WriteRawTag(34); output.WriteMessage(Update); } - if (delete_ != null) { + if (delete_ != null) + { output.WriteRawTag(42); output.WriteMessage(Delete); } - if (stmtExecute_ != null) { + if (stmtExecute_ != null) + { output.WriteRawTag(50); output.WriteMessage(StmtExecute); } - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (HasType) { - size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Type); + if (HasType) + { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int)Type); } - if (find_ != null) { + if (find_ != null) + { size += 1 + pb::CodedOutputStream.ComputeMessageSize(Find); } - if (insert_ != null) { + if (insert_ != null) + { size += 1 + pb::CodedOutputStream.ComputeMessageSize(Insert); } - if (update_ != null) { + if (update_ != null) + { size += 1 + pb::CodedOutputStream.ComputeMessageSize(Update); } - if (delete_ != null) { + if (delete_ != null) + { size += 1 + pb::CodedOutputStream.ComputeMessageSize(Delete); } - if (stmtExecute_ != null) { + if (stmtExecute_ != null) + { size += 1 + pb::CodedOutputStream.ComputeMessageSize(StmtExecute); } - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -642,39 +740,52 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(OneOfMessage other) { - if (other == null) { + public void MergeFrom(OneOfMessage other) + { + if (other == null) + { return; } - if (other.HasType) { + if (other.HasType) + { Type = other.Type; } - if (other.find_ != null) { - if (find_ == null) { + if (other.find_ != null) + { + if (find_ == null) + { Find = new global::Mysqlx.Crud.Find(); } Find.MergeFrom(other.Find); } - if (other.insert_ != null) { - if (insert_ == null) { + if (other.insert_ != null) + { + if (insert_ == null) + { Insert = new global::Mysqlx.Crud.Insert(); } Insert.MergeFrom(other.Insert); } - if (other.update_ != null) { - if (update_ == null) { + if (other.update_ != null) + { + if (update_ == null) + { Update = new global::Mysqlx.Crud.Update(); } Update.MergeFrom(other.Update); } - if (other.delete_ != null) { - if (delete_ == null) { + if (other.delete_ != null) + { + if (delete_ == null) + { Delete = new global::Mysqlx.Crud.Delete(); } Delete.MergeFrom(other.Delete); } - if (other.stmtExecute_ != null) { - if (stmtExecute_ == null) { + if (other.stmtExecute_ != null) + { + if (stmtExecute_ == null) + { StmtExecute = new global::Mysqlx.Sql.StmtExecute(); } StmtExecute.MergeFrom(other.StmtExecute); @@ -684,13 +795,18 @@ public void MergeFrom(OneOfMessage other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -735,73 +851,94 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 8: { - Type = (global::Mysqlx.Prepare.Prepare.Types.OneOfMessage.Types.Type) input.ReadEnum(); - break; - } - case 18: { - if (find_ == null) { - Find = new global::Mysqlx.Crud.Find(); + case 8: + { + Type = (global::Mysqlx.Prepare.Prepare.Types.OneOfMessage.Types.Type)input.ReadEnum(); + break; } - input.ReadMessage(Find); - break; - } - case 26: { - if (insert_ == null) { - Insert = new global::Mysqlx.Crud.Insert(); + case 18: + { + if (find_ == null) + { + Find = new global::Mysqlx.Crud.Find(); + } + input.ReadMessage(Find); + break; } - input.ReadMessage(Insert); - break; - } - case 34: { - if (update_ == null) { - Update = new global::Mysqlx.Crud.Update(); + case 26: + { + if (insert_ == null) + { + Insert = new global::Mysqlx.Crud.Insert(); + } + input.ReadMessage(Insert); + break; } - input.ReadMessage(Update); - break; - } - case 42: { - if (delete_ == null) { - Delete = new global::Mysqlx.Crud.Delete(); + case 34: + { + if (update_ == null) + { + Update = new global::Mysqlx.Crud.Update(); + } + input.ReadMessage(Update); + break; } - input.ReadMessage(Delete); - break; - } - case 50: { - if (stmtExecute_ == null) { - StmtExecute = new global::Mysqlx.Sql.StmtExecute(); + case 42: + { + if (delete_ == null) + { + Delete = new global::Mysqlx.Crud.Delete(); + } + input.ReadMessage(Delete); + break; + } + case 50: + { + if (stmtExecute_ == null) + { + StmtExecute = new global::Mysqlx.Sql.StmtExecute(); + } + input.ReadMessage(StmtExecute); + break; } - input.ReadMessage(StmtExecute); - break; - } } } } - #endif +#endif #region Nested types /// Container for nested types declared in the OneOfMessage message type. [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static partial class Types { + public static partial class Types + { /// /// Determine which of optional fields was set by the client /// (Workaround for missing "oneof" keyword in pb2.5) /// - public enum Type { + public enum Type + { [pbr::OriginalName("FIND")] Find = 0, [pbr::OriginalName("INSERT")] Insert = 1, [pbr::OriginalName("UPDATE")] Update = 2, @@ -835,10 +972,11 @@ public enum Type { ///@enduml ///@returns @ref Mysqlx::Ok /// - internal sealed partial class Execute : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class Execute : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Execute()); private pb::UnknownFieldSet _unknownFields; @@ -849,19 +987,22 @@ internal sealed partial class Execute : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Prepare.MysqlxPrepareReflection.Descriptor.MessageTypes[1]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Execute() { + public Execute() + { OnConstruction(); } @@ -869,7 +1010,8 @@ public Execute() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Execute(Execute other) : this() { + public Execute(Execute other) : this() + { _hasBits0 = other._hasBits0; stmtId_ = other.stmtId_; args_ = other.args_.Clone(); @@ -879,7 +1021,8 @@ public Execute(Execute other) : this() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Execute Clone() { + public Execute Clone() + { return new Execute(this); } @@ -893,9 +1036,11 @@ public Execute Clone() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public uint StmtId { + public uint StmtId + { get { if ((_hasBits0 & 1) != 0) { return stmtId_; } else { return StmtIdDefaultValue; } } - set { + set + { _hasBits0 |= 1; stmtId_ = value; } @@ -903,13 +1048,15 @@ public uint StmtId { /// Gets whether the "stmt_id" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasStmtId { + public bool HasStmtId + { get { return (_hasBits0 & 1) != 0; } } /// Clears the value of the "stmt_id" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearStmtId() { + public void ClearStmtId() + { _hasBits0 &= ~1; } @@ -923,7 +1070,8 @@ public void ClearStmtId() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public pbc::RepeatedField Args { + public pbc::RepeatedField Args + { get { return args_; } } @@ -938,9 +1086,11 @@ public void ClearStmtId() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool CompactMetadata { + public bool CompactMetadata + { get { if ((_hasBits0 & 2) != 0) { return compactMetadata_; } else { return CompactMetadataDefaultValue; } } - set { + set + { _hasBits0 |= 2; compactMetadata_ = value; } @@ -948,45 +1098,53 @@ public bool CompactMetadata { /// Gets whether the "compact_metadata" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasCompactMetadata { + public bool HasCompactMetadata + { get { return (_hasBits0 & 2) != 0; } } /// Clears the value of the "compact_metadata" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearCompactMetadata() { + public void ClearCompactMetadata() + { _hasBits0 &= ~2; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as Execute); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(Execute other) { - if (ReferenceEquals(other, null)) { + public bool Equals(Execute other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } if (StmtId != other.StmtId) return false; - if(!args_.Equals(other.args_)) return false; + if (!args_.Equals(other.args_)) return false; if (CompactMetadata != other.CompactMetadata) return false; return Equals(_unknownFields, other._unknownFields); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; if (HasStmtId) hash ^= StmtId.GetHashCode(); hash ^= args_.GetHashCode(); if (HasCompactMetadata) hash ^= CompactMetadata.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -994,16 +1152,18 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (HasStmtId) { output.WriteRawTag(8); output.WriteUInt32(StmtId); @@ -1016,40 +1176,48 @@ public void WriteTo(pb::CodedOutputStream output) { if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (HasStmtId) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (HasStmtId) + { output.WriteRawTag(8); output.WriteUInt32(StmtId); } args_.WriteTo(ref output, _repeated_args_codec); - if (HasCompactMetadata) { + if (HasCompactMetadata) + { output.WriteRawTag(24); output.WriteBool(CompactMetadata); } - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (HasStmtId) { + if (HasStmtId) + { size += 1 + pb::CodedOutputStream.ComputeUInt32Size(StmtId); } size += args_.CalculateSize(_repeated_args_codec); - if (HasCompactMetadata) { + if (HasCompactMetadata) + { size += 1 + 1; } - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -1057,15 +1225,19 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(Execute other) { - if (other == null) { + public void MergeFrom(Execute other) + { + if (other == null) + { return; } - if (other.HasStmtId) { + if (other.HasStmtId) + { StmtId = other.StmtId; } args_.Add(other.args_); - if (other.HasCompactMetadata) { + if (other.HasCompactMetadata) + { CompactMetadata = other.CompactMetadata; } _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); @@ -1073,13 +1245,18 @@ public void MergeFrom(Execute other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -1097,35 +1274,46 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 8: { - StmtId = input.ReadUInt32(); - break; - } - case 18: { - args_.AddEntriesFrom(ref input, _repeated_args_codec); - break; - } - case 24: { - CompactMetadata = input.ReadBool(); - break; - } + case 8: + { + StmtId = input.ReadUInt32(); + break; + } + case 18: + { + args_.AddEntriesFrom(ref input, _repeated_args_codec); + break; + } + case 24: + { + CompactMetadata = input.ReadBool(); + break; + } } } } - #endif +#endif } @@ -1144,10 +1332,11 @@ public void MergeFrom(pb::CodedInputStream input) { /// ///@returns @ref Mysqlx::Ok or @ref Mysqlx::Error /// - internal sealed partial class Deallocate : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class Deallocate : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Deallocate()); private pb::UnknownFieldSet _unknownFields; @@ -1158,19 +1347,22 @@ internal sealed partial class Deallocate : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Prepare.MysqlxPrepareReflection.Descriptor.MessageTypes[2]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Deallocate() { + public Deallocate() + { OnConstruction(); } @@ -1178,7 +1370,8 @@ public Deallocate() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Deallocate(Deallocate other) : this() { + public Deallocate(Deallocate other) : this() + { _hasBits0 = other._hasBits0; stmtId_ = other.stmtId_; _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); @@ -1186,7 +1379,8 @@ public Deallocate(Deallocate other) : this() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Deallocate Clone() { + public Deallocate Clone() + { return new Deallocate(this); } @@ -1200,9 +1394,11 @@ public Deallocate Clone() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public uint StmtId { + public uint StmtId + { get { if ((_hasBits0 & 1) != 0) { return stmtId_; } else { return StmtIdDefaultValue; } } - set { + set + { _hasBits0 |= 1; stmtId_ = value; } @@ -1210,29 +1406,35 @@ public uint StmtId { /// Gets whether the "stmt_id" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasStmtId { + public bool HasStmtId + { get { return (_hasBits0 & 1) != 0; } } /// Clears the value of the "stmt_id" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearStmtId() { + public void ClearStmtId() + { _hasBits0 &= ~1; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as Deallocate); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(Deallocate other) { - if (ReferenceEquals(other, null)) { + public bool Equals(Deallocate other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } if (StmtId != other.StmtId) return false; @@ -1241,10 +1443,12 @@ public bool Equals(Deallocate other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; if (HasStmtId) hash ^= StmtId.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -1252,16 +1456,18 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (HasStmtId) { output.WriteRawTag(8); output.WriteUInt32(StmtId); @@ -1269,31 +1475,37 @@ public void WriteTo(pb::CodedOutputStream output) { if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (HasStmtId) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (HasStmtId) + { output.WriteRawTag(8); output.WriteUInt32(StmtId); } - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (HasStmtId) { + if (HasStmtId) + { size += 1 + pb::CodedOutputStream.ComputeUInt32Size(StmtId); } - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -1301,11 +1513,14 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(Deallocate other) { - if (other == null) { + public void MergeFrom(Deallocate other) + { + if (other == null) + { return; } - if (other.HasStmtId) { + if (other.HasStmtId) + { StmtId = other.StmtId; } _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); @@ -1313,13 +1528,18 @@ public void MergeFrom(Deallocate other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -1329,27 +1549,36 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 8: { - StmtId = input.ReadUInt32(); - break; - } + case 8: + { + StmtId = input.ReadUInt32(); + break; + } } } } - #endif +#endif } @@ -1358,3 +1587,4 @@ public void MergeFrom(pb::CodedInputStream input) { } #endregion Designer generated code + diff --git a/MySQL.Data/src/X/Protocol/X/Protobuf/MysqlxResultset.cs b/MySQL.Data/src/X/Protocol/X/Protobuf/MysqlxResultset.cs index c80e9d959..909bf01e1 100644 --- a/MySQL.Data/src/X/Protocol/X/Protobuf/MysqlxResultset.cs +++ b/MySQL.Data/src/X/Protocol/X/Protobuf/MysqlxResultset.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2022, 2023, Oracle and/or its affiliates. +// Copyright © 2022, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -37,19 +37,23 @@ using pbc = global::Google.Protobuf.Collections; using pbr = global::Google.Protobuf.Reflection; using scg = global::System.Collections.Generic; -namespace Mysqlx.Resultset { +namespace Mysqlx.Resultset +{ /// Holder for reflection information generated from mysqlx_resultset.proto - internal static partial class MysqlxResultsetReflection { + public static partial class MysqlxResultsetReflection + { #region Descriptor /// File descriptor for mysqlx_resultset.proto - public static pbr::FileDescriptor Descriptor { + public static pbr::FileDescriptor Descriptor + { get { return descriptor; } } private static pbr::FileDescriptor descriptor; - static MysqlxResultsetReflection() { + static MysqlxResultsetReflection() + { byte[] descriptorData = global::System.Convert.FromBase64String( string.Concat( "ChZteXNxbHhfcmVzdWx0c2V0LnByb3RvEhBNeXNxbHguUmVzdWx0c2V0Ggxt", @@ -71,7 +75,7 @@ static MysqlxResultsetReflection() { "Chdjb20ubXlzcWwuY2oueC5wcm90b2J1Zg==")); descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, new pbr::FileDescriptor[] { global::Mysqlx.MysqlxReflection.Descriptor, }, - new pbr::GeneratedClrTypeInfo(new[] {typeof(global::Mysqlx.Resultset.ContentType_BYTES), typeof(global::Mysqlx.Resultset.ContentType_DATETIME), }, null, new pbr::GeneratedClrTypeInfo[] { + new pbr::GeneratedClrTypeInfo(new[] { typeof(global::Mysqlx.Resultset.ContentType_BYTES), typeof(global::Mysqlx.Resultset.ContentType_DATETIME), }, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::Mysqlx.Resultset.FetchDoneMoreOutParams), global::Mysqlx.Resultset.FetchDoneMoreOutParams.Parser, null, null, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Mysqlx.Resultset.FetchDoneMoreResultsets), global::Mysqlx.Resultset.FetchDoneMoreResultsets.Parser, null, null, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Mysqlx.Resultset.FetchDone), global::Mysqlx.Resultset.FetchDone.Parser, null, null, null, null, null), @@ -101,7 +105,8 @@ static MysqlxResultsetReflection() { ///like image manipulation, seeking into complex types in BLOBs, ... more ///types will be added. /// - internal enum ContentType_BYTES { + public enum ContentType_BYTES + { [pbr::OriginalName("GEOMETRY")] Geometry = 1, [pbr::OriginalName("JSON")] Json = 2, [pbr::OriginalName("XML")] Xml = 3, @@ -116,7 +121,8 @@ internal enum ContentType_BYTES { ///|DATE |0x0001 |DATETIME contains only date part | ///|DATETIME |0x0002 |DATETIME contains both date and time parts | /// - internal enum ContentType_DATETIME { + public enum ContentType_DATETIME + { [pbr::OriginalName("DATE")] Date = 1, [pbr::OriginalName("DATETIME")] Datetime = 2, } @@ -128,10 +134,11 @@ internal enum ContentType_DATETIME { ///* ///Resultsets are finished, OUT paramset is next: /// - internal sealed partial class FetchDoneMoreOutParams : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class FetchDoneMoreOutParams : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new FetchDoneMoreOutParams()); private pb::UnknownFieldSet _unknownFields; @@ -141,19 +148,22 @@ internal sealed partial class FetchDoneMoreOutParams : pb::IMessage - internal sealed partial class FetchDoneMoreResultsets : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class FetchDoneMoreResultsets : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new FetchDoneMoreResultsets()); private pb::UnknownFieldSet _unknownFields; @@ -297,19 +337,22 @@ internal sealed partial class FetchDoneMoreResultsets : pb::IMessage - internal sealed partial class FetchDone : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class FetchDone : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new FetchDone()); private pb::UnknownFieldSet _unknownFields; @@ -453,19 +526,22 @@ internal sealed partial class FetchDone : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Resultset.MysqlxResultsetReflection.Descriptor.MessageTypes[2]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public FetchDone() { + public FetchDone() + { OnConstruction(); } @@ -473,29 +549,35 @@ public FetchDone() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public FetchDone(FetchDone other) : this() { + public FetchDone(FetchDone other) : this() + { _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public FetchDone Clone() { + public FetchDone Clone() + { return new FetchDone(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as FetchDone); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(FetchDone other) { - if (ReferenceEquals(other, null)) { + public bool Equals(FetchDone other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } return Equals(_unknownFields, other._unknownFields); @@ -503,9 +585,11 @@ public bool Equals(FetchDone other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -513,37 +597,43 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (_unknownFields != null) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -551,8 +641,10 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(FetchDone other) { - if (other == null) { + public void MergeFrom(FetchDone other) + { + if (other == null) + { return; } _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); @@ -560,35 +652,48 @@ public void MergeFrom(FetchDone other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; } } } - #endif +#endif } @@ -596,10 +701,11 @@ public void MergeFrom(pb::CodedInputStream input) { ///* ///Cursor is opened; still, the execution of PrepFetch or PrepExecute ended /// - internal sealed partial class FetchSuspended : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class FetchSuspended : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new FetchSuspended()); private pb::UnknownFieldSet _unknownFields; @@ -609,19 +715,22 @@ internal sealed partial class FetchSuspended : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Resultset.MysqlxResultsetReflection.Descriptor.MessageTypes[3]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public FetchSuspended() { + public FetchSuspended() + { OnConstruction(); } @@ -629,29 +738,35 @@ public FetchSuspended() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public FetchSuspended(FetchSuspended other) : this() { + public FetchSuspended(FetchSuspended other) : this() + { _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public FetchSuspended Clone() { + public FetchSuspended Clone() + { return new FetchSuspended(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as FetchSuspended); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(FetchSuspended other) { - if (ReferenceEquals(other, null)) { + public bool Equals(FetchSuspended other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } return Equals(_unknownFields, other._unknownFields); @@ -659,9 +774,11 @@ public bool Equals(FetchSuspended other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -669,37 +786,43 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (_unknownFields != null) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -707,8 +830,10 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(FetchSuspended other) { - if (other == null) { + public void MergeFrom(FetchSuspended other) + { + if (other == null) + { return; } _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); @@ -716,35 +841,48 @@ public void MergeFrom(FetchSuspended other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; } } } - #endif +#endif } @@ -1075,10 +1213,11 @@ public void MergeFrom(pb::CodedInputStream input) { /// ///- ``[8] 0x03 F O O 0x03 B A R`` - a set with 2 items: FOO,BAR /// - internal sealed partial class ColumnMetaData : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class ColumnMetaData : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ColumnMetaData()); private pb::UnknownFieldSet _unknownFields; @@ -1089,19 +1228,22 @@ internal sealed partial class ColumnMetaData : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Resultset.MysqlxResultsetReflection.Descriptor.MessageTypes[4]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public ColumnMetaData() { + public ColumnMetaData() + { OnConstruction(); } @@ -1109,7 +1251,8 @@ public ColumnMetaData() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public ColumnMetaData(ColumnMetaData other) : this() { + public ColumnMetaData(ColumnMetaData other) : this() + { _hasBits0 = other._hasBits0; type_ = other.type_; name_ = other.name_; @@ -1128,7 +1271,8 @@ public ColumnMetaData(ColumnMetaData other) : this() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public ColumnMetaData Clone() { + public ColumnMetaData Clone() + { return new ColumnMetaData(this); } @@ -1142,9 +1286,11 @@ public ColumnMetaData Clone() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public global::Mysqlx.Resultset.ColumnMetaData.Types.FieldType Type { + public global::Mysqlx.Resultset.ColumnMetaData.Types.FieldType Type + { get { if ((_hasBits0 & 1) != 0) { return type_; } else { return TypeDefaultValue; } } - set { + set + { _hasBits0 |= 1; type_ = value; } @@ -1152,13 +1298,15 @@ public ColumnMetaData Clone() { /// Gets whether the "type" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasType { + public bool HasType + { get { return (_hasBits0 & 1) != 0; } } /// Clears the value of the "type" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearType() { + public void ClearType() + { _hasBits0 &= ~1; } @@ -1172,22 +1320,26 @@ public void ClearType() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public pb::ByteString Name { + public pb::ByteString Name + { get { return name_ ?? NameDefaultValue; } - set { + set + { name_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); } } /// Gets whether the "name" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasName { + public bool HasName + { get { return name_ != null; } } /// Clears the value of the "name" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearName() { + public void ClearName() + { name_ = null; } @@ -1201,22 +1353,26 @@ public void ClearName() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public pb::ByteString OriginalName { + public pb::ByteString OriginalName + { get { return originalName_ ?? OriginalNameDefaultValue; } - set { + set + { originalName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); } } /// Gets whether the "original_name" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasOriginalName { + public bool HasOriginalName + { get { return originalName_ != null; } } /// Clears the value of the "original_name" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearOriginalName() { + public void ClearOriginalName() + { originalName_ = null; } @@ -1230,22 +1386,26 @@ public void ClearOriginalName() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public pb::ByteString Table { + public pb::ByteString Table + { get { return table_ ?? TableDefaultValue; } - set { + set + { table_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); } } /// Gets whether the "table" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasTable { + public bool HasTable + { get { return table_ != null; } } /// Clears the value of the "table" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearTable() { + public void ClearTable() + { table_ = null; } @@ -1259,22 +1419,26 @@ public void ClearTable() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public pb::ByteString OriginalTable { + public pb::ByteString OriginalTable + { get { return originalTable_ ?? OriginalTableDefaultValue; } - set { + set + { originalTable_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); } } /// Gets whether the "original_table" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasOriginalTable { + public bool HasOriginalTable + { get { return originalTable_ != null; } } /// Clears the value of the "original_table" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearOriginalTable() { + public void ClearOriginalTable() + { originalTable_ = null; } @@ -1288,22 +1452,26 @@ public void ClearOriginalTable() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public pb::ByteString Schema { + public pb::ByteString Schema + { get { return schema_ ?? SchemaDefaultValue; } - set { + set + { schema_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); } } /// Gets whether the "schema" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasSchema { + public bool HasSchema + { get { return schema_ != null; } } /// Clears the value of the "schema" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearSchema() { + public void ClearSchema() + { schema_ = null; } @@ -1321,22 +1489,26 @@ public void ClearSchema() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public pb::ByteString Catalog { + public pb::ByteString Catalog + { get { return catalog_ ?? CatalogDefaultValue; } - set { + set + { catalog_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); } } /// Gets whether the "catalog" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasCatalog { + public bool HasCatalog + { get { return catalog_ != null; } } /// Clears the value of the "catalog" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearCatalog() { + public void ClearCatalog() + { catalog_ = null; } @@ -1347,9 +1519,11 @@ public void ClearCatalog() { private ulong collation_; [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public ulong Collation { + public ulong Collation + { get { if ((_hasBits0 & 2) != 0) { return collation_; } else { return CollationDefaultValue; } } - set { + set + { _hasBits0 |= 2; collation_ = value; } @@ -1357,13 +1531,15 @@ public ulong Collation { /// Gets whether the "collation" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasCollation { + public bool HasCollation + { get { return (_hasBits0 & 2) != 0; } } /// Clears the value of the "collation" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearCollation() { + public void ClearCollation() + { _hasBits0 &= ~2; } @@ -1378,9 +1554,11 @@ public void ClearCollation() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public uint FractionalDigits { + public uint FractionalDigits + { get { if ((_hasBits0 & 4) != 0) { return fractionalDigits_; } else { return FractionalDigitsDefaultValue; } } - set { + set + { _hasBits0 |= 4; fractionalDigits_ = value; } @@ -1388,13 +1566,15 @@ public uint FractionalDigits { /// Gets whether the "fractional_digits" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasFractionalDigits { + public bool HasFractionalDigits + { get { return (_hasBits0 & 4) != 0; } } /// Clears the value of the "fractional_digits" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearFractionalDigits() { + public void ClearFractionalDigits() + { _hasBits0 &= ~4; } @@ -1408,9 +1588,11 @@ public void ClearFractionalDigits() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public uint Length { + public uint Length + { get { if ((_hasBits0 & 8) != 0) { return length_; } else { return LengthDefaultValue; } } - set { + set + { _hasBits0 |= 8; length_ = value; } @@ -1418,13 +1600,15 @@ public uint Length { /// Gets whether the "length" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasLength { + public bool HasLength + { get { return (_hasBits0 & 8) != 0; } } /// Clears the value of the "length" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearLength() { + public void ClearLength() + { _hasBits0 &= ~8; } @@ -1455,9 +1639,11 @@ public void ClearLength() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public uint Flags { + public uint Flags + { get { if ((_hasBits0 & 16) != 0) { return flags_; } else { return FlagsDefaultValue; } } - set { + set + { _hasBits0 |= 16; flags_ = value; } @@ -1465,13 +1651,15 @@ public uint Flags { /// Gets whether the "flags" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasFlags { + public bool HasFlags + { get { return (_hasBits0 & 16) != 0; } } /// Clears the value of the "flags" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearFlags() { + public void ClearFlags() + { _hasBits0 &= ~16; } @@ -1497,9 +1685,11 @@ public void ClearFlags() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public uint ContentType { + public uint ContentType + { get { if ((_hasBits0 & 32) != 0) { return contentType_; } else { return ContentTypeDefaultValue; } } - set { + set + { _hasBits0 |= 32; contentType_ = value; } @@ -1507,29 +1697,35 @@ public uint ContentType { /// Gets whether the "content_type" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasContentType { + public bool HasContentType + { get { return (_hasBits0 & 32) != 0; } } /// Clears the value of the "content_type" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearContentType() { + public void ClearContentType() + { _hasBits0 &= ~32; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as ColumnMetaData); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(ColumnMetaData other) { - if (ReferenceEquals(other, null)) { + public bool Equals(ColumnMetaData other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } if (Type != other.Type) return false; @@ -1549,7 +1745,8 @@ public bool Equals(ColumnMetaData other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; if (HasType) hash ^= Type.GetHashCode(); if (HasName) hash ^= Name.GetHashCode(); @@ -1563,7 +1760,8 @@ public override int GetHashCode() { if (HasLength) hash ^= Length.GetHashCode(); if (HasFlags) hash ^= Flags.GetHashCode(); if (HasContentType) hash ^= ContentType.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -1571,16 +1769,18 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (HasType) { output.WriteRawTag(8); output.WriteEnum((int) Type); @@ -1632,108 +1832,136 @@ public void WriteTo(pb::CodedOutputStream output) { if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (HasType) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (HasType) + { output.WriteRawTag(8); - output.WriteEnum((int) Type); + output.WriteEnum((int)Type); } - if (HasName) { + if (HasName) + { output.WriteRawTag(18); output.WriteBytes(Name); } - if (HasOriginalName) { + if (HasOriginalName) + { output.WriteRawTag(26); output.WriteBytes(OriginalName); } - if (HasTable) { + if (HasTable) + { output.WriteRawTag(34); output.WriteBytes(Table); } - if (HasOriginalTable) { + if (HasOriginalTable) + { output.WriteRawTag(42); output.WriteBytes(OriginalTable); } - if (HasSchema) { + if (HasSchema) + { output.WriteRawTag(50); output.WriteBytes(Schema); } - if (HasCatalog) { + if (HasCatalog) + { output.WriteRawTag(58); output.WriteBytes(Catalog); } - if (HasCollation) { + if (HasCollation) + { output.WriteRawTag(64); output.WriteUInt64(Collation); } - if (HasFractionalDigits) { + if (HasFractionalDigits) + { output.WriteRawTag(72); output.WriteUInt32(FractionalDigits); } - if (HasLength) { + if (HasLength) + { output.WriteRawTag(80); output.WriteUInt32(Length); } - if (HasFlags) { + if (HasFlags) + { output.WriteRawTag(88); output.WriteUInt32(Flags); } - if (HasContentType) { + if (HasContentType) + { output.WriteRawTag(96); output.WriteUInt32(ContentType); } - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (HasType) { - size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Type); + if (HasType) + { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int)Type); } - if (HasName) { + if (HasName) + { size += 1 + pb::CodedOutputStream.ComputeBytesSize(Name); } - if (HasOriginalName) { + if (HasOriginalName) + { size += 1 + pb::CodedOutputStream.ComputeBytesSize(OriginalName); } - if (HasTable) { + if (HasTable) + { size += 1 + pb::CodedOutputStream.ComputeBytesSize(Table); } - if (HasOriginalTable) { + if (HasOriginalTable) + { size += 1 + pb::CodedOutputStream.ComputeBytesSize(OriginalTable); } - if (HasSchema) { + if (HasSchema) + { size += 1 + pb::CodedOutputStream.ComputeBytesSize(Schema); } - if (HasCatalog) { + if (HasCatalog) + { size += 1 + pb::CodedOutputStream.ComputeBytesSize(Catalog); } - if (HasCollation) { + if (HasCollation) + { size += 1 + pb::CodedOutputStream.ComputeUInt64Size(Collation); } - if (HasFractionalDigits) { + if (HasFractionalDigits) + { size += 1 + pb::CodedOutputStream.ComputeUInt32Size(FractionalDigits); } - if (HasLength) { + if (HasLength) + { size += 1 + pb::CodedOutputStream.ComputeUInt32Size(Length); } - if (HasFlags) { + if (HasFlags) + { size += 1 + pb::CodedOutputStream.ComputeUInt32Size(Flags); } - if (HasContentType) { + if (HasContentType) + { size += 1 + pb::CodedOutputStream.ComputeUInt32Size(ContentType); } - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -1741,44 +1969,58 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(ColumnMetaData other) { - if (other == null) { + public void MergeFrom(ColumnMetaData other) + { + if (other == null) + { return; } - if (other.HasType) { + if (other.HasType) + { Type = other.Type; } - if (other.HasName) { + if (other.HasName) + { Name = other.Name; } - if (other.HasOriginalName) { + if (other.HasOriginalName) + { OriginalName = other.OriginalName; } - if (other.HasTable) { + if (other.HasTable) + { Table = other.Table; } - if (other.HasOriginalTable) { + if (other.HasOriginalTable) + { OriginalTable = other.OriginalTable; } - if (other.HasSchema) { + if (other.HasSchema) + { Schema = other.Schema; } - if (other.HasCatalog) { + if (other.HasCatalog) + { Catalog = other.Catalog; } - if (other.HasCollation) { + if (other.HasCollation) + { Collation = other.Collation; } - if (other.HasFractionalDigits) { + if (other.HasFractionalDigits) + { FractionalDigits = other.FractionalDigits; } - if (other.HasLength) { + if (other.HasLength) + { Length = other.Length; } - if (other.HasFlags) { + if (other.HasFlags) + { Flags = other.Flags; } - if (other.HasContentType) { + if (other.HasContentType) + { ContentType = other.ContentType; } _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); @@ -1786,13 +2028,18 @@ public void MergeFrom(ColumnMetaData other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -1846,78 +2093,100 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 8: { - Type = (global::Mysqlx.Resultset.ColumnMetaData.Types.FieldType) input.ReadEnum(); - break; - } - case 18: { - Name = input.ReadBytes(); - break; - } - case 26: { - OriginalName = input.ReadBytes(); - break; - } - case 34: { - Table = input.ReadBytes(); - break; - } - case 42: { - OriginalTable = input.ReadBytes(); - break; - } - case 50: { - Schema = input.ReadBytes(); - break; - } - case 58: { - Catalog = input.ReadBytes(); - break; - } - case 64: { - Collation = input.ReadUInt64(); - break; - } - case 72: { - FractionalDigits = input.ReadUInt32(); - break; - } - case 80: { - Length = input.ReadUInt32(); - break; - } - case 88: { - Flags = input.ReadUInt32(); - break; - } - case 96: { - ContentType = input.ReadUInt32(); - break; - } + case 8: + { + Type = (global::Mysqlx.Resultset.ColumnMetaData.Types.FieldType)input.ReadEnum(); + break; + } + case 18: + { + Name = input.ReadBytes(); + break; + } + case 26: + { + OriginalName = input.ReadBytes(); + break; + } + case 34: + { + Table = input.ReadBytes(); + break; + } + case 42: + { + OriginalTable = input.ReadBytes(); + break; + } + case 50: + { + Schema = input.ReadBytes(); + break; + } + case 58: + { + Catalog = input.ReadBytes(); + break; + } + case 64: + { + Collation = input.ReadUInt64(); + break; + } + case 72: + { + FractionalDigits = input.ReadUInt32(); + break; + } + case 80: + { + Length = input.ReadUInt32(); + break; + } + case 88: + { + Flags = input.ReadUInt32(); + break; + } + case 96: + { + ContentType = input.ReadUInt32(); + break; + } } } } - #endif +#endif #region Nested types /// Container for nested types declared in the ColumnMetaData message type. [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static partial class Types { - public enum FieldType { + public static partial class Types + { + public enum FieldType + { [pbr::OriginalName("SINT")] Sint = 1, [pbr::OriginalName("UINT")] Uint = 2, [pbr::OriginalName("DOUBLE")] Double = 5, @@ -1946,10 +2215,11 @@ public enum FieldType { ///``ColumnMetadata``, as specified in the @ref Mysqlx::Resultset::ColumnMetaData ///description. /// - internal sealed partial class Row : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class Row : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Row()); private pb::UnknownFieldSet _unknownFields; @@ -1959,19 +2229,22 @@ internal sealed partial class Row : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Resultset.MysqlxResultsetReflection.Descriptor.MessageTypes[5]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Row() { + public Row() + { OnConstruction(); } @@ -1979,14 +2252,16 @@ public Row() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Row(Row other) : this() { + public Row(Row other) : this() + { field_ = other.field_.Clone(); _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Row Clone() { + public Row Clone() + { return new Row(this); } @@ -1997,35 +2272,42 @@ public Row Clone() { private readonly pbc::RepeatedField field_ = new pbc::RepeatedField(); [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public pbc::RepeatedField Field { + public pbc::RepeatedField Field + { get { return field_; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as Row); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(Row other) { - if (ReferenceEquals(other, null)) { + public bool Equals(Row other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } - if(!field_.Equals(other.field_)) return false; + if (!field_.Equals(other.field_)) return false; return Equals(_unknownFields, other._unknownFields); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; hash ^= field_.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -2033,40 +2315,46 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else field_.WriteTo(output, _repeated_field_codec); if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { field_.WriteTo(ref output, _repeated_field_codec); - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; size += field_.CalculateSize(_repeated_field_codec); - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -2074,8 +2362,10 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(Row other) { - if (other == null) { + public void MergeFrom(Row other) + { + if (other == null) + { return; } field_.Add(other.field_); @@ -2084,13 +2374,18 @@ public void MergeFrom(Row other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -2100,27 +2395,36 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 10: { - field_.AddEntriesFrom(ref input, _repeated_field_codec); - break; - } + case 10: + { + field_.AddEntriesFrom(ref input, _repeated_field_codec); + break; + } } } } - #endif +#endif } @@ -2129,3 +2433,4 @@ public void MergeFrom(pb::CodedInputStream input) { } #endregion Designer generated code + diff --git a/MySQL.Data/src/X/Protocol/X/Protobuf/MysqlxSession.cs b/MySQL.Data/src/X/Protocol/X/Protobuf/MysqlxSession.cs index 5ef3192e6..6a3c0f640 100644 --- a/MySQL.Data/src/X/Protocol/X/Protobuf/MysqlxSession.cs +++ b/MySQL.Data/src/X/Protocol/X/Protobuf/MysqlxSession.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2022, 2023, Oracle and/or its affiliates. +// Copyright © 2022, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -37,26 +37,30 @@ using pbc = global::Google.Protobuf.Collections; using pbr = global::Google.Protobuf.Reflection; using scg = global::System.Collections.Generic; -namespace Mysqlx.Session { +namespace Mysqlx.Session +{ /// Holder for reflection information generated from mysqlx_session.proto - internal static partial class MysqlxSessionReflection { + public static partial class MysqlxSessionReflection + { #region Descriptor /// File descriptor for mysqlx_session.proto - public static pbr::FileDescriptor Descriptor { + public static pbr::FileDescriptor Descriptor + { get { return descriptor; } } private static pbr::FileDescriptor descriptor; - static MysqlxSessionReflection() { + static MysqlxSessionReflection() + { byte[] descriptorData = global::System.Convert.FromBase64String( string.Concat( "ChRteXNxbHhfc2Vzc2lvbi5wcm90bxIOTXlzcWx4LlNlc3Npb24aDG15c3Fs", "eC5wcm90byJZChFBdXRoZW50aWNhdGVTdGFydBIRCgltZWNoX25hbWUYASAC", "KAkSEQoJYXV0aF9kYXRhGAIgASgMEhgKEGluaXRpYWxfcmVzcG9uc2UYAyAB", "KAw6BIjqMAQiMwoUQXV0aGVudGljYXRlQ29udGludWUSEQoJYXV0aF9kYXRh", - "GAEgAigMOgiQ6jADiOowBSIpCg5BdXRoZW50aWNhdGVPaxIRCglhdXRoX2Rh", + "GAEgAigMOgiI6jAFkOowAyIpCg5BdXRoZW50aWNhdGVPaxIRCglhdXRoX2Rh", "dGEYASABKAw6BJDqMAQiJwoFUmVzZXQSGAoJa2VlcF9vcGVuGAEgASgIOgVm", "YWxzZToEiOowBiINCgVDbG9zZToEiOowB0IZChdjb20ubXlzcWwuY2oueC5w", "cm90b2J1Zg==")); @@ -81,10 +85,11 @@ static MysqlxSessionReflection() { /// ///@returns @ref Mysqlx::Session::AuthenticateContinue /// - internal sealed partial class AuthenticateStart : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class AuthenticateStart : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new AuthenticateStart()); private pb::UnknownFieldSet _unknownFields; @@ -94,19 +99,22 @@ internal sealed partial class AuthenticateStart : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public string MechName { + public string MechName + { get { return mechName_ ?? MechNameDefaultValue; } - set { + set + { mechName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); } } /// Gets whether the "mech_name" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasMechName { + public bool HasMechName + { get { return mechName_ != null; } } /// Clears the value of the "mech_name" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearMechName() { + public void ClearMechName() + { mechName_ = null; } @@ -166,22 +180,26 @@ public void ClearMechName() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public pb::ByteString AuthData { + public pb::ByteString AuthData + { get { return authData_ ?? AuthDataDefaultValue; } - set { + set + { authData_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); } } /// Gets whether the "auth_data" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasAuthData { + public bool HasAuthData + { get { return authData_ != null; } } /// Clears the value of the "auth_data" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearAuthData() { + public void ClearAuthData() + { authData_ = null; } @@ -195,38 +213,46 @@ public void ClearAuthData() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public pb::ByteString InitialResponse { + public pb::ByteString InitialResponse + { get { return initialResponse_ ?? InitialResponseDefaultValue; } - set { + set + { initialResponse_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); } } /// Gets whether the "initial_response" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasInitialResponse { + public bool HasInitialResponse + { get { return initialResponse_ != null; } } /// Clears the value of the "initial_response" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearInitialResponse() { + public void ClearInitialResponse() + { initialResponse_ = null; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as AuthenticateStart); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(AuthenticateStart other) { - if (ReferenceEquals(other, null)) { + public bool Equals(AuthenticateStart other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } if (MechName != other.MechName) return false; @@ -237,12 +263,14 @@ public bool Equals(AuthenticateStart other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; if (HasMechName) hash ^= MechName.GetHashCode(); if (HasAuthData) hash ^= AuthData.GetHashCode(); if (HasInitialResponse) hash ^= InitialResponse.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -250,16 +278,18 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (HasMechName) { output.WriteRawTag(10); output.WriteString(MechName); @@ -275,45 +305,55 @@ public void WriteTo(pb::CodedOutputStream output) { if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (HasMechName) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (HasMechName) + { output.WriteRawTag(10); output.WriteString(MechName); } - if (HasAuthData) { + if (HasAuthData) + { output.WriteRawTag(18); output.WriteBytes(AuthData); } - if (HasInitialResponse) { + if (HasInitialResponse) + { output.WriteRawTag(26); output.WriteBytes(InitialResponse); } - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (HasMechName) { + if (HasMechName) + { size += 1 + pb::CodedOutputStream.ComputeStringSize(MechName); } - if (HasAuthData) { + if (HasAuthData) + { size += 1 + pb::CodedOutputStream.ComputeBytesSize(AuthData); } - if (HasInitialResponse) { + if (HasInitialResponse) + { size += 1 + pb::CodedOutputStream.ComputeBytesSize(InitialResponse); } - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -321,17 +361,22 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(AuthenticateStart other) { - if (other == null) { + public void MergeFrom(AuthenticateStart other) + { + if (other == null) + { return; } - if (other.HasMechName) { + if (other.HasMechName) + { MechName = other.MechName; } - if (other.HasAuthData) { + if (other.HasAuthData) + { AuthData = other.AuthData; } - if (other.HasInitialResponse) { + if (other.HasInitialResponse) + { InitialResponse = other.InitialResponse; } _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); @@ -339,13 +384,18 @@ public void MergeFrom(AuthenticateStart other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -363,35 +413,46 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 10: { - MechName = input.ReadString(); - break; - } - case 18: { - AuthData = input.ReadBytes(); - break; - } - case 26: { - InitialResponse = input.ReadBytes(); - break; - } + case 10: + { + MechName = input.ReadString(); + break; + } + case 18: + { + AuthData = input.ReadBytes(); + break; + } + case 26: + { + InitialResponse = input.ReadBytes(); + break; + } } } } - #endif +#endif } @@ -402,10 +463,11 @@ public void MergeFrom(pb::CodedInputStream input) { /// ///@returns Mysqlx::Session::AuthenticateContinue /// - internal sealed partial class AuthenticateContinue : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class AuthenticateContinue : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new AuthenticateContinue()); private pb::UnknownFieldSet _unknownFields; @@ -415,19 +477,22 @@ internal sealed partial class AuthenticateContinue : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public pb::ByteString AuthData { + public pb::ByteString AuthData + { get { return authData_ ?? AuthDataDefaultValue; } - set { + set + { authData_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); } } /// Gets whether the "auth_data" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasAuthData { + public bool HasAuthData + { get { return authData_ != null; } } /// Clears the value of the "auth_data" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearAuthData() { + public void ClearAuthData() + { authData_ = null; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as AuthenticateContinue); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(AuthenticateContinue other) { - if (ReferenceEquals(other, null)) { + public bool Equals(AuthenticateContinue other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } if (AuthData != other.AuthData) return false; @@ -496,10 +571,12 @@ public bool Equals(AuthenticateContinue other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; if (HasAuthData) hash ^= AuthData.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -507,16 +584,18 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (HasAuthData) { output.WriteRawTag(10); output.WriteBytes(AuthData); @@ -524,31 +603,37 @@ public void WriteTo(pb::CodedOutputStream output) { if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (HasAuthData) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (HasAuthData) + { output.WriteRawTag(10); output.WriteBytes(AuthData); } - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (HasAuthData) { + if (HasAuthData) + { size += 1 + pb::CodedOutputStream.ComputeBytesSize(AuthData); } - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -556,11 +641,14 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(AuthenticateContinue other) { - if (other == null) { + public void MergeFrom(AuthenticateContinue other) + { + if (other == null) + { return; } - if (other.HasAuthData) { + if (other.HasAuthData) + { AuthData = other.AuthData; } _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); @@ -568,13 +656,18 @@ public void MergeFrom(AuthenticateContinue other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -584,27 +677,36 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 10: { - AuthData = input.ReadBytes(); - break; - } + case 10: + { + AuthData = input.ReadBytes(); + break; + } } } } - #endif +#endif } @@ -612,10 +714,11 @@ public void MergeFrom(pb::CodedInputStream input) { ///* ///Sent by the server after successful authentication. /// - internal sealed partial class AuthenticateOk : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class AuthenticateOk : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new AuthenticateOk()); private pb::UnknownFieldSet _unknownFields; @@ -625,19 +728,22 @@ internal sealed partial class AuthenticateOk : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Session.MysqlxSessionReflection.Descriptor.MessageTypes[2]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public AuthenticateOk() { + public AuthenticateOk() + { OnConstruction(); } @@ -645,14 +751,16 @@ public AuthenticateOk() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public AuthenticateOk(AuthenticateOk other) : this() { + public AuthenticateOk(AuthenticateOk other) : this() + { authData_ = other.authData_; _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public AuthenticateOk Clone() { + public AuthenticateOk Clone() + { return new AuthenticateOk(this); } @@ -666,38 +774,46 @@ public AuthenticateOk Clone() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public pb::ByteString AuthData { + public pb::ByteString AuthData + { get { return authData_ ?? AuthDataDefaultValue; } - set { + set + { authData_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); } } /// Gets whether the "auth_data" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasAuthData { + public bool HasAuthData + { get { return authData_ != null; } } /// Clears the value of the "auth_data" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearAuthData() { + public void ClearAuthData() + { authData_ = null; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as AuthenticateOk); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(AuthenticateOk other) { - if (ReferenceEquals(other, null)) { + public bool Equals(AuthenticateOk other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } if (AuthData != other.AuthData) return false; @@ -706,10 +822,12 @@ public bool Equals(AuthenticateOk other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; if (HasAuthData) hash ^= AuthData.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -717,16 +835,18 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (HasAuthData) { output.WriteRawTag(10); output.WriteBytes(AuthData); @@ -734,31 +854,37 @@ public void WriteTo(pb::CodedOutputStream output) { if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (HasAuthData) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (HasAuthData) + { output.WriteRawTag(10); output.WriteBytes(AuthData); } - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (HasAuthData) { + if (HasAuthData) + { size += 1 + pb::CodedOutputStream.ComputeBytesSize(AuthData); } - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -766,11 +892,14 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(AuthenticateOk other) { - if (other == null) { + public void MergeFrom(AuthenticateOk other) + { + if (other == null) + { return; } - if (other.HasAuthData) { + if (other.HasAuthData) + { AuthData = other.AuthData; } _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); @@ -778,13 +907,18 @@ public void MergeFrom(AuthenticateOk other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -794,27 +928,36 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 10: { - AuthData = input.ReadBytes(); - break; - } + case 10: + { + AuthData = input.ReadBytes(); + break; + } } } } - #endif +#endif } @@ -824,10 +967,11 @@ public void MergeFrom(pb::CodedInputStream input) { /// ///@returns @ref Mysqlx::Ok /// - internal sealed partial class Reset : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class Reset : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Reset()); private pb::UnknownFieldSet _unknownFields; @@ -838,19 +982,22 @@ internal sealed partial class Reset : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Session.MysqlxSessionReflection.Descriptor.MessageTypes[3]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Reset() { + public Reset() + { OnConstruction(); } @@ -858,7 +1005,8 @@ public Reset() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Reset(Reset other) : this() { + public Reset(Reset other) : this() + { _hasBits0 = other._hasBits0; keepOpen_ = other.keepOpen_; _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); @@ -866,7 +1014,8 @@ public Reset(Reset other) : this() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Reset Clone() { + public Reset Clone() + { return new Reset(this); } @@ -881,9 +1030,11 @@ public Reset Clone() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool KeepOpen { + public bool KeepOpen + { get { if ((_hasBits0 & 1) != 0) { return keepOpen_; } else { return KeepOpenDefaultValue; } } - set { + set + { _hasBits0 |= 1; keepOpen_ = value; } @@ -891,29 +1042,35 @@ public bool KeepOpen { /// Gets whether the "keep_open" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasKeepOpen { + public bool HasKeepOpen + { get { return (_hasBits0 & 1) != 0; } } /// Clears the value of the "keep_open" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearKeepOpen() { + public void ClearKeepOpen() + { _hasBits0 &= ~1; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as Reset); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(Reset other) { - if (ReferenceEquals(other, null)) { + public bool Equals(Reset other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } if (KeepOpen != other.KeepOpen) return false; @@ -922,10 +1079,12 @@ public bool Equals(Reset other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; if (HasKeepOpen) hash ^= KeepOpen.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -933,16 +1092,18 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (HasKeepOpen) { output.WriteRawTag(8); output.WriteBool(KeepOpen); @@ -950,31 +1111,37 @@ public void WriteTo(pb::CodedOutputStream output) { if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (HasKeepOpen) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (HasKeepOpen) + { output.WriteRawTag(8); output.WriteBool(KeepOpen); } - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (HasKeepOpen) { + if (HasKeepOpen) + { size += 1 + 1; } - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -982,11 +1149,14 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(Reset other) { - if (other == null) { + public void MergeFrom(Reset other) + { + if (other == null) + { return; } - if (other.HasKeepOpen) { + if (other.HasKeepOpen) + { KeepOpen = other.KeepOpen; } _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); @@ -994,13 +1164,18 @@ public void MergeFrom(Reset other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -1010,27 +1185,36 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 8: { - KeepOpen = input.ReadBool(); - break; - } + case 8: + { + KeepOpen = input.ReadBool(); + break; + } } } } - #endif +#endif } @@ -1040,10 +1224,11 @@ public void MergeFrom(pb::CodedInputStream input) { /// ///@returns @ref Mysqlx::Ok /// - internal sealed partial class Close : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class Close : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Close()); private pb::UnknownFieldSet _unknownFields; @@ -1053,19 +1238,22 @@ internal sealed partial class Close : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Session.MysqlxSessionReflection.Descriptor.MessageTypes[4]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Close() { + public Close() + { OnConstruction(); } @@ -1073,29 +1261,35 @@ public Close() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Close(Close other) : this() { + public Close(Close other) : this() + { _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public Close Clone() { + public Close Clone() + { return new Close(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as Close); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(Close other) { - if (ReferenceEquals(other, null)) { + public bool Equals(Close other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } return Equals(_unknownFields, other._unknownFields); @@ -1103,9 +1297,11 @@ public bool Equals(Close other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -1113,37 +1309,43 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (_unknownFields != null) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -1151,8 +1353,10 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(Close other) { - if (other == null) { + public void MergeFrom(Close other) + { + if (other == null) + { return; } _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); @@ -1160,35 +1364,48 @@ public void MergeFrom(Close other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; } } } - #endif +#endif } @@ -1197,3 +1414,4 @@ public void MergeFrom(pb::CodedInputStream input) { } #endregion Designer generated code + diff --git a/MySQL.Data/src/X/Protocol/X/Protobuf/MysqlxSql.cs b/MySQL.Data/src/X/Protocol/X/Protobuf/MysqlxSql.cs index 7f8a00342..825b21188 100644 --- a/MySQL.Data/src/X/Protocol/X/Protobuf/MysqlxSql.cs +++ b/MySQL.Data/src/X/Protocol/X/Protobuf/MysqlxSql.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2022, 2023, Oracle and/or its affiliates. +// Copyright © 2022, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -37,19 +37,23 @@ using pbc = global::Google.Protobuf.Collections; using pbr = global::Google.Protobuf.Reflection; using scg = global::System.Collections.Generic; -namespace Mysqlx.Sql { +namespace Mysqlx.Sql +{ /// Holder for reflection information generated from mysqlx_sql.proto - internal static partial class MysqlxSqlReflection { + public static partial class MysqlxSqlReflection + { #region Descriptor /// File descriptor for mysqlx_sql.proto - public static pbr::FileDescriptor Descriptor { + public static pbr::FileDescriptor Descriptor + { get { return descriptor; } } private static pbr::FileDescriptor descriptor; - static MysqlxSqlReflection() { + static MysqlxSqlReflection() + { byte[] descriptorData = global::System.Convert.FromBase64String( string.Concat( "ChBteXNxbHhfc3FsLnByb3RvEgpNeXNxbHguU3FsGgxteXNxbHgucHJvdG8a", @@ -85,10 +89,11 @@ static MysqlxSqlReflection() { /// ///@returns zero or more @ref Mysqlx::Resultset followed by @ref Mysqlx::Sql::StmtExecuteOk /// - internal sealed partial class StmtExecute : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class StmtExecute : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new StmtExecute()); private pb::UnknownFieldSet _unknownFields; @@ -99,19 +104,22 @@ internal sealed partial class StmtExecute : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Sql.MysqlxSqlReflection.Descriptor.MessageTypes[0]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public StmtExecute() { + public StmtExecute() + { OnConstruction(); } @@ -119,7 +127,8 @@ public StmtExecute() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public StmtExecute(StmtExecute other) : this() { + public StmtExecute(StmtExecute other) : this() + { _hasBits0 = other._hasBits0; namespace_ = other.namespace_; stmt_ = other.stmt_; @@ -130,7 +139,8 @@ public StmtExecute(StmtExecute other) : this() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public StmtExecute Clone() { + public StmtExecute Clone() + { return new StmtExecute(this); } @@ -144,22 +154,26 @@ public StmtExecute Clone() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public string Namespace { + public string Namespace + { get { return namespace_ ?? NamespaceDefaultValue; } - set { + set + { namespace_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); } } /// Gets whether the "namespace" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasNamespace { + public bool HasNamespace + { get { return namespace_ != null; } } /// Clears the value of the "namespace" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearNamespace() { + public void ClearNamespace() + { namespace_ = null; } @@ -173,22 +187,26 @@ public void ClearNamespace() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public pb::ByteString Stmt { + public pb::ByteString Stmt + { get { return stmt_ ?? StmtDefaultValue; } - set { + set + { stmt_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); } } /// Gets whether the "stmt" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasStmt { + public bool HasStmt + { get { return stmt_ != null; } } /// Clears the value of the "stmt" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearStmt() { + public void ClearStmt() + { stmt_ = null; } @@ -202,7 +220,8 @@ public void ClearStmt() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public pbc::RepeatedField Args { + public pbc::RepeatedField Args + { get { return args_; } } @@ -217,9 +236,11 @@ public void ClearStmt() { /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool CompactMetadata { + public bool CompactMetadata + { get { if ((_hasBits0 & 1) != 0) { return compactMetadata_; } else { return CompactMetadataDefaultValue; } } - set { + set + { _hasBits0 |= 1; compactMetadata_ = value; } @@ -227,47 +248,55 @@ public bool CompactMetadata { /// Gets whether the "compact_metadata" field is set [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool HasCompactMetadata { + public bool HasCompactMetadata + { get { return (_hasBits0 & 1) != 0; } } /// Clears the value of the "compact_metadata" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void ClearCompactMetadata() { + public void ClearCompactMetadata() + { _hasBits0 &= ~1; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as StmtExecute); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(StmtExecute other) { - if (ReferenceEquals(other, null)) { + public bool Equals(StmtExecute other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } if (Namespace != other.Namespace) return false; if (Stmt != other.Stmt) return false; - if(!args_.Equals(other.args_)) return false; + if (!args_.Equals(other.args_)) return false; if (CompactMetadata != other.CompactMetadata) return false; return Equals(_unknownFields, other._unknownFields); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; if (HasNamespace) hash ^= Namespace.GetHashCode(); if (HasStmt) hash ^= Stmt.GetHashCode(); hash ^= args_.GetHashCode(); if (HasCompactMetadata) hash ^= CompactMetadata.GetHashCode(); - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -275,16 +304,18 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (HasStmt) { output.WriteRawTag(10); output.WriteBytes(Stmt); @@ -301,47 +332,57 @@ public void WriteTo(pb::CodedOutputStream output) { if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (HasStmt) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (HasStmt) + { output.WriteRawTag(10); output.WriteBytes(Stmt); } args_.WriteTo(ref output, _repeated_args_codec); - if (HasNamespace) { + if (HasNamespace) + { output.WriteRawTag(26); output.WriteString(Namespace); } - if (HasCompactMetadata) { + if (HasCompactMetadata) + { output.WriteRawTag(32); output.WriteBool(CompactMetadata); } - if (_unknownFields != null) { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (HasNamespace) { + if (HasNamespace) + { size += 1 + pb::CodedOutputStream.ComputeStringSize(Namespace); } - if (HasStmt) { + if (HasStmt) + { size += 1 + pb::CodedOutputStream.ComputeBytesSize(Stmt); } size += args_.CalculateSize(_repeated_args_codec); - if (HasCompactMetadata) { + if (HasCompactMetadata) + { size += 1 + 1; } - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -349,18 +390,23 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(StmtExecute other) { - if (other == null) { + public void MergeFrom(StmtExecute other) + { + if (other == null) + { return; } - if (other.HasNamespace) { + if (other.HasNamespace) + { Namespace = other.Namespace; } - if (other.HasStmt) { + if (other.HasStmt) + { Stmt = other.Stmt; } args_.Add(other.args_); - if (other.HasCompactMetadata) { + if (other.HasCompactMetadata) + { CompactMetadata = other.CompactMetadata; } _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); @@ -368,13 +414,18 @@ public void MergeFrom(StmtExecute other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; @@ -396,39 +447,51 @@ public void MergeFrom(pb::CodedInputStream input) { } } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; - case 10: { - Stmt = input.ReadBytes(); - break; - } - case 18: { - args_.AddEntriesFrom(ref input, _repeated_args_codec); - break; - } - case 26: { - Namespace = input.ReadString(); - break; - } - case 32: { - CompactMetadata = input.ReadBool(); - break; - } + case 10: + { + Stmt = input.ReadBytes(); + break; + } + case 18: + { + args_.AddEntriesFrom(ref input, _repeated_args_codec); + break; + } + case 26: + { + Namespace = input.ReadString(); + break; + } + case 32: + { + CompactMetadata = input.ReadBool(); + break; + } } } } - #endif +#endif } @@ -436,10 +499,11 @@ public void MergeFrom(pb::CodedInputStream input) { ///* ///Statement executed successfully /// - internal sealed partial class StmtExecuteOk : pb::IMessage - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class StmtExecuteOk : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE , pb::IBufferMessage - #endif +#endif { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new StmtExecuteOk()); private pb::UnknownFieldSet _unknownFields; @@ -449,19 +513,22 @@ internal sealed partial class StmtExecuteOk : pb::IMessage [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public static pbr::MessageDescriptor Descriptor { + public static pbr::MessageDescriptor Descriptor + { get { return global::Mysqlx.Sql.MysqlxSqlReflection.Descriptor.MessageTypes[1]; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - pbr::MessageDescriptor pb::IMessage.Descriptor { + pbr::MessageDescriptor pb::IMessage.Descriptor + { get { return Descriptor; } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public StmtExecuteOk() { + public StmtExecuteOk() + { OnConstruction(); } @@ -469,29 +536,35 @@ public StmtExecuteOk() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public StmtExecuteOk(StmtExecuteOk other) : this() { + public StmtExecuteOk(StmtExecuteOk other) : this() + { _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public StmtExecuteOk Clone() { + public StmtExecuteOk Clone() + { return new StmtExecuteOk(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override bool Equals(object other) { + public override bool Equals(object other) + { return Equals(other as StmtExecuteOk); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public bool Equals(StmtExecuteOk other) { - if (ReferenceEquals(other, null)) { + public bool Equals(StmtExecuteOk other) + { + if (ReferenceEquals(other, null)) + { return false; } - if (ReferenceEquals(other, this)) { + if (ReferenceEquals(other, this)) + { return true; } return Equals(_unknownFields, other._unknownFields); @@ -499,9 +572,11 @@ public bool Equals(StmtExecuteOk other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override int GetHashCode() { + public override int GetHashCode() + { int hash = 1; - if (_unknownFields != null) { + if (_unknownFields != null) + { hash ^= _unknownFields.GetHashCode(); } return hash; @@ -509,37 +584,43 @@ public override int GetHashCode() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public override string ToString() { + public override string ToString() + { return pb::JsonFormatter.ToDiagnosticString(this); } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void WriteTo(pb::CodedOutputStream output) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE output.WriteRawMessage(this); - #else +#else if (_unknownFields != null) { _unknownFields.WriteTo(output); } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { - if (_unknownFields != null) { + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (_unknownFields != null) + { _unknownFields.WriteTo(ref output); } } - #endif +#endif [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public int CalculateSize() { + public int CalculateSize() + { int size = 0; - if (_unknownFields != null) { + if (_unknownFields != null) + { size += _unknownFields.CalculateSize(); } return size; @@ -547,8 +628,10 @@ public int CalculateSize() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(StmtExecuteOk other) { - if (other == null) { + public void MergeFrom(StmtExecuteOk other) + { + if (other == null) + { return; } _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); @@ -556,35 +639,48 @@ public void MergeFrom(StmtExecuteOk other) { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - public void MergeFrom(pb::CodedInputStream input) { - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE input.ReadRawMessage(this); - #else +#else uint tag; while ((tag = input.ReadTag()) != 0) { - switch(tag) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); break; } } - #endif +#endif } - #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] - void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { uint tag; - while ((tag = input.ReadTag()) != 0) { - switch(tag) { + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { default: _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); break; } } } - #endif +#endif } @@ -593,3 +689,4 @@ public void MergeFrom(pb::CodedInputStream input) { } #endregion Designer generated code + diff --git a/MySQL.Data/src/X/Protocol/X/SetDecoder.cs b/MySQL.Data/src/X/Protocol/X/SetDecoder.cs index 0dcb395a8..e2262e6ca 100644 --- a/MySQL.Data/src/X/Protocol/X/SetDecoder.cs +++ b/MySQL.Data/src/X/Protocol/X/SetDecoder.cs @@ -1,74 +1,74 @@ -// Copyright (c) 2015, 2022, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data; -using MySql.Data.MySqlClient; -using MySql.Data.MySqlClient.X.XDevAPI.Common; -using System; -using System.Text; - -namespace MySqlX.Protocol.X -{ - internal class SetDecoder : ValueDecoder - { - private Encoding _encoding; - - public override void SetMetadata() - { - Column.Type = ColumnType.Set; - Column.ClrType = typeof(string); - ClrValueDecoder = DecodeValue; - - string charset = Column.CollationName.Split('_')[0]; - _encoding = CharSetMap.GetEncoding(charset); - } - - private object DecodeValue(byte[] bytes) - { - if (bytes == null || bytes.Length == 0) return null; - if (bytes.Length == 1 && bytes[0] == 0) return String.Empty; - if (bytes.Length == 1 && bytes[0] == 1) return String.Empty; - - StringBuilder sb = new StringBuilder(); - string delim = ""; - int len = bytes.Length; - int index = 0; - while (index < len - 1) - { - sb.Append(delim); - int strLen = bytes[index++]; - if ((index + strLen) > bytes.Length) - throw new MySqlException(ResourcesX.UnexpectedEndOfPacketFound); - sb.Append(_encoding.GetString(bytes, index, strLen)); - index += strLen; - delim = ","; - } - return sb.ToString(); - } - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data; +using MySql.Data.MySqlClient; +using MySql.Data.MySqlClient.X.XDevAPI.Common; +using System; +using System.Text; + +namespace MySqlX.Protocol.X +{ + internal class SetDecoder : ValueDecoder + { + private Encoding _encoding; + + public override void SetMetadata() + { + Column.Type = ColumnType.Set; + Column.ClrType = typeof(string); + ClrValueDecoder = DecodeValue; + + string charset = Column.CollationName.Split('_')[0]; + _encoding = CharSetMap.GetEncoding(charset); + } + + private object DecodeValue(byte[] bytes) + { + if (bytes == null || bytes.Length == 0) return null; + if (bytes.Length == 1 && bytes[0] == 0) return String.Empty; + if (bytes.Length == 1 && bytes[0] == 1) return String.Empty; + + StringBuilder sb = new StringBuilder(); + string delim = ""; + int len = bytes.Length; + int index = 0; + while (index < len - 1) + { + sb.Append(delim); + int strLen = bytes[index++]; + if ((index + strLen) > bytes.Length) + throw new MySqlException(ResourcesX.UnexpectedEndOfPacketFound); + sb.Append(_encoding.GetString(bytes, index, strLen)); + index += strLen; + delim = ","; + } + return sb.ToString(); + } + } +} diff --git a/MySQL.Data/src/X/Protocol/X/XDateTimeDecoder.cs b/MySQL.Data/src/X/Protocol/X/XDateTimeDecoder.cs index e14136758..2189fbe78 100644 --- a/MySQL.Data/src/X/Protocol/X/XDateTimeDecoder.cs +++ b/MySQL.Data/src/X/Protocol/X/XDateTimeDecoder.cs @@ -1,77 +1,77 @@ -// Copyright © 2015, 2016, Oracle and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - - -using Google.Protobuf; -using MySql.Data.MySqlClient; -using MySql.Data.MySqlClient.X.XDevAPI.Common; -using MySqlX.Data; -using MySqlX.XDevAPI; -using System; - -namespace MySqlX.Protocol.X -{ - internal class XDateTimeDecoder : ValueDecoder - { - public override void SetMetadata() - { - Column.Type = GetDbType(); - Column.ClrType = typeof(DateTime); - ClrValueDecoder = ValueDecoder; - } - - private ColumnType GetDbType() - { - if ((Flags & 1) != 0) - return ColumnType.Timestamp; - if (Column.Length == 10) - return ColumnType.Date; - return ColumnType.DateTime; - } - - public object ValueDecoder(byte[] bytes) - { - CodedInputStream input = new CodedInputStream(bytes); - UInt64 year = 0, month = 0, day = 0; - Int64 hour = 0, min = 0, sec = 0, usec = 0; - - year = input.ReadUInt64(); - month = input.ReadUInt64(); - day = input.ReadUInt64(); - if (!input.IsAtEnd) - hour = input.ReadInt64(); - if (!input.IsAtEnd) - min = input.ReadInt64(); - if (!input.IsAtEnd) - sec = input.ReadInt64(); - if (!input.IsAtEnd) - usec = input.ReadInt64(); - return new DateTime((int)year, (int)month, (int)day, (int)hour, (int)min, (int)sec).AddTicks(usec * 10); - } - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +using Google.Protobuf; +using MySql.Data.MySqlClient; +using MySql.Data.MySqlClient.X.XDevAPI.Common; +using MySqlX.Data; +using MySqlX.XDevAPI; +using System; + +namespace MySqlX.Protocol.X +{ + internal class XDateTimeDecoder : ValueDecoder + { + public override void SetMetadata() + { + Column.Type = GetDbType(); + Column.ClrType = typeof(DateTime); + ClrValueDecoder = ValueDecoder; + } + + private ColumnType GetDbType() + { + if ((Flags & 1) != 0) + return ColumnType.Timestamp; + if (Column.Length == 10) + return ColumnType.Date; + return ColumnType.DateTime; + } + + public object ValueDecoder(byte[] bytes) + { + CodedInputStream input = new CodedInputStream(bytes); + UInt64 year = 0, month = 0, day = 0; + Int64 hour = 0, min = 0, sec = 0, usec = 0; + + year = input.ReadUInt64(); + month = input.ReadUInt64(); + day = input.ReadUInt64(); + if (!input.IsAtEnd) + hour = input.ReadInt64(); + if (!input.IsAtEnd) + min = input.ReadInt64(); + if (!input.IsAtEnd) + sec = input.ReadInt64(); + if (!input.IsAtEnd) + usec = input.ReadInt64(); + return new DateTime((int)year, (int)month, (int)day, (int)hour, (int)min, (int)sec).AddTicks(usec * 10); + } + } +} diff --git a/MySQL.Data/src/X/Protocol/X/XProtocol.cs b/MySQL.Data/src/X/Protocol/X/XProtocol.cs index b43e68e2a..4cd9cad42 100644 --- a/MySQL.Data/src/X/Protocol/X/XProtocol.cs +++ b/MySQL.Data/src/X/Protocol/X/XProtocol.cs @@ -1,928 +1,928 @@ -// Copyright (c) 2015, 2023, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using Google.Protobuf; -using MySql.Data; -using MySql.Data.MySqlClient; -using Mysqlx; -using Mysqlx.Connection; -using Mysqlx.Crud; -using Mysqlx.Datatypes; -using Mysqlx.Expr; -using Mysqlx.Notice; -using Mysqlx.Prepare; -using Mysqlx.Resultset; -using Mysqlx.Session; -using Mysqlx.Sql; -using MySqlX.Communication; -using MySqlX.Data; -using MySqlX.DataAccess; -using MySqlX.Protocol.X; -using MySqlX.XDevAPI; -using MySqlX.XDevAPI.Common; -using MySqlX.XDevAPI.CRUD; -using System; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -#if !NETFRAMEWORK -using System.Text.Json; -#endif -using static Mysqlx.Datatypes.Object.Types; - -namespace MySqlX.Protocol -{ - internal class XProtocol : ProtocolBase - { - private CommunicationPacket _pendingPacket; - private XPacketReaderWriter _packetReaderWriter; - - public Capabilities Capabilities { get; protected set; } - - public XProtocol(XPacketReaderWriter packetReaderWriter) - { - _packetReaderWriter = packetReaderWriter; - } - - #region Authentication - - public void SendAuthStart(string method, byte[] authData, byte[] initialResponse) - { - AuthenticateStart authStart = new AuthenticateStart(); - authStart.MechName = method; - if (authData != null) authStart.AuthData = (ByteString.CopyFrom(authData)); - if (initialResponse != null) authStart.InitialResponse = (ByteString.CopyFrom(initialResponse)); - _packetReaderWriter.Write(ClientMessageId.SESS_AUTHENTICATE_START, authStart); - } - - public byte[] ReadAuthContinue() - { - CommunicationPacket p = ReadPacket(); - if (p.MessageType != (int)ServerMessageId.SESS_AUTHENTICATE_CONTINUE) - throw new MySqlException("Unexpected message encountered during authentication handshake"); - AuthenticateContinue response = AuthenticateContinue.Parser.ParseFrom(p.Buffer); - if (!response.AuthData.IsEmpty) - return response.AuthData.ToByteArray(); - return null; - } - - public void SendAuthContinue(byte[] data) - { - Debug.Assert(data != null); - AuthenticateContinue authCont = new AuthenticateContinue(); - authCont.AuthData = (ByteString.CopyFrom(data)); - _packetReaderWriter.Write(ClientMessageId.SESS_AUTHENTICATE_CONTINUE, authCont); - } - - public void ReadAuthOk() - { - CommunicationPacket p = ReadPacket(); - switch ((ServerMessageId)p.MessageType) - { - case ServerMessageId.SESS_AUTHENTICATE_OK: - break; - - case ServerMessageId.ERROR: - var error = Error.Parser.ParseFrom(p.Buffer); - throw new MySqlException(error.Code, error.SqlState, error.Msg); - - case ServerMessageId.NOTICE: - ///TODO: fix this - //ProcessNotice(p, new Result(null)); - ReadAuthOk(); - break; - - default: - throw new MySqlException("Unexpected message encountered during authentication handshake"); - } - } - - #endregion - - public void GetServerCapabilities() - { - _packetReaderWriter.Write(ClientMessageId.CON_CAPABILITIES_GET, new CapabilitiesGet()); - CommunicationPacket packet = ReadPacket(); - - if (packet.MessageType == (int)ServerMessageId.NOTICE) - packet = ReadPacket(); - - if (packet.MessageType != (int)ServerMessageId.CONN_CAPABILITIES) - { - if (packet.MessageType == (int)ServerMessageId.ERROR) - DecodeAndThrowError(packet); - else - ThrowUnexpectedMessage(packet.MessageType, (int)ServerMessageId.CONN_CAPABILITIES); - } - Capabilities = Capabilities.Parser.ParseFrom(packet.Buffer); - } - - public void SetCapabilities(Dictionary clientCapabilities) - { - if (clientCapabilities == null || clientCapabilities.Count == 0) - return; - - var builder = new CapabilitiesSet(); - var capabilities = new Capabilities(); - foreach (var cap in clientCapabilities) - { - var value = new Any(); - - if (cap.Key == "tls") - value = ExprUtil.BuildAny(cap.Value); - else if (cap.Key == "session_connect_attrs" || cap.Key == "compression") - { - var obj = new Mysqlx.Datatypes.Object(); - - if (cap.Key == "session_connect_attrs") - { - foreach (var pair in (Dictionary)cap.Value) - obj.Fld.Add(new ObjectField { Key = pair.Key, Value = ExprUtil.BuildAny(pair.Value) }); - } - else if (cap.Key == "compression") - { - foreach (var pair in (Dictionary)cap.Value) - obj.Fld.Add(new ObjectField { Key = pair.Key, Value = ExprUtil.BuildAny(pair.Value) }); - } - - value = new Any { Type = Any.Types.Type.Object, Obj = obj }; - } - - var capabilityMsg = new Capability() { Name = cap.Key, Value = value }; - capabilities.Capabilities_.Add(capabilityMsg); - } - - builder.Capabilities = capabilities; - _packetReaderWriter.Write(ClientMessageId.CON_CAPABILITIES_SET, builder); - ReadOk(); - } - - private void ThrowUnexpectedMessage(int received, int expected) - { - if (received == 10) // Connection to XProtocol using ClassicProtocol port - throw new MySqlException("Unsupported protocol version."); - throw new MySqlException( - String.Format("Expected message id: {0}. Received message id: {1}", expected, received)); - } - - public override void SendSQL(string sql, params object[] args) - { - SendExecuteSQLStatement(sql, args); - } - - public override bool HasData(BaseResult rs) - { - while (true) - { - CommunicationPacket packet = PeekPacket(); - switch (packet.MessageType) - { - case (int)ServerMessageId.RESULTSET_COLUMN_META_DATA: - return true; - case (int)ServerMessageId.NOTICE: - ProcessNotice(packet, rs); - packet = ReadPacket(); - break; - case (int)ServerMessageId.ERROR: - packet = ReadPacket(); - DecodeAndThrowError(packet); - break; - default: - return false; - } - } - } - - private CommunicationPacket PeekPacket() - { - if (_pendingPacket != null) return _pendingPacket; - _pendingPacket = _packetReaderWriter.Read(); - return _pendingPacket; - } - - private CommunicationPacket ReadPacket() - { - while (true) - { - CommunicationPacket p = _pendingPacket != null ? _pendingPacket : _packetReaderWriter.Read(); - _pendingPacket = null; - return p; - } - } - - private void ProcessGlobalNotice(Mysqlx.Notice.Frame frame) - { - } - - private void ProcessNotice(CommunicationPacket packet, BaseResult rs) - { - Frame frame = Frame.Parser.ParseFrom(packet.Buffer); - if (frame.Scope == Frame.Types.Scope.Global) - { - ProcessGlobalNotice(frame); - return; - } - - // if we get here the notice is local - switch ((NoticeType)frame.Type) - { - case NoticeType.Warning: - ProcessWarning(rs, frame.Payload.ToByteArray()); - break; - case NoticeType.SessionStateChanged: - ProcessSessionStateChanged(rs, frame.Payload.ToByteArray()); - break; - case NoticeType.SessionVariableChanged: - break; - default: // will ignore unknown notices from the server - break; - } - } - - private void ProcessSessionStateChanged(BaseResult rs, byte[] payload) - { - SessionStateChanged state = SessionStateChanged.Parser.ParseFrom(payload); - switch (state.Param) - { - case SessionStateChanged.Types.Parameter.RowsAffected: - rs._recordsAffected = state.Value[0].VUnsignedInt; - rs._affectedItemsCount = rs._recordsAffected; - break; - case SessionStateChanged.Types.Parameter.GeneratedInsertId: - rs._autoIncrementValue = state.Value[0].VUnsignedInt; - break; - case SessionStateChanged.Types.Parameter.ProducedMessage: - rs.AddWarning(new WarningInfo(0, state.Value[0].VString.Value.ToStringUtf8())); - break; - case SessionStateChanged.Types.Parameter.GeneratedDocumentIds: - foreach (var value in state.Value) - rs._documentIds.Add(value.VOctets.Value.ToStringUtf8()); - break; - //handle the other ones - //default: SessionStateChanged(state); - } - } - - private void ProcessWarning(BaseResult rs, byte[] payload) - { - Warning w = Warning.Parser.ParseFrom(payload); - WarningInfo warning = new WarningInfo(w.Code, w.Msg); - if (w.HasLevel) - warning.Level = (uint)w.Level; - rs.AddWarning(warning); - } - - private Any CreateAny(object o) - { - if (o is string) return ExprUtil.BuildAny((string)o); - if (o is bool) return ExprUtil.BuildAny((bool)o); - return ExprUtil.BuildAny(o); - } - - private ObjectField CreateObject(string key, object value, bool evaluateStringExpression = true) - { - return ExprUtil.BuildObject(key, value, evaluateStringExpression); - } - - public void SendSessionClose() - { - _packetReaderWriter.Write(ClientMessageId.SESS_CLOSE, new Mysqlx.Session.Close()); - } - - public void SendConnectionClose() - { - Mysqlx.Connection.Close connClose = new Mysqlx.Connection.Close(); - _packetReaderWriter.Write(ClientMessageId.CON_CLOSE, connClose); - } - - internal StmtExecute CreateExecuteSQLStatement(string stmt, params object[] args) - { - StmtExecute stmtExecute = new StmtExecute(); - stmtExecute.Namespace = "sql"; - stmtExecute.Stmt = ByteString.CopyFromUtf8(stmt); - stmtExecute.CompactMetadata = false; - if (args != null) - { - foreach (object arg in args) - stmtExecute.Args.Add(CreateAny(arg)); - } - - return stmtExecute; - } - - public void SendExecuteSQLStatement(string stmt, params object[] args) - { - StmtExecute stmtExecute = CreateExecuteSQLStatement(stmt, args); - _packetReaderWriter.Write(ClientMessageId.SQL_STMT_EXECUTE, stmtExecute); - } - - public void SendExecuteStatement(string ns, string stmt, params KeyValuePair[] args) - { - StmtExecute stmtExecute = new StmtExecute(); - stmtExecute.Namespace = ns; - stmtExecute.Stmt = ByteString.CopyFromUtf8(stmt); - stmtExecute.CompactMetadata = false; - if (args != null) - { - var any = ExprUtil.BuildEmptyAny(Any.Types.Type.Object); - - foreach (var arg in args) - { - switch (stmt) - { - case "drop_collection_index": - any.Obj.Fld.Add(CreateObject(arg.Key, arg.Value, false)); - break; - default: - any.Obj.Fld.Add(CreateObject(arg.Key, arg.Value)); - break; - } - } - stmtExecute.Args.Add(any); - } - - _packetReaderWriter.Write(ClientMessageId.SQL_STMT_EXECUTE, stmtExecute); - } - - /// - /// Build the message to be sent to MySQL Server to execute statement "Create" or "Modify" collection with schema options - /// - /// The namespace - /// The name of the command to be executed on MySql Server - /// Array of KeyValuePairs with the parameters required to build the message - /// void. - public void SendExecuteStatementOptions(string ns, string stmt, params KeyValuePair[] args) - { - StmtExecute stmtExecute = new StmtExecute(); - stmtExecute.Namespace = ns; - stmtExecute.Stmt = ByteString.CopyFromUtf8(stmt); - stmtExecute.CompactMetadata = false; - if (args != null) - { - var options = new ObjectField(); - var validation = new ObjectField(); - var reuse_obj = new ObjectField(); - var optionsAny = ExprUtil.BuildEmptyAny(Any.Types.Type.Object); - var any = ExprUtil.BuildEmptyAny(Any.Types.Type.Object); - var innerAny = ExprUtil.BuildEmptyAny(Any.Types.Type.Object); - var reuse_any = ExprUtil.BuildEmptyAny(Any.Types.Type.Object); - foreach (var arg in args) - { - if (arg.Value is Dictionary && arg.Key == "options") - { - foreach (var field in arg.Value as Dictionary) - { - innerAny.Obj.Fld.Add(CreateObject(field.Key, field.Value)); - } - } - else if (arg.Key == "reuse_existing") - { - reuse_any = ExprUtil.BuildAny(arg.Value); - } - else - { - any.Obj.Fld.Add(CreateObject(arg.Key, arg.Value)); - } - } - options.Key = "options"; - validation.Key = "validation"; - validation.Value = innerAny; - reuse_obj.Key = "reuse_existing"; - reuse_obj.Value = reuse_any; - optionsAny.Obj.Fld.Add(validation); - if (stmt == "create_collection") - { - optionsAny.Obj.Fld.Add(reuse_obj); - } - options.Value = optionsAny; - any.Obj.Fld.Add(options); - stmtExecute.Args.Add(any); - } - - _packetReaderWriter.Write(ClientMessageId.SQL_STMT_EXECUTE, stmtExecute); - } - - public void SendCreateCollectionIndexStatement(string ns, string stmt, params KeyValuePair[] args) - { - StmtExecute stmtExecute = new StmtExecute(); - stmtExecute.Namespace = ns; - stmtExecute.Stmt = ByteString.CopyFromUtf8(stmt); - stmtExecute.CompactMetadata = false; - if (args != null) - { - var any = ExprUtil.BuildEmptyAny(Any.Types.Type.Object); - var array = new Mysqlx.Datatypes.Array(); - foreach (var arg in args) - { - if (arg.Value is Dictionary && arg.Key == "constraint") - { - var innerAny = ExprUtil.BuildEmptyAny(Any.Types.Type.Object); - foreach (var field in arg.Value as Dictionary) - innerAny.Obj.Fld.Add(CreateObject(field.Key, field.Value, field.Key == "member" ? true : false)); - - array.Value.Add(innerAny); - } - else - any.Obj.Fld.Add(CreateObject(arg.Key, arg.Value, false)); - } - - if (array.Value.Count > 0) - { - var constraint = new ObjectField(); - constraint.Key = "constraint"; - var constraintAny = ExprUtil.BuildEmptyAny(Any.Types.Type.Array); - constraintAny.Array = array; - constraint.Value = constraintAny; - any.Obj.Fld.Add(constraint); - } - - stmtExecute.Args.Add(any); - } - - _packetReaderWriter.Write(ClientMessageId.SQL_STMT_EXECUTE, stmtExecute); - } - - private void DecodeAndThrowError(CommunicationPacket p) - { - Error e = Error.Parser.ParseFrom(p.Buffer); - throw new MySqlException(e.Code, e.SqlState, e.Msg); - } - - public override List ReadRow(BaseResult rs) - { - CommunicationPacket packet = PeekPacket(); - if (packet.MessageType != (int)ServerMessageId.RESULTSET_ROW) - { - if (rs != null) - CloseResult(rs); - - return null; - } - - var protoRow = Row.Parser.ParseFrom(ReadPacket().Buffer); - var values = new List(protoRow.Field.Count); - for (int i = 0; i < protoRow.Field.Count; i++) - values.Add(protoRow.Field[i].ToByteArray()); - - return values; - } - - public override void CloseResult(BaseResult rs) - { - rs._hasData = false; - while (true) - { - CommunicationPacket p = PeekPacket(); - if (p.MessageType == (int)ServerMessageId.RESULTSET_FETCH_DONE_MORE_RESULTSETS) - { - rs._hasMoreResults = true; - ReadPacket(); - break; - } - if (p.MessageType == (int)ServerMessageId.OK) - { - ReadOk(); - break; - } - if (p.MessageType == (int)ServerMessageId.RESULTSET_FETCH_DONE) - ReadPacket(); - else if (p.MessageType == (int)ServerMessageId.NOTICE) - ProcessNotice(ReadPacket(), rs); - else if (p.MessageType == (int)ServerMessageId.ERROR) - { - rs._session.ActiveResult = null; - DecodeAndThrowError(ReadPacket()); - } - else if (p.MessageType == (int)ServerMessageId.SQL_STMT_EXECUTE_OK) - { - ReadPacket(); - break; - } - else - throw new MySqlException(ResourcesX.ThrowingAwayResults); - } - } - - public override List LoadColumnMetadata() - { - List columns = new List(); - // we assume our caller has already validated that metadata is there - while (true) - { - if (PeekPacket().MessageType != (int)ServerMessageId.RESULTSET_COLUMN_META_DATA) return columns; - CommunicationPacket p = ReadPacket(); - ColumnMetaData response = ColumnMetaData.Parser.ParseFrom(p.Buffer); - columns.Add(DecodeColumn(response)); - } - } - - private XDevAPI.Relational.Column DecodeColumn(ColumnMetaData colData) - { - XDevAPI.Relational.Column c = new XDevAPI.Relational.Column(); - c._decoder = XValueDecoderFactory.GetValueDecoder(c, colData.Type); - c._decoder.Column = c; - - if (!colData.Name.IsEmpty) - c.ColumnLabel = colData.Name.ToStringUtf8(); - if (!colData.OriginalName.IsEmpty) - c.ColumnName = colData.OriginalName.ToStringUtf8(); - if (!colData.Table.IsEmpty) - c.TableLabel = colData.Table.ToStringUtf8(); - if (!colData.OriginalTable.IsEmpty) - c.TableName = colData.OriginalTable.ToStringUtf8(); - if (!colData.Schema.IsEmpty) - c.SchemaName = colData.Schema.ToStringUtf8(); - if (!colData.Catalog.IsEmpty) - c.DatabaseName = colData.Catalog.ToStringUtf8(); - if (colData.Collation > 0) - { - c._collationNumber = colData.Collation; - c.CollationName = CollationMap.GetCollationName((int)colData.Collation); - c.CharacterSetName = c.CollationName.Split('_')[0]; - } - if (colData.Length > 0) - c.Length = colData.Length; - if (colData.FractionalDigits > 0) - c.FractionalDigits = colData.FractionalDigits; - if (colData.Flags > 0) - c._decoder.Flags = colData.Flags; - if (colData.ContentType > 0) - c._decoder.ContentType = colData.ContentType; - c._decoder.SetMetadata(); - return c; - } - - internal Insert CreateInsertMessage(string schema, bool isRelational, string collection, object[] rows, string[] columns, bool upsert) - { - Insert msg = new Mysqlx.Crud.Insert(); - msg.Collection = ExprUtil.BuildCollection(schema, collection); - msg.DataModel = (isRelational ? DataModel.Table : DataModel.Document); - msg.Upsert = upsert; - if (columns != null && columns.Length > 0) - { - foreach (string column in columns) - msg.Projection.Add(new ExprParser(column).ParseTableInsertField()); - } - - foreach (object row in rows) - { - Mysqlx.Crud.Insert.Types.TypedRow typedRow = new Mysqlx.Crud.Insert.Types.TypedRow(); - object[] fields = row.GetType().IsArray ? (object[])row : new object[] { row }; - foreach (object field in fields) - if (field is null) - typedRow.Field.Add(ExprUtil.BuildLiteralNullScalar()); - else - { - if (field is DbDoc || field.GetType().Namespace == "System") - typedRow.Field.Add(ExprUtil.BuildLiteralScalar(Convert.ToString(field))); - else - { -#if !NETFRAMEWORK - string jsonString = JsonSerializer.Serialize(field); - typedRow.Field.Add(ExprUtil.BuildLiteralScalar(jsonString)); -#else - throw new MySqlException(ResourcesX.CustomTypeNotSupported); -#endif - } - } - - msg.Row.Add(typedRow); - } - - return msg; - } - - public void SendInsert(string schema, bool isRelational, string collection, object[] rows, string[] columns, bool upsert) - { - Insert msg = CreateInsertMessage(schema, isRelational, collection, rows, columns, upsert); - _packetReaderWriter.Write(ClientMessageId.CRUD_INSERT, msg); - } - - private void ApplyFilter(Action setLimit, Action setCriteria, Action> setOrder, FilterParams filter, Action> addParams) - { - if (filter.HasLimit) - { - var limit = new Limit(); - limit.RowCount = (ulong)filter.Limit; - if (filter.Offset != -1) limit.Offset = (ulong)filter.Offset; - setLimit(limit); - } - if (!string.IsNullOrEmpty(filter.Condition)) - { - setCriteria(filter.GetConditionExpression(filter.IsRelational)); - if (filter.Parameters != null && filter.Parameters.Count > 0) - addParams(filter.GetArgsExpression(filter.Parameters)); - } - if (filter.OrderBy != null && filter.OrderBy.Length > 0) - setOrder(filter.GetOrderByExpressions(filter.IsRelational)); - - } - - internal Delete CreateDeleteMessage(string schema, string collection, bool isRelational, FilterParams filter) - { - var msg = new Delete(); - msg.DataModel = (isRelational ? DataModel.Table : DataModel.Document); - msg.Collection = ExprUtil.BuildCollection(schema, collection); - ApplyFilter(v => msg.Limit = v, v => msg.Criteria = v, msg.Order.Add, filter, msg.Args.Add); - - return msg; - } - - /// - /// Sends the delete documents message - /// - public void SendDelete(string schema, string collection, bool isRelational, FilterParams filter) - { - var msg = CreateDeleteMessage(schema, collection, isRelational, filter); - _packetReaderWriter.Write(ClientMessageId.CRUD_DELETE, msg); - } - - internal Update CreateUpdateMessage(string schema, string collection, bool isRelational, FilterParams filter, List updates) - { - var msg = new Update(); - msg.DataModel = (isRelational ? DataModel.Table : DataModel.Document); - msg.Collection = ExprUtil.BuildCollection(schema, collection); - ApplyFilter(v => msg.Limit = v, v => msg.Criteria = v, msg.Order.Add, filter, msg.Args.Add); - - foreach (var update in updates) - { - var updateBuilder = new UpdateOperation(); - updateBuilder.Operation = update.Type; - updateBuilder.Source = update.GetSource(isRelational); - if (update.Type != UpdateOperation.Types.UpdateType.ItemRemove - || (update.Type == UpdateOperation.Types.UpdateType.ItemRemove && update.HasValue)) - updateBuilder.Value = update.GetValue(update.Type); - msg.Operation.Add(updateBuilder); - } - - return msg; - } - - /// - /// Sends the CRUD modify message - /// - public void SendUpdate(string schema, string collection, bool isRelational, FilterParams filter, List updates) - { - var msg = CreateUpdateMessage(schema, collection, isRelational, filter, updates); - _packetReaderWriter.Write(ClientMessageId.CRUD_UPDATE, msg); - } - - internal Find CreateFindMessage(string schema, string collection, bool isRelational, FilterParams filter, FindParams findParams) - { - var builder = new Find(); - builder.Collection = ExprUtil.BuildCollection(schema, collection); - builder.DataModel = (isRelational ? DataModel.Table : DataModel.Document); - if (findParams.GroupBy != null && findParams.GroupBy.Length > 0) - builder.Grouping.AddRange(new ExprParser(ExprUtil.JoinString(findParams.GroupBy)).ParseExprList()); - if (findParams.GroupByCritieria != null) - builder.GroupingCriteria = new ExprParser(findParams.GroupByCritieria).Parse(); - if (findParams.Locking != 0) builder.Locking = (Find.Types.RowLock)findParams.Locking; - if (findParams.LockingOption != 0) builder.LockingOptions = (Find.Types.RowLockOptions)findParams.LockingOption; - if (findParams.Projection != null && findParams.Projection.Length > 0) - { - var parser = new ExprParser(ExprUtil.JoinString(findParams.Projection)); - builder.Projection.Add(builder.DataModel == DataModel.Document ? - parser.ParseDocumentProjection() : - parser.ParseTableSelectProjection()); - - if (parser.tokenPos < parser.tokens.Count) - throw new ArgumentException(string.Format("Expression has unexpected token '{0}' at position {1}.", parser.tokens[parser.tokenPos].value, parser.tokenPos)); - } - ApplyFilter(v => builder.Limit = v, v => builder.Criteria = v, builder.Order.Add, filter, builder.Args.Add); - return builder; - } - - public void SendFind(string schema, string collection, bool isRelational, FilterParams filter, FindParams findParams) - { - var builder = CreateFindMessage(schema, collection, isRelational, filter, findParams); - _packetReaderWriter.Write(ClientMessageId.CRUD_FIND, builder); - } - - public void SendExpectOpen(Mysqlx.Expect.Open.Types.Condition.Types.Key condition, object value = null) - { - var builder = new Mysqlx.Expect.Open(); - var cond = new Mysqlx.Expect.Open.Types.Condition(); - cond.ConditionKey = (uint)condition; - cond.ConditionValue = value != null ? ByteString.CopyFromUtf8((string)value) : null; - builder.Cond.Add(cond); - _packetReaderWriter.Write(ClientMessageId.EXPECT_OPEN, builder); - } - - public void SendResetSession(bool sessionResetNoReauthentication) - { - var builder = new Mysqlx.Session.Reset(); - - if (sessionResetNoReauthentication) { builder.KeepOpen = sessionResetNoReauthentication; } - _packetReaderWriter.Write(ClientMessageId.SESS_RESET, builder); - } - - internal void ReadOkClose() - { - try - { - string response = ReadOk(); - if (response.IndexOf("bye", 0, StringComparison.OrdinalIgnoreCase) < 0) - throw new ArgumentException(); - } - catch (IOException) - { - // TODO connection is closed - } - catch (Exception ex) - { - throw new MySqlException("Unexpected message encountered during closing session", ex); - } - } - - internal string ReadOk() - { - CommunicationPacket p = ReadPacket(); - if (p.MessageType == (int)ServerMessageId.ERROR) - { - var error = Error.Parser.ParseFrom(p.Buffer); - throw new MySqlException(error.Code, error.SqlState, error.Msg); - } - if (p.MessageType == (int)ServerMessageId.OK) - { - var response = Ok.Parser.ParseFrom(p.Buffer); - return response.Msg; - } - else - throw new InvalidOperationException(); - } - - internal void SetXPackets(XPacketReaderWriter readerwriter) - { - _packetReaderWriter = readerwriter; - } - - public void SendPrepareStatement(uint stmtId, - PreparedStatementType type, - string schema, - string collection, - bool isRelational, - FilterParams filter, - FindParams findParams, - List updateSpecs = null, - object[] rows = null, - string[] columns = null, - bool upsert = false, - string sql = null) - { - var builder = new Prepare(); - builder.StmtId = stmtId; - builder.Stmt = new Prepare.Types.OneOfMessage(); - switch (type) - { - case PreparedStatementType.Find: - builder.Stmt.Type = Prepare.Types.OneOfMessage.Types.Type.Find; - var message = CreateFindMessage(schema, collection, isRelational, filter, findParams); - message.Args.Clear(); - if (filter.HasLimit) - { - uint positionFind = (uint)filter.Parameters.Count; - message.Limit = null; - message.LimitExpr = new LimitExpr - { - RowCount = new Expr - { - Type = Expr.Types.Type.Placeholder, - Position = positionFind++ - }, - Offset = new Expr - { - Type = Expr.Types.Type.Placeholder, - Position = positionFind++ - } - }; - } - builder.Stmt.Find = message; - break; - - case PreparedStatementType.Update: - builder.Stmt.Type = Prepare.Types.OneOfMessage.Types.Type.Update; - var updateMessage = CreateUpdateMessage(schema, collection, isRelational, filter, updateSpecs); - updateMessage.Args.Clear(); - if (filter.HasLimit) - { - uint positionUpdate = (uint)filter.Parameters.Count; - updateMessage.Limit = null; - updateMessage.LimitExpr = new LimitExpr - { - RowCount = new Expr - { - Type = Expr.Types.Type.Placeholder, - Position = positionUpdate++ - } - }; - } - builder.Stmt.Update = updateMessage; - break; - - case PreparedStatementType.Delete: - builder.Stmt.Type = Prepare.Types.OneOfMessage.Types.Type.Delete; - var deleteMessage = CreateDeleteMessage(schema, collection, isRelational, filter); - deleteMessage.Args.Clear(); - if (filter.HasLimit) - { - uint positionDelete = (uint)filter.Parameters.Count; - deleteMessage.Limit = null; - deleteMessage.LimitExpr = new LimitExpr - { - RowCount = new Expr - { - Type = Expr.Types.Type.Placeholder, - Position = positionDelete++ - } - }; - } - builder.Stmt.Delete = deleteMessage; - break; - - case PreparedStatementType.Insert: - builder.Stmt.Type = Prepare.Types.OneOfMessage.Types.Type.Insert; - var insertMessage = CreateInsertMessage(schema, isRelational, collection, rows, columns, upsert); - insertMessage.Args.Clear(); - uint position = 0; - foreach (var row in insertMessage.Row) - { - foreach (var field in row.Field) - { - if (field.Type == Expr.Types.Type.Literal) - { - field.Type = Expr.Types.Type.Placeholder; - field.Literal = null; - field.Position = position++; - } - } - } - builder.Stmt.Insert = insertMessage; - break; - - case PreparedStatementType.SqlStatement: - builder.Stmt.Type = Prepare.Types.OneOfMessage.Types.Type.Stmt; - var sqlMessage = CreateExecuteSQLStatement(sql, rows); - sqlMessage.Args.Clear(); - builder.Stmt.StmtExecute = sqlMessage; - break; - } - - _packetReaderWriter.Write((int)ClientMessages.Types.Type.PreparePrepare, builder); - ReadOk(); - } - - public void SendExecutePreparedStatement(uint stmtId, IEnumerable args) - { - var builder = new Execute(); - builder.StmtId = stmtId; - AddArgs(builder.Args.Add, args); - - _packetReaderWriter.Write((int)ClientMessages.Types.Type.PrepareExecute, builder); - } - - public void AddArgs(Action addFunction, IEnumerable args) - { - foreach (var arg in args) - { - if (arg.GetType().IsArray) - AddArgs(addFunction, (System.Array)arg); - else - addFunction(ExprUtil.BuildAny(arg)); - } - } - - public void SendDeallocatePreparedStatement(uint stmtId) - { - var builder = new Deallocate(); - builder.StmtId = stmtId; - _packetReaderWriter.Write((int)ClientMessages.Types.Type.PrepareDeallocate, builder); - ReadOk(); - } - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using Google.Protobuf; +using MySql.Data; +using MySql.Data.MySqlClient; +using Mysqlx; +using Mysqlx.Connection; +using Mysqlx.Crud; +using Mysqlx.Datatypes; +using Mysqlx.Expr; +using Mysqlx.Notice; +using Mysqlx.Prepare; +using Mysqlx.Resultset; +using Mysqlx.Session; +using Mysqlx.Sql; +using MySqlX.Communication; +using MySqlX.Data; +using MySqlX.DataAccess; +using MySqlX.Protocol.X; +using MySqlX.XDevAPI; +using MySqlX.XDevAPI.Common; +using MySqlX.XDevAPI.CRUD; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +#if !NETFRAMEWORK +using System.Text.Json; +#endif +using static Mysqlx.Datatypes.Object.Types; + +namespace MySqlX.Protocol +{ + internal class XProtocol : ProtocolBase + { + private CommunicationPacket _pendingPacket; + private XPacketReaderWriter _packetReaderWriter; + + public Capabilities Capabilities { get; protected set; } + + public XProtocol(XPacketReaderWriter packetReaderWriter) + { + _packetReaderWriter = packetReaderWriter; + } + + #region Authentication + + public void SendAuthStart(string method, byte[] authData, byte[] initialResponse) + { + AuthenticateStart authStart = new AuthenticateStart(); + authStart.MechName = method; + if (authData != null) authStart.AuthData = (ByteString.CopyFrom(authData)); + if (initialResponse != null) authStart.InitialResponse = (ByteString.CopyFrom(initialResponse)); + _packetReaderWriter.Write(ClientMessageId.SESS_AUTHENTICATE_START, authStart); + } + + public byte[] ReadAuthContinue() + { + CommunicationPacket p = ReadPacket(); + if (p.MessageType != (int)ServerMessageId.SESS_AUTHENTICATE_CONTINUE) + throw new MySqlException("Unexpected message encountered during authentication handshake"); + AuthenticateContinue response = AuthenticateContinue.Parser.ParseFrom(p.Buffer); + if (!response.AuthData.IsEmpty) + return response.AuthData.ToByteArray(); + return null; + } + + public void SendAuthContinue(byte[] data) + { + Debug.Assert(data != null); + AuthenticateContinue authCont = new AuthenticateContinue(); + authCont.AuthData = (ByteString.CopyFrom(data)); + _packetReaderWriter.Write(ClientMessageId.SESS_AUTHENTICATE_CONTINUE, authCont); + } + + public void ReadAuthOk() + { + CommunicationPacket p = ReadPacket(); + switch ((ServerMessageId)p.MessageType) + { + case ServerMessageId.SESS_AUTHENTICATE_OK: + break; + + case ServerMessageId.ERROR: + var error = Error.Parser.ParseFrom(p.Buffer); + throw new MySqlException(error.Code, error.SqlState, error.Msg); + + case ServerMessageId.NOTICE: + ///TODO: fix this + //ProcessNotice(p, new Result(null)); + ReadAuthOk(); + break; + + default: + throw new MySqlException("Unexpected message encountered during authentication handshake"); + } + } + + #endregion + + public void GetServerCapabilities() + { + _packetReaderWriter.Write(ClientMessageId.CON_CAPABILITIES_GET, new CapabilitiesGet()); + CommunicationPacket packet = ReadPacket(); + + if (packet.MessageType == (int)ServerMessageId.NOTICE) + packet = ReadPacket(); + + if (packet.MessageType != (int)ServerMessageId.CONN_CAPABILITIES) + { + if (packet.MessageType == (int)ServerMessageId.ERROR) + DecodeAndThrowError(packet); + else + ThrowUnexpectedMessage(packet.MessageType, (int)ServerMessageId.CONN_CAPABILITIES); + } + Capabilities = Capabilities.Parser.ParseFrom(packet.Buffer); + } + + public void SetCapabilities(Dictionary clientCapabilities) + { + if (clientCapabilities == null || clientCapabilities.Count == 0) + return; + + var builder = new CapabilitiesSet(); + var capabilities = new Capabilities(); + foreach (var cap in clientCapabilities) + { + var value = new Any(); + + if (cap.Key == "tls") + value = ExprUtil.BuildAny(cap.Value); + else if (cap.Key == "session_connect_attrs" || cap.Key == "compression") + { + var obj = new Mysqlx.Datatypes.Object(); + + if (cap.Key == "session_connect_attrs") + { + foreach (var pair in (Dictionary)cap.Value) + obj.Fld.Add(new ObjectField { Key = pair.Key, Value = ExprUtil.BuildAny(pair.Value) }); + } + else if (cap.Key == "compression") + { + foreach (var pair in (Dictionary)cap.Value) + obj.Fld.Add(new ObjectField { Key = pair.Key, Value = ExprUtil.BuildAny(pair.Value) }); + } + + value = new Any { Type = Any.Types.Type.Object, Obj = obj }; + } + + var capabilityMsg = new Capability() { Name = cap.Key, Value = value }; + capabilities.Capabilities_.Add(capabilityMsg); + } + + builder.Capabilities = capabilities; + _packetReaderWriter.Write(ClientMessageId.CON_CAPABILITIES_SET, builder); + ReadOk(); + } + + private void ThrowUnexpectedMessage(int received, int expected) + { + if (received == 10) // Connection to XProtocol using ClassicProtocol port + throw new MySqlException("Unsupported protocol version."); + throw new MySqlException( + String.Format("Expected message id: {0}. Received message id: {1}", expected, received)); + } + + public override void SendSQL(string sql, params object[] args) + { + SendExecuteSQLStatement(sql, args); + } + + public override bool HasData(BaseResult rs) + { + while (true) + { + CommunicationPacket packet = PeekPacket(); + switch (packet.MessageType) + { + case (int)ServerMessageId.RESULTSET_COLUMN_META_DATA: + return true; + case (int)ServerMessageId.NOTICE: + ProcessNotice(packet, rs); + packet = ReadPacket(); + break; + case (int)ServerMessageId.ERROR: + packet = ReadPacket(); + DecodeAndThrowError(packet); + break; + default: + return false; + } + } + } + + private CommunicationPacket PeekPacket() + { + if (_pendingPacket != null) return _pendingPacket; + _pendingPacket = _packetReaderWriter.Read(); + return _pendingPacket; + } + + private CommunicationPacket ReadPacket() + { + while (true) + { + CommunicationPacket p = _pendingPacket != null ? _pendingPacket : _packetReaderWriter.Read(); + _pendingPacket = null; + return p; + } + } + + private void ProcessGlobalNotice(Mysqlx.Notice.Frame frame) + { + } + + private void ProcessNotice(CommunicationPacket packet, BaseResult rs) + { + Frame frame = Frame.Parser.ParseFrom(packet.Buffer); + if (frame.Scope == Frame.Types.Scope.Global) + { + ProcessGlobalNotice(frame); + return; + } + + // if we get here the notice is local + switch ((NoticeType)frame.Type) + { + case NoticeType.Warning: + ProcessWarning(rs, frame.Payload.ToByteArray()); + break; + case NoticeType.SessionStateChanged: + ProcessSessionStateChanged(rs, frame.Payload.ToByteArray()); + break; + case NoticeType.SessionVariableChanged: + break; + default: // will ignore unknown notices from the server + break; + } + } + + private void ProcessSessionStateChanged(BaseResult rs, byte[] payload) + { + SessionStateChanged state = SessionStateChanged.Parser.ParseFrom(payload); + switch (state.Param) + { + case SessionStateChanged.Types.Parameter.RowsAffected: + rs._recordsAffected = state.Value[0].VUnsignedInt; + rs._affectedItemsCount = rs._recordsAffected; + break; + case SessionStateChanged.Types.Parameter.GeneratedInsertId: + rs._autoIncrementValue = state.Value[0].VUnsignedInt; + break; + case SessionStateChanged.Types.Parameter.ProducedMessage: + rs.AddWarning(new WarningInfo(0, state.Value[0].VString.Value.ToStringUtf8())); + break; + case SessionStateChanged.Types.Parameter.GeneratedDocumentIds: + foreach (var value in state.Value) + rs._documentIds.Add(value.VOctets.Value.ToStringUtf8()); + break; + //handle the other ones + //default: SessionStateChanged(state); + } + } + + private void ProcessWarning(BaseResult rs, byte[] payload) + { + Warning w = Warning.Parser.ParseFrom(payload); + WarningInfo warning = new WarningInfo(w.Code, w.Msg); + if (w.HasLevel) + warning.Level = (uint)w.Level; + rs.AddWarning(warning); + } + + private Any CreateAny(object o) + { + if (o is string) return ExprUtil.BuildAny((string)o); + if (o is bool) return ExprUtil.BuildAny((bool)o); + return ExprUtil.BuildAny(o); + } + + private ObjectField CreateObject(string key, object value, bool evaluateStringExpression = true) + { + return ExprUtil.BuildObject(key, value, evaluateStringExpression); + } + + public void SendSessionClose() + { + _packetReaderWriter.Write(ClientMessageId.SESS_CLOSE, new Mysqlx.Session.Close()); + } + + public void SendConnectionClose() + { + Mysqlx.Connection.Close connClose = new Mysqlx.Connection.Close(); + _packetReaderWriter.Write(ClientMessageId.CON_CLOSE, connClose); + } + + internal StmtExecute CreateExecuteSQLStatement(string stmt, params object[] args) + { + StmtExecute stmtExecute = new StmtExecute(); + stmtExecute.Namespace = "sql"; + stmtExecute.Stmt = ByteString.CopyFromUtf8(stmt); + stmtExecute.CompactMetadata = false; + if (args != null) + { + foreach (object arg in args) + stmtExecute.Args.Add(CreateAny(arg)); + } + + return stmtExecute; + } + + public void SendExecuteSQLStatement(string stmt, params object[] args) + { + StmtExecute stmtExecute = CreateExecuteSQLStatement(stmt, args); + _packetReaderWriter.Write(ClientMessageId.SQL_STMT_EXECUTE, stmtExecute); + } + + public void SendExecuteStatement(string ns, string stmt, params KeyValuePair[] args) + { + StmtExecute stmtExecute = new StmtExecute(); + stmtExecute.Namespace = ns; + stmtExecute.Stmt = ByteString.CopyFromUtf8(stmt); + stmtExecute.CompactMetadata = false; + if (args != null) + { + var any = ExprUtil.BuildEmptyAny(Any.Types.Type.Object); + + foreach (var arg in args) + { + switch (stmt) + { + case "drop_collection_index": + any.Obj.Fld.Add(CreateObject(arg.Key, arg.Value, false)); + break; + default: + any.Obj.Fld.Add(CreateObject(arg.Key, arg.Value)); + break; + } + } + stmtExecute.Args.Add(any); + } + + _packetReaderWriter.Write(ClientMessageId.SQL_STMT_EXECUTE, stmtExecute); + } + + /// + /// Build the message to be sent to MySQL Server to execute statement "Create" or "Modify" collection with schema options + /// + /// The namespace + /// The name of the command to be executed on MySql Server + /// Array of KeyValuePairs with the parameters required to build the message + /// void. + public void SendExecuteStatementOptions(string ns, string stmt, params KeyValuePair[] args) + { + StmtExecute stmtExecute = new StmtExecute(); + stmtExecute.Namespace = ns; + stmtExecute.Stmt = ByteString.CopyFromUtf8(stmt); + stmtExecute.CompactMetadata = false; + if (args != null) + { + var options = new ObjectField(); + var validation = new ObjectField(); + var reuse_obj = new ObjectField(); + var optionsAny = ExprUtil.BuildEmptyAny(Any.Types.Type.Object); + var any = ExprUtil.BuildEmptyAny(Any.Types.Type.Object); + var innerAny = ExprUtil.BuildEmptyAny(Any.Types.Type.Object); + var reuse_any = ExprUtil.BuildEmptyAny(Any.Types.Type.Object); + foreach (var arg in args) + { + if (arg.Value is Dictionary && arg.Key == "options") + { + foreach (var field in arg.Value as Dictionary) + { + innerAny.Obj.Fld.Add(CreateObject(field.Key, field.Value)); + } + } + else if (arg.Key == "reuse_existing") + { + reuse_any = ExprUtil.BuildAny(arg.Value); + } + else + { + any.Obj.Fld.Add(CreateObject(arg.Key, arg.Value)); + } + } + options.Key = "options"; + validation.Key = "validation"; + validation.Value = innerAny; + reuse_obj.Key = "reuse_existing"; + reuse_obj.Value = reuse_any; + optionsAny.Obj.Fld.Add(validation); + if (stmt == "create_collection") + { + optionsAny.Obj.Fld.Add(reuse_obj); + } + options.Value = optionsAny; + any.Obj.Fld.Add(options); + stmtExecute.Args.Add(any); + } + + _packetReaderWriter.Write(ClientMessageId.SQL_STMT_EXECUTE, stmtExecute); + } + + public void SendCreateCollectionIndexStatement(string ns, string stmt, params KeyValuePair[] args) + { + StmtExecute stmtExecute = new StmtExecute(); + stmtExecute.Namespace = ns; + stmtExecute.Stmt = ByteString.CopyFromUtf8(stmt); + stmtExecute.CompactMetadata = false; + if (args != null) + { + var any = ExprUtil.BuildEmptyAny(Any.Types.Type.Object); + var array = new Mysqlx.Datatypes.Array(); + foreach (var arg in args) + { + if (arg.Value is Dictionary && arg.Key == "constraint") + { + var innerAny = ExprUtil.BuildEmptyAny(Any.Types.Type.Object); + foreach (var field in arg.Value as Dictionary) + innerAny.Obj.Fld.Add(CreateObject(field.Key, field.Value, field.Key == "member" ? true : false)); + + array.Value.Add(innerAny); + } + else + any.Obj.Fld.Add(CreateObject(arg.Key, arg.Value, false)); + } + + if (array.Value.Count > 0) + { + var constraint = new ObjectField(); + constraint.Key = "constraint"; + var constraintAny = ExprUtil.BuildEmptyAny(Any.Types.Type.Array); + constraintAny.Array = array; + constraint.Value = constraintAny; + any.Obj.Fld.Add(constraint); + } + + stmtExecute.Args.Add(any); + } + + _packetReaderWriter.Write(ClientMessageId.SQL_STMT_EXECUTE, stmtExecute); + } + + private void DecodeAndThrowError(CommunicationPacket p) + { + Error e = Error.Parser.ParseFrom(p.Buffer); + throw new MySqlException(e.Code, e.SqlState, e.Msg); + } + + public override List ReadRow(BaseResult rs) + { + CommunicationPacket packet = PeekPacket(); + if (packet.MessageType != (int)ServerMessageId.RESULTSET_ROW) + { + if (rs != null) + CloseResult(rs); + + return null; + } + + var protoRow = Row.Parser.ParseFrom(ReadPacket().Buffer); + var values = new List(protoRow.Field.Count); + for (int i = 0; i < protoRow.Field.Count; i++) + values.Add(protoRow.Field[i].ToByteArray()); + + return values; + } + + public override void CloseResult(BaseResult rs) + { + rs._hasData = false; + while (true) + { + CommunicationPacket p = PeekPacket(); + if (p.MessageType == (int)ServerMessageId.RESULTSET_FETCH_DONE_MORE_RESULTSETS) + { + rs._hasMoreResults = true; + ReadPacket(); + break; + } + if (p.MessageType == (int)ServerMessageId.OK) + { + ReadOk(); + break; + } + if (p.MessageType == (int)ServerMessageId.RESULTSET_FETCH_DONE) + ReadPacket(); + else if (p.MessageType == (int)ServerMessageId.NOTICE) + ProcessNotice(ReadPacket(), rs); + else if (p.MessageType == (int)ServerMessageId.ERROR) + { + rs._session.ActiveResult = null; + DecodeAndThrowError(ReadPacket()); + } + else if (p.MessageType == (int)ServerMessageId.SQL_STMT_EXECUTE_OK) + { + ReadPacket(); + break; + } + else + throw new MySqlException(ResourcesX.ThrowingAwayResults); + } + } + + public override List LoadColumnMetadata() + { + List columns = new List(); + // we assume our caller has already validated that metadata is there + while (true) + { + if (PeekPacket().MessageType != (int)ServerMessageId.RESULTSET_COLUMN_META_DATA) return columns; + CommunicationPacket p = ReadPacket(); + ColumnMetaData response = ColumnMetaData.Parser.ParseFrom(p.Buffer); + columns.Add(DecodeColumn(response)); + } + } + + private XDevAPI.Relational.Column DecodeColumn(ColumnMetaData colData) + { + XDevAPI.Relational.Column c = new XDevAPI.Relational.Column(); + c._decoder = XValueDecoderFactory.GetValueDecoder(c, colData.Type); + c._decoder.Column = c; + + if (!colData.Name.IsEmpty) + c.ColumnLabel = colData.Name.ToStringUtf8(); + if (!colData.OriginalName.IsEmpty) + c.ColumnName = colData.OriginalName.ToStringUtf8(); + if (!colData.Table.IsEmpty) + c.TableLabel = colData.Table.ToStringUtf8(); + if (!colData.OriginalTable.IsEmpty) + c.TableName = colData.OriginalTable.ToStringUtf8(); + if (!colData.Schema.IsEmpty) + c.SchemaName = colData.Schema.ToStringUtf8(); + if (!colData.Catalog.IsEmpty) + c.DatabaseName = colData.Catalog.ToStringUtf8(); + if (colData.Collation > 0) + { + c._collationNumber = colData.Collation; + c.CollationName = CollationMap.GetCollationName((int)colData.Collation); + c.CharacterSetName = c.CollationName.Split('_')[0]; + } + if (colData.Length > 0) + c.Length = colData.Length; + if (colData.FractionalDigits > 0) + c.FractionalDigits = colData.FractionalDigits; + if (colData.Flags > 0) + c._decoder.Flags = colData.Flags; + if (colData.ContentType > 0) + c._decoder.ContentType = colData.ContentType; + c._decoder.SetMetadata(); + return c; + } + + internal Insert CreateInsertMessage(string schema, bool isRelational, string collection, object[] rows, string[] columns, bool upsert) + { + Insert msg = new Mysqlx.Crud.Insert(); + msg.Collection = ExprUtil.BuildCollection(schema, collection); + msg.DataModel = (isRelational ? DataModel.Table : DataModel.Document); + msg.Upsert = upsert; + if (columns != null && columns.Length > 0) + { + foreach (string column in columns) + msg.Projection.Add(new ExprParser(column).ParseTableInsertField()); + } + + foreach (object row in rows) + { + Mysqlx.Crud.Insert.Types.TypedRow typedRow = new Mysqlx.Crud.Insert.Types.TypedRow(); + object[] fields = row.GetType().IsArray ? (object[])row : new object[] { row }; + foreach (object field in fields) + if (field is null) + typedRow.Field.Add(ExprUtil.BuildLiteralNullScalar()); + else + { + if (field is DbDoc || field.GetType().Namespace == "System") + typedRow.Field.Add(ExprUtil.BuildLiteralScalar(Convert.ToString(field))); + else + { +#if !NETFRAMEWORK + string jsonString = JsonSerializer.Serialize(field); + typedRow.Field.Add(ExprUtil.BuildLiteralScalar(jsonString)); +#else + throw new MySqlException(ResourcesX.CustomTypeNotSupported); +#endif + } + } + + msg.Row.Add(typedRow); + } + + return msg; + } + + public void SendInsert(string schema, bool isRelational, string collection, object[] rows, string[] columns, bool upsert) + { + Insert msg = CreateInsertMessage(schema, isRelational, collection, rows, columns, upsert); + _packetReaderWriter.Write(ClientMessageId.CRUD_INSERT, msg); + } + + private void ApplyFilter(Action setLimit, Action setCriteria, Action> setOrder, FilterParams filter, Action> addParams) + { + if (filter.HasLimit) + { + var limit = new Limit(); + limit.RowCount = (ulong)filter.Limit; + if (filter.Offset != -1) limit.Offset = (ulong)filter.Offset; + setLimit(limit); + } + if (!string.IsNullOrEmpty(filter.Condition)) + { + setCriteria(filter.GetConditionExpression(filter.IsRelational)); + if (filter.Parameters != null && filter.Parameters.Count > 0) + addParams(filter.GetArgsExpression(filter.Parameters)); + } + if (filter.OrderBy != null && filter.OrderBy.Length > 0) + setOrder(filter.GetOrderByExpressions(filter.IsRelational)); + + } + + internal Delete CreateDeleteMessage(string schema, string collection, bool isRelational, FilterParams filter) + { + var msg = new Delete(); + msg.DataModel = (isRelational ? DataModel.Table : DataModel.Document); + msg.Collection = ExprUtil.BuildCollection(schema, collection); + ApplyFilter(v => msg.Limit = v, v => msg.Criteria = v, msg.Order.Add, filter, msg.Args.Add); + + return msg; + } + + /// + /// Sends the delete documents message + /// + public void SendDelete(string schema, string collection, bool isRelational, FilterParams filter) + { + var msg = CreateDeleteMessage(schema, collection, isRelational, filter); + _packetReaderWriter.Write(ClientMessageId.CRUD_DELETE, msg); + } + + internal Update CreateUpdateMessage(string schema, string collection, bool isRelational, FilterParams filter, List updates) + { + var msg = new Update(); + msg.DataModel = (isRelational ? DataModel.Table : DataModel.Document); + msg.Collection = ExprUtil.BuildCollection(schema, collection); + ApplyFilter(v => msg.Limit = v, v => msg.Criteria = v, msg.Order.Add, filter, msg.Args.Add); + + foreach (var update in updates) + { + var updateBuilder = new UpdateOperation(); + updateBuilder.Operation = update.Type; + updateBuilder.Source = update.GetSource(isRelational); + if (update.Type != UpdateOperation.Types.UpdateType.ItemRemove + || (update.Type == UpdateOperation.Types.UpdateType.ItemRemove && update.HasValue)) + updateBuilder.Value = update.GetValue(update.Type); + msg.Operation.Add(updateBuilder); + } + + return msg; + } + + /// + /// Sends the CRUD modify message + /// + public void SendUpdate(string schema, string collection, bool isRelational, FilterParams filter, List updates) + { + var msg = CreateUpdateMessage(schema, collection, isRelational, filter, updates); + _packetReaderWriter.Write(ClientMessageId.CRUD_UPDATE, msg); + } + + internal Find CreateFindMessage(string schema, string collection, bool isRelational, FilterParams filter, FindParams findParams) + { + var builder = new Find(); + builder.Collection = ExprUtil.BuildCollection(schema, collection); + builder.DataModel = (isRelational ? DataModel.Table : DataModel.Document); + if (findParams.GroupBy != null && findParams.GroupBy.Length > 0) + builder.Grouping.AddRange(new ExprParser(ExprUtil.JoinString(findParams.GroupBy)).ParseExprList()); + if (findParams.GroupByCritieria != null) + builder.GroupingCriteria = new ExprParser(findParams.GroupByCritieria).Parse(); + if (findParams.Locking != 0) builder.Locking = (Find.Types.RowLock)findParams.Locking; + if (findParams.LockingOption != 0) builder.LockingOptions = (Find.Types.RowLockOptions)findParams.LockingOption; + if (findParams.Projection != null && findParams.Projection.Length > 0) + { + var parser = new ExprParser(ExprUtil.JoinString(findParams.Projection)); + builder.Projection.Add(builder.DataModel == DataModel.Document ? + parser.ParseDocumentProjection() : + parser.ParseTableSelectProjection()); + + if (parser.tokenPos < parser.tokens.Count) + throw new ArgumentException(string.Format("Expression has unexpected token '{0}' at position {1}.", parser.tokens[parser.tokenPos].value, parser.tokenPos)); + } + ApplyFilter(v => builder.Limit = v, v => builder.Criteria = v, builder.Order.Add, filter, builder.Args.Add); + return builder; + } + + public void SendFind(string schema, string collection, bool isRelational, FilterParams filter, FindParams findParams) + { + var builder = CreateFindMessage(schema, collection, isRelational, filter, findParams); + _packetReaderWriter.Write(ClientMessageId.CRUD_FIND, builder); + } + + public void SendExpectOpen(Mysqlx.Expect.Open.Types.Condition.Types.Key condition, object value = null) + { + var builder = new Mysqlx.Expect.Open(); + var cond = new Mysqlx.Expect.Open.Types.Condition(); + cond.ConditionKey = (uint)condition; + cond.ConditionValue = value != null ? ByteString.CopyFromUtf8((string)value) : null; + builder.Cond.Add(cond); + _packetReaderWriter.Write(ClientMessageId.EXPECT_OPEN, builder); + } + + public void SendResetSession(bool sessionResetNoReauthentication) + { + var builder = new Mysqlx.Session.Reset(); + + if (sessionResetNoReauthentication) { builder.KeepOpen = sessionResetNoReauthentication; } + _packetReaderWriter.Write(ClientMessageId.SESS_RESET, builder); + } + + internal void ReadOkClose() + { + try + { + string response = ReadOk(); + if (response.IndexOf("bye", 0, StringComparison.OrdinalIgnoreCase) < 0) + throw new ArgumentException(); + } + catch (IOException) + { + // TODO connection is closed + } + catch (Exception ex) + { + throw new MySqlException("Unexpected message encountered during closing session", ex); + } + } + + internal string ReadOk() + { + CommunicationPacket p = ReadPacket(); + if (p.MessageType == (int)ServerMessageId.ERROR) + { + var error = Error.Parser.ParseFrom(p.Buffer); + throw new MySqlException(error.Code, error.SqlState, error.Msg); + } + if (p.MessageType == (int)ServerMessageId.OK) + { + var response = Ok.Parser.ParseFrom(p.Buffer); + return response.Msg; + } + else + throw new InvalidOperationException(); + } + + internal void SetXPackets(XPacketReaderWriter readerwriter) + { + _packetReaderWriter = readerwriter; + } + + public void SendPrepareStatement(uint stmtId, + PreparedStatementType type, + string schema, + string collection, + bool isRelational, + FilterParams filter, + FindParams findParams, + List updateSpecs = null, + object[] rows = null, + string[] columns = null, + bool upsert = false, + string sql = null) + { + var builder = new Prepare(); + builder.StmtId = stmtId; + builder.Stmt = new Prepare.Types.OneOfMessage(); + switch (type) + { + case PreparedStatementType.Find: + builder.Stmt.Type = Prepare.Types.OneOfMessage.Types.Type.Find; + var message = CreateFindMessage(schema, collection, isRelational, filter, findParams); + message.Args.Clear(); + if (filter.HasLimit) + { + uint positionFind = (uint)filter.Parameters.Count; + message.Limit = null; + message.LimitExpr = new LimitExpr + { + RowCount = new Expr + { + Type = Expr.Types.Type.Placeholder, + Position = positionFind++ + }, + Offset = new Expr + { + Type = Expr.Types.Type.Placeholder, + Position = positionFind++ + } + }; + } + builder.Stmt.Find = message; + break; + + case PreparedStatementType.Update: + builder.Stmt.Type = Prepare.Types.OneOfMessage.Types.Type.Update; + var updateMessage = CreateUpdateMessage(schema, collection, isRelational, filter, updateSpecs); + updateMessage.Args.Clear(); + if (filter.HasLimit) + { + uint positionUpdate = (uint)filter.Parameters.Count; + updateMessage.Limit = null; + updateMessage.LimitExpr = new LimitExpr + { + RowCount = new Expr + { + Type = Expr.Types.Type.Placeholder, + Position = positionUpdate++ + } + }; + } + builder.Stmt.Update = updateMessage; + break; + + case PreparedStatementType.Delete: + builder.Stmt.Type = Prepare.Types.OneOfMessage.Types.Type.Delete; + var deleteMessage = CreateDeleteMessage(schema, collection, isRelational, filter); + deleteMessage.Args.Clear(); + if (filter.HasLimit) + { + uint positionDelete = (uint)filter.Parameters.Count; + deleteMessage.Limit = null; + deleteMessage.LimitExpr = new LimitExpr + { + RowCount = new Expr + { + Type = Expr.Types.Type.Placeholder, + Position = positionDelete++ + } + }; + } + builder.Stmt.Delete = deleteMessage; + break; + + case PreparedStatementType.Insert: + builder.Stmt.Type = Prepare.Types.OneOfMessage.Types.Type.Insert; + var insertMessage = CreateInsertMessage(schema, isRelational, collection, rows, columns, upsert); + insertMessage.Args.Clear(); + uint position = 0; + foreach (var row in insertMessage.Row) + { + foreach (var field in row.Field) + { + if (field.Type == Expr.Types.Type.Literal) + { + field.Type = Expr.Types.Type.Placeholder; + field.Literal = null; + field.Position = position++; + } + } + } + builder.Stmt.Insert = insertMessage; + break; + + case PreparedStatementType.SqlStatement: + builder.Stmt.Type = Prepare.Types.OneOfMessage.Types.Type.Stmt; + var sqlMessage = CreateExecuteSQLStatement(sql, rows); + sqlMessage.Args.Clear(); + builder.Stmt.StmtExecute = sqlMessage; + break; + } + + _packetReaderWriter.Write((int)ClientMessages.Types.Type.PreparePrepare, builder); + ReadOk(); + } + + public void SendExecutePreparedStatement(uint stmtId, IEnumerable args) + { + var builder = new Execute(); + builder.StmtId = stmtId; + AddArgs(builder.Args.Add, args); + + _packetReaderWriter.Write((int)ClientMessages.Types.Type.PrepareExecute, builder); + } + + public void AddArgs(Action addFunction, IEnumerable args) + { + foreach (var arg in args) + { + if (arg.GetType().IsArray) + AddArgs(addFunction, (System.Array)arg); + else + addFunction(ExprUtil.BuildAny(arg)); + } + } + + public void SendDeallocatePreparedStatement(uint stmtId) + { + var builder = new Deallocate(); + builder.StmtId = stmtId; + _packetReaderWriter.Write((int)ClientMessages.Types.Type.PrepareDeallocate, builder); + ReadOk(); + } + } +} diff --git a/MySQL.Data/src/X/Protocol/X/XTimeDecoder.cs b/MySQL.Data/src/X/Protocol/X/XTimeDecoder.cs index 70164289e..390460438 100644 --- a/MySQL.Data/src/X/Protocol/X/XTimeDecoder.cs +++ b/MySQL.Data/src/X/Protocol/X/XTimeDecoder.cs @@ -1,66 +1,66 @@ -// Copyright © 2015, 2016, Oracle and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - - -using Google.Protobuf; -using MySql.Data.MySqlClient; -using MySql.Data.MySqlClient.X.XDevAPI.Common; -using MySqlX.Data; -using MySqlX.XDevAPI; -using System; - -namespace MySqlX.Protocol.X -{ - internal class XTimeDecoder : ValueDecoder - { - public override void SetMetadata() - { - Column.Type = ColumnType.Time; - Column.ClrType = typeof(TimeSpan); - ClrValueDecoder = ValueDecoder; - } - - public object ValueDecoder(byte[] bytes) - { - CodedInputStream input = new CodedInputStream(bytes); - Int64 hour = 0, min = 0, sec = 0, usec = 0; - - bool negative = input.ReadInt32() > 0; - if (!input.IsAtEnd) - hour = input.ReadInt64(); - if (!input.IsAtEnd) - min = input.ReadInt64(); - if (!input.IsAtEnd) - sec = input.ReadInt64(); - if (!input.IsAtEnd) - usec = input.ReadInt64(); - if (negative) hour *= -1; - return new TimeSpan(0, (int)hour, (int)min, (int)sec, (int)usec * 1000); - } - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +using Google.Protobuf; +using MySql.Data.MySqlClient; +using MySql.Data.MySqlClient.X.XDevAPI.Common; +using MySqlX.Data; +using MySqlX.XDevAPI; +using System; + +namespace MySqlX.Protocol.X +{ + internal class XTimeDecoder : ValueDecoder + { + public override void SetMetadata() + { + Column.Type = ColumnType.Time; + Column.ClrType = typeof(TimeSpan); + ClrValueDecoder = ValueDecoder; + } + + public object ValueDecoder(byte[] bytes) + { + CodedInputStream input = new CodedInputStream(bytes); + Int64 hour = 0, min = 0, sec = 0, usec = 0; + + bool negative = input.ReadInt32() > 0; + if (!input.IsAtEnd) + hour = input.ReadInt64(); + if (!input.IsAtEnd) + min = input.ReadInt64(); + if (!input.IsAtEnd) + sec = input.ReadInt64(); + if (!input.IsAtEnd) + usec = input.ReadInt64(); + if (negative) hour *= -1; + return new TimeSpan(0, (int)hour, (int)min, (int)sec, (int)usec * 1000); + } + } +} diff --git a/MySQL.Data/src/X/Protocol/X/XValueDecoderFactory.cs b/MySQL.Data/src/X/Protocol/X/XValueDecoderFactory.cs index 047547527..634ce78b1 100644 --- a/MySQL.Data/src/X/Protocol/X/XValueDecoderFactory.cs +++ b/MySQL.Data/src/X/Protocol/X/XValueDecoderFactory.cs @@ -1,56 +1,56 @@ -// Copyright © 2015, 2016, Oracle and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - - -using MySql.Data.MySqlClient; -using MySqlX.XDevAPI.Relational; - -namespace MySqlX.Protocol.X -{ - internal class XValueDecoderFactory - { - public static ValueDecoder GetValueDecoder(Column c, Mysqlx.Resultset.ColumnMetaData.Types.FieldType type) - { - switch (type) - { - case Mysqlx.Resultset.ColumnMetaData.Types.FieldType.Bit: return new BitDecoder(); - case Mysqlx.Resultset.ColumnMetaData.Types.FieldType.Bytes: return new ByteDecoder(false); - case Mysqlx.Resultset.ColumnMetaData.Types.FieldType.Enum: return new ByteDecoder(true); - case Mysqlx.Resultset.ColumnMetaData.Types.FieldType.Set: return new SetDecoder(); - case Mysqlx.Resultset.ColumnMetaData.Types.FieldType.Time: return new XTimeDecoder(); - case Mysqlx.Resultset.ColumnMetaData.Types.FieldType.Datetime: return new XDateTimeDecoder(); - case Mysqlx.Resultset.ColumnMetaData.Types.FieldType.Sint: return new IntegerDecoder(true); - case Mysqlx.Resultset.ColumnMetaData.Types.FieldType.Uint: return new IntegerDecoder(false); - case Mysqlx.Resultset.ColumnMetaData.Types.FieldType.Float: return new FloatDecoder(true); - case Mysqlx.Resultset.ColumnMetaData.Types.FieldType.Double: return new FloatDecoder(false); - case Mysqlx.Resultset.ColumnMetaData.Types.FieldType.Decimal: return new DecimalDecoder(); - } - throw new MySqlException("Unknown field type " + type.ToString()); - } - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +using MySql.Data.MySqlClient; +using MySqlX.XDevAPI.Relational; + +namespace MySqlX.Protocol.X +{ + internal class XValueDecoderFactory + { + public static ValueDecoder GetValueDecoder(Column c, Mysqlx.Resultset.ColumnMetaData.Types.FieldType type) + { + switch (type) + { + case Mysqlx.Resultset.ColumnMetaData.Types.FieldType.Bit: return new BitDecoder(); + case Mysqlx.Resultset.ColumnMetaData.Types.FieldType.Bytes: return new ByteDecoder(false); + case Mysqlx.Resultset.ColumnMetaData.Types.FieldType.Enum: return new ByteDecoder(true); + case Mysqlx.Resultset.ColumnMetaData.Types.FieldType.Set: return new SetDecoder(); + case Mysqlx.Resultset.ColumnMetaData.Types.FieldType.Time: return new XTimeDecoder(); + case Mysqlx.Resultset.ColumnMetaData.Types.FieldType.Datetime: return new XDateTimeDecoder(); + case Mysqlx.Resultset.ColumnMetaData.Types.FieldType.Sint: return new IntegerDecoder(true); + case Mysqlx.Resultset.ColumnMetaData.Types.FieldType.Uint: return new IntegerDecoder(false); + case Mysqlx.Resultset.ColumnMetaData.Types.FieldType.Float: return new FloatDecoder(true); + case Mysqlx.Resultset.ColumnMetaData.Types.FieldType.Double: return new FloatDecoder(false); + case Mysqlx.Resultset.ColumnMetaData.Types.FieldType.Decimal: return new DecimalDecoder(); + } + throw new MySqlException("Unknown field type " + type.ToString()); + } + } +} diff --git a/MySQL.Data/src/X/RoutingServices/DefaultRoutingService.cs b/MySQL.Data/src/X/RoutingServices/DefaultRoutingService.cs index ea44cbd6d..cf1a6ac14 100644 --- a/MySQL.Data/src/X/RoutingServices/DefaultRoutingService.cs +++ b/MySQL.Data/src/X/RoutingServices/DefaultRoutingService.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2015, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/X/RoutingServices/RoutingServiceBase.cs b/MySQL.Data/src/X/RoutingServices/RoutingServiceBase.cs index 37fbf555b..6d463413e 100644 --- a/MySQL.Data/src/X/RoutingServices/RoutingServiceBase.cs +++ b/MySQL.Data/src/X/RoutingServices/RoutingServiceBase.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2015, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/X/Serialization/JsonParser.cs b/MySQL.Data/src/X/Serialization/JsonParser.cs index e92792c57..769d68afd 100644 --- a/MySQL.Data/src/X/Serialization/JsonParser.cs +++ b/MySQL.Data/src/X/Serialization/JsonParser.cs @@ -1,213 +1,213 @@ -// Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySqlX.XDevAPI; -using System; -using System.Collections.Generic; - -namespace MySqlX.Serialization -{ - /// - /// Main class for parsing json strings. - /// - public class JsonParser - { - private int _pos = 0; - private String _input; - - /// - /// Initializes a new instance of the JsonParser class. - /// - public JsonParser() - {} - - /// - /// Parses the received string into a dictionary. - /// - /// The string to parse. - /// A object that represents the parsed string. - public static Dictionary Parse(string s) - { - JsonParser p = new JsonParser(); - return p.ParseInternal(s); - } - - private Dictionary ParseInternal(string s) - { - _input = s; - Dictionary dic = ReadGroup(); - if (_pos != _input.Length) - throw new IndexOutOfRangeException("It's not the end of stream."); - return dic; - } - - private Dictionary ReadGroup() - { - Dictionary values = new Dictionary(); - - RequireToken('{'); - if (PeekToken() != '}') - while (true) - { - string key = ReadQuotedToken(); - if (key == null) break; - RequireToken(':'); - var obj = ReadValue(); - values[key] = obj; - if (PeekToken() == '}') break; - RequireToken(','); - } - RequireToken('}'); - return values; - } - - private object ReadValue() - { - char t = PeekToken(); - if (t == '"') return ReadQuotedToken(); - if (t == '{') return ReadGroup(); - if (t == '[') return ReadArray(); - string stringValue = ReadUntilToken(',', '}', ']'); - bool flag; - if (bool.TryParse(stringValue, out flag)) return flag; - if (stringValue.Trim() == "null") return null; - int intValue; - long longValue; - double doubleValue; - if (int.TryParse(stringValue, out intValue)) return intValue; - if (long.TryParse(stringValue, out longValue)) return longValue; - if (double.TryParse( - stringValue, - System.Globalization.NumberStyles.Any, - System.Globalization.CultureInfo.InvariantCulture, - out doubleValue)) - return doubleValue; - - // May be a function. - int openingParen = 0; - for (int i=0; i0) - { - stringValue += ReadUntilToken(')') + ")"; - RequireToken(')'); - openingParen--; - } - - return new MySqlExpression(stringValue); - } - - private object[] ReadArray() - { - List values = new List(); - - RequireToken('['); - while (true) - { - values.Add(ReadValue()); - if (PeekToken() == ']') break; - RequireToken(','); - } - RequireToken(']'); - return values.ToArray(); - } - - private char PeekToken() - { - SkipWhite(); - if (_pos == _input.Length) - throw new Exception("Unexpected end of stream found."); - return _input[_pos]; - } - - private string ReadQuotedToken() - { - RequireToken('"'); - string val = ReadUntilToken('"'); - RequireToken('"'); - return val; - } - - private bool TokenInGroup(char[] tokens, char c) - { - foreach (char token in tokens) - if (token == c) return true; - return false; - } - - private string ReadUntilToken(params char[] end) - { - string val = ""; - bool escapedQuoteExpected = false; - while (_pos < _input.Length) - { - char c = _input[_pos++]; - - if (!escapedQuoteExpected) - { - if (c == 92) - escapedQuoteExpected = true; - else if (TokenInGroup(end, c)) - { - _pos--; - return val; - } - } - else if (c == 34) - escapedQuoteExpected = false; - - val += c; - } - throw new Exception("Failed to find ending '\"' while reading stream."); - } - - private void RequireToken(char token) - { - if (!ReadToken(token)) - throw new Exception("Expected token '" + token + "'"); - } - - private bool ReadToken(char token) - { - SkipWhite(); - if (_pos == _input.Length) return false; - char c = _input[_pos++]; - return c == token; - } - - private void SkipWhite() - { - while (Char.IsWhiteSpace(_input[_pos])) - _pos++; - } - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySqlX.XDevAPI; +using System; +using System.Collections.Generic; + +namespace MySqlX.Serialization +{ + /// + /// Main class for parsing json strings. + /// + public class JsonParser + { + private int _pos = 0; + private String _input; + + /// + /// Initializes a new instance of the JsonParser class. + /// + public JsonParser() + {} + + /// + /// Parses the received string into a dictionary. + /// + /// The string to parse. + /// A object that represents the parsed string. + public static Dictionary Parse(string s) + { + JsonParser p = new JsonParser(); + return p.ParseInternal(s); + } + + private Dictionary ParseInternal(string s) + { + _input = s; + Dictionary dic = ReadGroup(); + if (_pos != _input.Length) + throw new IndexOutOfRangeException("It's not the end of stream."); + return dic; + } + + private Dictionary ReadGroup() + { + Dictionary values = new Dictionary(); + + RequireToken('{'); + if (PeekToken() != '}') + while (true) + { + string key = ReadQuotedToken(); + if (key == null) break; + RequireToken(':'); + var obj = ReadValue(); + values[key] = obj; + if (PeekToken() == '}') break; + RequireToken(','); + } + RequireToken('}'); + return values; + } + + private object ReadValue() + { + char t = PeekToken(); + if (t == '"') return ReadQuotedToken(); + if (t == '{') return ReadGroup(); + if (t == '[') return ReadArray(); + string stringValue = ReadUntilToken(',', '}', ']'); + bool flag; + if (bool.TryParse(stringValue, out flag)) return flag; + if (stringValue.Trim() == "null") return null; + int intValue; + long longValue; + double doubleValue; + if (int.TryParse(stringValue, out intValue)) return intValue; + if (long.TryParse(stringValue, out longValue)) return longValue; + if (double.TryParse( + stringValue, + System.Globalization.NumberStyles.Any, + System.Globalization.CultureInfo.InvariantCulture, + out doubleValue)) + return doubleValue; + + // May be a function. + int openingParen = 0; + for (int i=0; i0) + { + stringValue += ReadUntilToken(')') + ")"; + RequireToken(')'); + openingParen--; + } + + return new MySqlExpression(stringValue); + } + + private object[] ReadArray() + { + List values = new List(); + + RequireToken('['); + while (true) + { + values.Add(ReadValue()); + if (PeekToken() == ']') break; + RequireToken(','); + } + RequireToken(']'); + return values.ToArray(); + } + + private char PeekToken() + { + SkipWhite(); + if (_pos == _input.Length) + throw new Exception("Unexpected end of stream found."); + return _input[_pos]; + } + + private string ReadQuotedToken() + { + RequireToken('"'); + string val = ReadUntilToken('"'); + RequireToken('"'); + return val; + } + + private bool TokenInGroup(char[] tokens, char c) + { + foreach (char token in tokens) + if (token == c) return true; + return false; + } + + private string ReadUntilToken(params char[] end) + { + string val = ""; + bool escapedQuoteExpected = false; + while (_pos < _input.Length) + { + char c = _input[_pos++]; + + if (!escapedQuoteExpected) + { + if (c == 92) + escapedQuoteExpected = true; + else if (TokenInGroup(end, c)) + { + _pos--; + return val; + } + } + else if (c == 34) + escapedQuoteExpected = false; + + val += c; + } + throw new Exception("Failed to find ending '\"' while reading stream."); + } + + private void RequireToken(char token) + { + if (!ReadToken(token)) + throw new Exception("Expected token '" + token + "'"); + } + + private bool ReadToken(char token) + { + SkipWhite(); + if (_pos == _input.Length) return false; + char c = _input[_pos++]; + return c == token; + } + + private void SkipWhite() + { + while (Char.IsWhiteSpace(_input[_pos])) + _pos++; + } + } +} diff --git a/MySQL.Data/src/X/Sessions/InternalSession.cs b/MySQL.Data/src/X/Sessions/InternalSession.cs index a8a414c71..bc58494da 100644 --- a/MySQL.Data/src/X/Sessions/InternalSession.cs +++ b/MySQL.Data/src/X/Sessions/InternalSession.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2015, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/X/Sessions/QueueTaskScheduler.cs b/MySQL.Data/src/X/Sessions/QueueTaskScheduler.cs index 20528191c..adee17560 100644 --- a/MySQL.Data/src/X/Sessions/QueueTaskScheduler.cs +++ b/MySQL.Data/src/X/Sessions/QueueTaskScheduler.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2015, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/X/Sessions/XInternalSession.cs b/MySQL.Data/src/X/Sessions/XInternalSession.cs index c64286b34..2bf7e8f15 100644 --- a/MySQL.Data/src/X/Sessions/XInternalSession.cs +++ b/MySQL.Data/src/X/Sessions/XInternalSession.cs @@ -1,1056 +1,1056 @@ -// Copyright (c) 2015, 2023, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data; -using MySql.Data.Common; -using MySql.Data.MySqlClient; -using MySql.Data.MySqlClient.Authentication; -using MySqlX.Communication; -using MySqlX.Protocol; -using MySqlX.Protocol.X; -using MySqlX.Security; -using MySqlX.XDevAPI; -using MySqlX.XDevAPI.Common; -using MySqlX.XDevAPI.CRUD; -using MySqlX.XDevAPI.Relational; -using System; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Threading; - -namespace MySqlX.Sessions -{ - /// - /// Implementation class of InternalSession to manage connections using the Xprotocol type object. - /// - internal class XInternalSession : InternalSession - { - /// - /// Defines the compression controller that will be passed on the instance when - /// compression is enabled. - /// - private XCompressionController _readerCompressionController; - - /// - /// Defines the compression controller that will be passed on the instance when - /// compression is enabled. - /// - private XCompressionController _writerCompressionController; - - private XProtocol _protocol; - private XPacketReaderWriter _packetReaderWriter; - private bool _serverSupportsTls = false; - private const string mysqlxNamespace = "mysqlx"; - internal bool _supportsPreparedStatements = true; - private int _stmtId = 0; - private List _preparedStatements = new List(); - internal bool? _sessionResetNoReauthentication = null; - internal MyNetworkStream _myNetworkStream; - - public XInternalSession(MySqlXConnectionStringBuilder settings) : base(settings) - { - } - - protected override void Open() - { - bool isUnix = Settings.ConnectionProtocol == MySqlConnectionProtocol.Unix || - Settings.ConnectionProtocol == MySqlConnectionProtocol.UnixSocket; - - _stream = MyNetworkStream.CreateStreamAsync( - Settings.Server == "127.0.0.1" || Settings.Server == "::1" - ? "localhost" - : Settings.Server, - Settings.ConnectTimeout, - Settings.Keepalive, - Settings.Port, - isUnix, false).GetAwaiter().GetResult(); - _myNetworkStream = (MyNetworkStream)_stream; - if (_stream == null) - throw new MySqlException(ResourcesX.UnableToConnect); - - _packetReaderWriter = new XPacketReaderWriter(_stream, _myNetworkStream.Socket); - _protocol = new XProtocol(_packetReaderWriter); - - Settings.CharacterSet = string.IsNullOrWhiteSpace(Settings.CharacterSet) ? "utf8mb4" : Settings.CharacterSet; - var encoding = CharSetMap.GetEncoding(Settings.CharacterSet); - - SetState(SessionState.Connecting, false); - - try - { - GetAndSetCapabilities(); - } - catch (Exception) - { - throw; - } - - // Validates use of TLS. - if (Settings.SslMode != MySqlSslMode.Disabled) - { - if (_serverSupportsTls) - { - var result = new Ssl( - Settings.Server, - Settings.SslMode, - Settings.CertificateFile, - Settings.CertificateStoreLocation, - Settings.CertificatePassword, - Settings.CertificateThumbprint, - Settings.SslCa, - Settings.SslCert, - Settings.SslKey, - Settings.TlsVersion, - Settings.ConnectTimeout) - .StartSSLAsync(_stream, encoding, Settings.ToString(), CancellationToken.None, false).GetAwaiter().GetResult(); - - _stream = result.Item2; - - if (_readerCompressionController != null && _readerCompressionController.IsCompressionEnabled) - { - _packetReaderWriter = new XPacketReaderWriter(_stream, _readerCompressionController, _writerCompressionController, _myNetworkStream.Socket); - } - else - { - _packetReaderWriter = new XPacketReaderWriter(_stream, _myNetworkStream.Socket); - } - - _protocol.SetXPackets(_packetReaderWriter); - } - else - { - // Client requires SSL connections. - string message = String.Format(Resources.NoServerSSLSupport, - Settings.Server); - throw new MySqlException(message); - } - } - else if (_readerCompressionController != null && _readerCompressionController.IsCompressionEnabled) - { - _packetReaderWriter = new XPacketReaderWriter(_stream, _readerCompressionController, _writerCompressionController, _myNetworkStream.Socket); - _protocol.SetXPackets(_packetReaderWriter); - } - - Authenticate(); - - SetState(SessionState.Open, false); - } - - internal void Authenticate() - { - // Default authentication - if (Settings.Auth == MySqlAuthenticationMode.Default) - { - if ((Settings.SslMode != MySqlSslMode.Disabled && _serverSupportsTls) || Settings.ConnectionProtocol == MySqlConnectionProtocol.Unix) - { - Settings.Auth = MySqlAuthenticationMode.PLAIN; - AuthenticatePlain(); - } - else - { - bool authenticated = false; - // first try using MYSQL41 - Settings.Auth = MySqlAuthenticationMode.MYSQL41; - try - { - AuthenticateMySQL41(); - authenticated = true; - } - catch (MySqlException ex) - { - // code 1045 Invalid user or password - if (ex.Code != 1045) - throw; - } - - // second try using SHA256_MEMORY - if (!authenticated) - { - try - { - Settings.Auth = MySqlAuthenticationMode.SHA256_MEMORY; - AuthenticateSha256Memory(); - authenticated = true; - } - catch (MySqlException ex) - { - // code 1045 Invalid user or password - if (ex.Code == 1045) - throw new MySqlException(1045, "HY000", ResourcesX.AuthenticationFailed); - else - throw; - } - } - } - } - // User defined authentication - else - { - switch (Settings.Auth) - { - case MySqlAuthenticationMode.PLAIN: - AuthenticatePlain(); - break; - case MySqlAuthenticationMode.MYSQL41: - AuthenticateMySQL41(); - break; - case MySqlAuthenticationMode.EXTERNAL: - AuthenticateExternal(); - break; - case MySqlAuthenticationMode.SHA256_MEMORY: - AuthenticateSha256Memory(); - break; - default: - throw new NotImplementedException(Settings.Auth.ToString()); - } - } - } - - private void GetAndSetCapabilities() - { - _protocol.GetServerCapabilities(); - var clientCapabilities = new Dictionary(); - Mysqlx.Connection.Capability capability = null; - - // Validates TLS use. - if (Settings.SslMode != MySqlSslMode.Disabled) - { - capability = _protocol.Capabilities.Capabilities_.FirstOrDefault(i => i.Name.ToLowerInvariant() == "tls"); - if (capability != null) - { - _serverSupportsTls = true; - clientCapabilities.Add("tls", "1"); - } - } - - // Set connection-attributes. - if (Settings.ConnectionAttributes.ToLower() != "false") - clientCapabilities.Add("session_connect_attrs", GetConnectionAttributes(Settings.ConnectionAttributes)); - - // Set compression algorithm. - if (Settings.Compression != CompressionType.Disabled) - { - capability = _protocol.Capabilities.Capabilities_.FirstOrDefault(i => i.Name.ToLowerInvariant() == XCompressionController.COMPRESSION_KEY); - - // Raise error if client expects compression but server doesn't support it. - if (Settings.Compression == CompressionType.Required && capability == null) - { - throw new NotSupportedException(ResourcesX.CompressionNotSupportedByServer); - } - - // Update capabilities with the compression algorithm negotiation if server supports compression. - if (capability != null) - { - var algorithmsDictionary = capability.Value.Obj.Fld.ToDictionary( - field => field.Key, - field => field.Value.Array.Value.ToDictionary(value => value.Scalar.VString.Value.ToStringUtf8().ToLowerInvariant()).Keys.ToList()); - - if (algorithmsDictionary.ContainsKey(XCompressionController.ALGORITHMS_SUBKEY)) - { - var supportedCompressionAlgorithms = algorithmsDictionary[XCompressionController.ALGORITHMS_SUBKEY].ToList().ToArray(); - VerifyDefaultOrder(ref supportedCompressionAlgorithms); - var userCompressionAlgorithms = NegotiateUserAgainstClientAlgorithms(Settings.CompressionAlgorithm); - var compressionCapabilities = NegotiateCompression(supportedCompressionAlgorithms, userCompressionAlgorithms); - if (compressionCapabilities != null) - { - clientCapabilities.Add(XCompressionController.COMPRESSION_KEY, compressionCapabilities); - var compressionAlgorithm = compressionCapabilities.First().Value.ToString(); - _readerCompressionController = new XCompressionController((CompressionAlgorithms)Enum.Parse(typeof(CompressionAlgorithms), compressionAlgorithm), false); - _writerCompressionController = new XCompressionController((CompressionAlgorithms)Enum.Parse(typeof(CompressionAlgorithms), compressionAlgorithm), true); - _packetReaderWriter = new XPacketReaderWriter(_stream, _readerCompressionController, _writerCompressionController, _myNetworkStream.Socket); - - } - } - } - } - - try - { - _protocol.SetCapabilities(clientCapabilities); - } - catch (MySqlException ex) - { - if (ex.Message == "Capability 'session_connect_attrs' doesn't exist") - clientCapabilities.Remove("session_connect_attrs"); - _protocol.SetCapabilities(clientCapabilities); - } - } - - /// - /// Reorder the list of algorithms retrieved from server to the preferred order - /// - private void VerifyDefaultOrder(ref string[] algorithms) - { - var clientSupportedAlgorithms = Enum.GetNames(typeof(CompressionAlgorithms)); - List output = new List(); - foreach (var item in clientSupportedAlgorithms) - { - if (algorithms.Contains(item)) - { - output.Add(item); - } - } - algorithms = output.ToArray(); - } - - /// - /// Validate the algorithms given in the connection string are valid compared with enum CompressionAlgorithms - /// - public List NegotiateUserAgainstClientAlgorithms(string inputString) - { - inputString = inputString.Contains("[") ? inputString.Replace("[", string.Empty) : inputString; - inputString = inputString.Contains("]") ? inputString.Replace("]", string.Empty) : inputString; - inputString.Trim(); - if (string.IsNullOrEmpty(inputString)) - { - return Enum.GetNames(typeof(CompressionAlgorithms)).ToList(); - } - var elements = inputString.ToLowerInvariant().Split(','); - List ret = new List(); - for (var i = 0; i < elements.Length; i++) - { - switch (elements[i].ToLowerInvariant()) - { - case "lz4": - case "lz4_message": - elements[i] = CompressionAlgorithms.lz4_message.ToString(); - break; - case "zstd": - case "zstd_stream": - elements[i] = CompressionAlgorithms.zstd_stream.ToString(); - break; - - case "deflate": - case "deflate_stream": -#if NETFRAMEWORK - if (elements.Length == 1 && Settings.Compression == CompressionType.Required) - { - throw new NotSupportedException(string.Format(ResourcesX.CompressionForSpecificAlgorithmNotSupportedInNetFramework, elements[i])); - } -#else - elements[i] = CompressionAlgorithms.deflate_stream.ToString(); -#endif - break; - - } - if (Enum.IsDefined(typeof(CompressionAlgorithms), elements[i])) - { - ret.Add(elements[i]); - } - } - return ret; - } - - /// - /// Negotiates compression capabilities with the server. - /// - /// An array containing the compression algorithms supported by the server. - /// An array containing the compression algorithms given by user/client. - private Dictionary NegotiateCompression(string[] serverSupportedAlgorithms, List clientAgainstUserAlgorithms) - { - if (serverSupportedAlgorithms == null || serverSupportedAlgorithms.Length == 0) - { - if (Settings.Compression == CompressionType.Required && clientAgainstUserAlgorithms.Count > 0) - { - throw new NotSupportedException(ResourcesX.CompressionAlgorithmNegotiationFailed); - } - return null; - } - - // If server and client don't have matching compression algorithms either log a warning message - // or raise an exception based on the selected compression type. - if (!clientAgainstUserAlgorithms.Any(element => serverSupportedAlgorithms.Contains(element))) - { - if (Settings.Compression == CompressionType.Preferred) - { - MySqlTrace.LogWarning(-1, ResourcesX.CompressionAlgorithmNegotiationFailed); - return null; - } - else if (Settings.Compression == CompressionType.Required) - { - throw new NotSupportedException(ResourcesX.CompressionAlgorithmNegotiationFailed); - } - } - - string negotiatedAlgorithm = null; - for (int index = 0; index < clientAgainstUserAlgorithms.Count; index++) - { - if (!serverSupportedAlgorithms.Contains(clientAgainstUserAlgorithms[index])) - { - continue; - } - - negotiatedAlgorithm = clientAgainstUserAlgorithms[index]; - break; - } - - if (negotiatedAlgorithm == null) - { - return null; - } - - // Create the compression capability object. - var compressionCapabilities = new Dictionary(); - compressionCapabilities.Add(XCompressionController.ALGORITHMS_SUBKEY, negotiatedAlgorithm); - compressionCapabilities.Add(XCompressionController.SERVER_COMBINE_MIXED_MESSAGES_SUBKEY, XCompressionController.DEFAULT_SERVER_COMBINE_MIXED_MESSAGES_VALUE); - - // TODO: For future use. - //compressionCapabilities.Add(XCompressionController.SERVER_MAX_COMBINE_MESSAGES_SUBKEY, XCompressionController.DEFAULT_SERVER_MAX_COMBINE_MESSAGES_VALUE); - - return compressionCapabilities; - } - - private Dictionary GetConnectionAttributes(string connectionAttrs) - { - Dictionary attrs = new Dictionary(); - - if (connectionAttrs.StartsWith("[") && connectionAttrs.EndsWith("]")) - { - connectionAttrs = connectionAttrs.Substring(1, connectionAttrs.Length - 2); - - if (!string.IsNullOrWhiteSpace(connectionAttrs)) - { - foreach (var pair in connectionAttrs.Split(',')) - { - string[] keyValue = pair.Split('='); - string key = keyValue[0].Trim(); - string value = keyValue.Length > 1 ? keyValue[1].Trim() : string.Empty; - - if (key == string.Empty) - throw new MySqlException(ResourcesX.EmptyKeyConnectionAttribute); - - if (key.StartsWith("_")) - throw new MySqlException(ResourcesX.InvalidUserDefinedAttribute); - - try { attrs.Add(key, value); } - catch (ArgumentException) { throw new MySqlException(string.Format(ResourcesX.DuplicateUserDefinedAttribute, key)); } - } - } - } - else if (connectionAttrs != "true") - throw new MySqlException(ResourcesX.InvalidConnectionAttributes); - - MySqlConnectAttrs clientAttrs = new MySqlConnectAttrs(); - attrs.Add("_pid", clientAttrs.PID); - attrs.Add("_platform", clientAttrs.Platform); - attrs.Add("_os", clientAttrs.OSName); - attrs.Add("_source_host", Settings.Server); - attrs.Add("_client_name", clientAttrs.ClientName); - attrs.Add("_client_version", clientAttrs.ClientVersion); - attrs.Add("_client_license", clientAttrs.ClientLicence); - attrs.Add("_framework", clientAttrs.Framework); - - return attrs; - } - - private void AuthenticateMySQL41() - { - MySQL41AuthenticationPlugin plugin = new MySQL41AuthenticationPlugin(Settings); - _protocol.SendAuthStart(plugin.AuthName, null, null); - byte[] extraData = _protocol.ReadAuthContinue(); - _protocol.SendAuthContinue(plugin.Continue(extraData)); - _protocol.ReadAuthOk(); - } - - private void AuthenticatePlain() - { - PlainAuthenticationPlugin plugin = new PlainAuthenticationPlugin(Settings); - _protocol.SendAuthStart(plugin.AuthName, plugin.GetAuthData(), null); - _protocol.ReadAuthOk(); - } - - private void AuthenticateExternal() - { - ExternalAuthenticationPlugin plugin = new ExternalAuthenticationPlugin(Settings); - _protocol.SendAuthStart(plugin.AuthName, Encoding.UTF8.GetBytes(""), null); - _protocol.ReadAuthOk(); - } - - private void AuthenticateSha256Memory() - { - Sha256MemoryAuthenticationPlugin plugin = new Sha256MemoryAuthenticationPlugin(); - _protocol.SendAuthStart(plugin.PluginName, null, null); - byte[] nonce = _protocol.ReadAuthContinue(); - - string data = $"{Settings.Database}\0{Settings.UserID}\0"; - byte[] byteData = Encoding.UTF8.GetBytes(data); - byte[] clientHash = plugin.GetClientHash(Settings.Password, nonce); - byte[] authData = new byte[byteData.Length + clientHash.Length]; - byteData.CopyTo(authData, 0); - clientHash.CopyTo(authData, byteData.Length); - - _protocol.SendAuthContinue(authData); - _protocol.ReadAuthOk(); - } - - protected internal void SetState(SessionState newState, bool broadcast) - { - if (newState == SessionState && !broadcast) - return; - SessionState oldSessionState = SessionState; - SessionState = newState; - - //TODO check if we need to send this event - //if (broadcast) - //OnStateChange(new StateChangeEventArgs(oldConnectionState, connectionState)); - } - - internal override ProtocolBase GetProtocol() - { - return _protocol; - } - - public override void Close() - { - try - { - try - { - // Deallocate compression objects. - _readerCompressionController?.Close(); - _writerCompressionController?.Close(); - - // Deallocate all the remaining prepared statements for current session. - foreach (int stmtId in _preparedStatements) - { - if (!_myNetworkStream.IsSocketClosed) - { - DeallocatePreparedStatement(stmtId); - } - _preparedStatements.Remove(stmtId); - } - } - catch (Exception) - { - //TODO log exception - } - - if (!_myNetworkStream.IsSocketClosed) - { - _protocol.SendSessionClose(); - } - } - finally - { - SessionState = SessionState.Closed; - _stream.Dispose(); - } - } - - public void CreateCollection(string schemaName, string collectionName) - { - ExecuteCmdNonQuery(XpluginStatementCommand.XPLUGIN_STMT_CREATE_COLLECTION, - true, - new KeyValuePair("schema", schemaName), - new KeyValuePair("name", collectionName)); - } - - /// - /// Prepare the dictionary of arguments required to create a MySQL message. - /// - /// The name of the MySQL schema. - /// The name of the collection. - /// This object hold the parameters required to create the collection. - /// - /// Collection referente. - public void CreateCollection(string schemaName, string collectionName, CreateCollectionOptions options) - { - var dictionary = new Dictionary(); - if (!options.Equals(null)) - { - if (!string.IsNullOrEmpty(options.Validation.Level.ToString())) - { - dictionary.Add("level", (string)options.Validation.Level.ToString().ToLowerInvariant()); - } - - if (!string.IsNullOrEmpty(options.Validation.Schema)) - { - dictionary.Add("schema", new DbDoc(options.Validation.Schema)); - } - } - - ExecuteCmdNonQueryOptions(XpluginStatementCommand.XPLUGIN_STMT_CREATE_COLLECTION, - true, - new KeyValuePair("schema", schemaName), - new KeyValuePair("name", collectionName), - new KeyValuePair("reuse_existing", options.ReuseExisting), - new KeyValuePair("options", dictionary) - ); - } - - /// - /// Prepare the dictionary of arguments required to Modify a MySQL message. - /// - /// The name of the MySQL schema. - /// The name of the collection. - /// This object hold the parameters required to Modify the collection. - /// - public void ModifyCollection(string schemaName, string collectionName, ModifyCollectionOptions? options) - { - var dictionary = new Dictionary(); - if (!options.Equals(null)) - { - if (options.Value.Validation.Level != null) - { - dictionary.Add("level", options.Value.Validation.Level.ToString().ToLowerInvariant()); - } - if (options.Value.Validation.Schema != null) - { - dictionary.Add("schema", new DbDoc(options.Value.Validation.Schema)); - } - } - ExecuteCmdNonQueryOptions(XpluginStatementCommand.XPLUGIN_STMT_MODIFY_COLLECTION, - true, - new KeyValuePair("schema", schemaName), - new KeyValuePair("name", collectionName), - new KeyValuePair("options", dictionary)); - } - - public void DropCollection(string schemaName, string collectionName) - { - ExecuteCmdNonQuery(XpluginStatementCommand.XPLUGIN_STMT_DROP_COLLECTION, - true, - new KeyValuePair("schema", schemaName), - new KeyValuePair("name", collectionName)); - } - - public Result CreateCollectionIndex(CreateCollectionIndexStatement statement) - { - List> args = new List>(); - args.Add(new KeyValuePair("name", statement.createIndexParams.IndexName)); - args.Add(new KeyValuePair("collection", statement.Target.Name)); - args.Add(new KeyValuePair("schema", statement.Target.Schema.Name)); - args.Add(new KeyValuePair("unique", false)); - - if (statement.createIndexParams.Type != null) - args.Add(new KeyValuePair("type", statement.createIndexParams.Type)); - - for (int i = 0; i < statement.createIndexParams.Fields.Count; i++) - { - var field = statement.createIndexParams.Fields[i]; - var dictionary = new Dictionary(); - dictionary.Add("member", field.Field); - if (field.Type != null) - dictionary.Add("type", field.Type); - - if (field.Required == null) - dictionary.Add("required", false); - else - dictionary.Add("required", (bool)field.Required); - - if (field.Options != null) - dictionary.Add("options", (ulong)field.Options); - - if (field.Srid != null) - dictionary.Add("srid", (ulong)field.Srid); - - if (field.Array != null) - dictionary.Add("array", (bool)field.Array); - - args.Add(new KeyValuePair("constraint", dictionary)); - } - - return ExecuteCreateCollectionIndex(XpluginStatementCommand.XPLUGIN_STMT_CREATE_COLLECTION_INDEX, false, args.ToArray()); - } - - public void DropCollectionIndex(string schemaName, string collectionName, string indexName) - { - List> args = new List>(); - args.Add(new KeyValuePair("schema", schemaName)); - args.Add(new KeyValuePair("collection", collectionName)); - args.Add(new KeyValuePair("name", indexName)); - ExecuteCmdNonQuery(XpluginStatementCommand.XPLUGIN_STMT_DROP_COLLECTION_INDEX, false, args.ToArray()); - } - - public long TableCount(Schema schema, string name, string type) - { - try - { - string sql = String.Format("SELECT COUNT(*) FROM {0}.{1}", - ExprUnparser.QuoteIdentifier(schema.Name), ExprUnparser.QuoteIdentifier(name)); - return (long)ExecuteQueryAsScalar(sql); - } - catch (MySqlException ex) when (ex.Code == 1146) - { - throw new MySqlException(string.Format(ResourcesX.CollectionTableDoesNotExist, type.ToString(), name, schema.Name), (int)ex.Code); - } - } - - public bool TableExists(Schema schema, string name) - { - string sql = String.Format("SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = '{0}' AND table_name = '{1}'", - schema.Name, name); - long count = (long)ExecuteQueryAsScalar(sql); - return count != 0; - } - - private Result ExecuteCmdNonQuery(string cmd, bool throwOnFail, params KeyValuePair[] args) - { - _protocol.SendExecuteStatement(mysqlxNamespace, cmd, args); - return new Result(this); - } - - private Result ExecuteCmdNonQueryOptions(string cmd, bool throwOnFail, params KeyValuePair[] args) - { - _protocol.SendExecuteStatementOptions(mysqlxNamespace, cmd, args); - return new Result(this); - } - - private Result ExecuteCreateCollectionIndex(string cmd, bool throwOnFail, params KeyValuePair[] args) - { - _protocol.SendCreateCollectionIndexStatement(mysqlxNamespace, cmd, args); - return new Result(this); - } - - public List GetObjectList(Schema s, params string[] types) where T : DatabaseObject - { - for (int i = 0; i < types.Length; i++) - types[i] = types[i].ToUpperInvariant(); - RowResult result = GetRowResult("list_objects", new KeyValuePair("schema", s.Name)); - var rows = result.FetchAll(); - - List docs = new List(); - foreach (var row in rows) - { - if (!types.Contains(row.GetString("type").ToUpperInvariant())) continue; - - List parameters = new List(new object[] { s, row.GetString("name") }); - if (row["name"] is Byte[]) - { - Byte[] byteArray = row["name"] as Byte[]; - parameters[1] = Encoding.UTF8.GetString(byteArray, 0, byteArray.Length); - } - - switch (row.GetString("type").ToUpperInvariant()) - { - case "TABLE": - parameters.Add(false); - break; - case "VIEW": - parameters.Add(true); - break; - } - T t = (T)Activator.CreateInstance(typeof(T), - BindingFlags.NonPublic | BindingFlags.Instance, - null, parameters.ToArray(), null); - docs.Add(t); - } - return docs; - } - - public string GetObjectType(Schema s, string name) - { - RowResult result = GetRowResult("list_objects", - new KeyValuePair("schema", s.Name), - new KeyValuePair("pattern", name)); - var row = result.FetchOne(); - if (row == null) - throw new MySqlException(string.Format(ResourcesX.NoObjectFound, name)); - System.Diagnostics.Debug.Assert(result.FetchOne() == null); - return row.GetString("type"); - } - - public RowResult GetRowResult(string cmd, params KeyValuePair[] args) - { - _protocol.SendExecuteStatement(mysqlxNamespace, cmd, args); - return new RowResult(this); - } - - public Result Insert(Collection collection, object[] json, List newIds, bool upsert) - { - _protocol.SendInsert(collection.Schema.Name, false, collection.Name, json, null, upsert); - return new Result(this); - } - - public Result DeleteDocs(RemoveStatement rs) - { - _protocol.SendDelete(rs.Target.Schema.Name, rs.Target.Name, false, rs.FilterData); - return new Result(this); - } - - public Result DeleteRows(TableDeleteStatement statement) - { - _protocol.SendDelete(statement.Target.Schema.Name, - statement.Target.Name, true, - statement.FilterData); - return new Result(this); - } - - public Result ModifyDocs(ModifyStatement ms) - { - _protocol.SendUpdate(ms.Target.Schema.Name, ms.Target.Name, false, ms.FilterData, ms.Updates); - return new Result(this); - } - - public Result UpdateRows(TableUpdateStatement statement) - { - _protocol.SendUpdate(statement.Target.Schema.Name, - statement.Target.Name, true, - statement.FilterData, - statement.updates); - return new Result(this); - } - - public DocResult FindDocs(FindStatement fs) - { - _protocol.SendFind(fs.Target.Schema.Name, fs.Target.Name, false, fs.FilterData, fs.findParams); - DocResult result = new DocResult(this); - return result; - } - - public RowResult FindRows(TableSelectStatement ss) - { - _protocol.SendFind(ss.Target.Schema.Name, ss.Target.Name, true, ss.FilterData, ss.findParams); - return new RowResult(this); - } - - public Result InsertRows(TableInsertStatement statement) - { - _protocol.SendInsert(statement.Target.Schema.Name, true, statement.Target.Name, statement.values.ToArray(), statement.fields, false); - return new Result(this); - } - - protected Result ExpectOpen(Mysqlx.Expect.Open.Types.Condition.Types.Key condition, object value = null) - { - _protocol.SendExpectOpen(condition, value); - return new Result(this); - } - - public Result ExpectDocidGenerated() - { - return ExpectOpen(Mysqlx.Expect.Open.Types.Condition.Types.Key.ExpectDocidGenerated); - } - - public void ResetSession() - { - if (_sessionResetNoReauthentication == null) - { - try - { - if (!_myNetworkStream.IsSocketClosed) - { - ExpectOpen(Mysqlx.Expect.Open.Types.Condition.Types.Key.ExpectFieldExist, "6.1"); - } - _sessionResetNoReauthentication = true; - } - catch - { - _sessionResetNoReauthentication = false; - } - } - - if (!_myNetworkStream.IsSocketClosed) - { - _protocol.SendResetSession((bool)_sessionResetNoReauthentication); - _protocol.ReadOk(); - } - } - - public int PrepareStatement(BaseStatement statement) - where TResult : BaseResult - { - int stmtId = Interlocked.Increment(ref _stmtId); - string stmtType = statement.GetType().Name; - - if (stmtType == typeof(FindStatement<>).Name) - { - FindStatement fs = statement as FindStatement; - string s = typeof(TDoc).Name; - Debug.Assert(fs != null); - _protocol.SendPrepareStatement( - (uint)stmtId, - DataAccess.PreparedStatementType.Find, - fs.Target.Schema.Name, - fs.Target.Name, - false, - fs.FilterData, - fs.findParams); - } - else if (stmtType == typeof(TableSelectStatement).Name) - { - TableSelectStatement ss = statement as TableSelectStatement; - Debug.Assert(ss != null); - _protocol.SendPrepareStatement( - (uint)stmtId, - DataAccess.PreparedStatementType.Find, - ss.Target.Schema.Name, - ss.Target.Name, - true, - ss.FilterData, - ss.findParams); - } - else if (stmtType == typeof(ModifyStatement<>).Name) - { - ModifyStatement ms = statement as ModifyStatement; - Debug.Assert(ms != null); - _protocol.SendPrepareStatement( - (uint)stmtId, - DataAccess.PreparedStatementType.Update, - ms.Target.Schema.Name, - ms.Target.Name, - false, - ms.FilterData, - null, - ms.Updates); - } - else if (stmtType == typeof(TableUpdateStatement).Name) - { - TableUpdateStatement us = statement as TableUpdateStatement; - Debug.Assert(us != null); - _protocol.SendPrepareStatement( - (uint)stmtId, - DataAccess.PreparedStatementType.Update, - us.Target.Schema.Name, - us.Target.Name, - true, - us.FilterData, - null, - us.updates); - } - else if (stmtType == typeof(RemoveStatement<>).Name) - { - string s = typeof(TDoc).Name; - RemoveStatement rs = statement as RemoveStatement; - Debug.Assert(rs != null); - _protocol.SendPrepareStatement( - (uint)stmtId, - DataAccess.PreparedStatementType.Delete, - rs.Target.Schema.Name, - rs.Target.Name, - false, - rs.FilterData, - null); - } - else if (stmtType == typeof(TableDeleteStatement).Name) - { - TableDeleteStatement ds = statement as TableDeleteStatement; - Debug.Assert(ds != null); - _protocol.SendPrepareStatement( - (uint)stmtId, - DataAccess.PreparedStatementType.Delete, - ds.Target.Schema.Name, - ds.Target.Name, - true, - ds.FilterData, - null); - } - else if (stmtType == typeof(TableInsertStatement).Name) - { - TableInsertStatement insert = statement as TableInsertStatement; - Debug.Assert(insert != null); - _protocol.SendPrepareStatement( - (uint)stmtId, - DataAccess.PreparedStatementType.Insert, - insert.Target.Schema.Name, - insert.Target.Name, - true, - null, - null, - null, - insert.values.ToArray(), - insert.fields, - false); - } - else if (stmtType == typeof(SqlStatement).Name) - { - SqlStatement sqlStatement = statement as SqlStatement; - Debug.Assert(sqlStatement != null); - _protocol.SendPrepareStatement( - (uint)stmtId, - DataAccess.PreparedStatementType.SqlStatement, - null, - null, - true, - null, - null, - null, - sqlStatement.parameters.ToArray(), - null, - false, - sqlStatement.SQL); - } - else - { - throw new NotSupportedException(statement.GetType().Name); - } - - _preparedStatements.Add(stmtId); - return stmtId; - } - - public TResult ExecutePreparedStatement(int stmtId, IEnumerable args) - where TResult : BaseResult - { - _protocol.SendExecutePreparedStatement((uint)stmtId, args); - BaseResult result = null; - if (typeof(TResult) == typeof(DocResult)) - result = new DocResult(this); - else if (typeof(TResult) == typeof(RowResult)) - result = new RowResult(this); - else if (typeof(TResult) == typeof(SqlResult)) - result = new SqlResult(this); - else if (typeof(TResult) == typeof(Result)) - result = new Result(this); - else - throw new ArgumentNullException(typeof(TResult).Name); - - return (TResult)result; - } - - public void DeallocatePreparedStatement(int stmtId) - { - _protocol.SendDeallocatePreparedStatement((uint)stmtId); - _preparedStatements.Remove(stmtId); - } - - /// - /// Gets the compression algorithm being used to compress or decompress data. - /// - /// Flag to indicate if the compression algorithm should be - /// retrieved from the reader or writer controller. - /// The name of the compression algorithm being used if any. - /// null if no compression algorithm is being used. - public string GetCompressionAlgorithm(bool fromReaderController) - { - if (fromReaderController && _readerCompressionController != null) - { - return _readerCompressionController.CompressionAlgorithm.ToString(); - } - else if (!fromReaderController && _writerCompressionController != null) - { - return _writerCompressionController.CompressionAlgorithm.ToString(); - } - - return null; - } - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data; +using MySql.Data.Common; +using MySql.Data.MySqlClient; +using MySql.Data.MySqlClient.Authentication; +using MySqlX.Communication; +using MySqlX.Protocol; +using MySqlX.Protocol.X; +using MySqlX.Security; +using MySqlX.XDevAPI; +using MySqlX.XDevAPI.Common; +using MySqlX.XDevAPI.CRUD; +using MySqlX.XDevAPI.Relational; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading; + +namespace MySqlX.Sessions +{ + /// + /// Implementation class of InternalSession to manage connections using the Xprotocol type object. + /// + internal class XInternalSession : InternalSession + { + /// + /// Defines the compression controller that will be passed on the instance when + /// compression is enabled. + /// + private XCompressionController _readerCompressionController; + + /// + /// Defines the compression controller that will be passed on the instance when + /// compression is enabled. + /// + private XCompressionController _writerCompressionController; + + private XProtocol _protocol; + private XPacketReaderWriter _packetReaderWriter; + private bool _serverSupportsTls = false; + private const string mysqlxNamespace = "mysqlx"; + internal bool _supportsPreparedStatements = true; + private int _stmtId = 0; + private List _preparedStatements = new List(); + internal bool? _sessionResetNoReauthentication = null; + internal MyNetworkStream _myNetworkStream; + + public XInternalSession(MySqlXConnectionStringBuilder settings) : base(settings) + { + } + + protected override void Open() + { + bool isUnix = Settings.ConnectionProtocol == MySqlConnectionProtocol.Unix || + Settings.ConnectionProtocol == MySqlConnectionProtocol.UnixSocket; + + _stream = MyNetworkStream.CreateStreamAsync( + Settings.Server == "127.0.0.1" || Settings.Server == "::1" + ? "localhost" + : Settings.Server, + Settings.ConnectTimeout, + Settings.Keepalive, + Settings.Port, + isUnix, false).GetAwaiter().GetResult(); + _myNetworkStream = (MyNetworkStream)_stream; + if (_stream == null) + throw new MySqlException(ResourcesX.UnableToConnect); + + _packetReaderWriter = new XPacketReaderWriter(_stream, _myNetworkStream.Socket); + _protocol = new XProtocol(_packetReaderWriter); + + Settings.CharacterSet = string.IsNullOrWhiteSpace(Settings.CharacterSet) ? "utf8mb4" : Settings.CharacterSet; + var encoding = CharSetMap.GetEncoding(Settings.CharacterSet); + + SetState(SessionState.Connecting, false); + + try + { + GetAndSetCapabilities(); + } + catch (Exception) + { + throw; + } + + // Validates use of TLS. + if (Settings.SslMode != MySqlSslMode.Disabled) + { + if (_serverSupportsTls) + { + var result = new Ssl( + Settings.Server, + Settings.SslMode, + Settings.CertificateFile, + Settings.CertificateStoreLocation, + Settings.CertificatePassword, + Settings.CertificateThumbprint, + Settings.SslCa, + Settings.SslCert, + Settings.SslKey, + Settings.TlsVersion, + Settings.ConnectTimeout) + .StartSSLAsync(_stream, encoding, Settings.ToString(), CancellationToken.None, false).GetAwaiter().GetResult(); + + _stream = result.Item2; + + if (_readerCompressionController != null && _readerCompressionController.IsCompressionEnabled) + { + _packetReaderWriter = new XPacketReaderWriter(_stream, _readerCompressionController, _writerCompressionController, _myNetworkStream.Socket); + } + else + { + _packetReaderWriter = new XPacketReaderWriter(_stream, _myNetworkStream.Socket); + } + + _protocol.SetXPackets(_packetReaderWriter); + } + else + { + // Client requires SSL connections. + string message = String.Format(Resources.NoServerSSLSupport, + Settings.Server); + throw new MySqlException(message); + } + } + else if (_readerCompressionController != null && _readerCompressionController.IsCompressionEnabled) + { + _packetReaderWriter = new XPacketReaderWriter(_stream, _readerCompressionController, _writerCompressionController, _myNetworkStream.Socket); + _protocol.SetXPackets(_packetReaderWriter); + } + + Authenticate(); + + SetState(SessionState.Open, false); + } + + internal void Authenticate() + { + // Default authentication + if (Settings.Auth == MySqlAuthenticationMode.Default) + { + if ((Settings.SslMode != MySqlSslMode.Disabled && _serverSupportsTls) || Settings.ConnectionProtocol == MySqlConnectionProtocol.Unix) + { + Settings.Auth = MySqlAuthenticationMode.PLAIN; + AuthenticatePlain(); + } + else + { + bool authenticated = false; + // first try using MYSQL41 + Settings.Auth = MySqlAuthenticationMode.MYSQL41; + try + { + AuthenticateMySQL41(); + authenticated = true; + } + catch (MySqlException ex) + { + // code 1045 Invalid user or password + if (ex.Code != 1045) + throw; + } + + // second try using SHA256_MEMORY + if (!authenticated) + { + try + { + Settings.Auth = MySqlAuthenticationMode.SHA256_MEMORY; + AuthenticateSha256Memory(); + authenticated = true; + } + catch (MySqlException ex) + { + // code 1045 Invalid user or password + if (ex.Code == 1045) + throw new MySqlException(1045, "HY000", ResourcesX.AuthenticationFailed); + else + throw; + } + } + } + } + // User defined authentication + else + { + switch (Settings.Auth) + { + case MySqlAuthenticationMode.PLAIN: + AuthenticatePlain(); + break; + case MySqlAuthenticationMode.MYSQL41: + AuthenticateMySQL41(); + break; + case MySqlAuthenticationMode.EXTERNAL: + AuthenticateExternal(); + break; + case MySqlAuthenticationMode.SHA256_MEMORY: + AuthenticateSha256Memory(); + break; + default: + throw new NotImplementedException(Settings.Auth.ToString()); + } + } + } + + private void GetAndSetCapabilities() + { + _protocol.GetServerCapabilities(); + var clientCapabilities = new Dictionary(); + Mysqlx.Connection.Capability capability = null; + + // Validates TLS use. + if (Settings.SslMode != MySqlSslMode.Disabled) + { + capability = _protocol.Capabilities.Capabilities_.FirstOrDefault(i => i.Name.ToLowerInvariant() == "tls"); + if (capability != null) + { + _serverSupportsTls = true; + clientCapabilities.Add("tls", "1"); + } + } + + // Set connection-attributes. + if (Settings.ConnectionAttributes.ToLower() != "false") + clientCapabilities.Add("session_connect_attrs", GetConnectionAttributes(Settings.ConnectionAttributes)); + + // Set compression algorithm. + if (Settings.Compression != CompressionType.Disabled) + { + capability = _protocol.Capabilities.Capabilities_.FirstOrDefault(i => i.Name.ToLowerInvariant() == XCompressionController.COMPRESSION_KEY); + + // Raise error if client expects compression but server doesn't support it. + if (Settings.Compression == CompressionType.Required && capability == null) + { + throw new NotSupportedException(ResourcesX.CompressionNotSupportedByServer); + } + + // Update capabilities with the compression algorithm negotiation if server supports compression. + if (capability != null) + { + var algorithmsDictionary = capability.Value.Obj.Fld.ToDictionary( + field => field.Key, + field => field.Value.Array.Value.ToDictionary(value => value.Scalar.VString.Value.ToStringUtf8().ToLowerInvariant()).Keys.ToList()); + + if (algorithmsDictionary.ContainsKey(XCompressionController.ALGORITHMS_SUBKEY)) + { + var supportedCompressionAlgorithms = algorithmsDictionary[XCompressionController.ALGORITHMS_SUBKEY].ToList().ToArray(); + VerifyDefaultOrder(ref supportedCompressionAlgorithms); + var userCompressionAlgorithms = NegotiateUserAgainstClientAlgorithms(Settings.CompressionAlgorithm); + var compressionCapabilities = NegotiateCompression(supportedCompressionAlgorithms, userCompressionAlgorithms); + if (compressionCapabilities != null) + { + clientCapabilities.Add(XCompressionController.COMPRESSION_KEY, compressionCapabilities); + var compressionAlgorithm = compressionCapabilities.First().Value.ToString(); + _readerCompressionController = new XCompressionController((CompressionAlgorithms)Enum.Parse(typeof(CompressionAlgorithms), compressionAlgorithm), false); + _writerCompressionController = new XCompressionController((CompressionAlgorithms)Enum.Parse(typeof(CompressionAlgorithms), compressionAlgorithm), true); + _packetReaderWriter = new XPacketReaderWriter(_stream, _readerCompressionController, _writerCompressionController, _myNetworkStream.Socket); + + } + } + } + } + + try + { + _protocol.SetCapabilities(clientCapabilities); + } + catch (MySqlException ex) + { + if (ex.Message == "Capability 'session_connect_attrs' doesn't exist") + clientCapabilities.Remove("session_connect_attrs"); + _protocol.SetCapabilities(clientCapabilities); + } + } + + /// + /// Reorder the list of algorithms retrieved from server to the preferred order + /// + private void VerifyDefaultOrder(ref string[] algorithms) + { + var clientSupportedAlgorithms = Enum.GetNames(typeof(CompressionAlgorithms)); + List output = new List(); + foreach (var item in clientSupportedAlgorithms) + { + if (algorithms.Contains(item)) + { + output.Add(item); + } + } + algorithms = output.ToArray(); + } + + /// + /// Validate the algorithms given in the connection string are valid compared with enum CompressionAlgorithms + /// + public List NegotiateUserAgainstClientAlgorithms(string inputString) + { + inputString = inputString.Contains("[") ? inputString.Replace("[", string.Empty) : inputString; + inputString = inputString.Contains("]") ? inputString.Replace("]", string.Empty) : inputString; + inputString.Trim(); + if (string.IsNullOrEmpty(inputString)) + { + return Enum.GetNames(typeof(CompressionAlgorithms)).ToList(); + } + var elements = inputString.ToLowerInvariant().Split(','); + List ret = new List(); + for (var i = 0; i < elements.Length; i++) + { + switch (elements[i].ToLowerInvariant()) + { + case "lz4": + case "lz4_message": + elements[i] = CompressionAlgorithms.lz4_message.ToString(); + break; + case "zstd": + case "zstd_stream": + elements[i] = CompressionAlgorithms.zstd_stream.ToString(); + break; + + case "deflate": + case "deflate_stream": +#if NETFRAMEWORK + if (elements.Length == 1 && Settings.Compression == CompressionType.Required) + { + throw new NotSupportedException(string.Format(ResourcesX.CompressionForSpecificAlgorithmNotSupportedInNetFramework, elements[i])); + } +#else + elements[i] = CompressionAlgorithms.deflate_stream.ToString(); +#endif + break; + + } + if (Enum.IsDefined(typeof(CompressionAlgorithms), elements[i])) + { + ret.Add(elements[i]); + } + } + return ret; + } + + /// + /// Negotiates compression capabilities with the server. + /// + /// An array containing the compression algorithms supported by the server. + /// An array containing the compression algorithms given by user/client. + private Dictionary NegotiateCompression(string[] serverSupportedAlgorithms, List clientAgainstUserAlgorithms) + { + if (serverSupportedAlgorithms == null || serverSupportedAlgorithms.Length == 0) + { + if (Settings.Compression == CompressionType.Required && clientAgainstUserAlgorithms.Count > 0) + { + throw new NotSupportedException(ResourcesX.CompressionAlgorithmNegotiationFailed); + } + return null; + } + + // If server and client don't have matching compression algorithms either log a warning message + // or raise an exception based on the selected compression type. + if (!clientAgainstUserAlgorithms.Any(element => serverSupportedAlgorithms.Contains(element))) + { + if (Settings.Compression == CompressionType.Preferred) + { + MySqlTrace.LogWarning(-1, ResourcesX.CompressionAlgorithmNegotiationFailed); + return null; + } + else if (Settings.Compression == CompressionType.Required) + { + throw new NotSupportedException(ResourcesX.CompressionAlgorithmNegotiationFailed); + } + } + + string negotiatedAlgorithm = null; + for (int index = 0; index < clientAgainstUserAlgorithms.Count; index++) + { + if (!serverSupportedAlgorithms.Contains(clientAgainstUserAlgorithms[index])) + { + continue; + } + + negotiatedAlgorithm = clientAgainstUserAlgorithms[index]; + break; + } + + if (negotiatedAlgorithm == null) + { + return null; + } + + // Create the compression capability object. + var compressionCapabilities = new Dictionary(); + compressionCapabilities.Add(XCompressionController.ALGORITHMS_SUBKEY, negotiatedAlgorithm); + compressionCapabilities.Add(XCompressionController.SERVER_COMBINE_MIXED_MESSAGES_SUBKEY, XCompressionController.DEFAULT_SERVER_COMBINE_MIXED_MESSAGES_VALUE); + + // TODO: For future use. + //compressionCapabilities.Add(XCompressionController.SERVER_MAX_COMBINE_MESSAGES_SUBKEY, XCompressionController.DEFAULT_SERVER_MAX_COMBINE_MESSAGES_VALUE); + + return compressionCapabilities; + } + + private Dictionary GetConnectionAttributes(string connectionAttrs) + { + Dictionary attrs = new Dictionary(); + + if (connectionAttrs.StartsWith("[") && connectionAttrs.EndsWith("]")) + { + connectionAttrs = connectionAttrs.Substring(1, connectionAttrs.Length - 2); + + if (!string.IsNullOrWhiteSpace(connectionAttrs)) + { + foreach (var pair in connectionAttrs.Split(',')) + { + string[] keyValue = pair.Split('='); + string key = keyValue[0].Trim(); + string value = keyValue.Length > 1 ? keyValue[1].Trim() : string.Empty; + + if (key == string.Empty) + throw new MySqlException(ResourcesX.EmptyKeyConnectionAttribute); + + if (key.StartsWith("_")) + throw new MySqlException(ResourcesX.InvalidUserDefinedAttribute); + + try { attrs.Add(key, value); } + catch (ArgumentException) { throw new MySqlException(string.Format(ResourcesX.DuplicateUserDefinedAttribute, key)); } + } + } + } + else if (connectionAttrs != "true") + throw new MySqlException(ResourcesX.InvalidConnectionAttributes); + + MySqlConnectAttrs clientAttrs = new MySqlConnectAttrs(); + attrs.Add("_pid", clientAttrs.PID); + attrs.Add("_platform", clientAttrs.Platform); + attrs.Add("_os", clientAttrs.OSName); + attrs.Add("_source_host", Settings.Server); + attrs.Add("_client_name", clientAttrs.ClientName); + attrs.Add("_client_version", clientAttrs.ClientVersion); + attrs.Add("_client_license", clientAttrs.ClientLicence); + attrs.Add("_framework", clientAttrs.Framework); + + return attrs; + } + + private void AuthenticateMySQL41() + { + MySQL41AuthenticationPlugin plugin = new MySQL41AuthenticationPlugin(Settings); + _protocol.SendAuthStart(plugin.AuthName, null, null); + byte[] extraData = _protocol.ReadAuthContinue(); + _protocol.SendAuthContinue(plugin.Continue(extraData)); + _protocol.ReadAuthOk(); + } + + private void AuthenticatePlain() + { + PlainAuthenticationPlugin plugin = new PlainAuthenticationPlugin(Settings); + _protocol.SendAuthStart(plugin.AuthName, plugin.GetAuthData(), null); + _protocol.ReadAuthOk(); + } + + private void AuthenticateExternal() + { + ExternalAuthenticationPlugin plugin = new ExternalAuthenticationPlugin(Settings); + _protocol.SendAuthStart(plugin.AuthName, Encoding.UTF8.GetBytes(""), null); + _protocol.ReadAuthOk(); + } + + private void AuthenticateSha256Memory() + { + Sha256MemoryAuthenticationPlugin plugin = new Sha256MemoryAuthenticationPlugin(); + _protocol.SendAuthStart(plugin.PluginName, null, null); + byte[] nonce = _protocol.ReadAuthContinue(); + + string data = $"{Settings.Database}\0{Settings.UserID}\0"; + byte[] byteData = Encoding.UTF8.GetBytes(data); + byte[] clientHash = plugin.GetClientHash(Settings.Password, nonce); + byte[] authData = new byte[byteData.Length + clientHash.Length]; + byteData.CopyTo(authData, 0); + clientHash.CopyTo(authData, byteData.Length); + + _protocol.SendAuthContinue(authData); + _protocol.ReadAuthOk(); + } + + protected internal void SetState(SessionState newState, bool broadcast) + { + if (newState == SessionState && !broadcast) + return; + SessionState oldSessionState = SessionState; + SessionState = newState; + + //TODO check if we need to send this event + //if (broadcast) + //OnStateChange(new StateChangeEventArgs(oldConnectionState, connectionState)); + } + + internal override ProtocolBase GetProtocol() + { + return _protocol; + } + + public override void Close() + { + try + { + try + { + // Deallocate compression objects. + _readerCompressionController?.Close(); + _writerCompressionController?.Close(); + + // Deallocate all the remaining prepared statements for current session. + foreach (int stmtId in _preparedStatements) + { + if (!_myNetworkStream.IsSocketClosed) + { + DeallocatePreparedStatement(stmtId); + } + _preparedStatements.Remove(stmtId); + } + } + catch (Exception) + { + //TODO log exception + } + + if (!_myNetworkStream.IsSocketClosed) + { + _protocol.SendSessionClose(); + } + } + finally + { + SessionState = SessionState.Closed; + _stream.Dispose(); + } + } + + public void CreateCollection(string schemaName, string collectionName) + { + ExecuteCmdNonQuery(XpluginStatementCommand.XPLUGIN_STMT_CREATE_COLLECTION, + true, + new KeyValuePair("schema", schemaName), + new KeyValuePair("name", collectionName)); + } + + /// + /// Prepare the dictionary of arguments required to create a MySQL message. + /// + /// The name of the MySQL schema. + /// The name of the collection. + /// This object hold the parameters required to create the collection. + /// + /// Collection referente. + public void CreateCollection(string schemaName, string collectionName, CreateCollectionOptions options) + { + var dictionary = new Dictionary(); + if (!options.Equals(null)) + { + if (!string.IsNullOrEmpty(options.Validation.Level.ToString())) + { + dictionary.Add("level", (string)options.Validation.Level.ToString().ToLowerInvariant()); + } + + if (!string.IsNullOrEmpty(options.Validation.Schema)) + { + dictionary.Add("schema", new DbDoc(options.Validation.Schema)); + } + } + + ExecuteCmdNonQueryOptions(XpluginStatementCommand.XPLUGIN_STMT_CREATE_COLLECTION, + true, + new KeyValuePair("schema", schemaName), + new KeyValuePair("name", collectionName), + new KeyValuePair("reuse_existing", options.ReuseExisting), + new KeyValuePair("options", dictionary) + ); + } + + /// + /// Prepare the dictionary of arguments required to Modify a MySQL message. + /// + /// The name of the MySQL schema. + /// The name of the collection. + /// This object hold the parameters required to Modify the collection. + /// + public void ModifyCollection(string schemaName, string collectionName, ModifyCollectionOptions? options) + { + var dictionary = new Dictionary(); + if (!options.Equals(null)) + { + if (options.Value.Validation.Level != null) + { + dictionary.Add("level", options.Value.Validation.Level.ToString().ToLowerInvariant()); + } + if (options.Value.Validation.Schema != null) + { + dictionary.Add("schema", new DbDoc(options.Value.Validation.Schema)); + } + } + ExecuteCmdNonQueryOptions(XpluginStatementCommand.XPLUGIN_STMT_MODIFY_COLLECTION, + true, + new KeyValuePair("schema", schemaName), + new KeyValuePair("name", collectionName), + new KeyValuePair("options", dictionary)); + } + + public void DropCollection(string schemaName, string collectionName) + { + ExecuteCmdNonQuery(XpluginStatementCommand.XPLUGIN_STMT_DROP_COLLECTION, + true, + new KeyValuePair("schema", schemaName), + new KeyValuePair("name", collectionName)); + } + + public Result CreateCollectionIndex(CreateCollectionIndexStatement statement) + { + List> args = new List>(); + args.Add(new KeyValuePair("name", statement.createIndexParams.IndexName)); + args.Add(new KeyValuePair("collection", statement.Target.Name)); + args.Add(new KeyValuePair("schema", statement.Target.Schema.Name)); + args.Add(new KeyValuePair("unique", false)); + + if (statement.createIndexParams.Type != null) + args.Add(new KeyValuePair("type", statement.createIndexParams.Type)); + + for (int i = 0; i < statement.createIndexParams.Fields.Count; i++) + { + var field = statement.createIndexParams.Fields[i]; + var dictionary = new Dictionary(); + dictionary.Add("member", field.Field); + if (field.Type != null) + dictionary.Add("type", field.Type); + + if (field.Required == null) + dictionary.Add("required", false); + else + dictionary.Add("required", (bool)field.Required); + + if (field.Options != null) + dictionary.Add("options", (ulong)field.Options); + + if (field.Srid != null) + dictionary.Add("srid", (ulong)field.Srid); + + if (field.Array != null) + dictionary.Add("array", (bool)field.Array); + + args.Add(new KeyValuePair("constraint", dictionary)); + } + + return ExecuteCreateCollectionIndex(XpluginStatementCommand.XPLUGIN_STMT_CREATE_COLLECTION_INDEX, false, args.ToArray()); + } + + public void DropCollectionIndex(string schemaName, string collectionName, string indexName) + { + List> args = new List>(); + args.Add(new KeyValuePair("schema", schemaName)); + args.Add(new KeyValuePair("collection", collectionName)); + args.Add(new KeyValuePair("name", indexName)); + ExecuteCmdNonQuery(XpluginStatementCommand.XPLUGIN_STMT_DROP_COLLECTION_INDEX, false, args.ToArray()); + } + + public long TableCount(Schema schema, string name, string type) + { + try + { + string sql = String.Format("SELECT COUNT(*) FROM {0}.{1}", + ExprUnparser.QuoteIdentifier(schema.Name), ExprUnparser.QuoteIdentifier(name)); + return (long)ExecuteQueryAsScalar(sql); + } + catch (MySqlException ex) when (ex.Code == 1146) + { + throw new MySqlException(string.Format(ResourcesX.CollectionTableDoesNotExist, type.ToString(), name, schema.Name), (int)ex.Code); + } + } + + public bool TableExists(Schema schema, string name) + { + string sql = String.Format("SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = '{0}' AND table_name = '{1}'", + schema.Name, name); + long count = (long)ExecuteQueryAsScalar(sql); + return count != 0; + } + + private Result ExecuteCmdNonQuery(string cmd, bool throwOnFail, params KeyValuePair[] args) + { + _protocol.SendExecuteStatement(mysqlxNamespace, cmd, args); + return new Result(this); + } + + private Result ExecuteCmdNonQueryOptions(string cmd, bool throwOnFail, params KeyValuePair[] args) + { + _protocol.SendExecuteStatementOptions(mysqlxNamespace, cmd, args); + return new Result(this); + } + + private Result ExecuteCreateCollectionIndex(string cmd, bool throwOnFail, params KeyValuePair[] args) + { + _protocol.SendCreateCollectionIndexStatement(mysqlxNamespace, cmd, args); + return new Result(this); + } + + public List GetObjectList(Schema s, params string[] types) where T : DatabaseObject + { + for (int i = 0; i < types.Length; i++) + types[i] = types[i].ToUpperInvariant(); + RowResult result = GetRowResult("list_objects", new KeyValuePair("schema", s.Name)); + var rows = result.FetchAll(); + + List docs = new List(); + foreach (var row in rows) + { + if (!types.Contains(row.GetString("type").ToUpperInvariant())) continue; + + List parameters = new List(new object[] { s, row.GetString("name") }); + if (row["name"] is Byte[]) + { + Byte[] byteArray = row["name"] as Byte[]; + parameters[1] = Encoding.UTF8.GetString(byteArray, 0, byteArray.Length); + } + + switch (row.GetString("type").ToUpperInvariant()) + { + case "TABLE": + parameters.Add(false); + break; + case "VIEW": + parameters.Add(true); + break; + } + T t = (T)Activator.CreateInstance(typeof(T), + BindingFlags.NonPublic | BindingFlags.Instance, + null, parameters.ToArray(), null); + docs.Add(t); + } + return docs; + } + + public string GetObjectType(Schema s, string name) + { + RowResult result = GetRowResult("list_objects", + new KeyValuePair("schema", s.Name), + new KeyValuePair("pattern", name)); + var row = result.FetchOne(); + if (row == null) + throw new MySqlException(string.Format(ResourcesX.NoObjectFound, name)); + System.Diagnostics.Debug.Assert(result.FetchOne() == null); + return row.GetString("type"); + } + + public RowResult GetRowResult(string cmd, params KeyValuePair[] args) + { + _protocol.SendExecuteStatement(mysqlxNamespace, cmd, args); + return new RowResult(this); + } + + public Result Insert(Collection collection, object[] json, List newIds, bool upsert) + { + _protocol.SendInsert(collection.Schema.Name, false, collection.Name, json, null, upsert); + return new Result(this); + } + + public Result DeleteDocs(RemoveStatement rs) + { + _protocol.SendDelete(rs.Target.Schema.Name, rs.Target.Name, false, rs.FilterData); + return new Result(this); + } + + public Result DeleteRows(TableDeleteStatement statement) + { + _protocol.SendDelete(statement.Target.Schema.Name, + statement.Target.Name, true, + statement.FilterData); + return new Result(this); + } + + public Result ModifyDocs(ModifyStatement ms) + { + _protocol.SendUpdate(ms.Target.Schema.Name, ms.Target.Name, false, ms.FilterData, ms.Updates); + return new Result(this); + } + + public Result UpdateRows(TableUpdateStatement statement) + { + _protocol.SendUpdate(statement.Target.Schema.Name, + statement.Target.Name, true, + statement.FilterData, + statement.updates); + return new Result(this); + } + + public DocResult FindDocs(FindStatement fs) + { + _protocol.SendFind(fs.Target.Schema.Name, fs.Target.Name, false, fs.FilterData, fs.findParams); + DocResult result = new DocResult(this); + return result; + } + + public RowResult FindRows(TableSelectStatement ss) + { + _protocol.SendFind(ss.Target.Schema.Name, ss.Target.Name, true, ss.FilterData, ss.findParams); + return new RowResult(this); + } + + public Result InsertRows(TableInsertStatement statement) + { + _protocol.SendInsert(statement.Target.Schema.Name, true, statement.Target.Name, statement.values.ToArray(), statement.fields, false); + return new Result(this); + } + + protected Result ExpectOpen(Mysqlx.Expect.Open.Types.Condition.Types.Key condition, object value = null) + { + _protocol.SendExpectOpen(condition, value); + return new Result(this); + } + + public Result ExpectDocidGenerated() + { + return ExpectOpen(Mysqlx.Expect.Open.Types.Condition.Types.Key.ExpectDocidGenerated); + } + + public void ResetSession() + { + if (_sessionResetNoReauthentication == null) + { + try + { + if (!_myNetworkStream.IsSocketClosed) + { + ExpectOpen(Mysqlx.Expect.Open.Types.Condition.Types.Key.ExpectFieldExist, "6.1"); + } + _sessionResetNoReauthentication = true; + } + catch + { + _sessionResetNoReauthentication = false; + } + } + + if (!_myNetworkStream.IsSocketClosed) + { + _protocol.SendResetSession((bool)_sessionResetNoReauthentication); + _protocol.ReadOk(); + } + } + + public int PrepareStatement(BaseStatement statement) + where TResult : BaseResult + { + int stmtId = Interlocked.Increment(ref _stmtId); + string stmtType = statement.GetType().Name; + + if (stmtType == typeof(FindStatement<>).Name) + { + FindStatement fs = statement as FindStatement; + string s = typeof(TDoc).Name; + Debug.Assert(fs != null); + _protocol.SendPrepareStatement( + (uint)stmtId, + DataAccess.PreparedStatementType.Find, + fs.Target.Schema.Name, + fs.Target.Name, + false, + fs.FilterData, + fs.findParams); + } + else if (stmtType == typeof(TableSelectStatement).Name) + { + TableSelectStatement ss = statement as TableSelectStatement; + Debug.Assert(ss != null); + _protocol.SendPrepareStatement( + (uint)stmtId, + DataAccess.PreparedStatementType.Find, + ss.Target.Schema.Name, + ss.Target.Name, + true, + ss.FilterData, + ss.findParams); + } + else if (stmtType == typeof(ModifyStatement<>).Name) + { + ModifyStatement ms = statement as ModifyStatement; + Debug.Assert(ms != null); + _protocol.SendPrepareStatement( + (uint)stmtId, + DataAccess.PreparedStatementType.Update, + ms.Target.Schema.Name, + ms.Target.Name, + false, + ms.FilterData, + null, + ms.Updates); + } + else if (stmtType == typeof(TableUpdateStatement).Name) + { + TableUpdateStatement us = statement as TableUpdateStatement; + Debug.Assert(us != null); + _protocol.SendPrepareStatement( + (uint)stmtId, + DataAccess.PreparedStatementType.Update, + us.Target.Schema.Name, + us.Target.Name, + true, + us.FilterData, + null, + us.updates); + } + else if (stmtType == typeof(RemoveStatement<>).Name) + { + string s = typeof(TDoc).Name; + RemoveStatement rs = statement as RemoveStatement; + Debug.Assert(rs != null); + _protocol.SendPrepareStatement( + (uint)stmtId, + DataAccess.PreparedStatementType.Delete, + rs.Target.Schema.Name, + rs.Target.Name, + false, + rs.FilterData, + null); + } + else if (stmtType == typeof(TableDeleteStatement).Name) + { + TableDeleteStatement ds = statement as TableDeleteStatement; + Debug.Assert(ds != null); + _protocol.SendPrepareStatement( + (uint)stmtId, + DataAccess.PreparedStatementType.Delete, + ds.Target.Schema.Name, + ds.Target.Name, + true, + ds.FilterData, + null); + } + else if (stmtType == typeof(TableInsertStatement).Name) + { + TableInsertStatement insert = statement as TableInsertStatement; + Debug.Assert(insert != null); + _protocol.SendPrepareStatement( + (uint)stmtId, + DataAccess.PreparedStatementType.Insert, + insert.Target.Schema.Name, + insert.Target.Name, + true, + null, + null, + null, + insert.values.ToArray(), + insert.fields, + false); + } + else if (stmtType == typeof(SqlStatement).Name) + { + SqlStatement sqlStatement = statement as SqlStatement; + Debug.Assert(sqlStatement != null); + _protocol.SendPrepareStatement( + (uint)stmtId, + DataAccess.PreparedStatementType.SqlStatement, + null, + null, + true, + null, + null, + null, + sqlStatement.parameters.ToArray(), + null, + false, + sqlStatement.SQL); + } + else + { + throw new NotSupportedException(statement.GetType().Name); + } + + _preparedStatements.Add(stmtId); + return stmtId; + } + + public TResult ExecutePreparedStatement(int stmtId, IEnumerable args) + where TResult : BaseResult + { + _protocol.SendExecutePreparedStatement((uint)stmtId, args); + BaseResult result = null; + if (typeof(TResult) == typeof(DocResult)) + result = new DocResult(this); + else if (typeof(TResult) == typeof(RowResult)) + result = new RowResult(this); + else if (typeof(TResult) == typeof(SqlResult)) + result = new SqlResult(this); + else if (typeof(TResult) == typeof(Result)) + result = new Result(this); + else + throw new ArgumentNullException(typeof(TResult).Name); + + return (TResult)result; + } + + public void DeallocatePreparedStatement(int stmtId) + { + _protocol.SendDeallocatePreparedStatement((uint)stmtId); + _preparedStatements.Remove(stmtId); + } + + /// + /// Gets the compression algorithm being used to compress or decompress data. + /// + /// Flag to indicate if the compression algorithm should be + /// retrieved from the reader or writer controller. + /// The name of the compression algorithm being used if any. + /// null if no compression algorithm is being used. + public string GetCompressionAlgorithm(bool fromReaderController) + { + if (fromReaderController && _readerCompressionController != null) + { + return _readerCompressionController.CompressionAlgorithm.ToString(); + } + else if (!fromReaderController && _writerCompressionController != null) + { + return _writerCompressionController.CompressionAlgorithm.ToString(); + } + + return null; + } + } +} diff --git a/MySQL.Data/src/X/XDevAPI/BaseSession.cs b/MySQL.Data/src/X/XDevAPI/BaseSession.cs index 4fdc98720..8be04de67 100644 --- a/MySQL.Data/src/X/XDevAPI/BaseSession.cs +++ b/MySQL.Data/src/X/XDevAPI/BaseSession.cs @@ -1,834 +1,834 @@ -// Copyright (c) 2015, 2022, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data; -using MySql.Data.Common; -using MySql.Data.Failover; -using MySql.Data.MySqlClient; -using MySqlX.Common; -using MySqlX.Sessions; -using MySqlX.XDevAPI.Relational; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Text.RegularExpressions; - -namespace MySqlX.XDevAPI -{ - /// - /// Represents a base class for a Session. - /// - public abstract class BaseSession : IDisposable - { - private InternalSession _internalSession; - private string _connectionString; - private bool _isDefaultPort = true; - private const uint X_PROTOCOL_DEFAULT_PORT = 33060; - private const char CONNECTION_DATA_KEY_SEPARATOR = ';'; - private const char CONNECTION_DATA_VALUE_SEPARATOR = '='; - private const string PORT_CONNECTION_OPTION_KEYWORD = "port"; - private const string SERVER_CONNECTION_OPTION_KEYWORD = "server"; - private const string CONNECT_TIMEOUT_CONNECTION_OPTION_KEYWORD = "connect-timeout"; - private const string CONNECTION_ATTRIBUTES_CONNECTION_OPTION_KEYWORD = "connection-attributes"; - private const string DNS_SRV_CONNECTION_OPTION_KEYWORD = "dns-srv"; - private const string DNS_SRV_URI_SCHEME = "mysqlx+srv"; - private const string MYSQLX_URI_SCHEME = "mysqlx"; - internal QueueTaskScheduler _scheduler = new QueueTaskScheduler(); - protected readonly Client _client; - - internal InternalSession InternalSession - { - get - { - if (_internalSession == null) - throw new MySqlException(ResourcesX.InvalidSession); - return _internalSession; - } - } - - internal XInternalSession XSession - { - get { return InternalSession as XInternalSession; } - } - - internal DateTime IdleSince { get; set; } - - #region Session status properties - - private DBVersion? _version = null; - - internal DBVersion Version => _version ?? (_version = XSession.GetServerVersion()).Value; - - private int? _threadId = null; - internal int ThreadId => _threadId ?? (_threadId = XSession.GetThreadId()).Value; - - /// - /// Flag to set if prepared statements are supported. - /// - internal bool SupportsPreparedStatements { get; set; } = true; - - #endregion - - /// - /// Gets the connection settings for this session. - /// - public MySqlXConnectionStringBuilder Settings { get; private set; } - - /// - /// Gets the currently active schema. - /// - public Schema Schema { get; protected set; } - - /// - /// Gets the default schema provided when creating the session. - /// - public Schema DefaultSchema { get; private set; } - - /// - /// Gets the connection uri representation of the connection options provided during the creation of the session. - /// - public String Uri - { - get - { - var builder = new StringBuilder(string.Format("mysqlx://{0}:{1}{2}?", - Settings.Server, - Settings.Port, - string.IsNullOrEmpty(Settings.Database) ? - string.Empty : - "/" + Settings.Database)); - var firstItemAdded = false; - var certificateFileAdded = false; - foreach (var item in Settings.values) - { - // Skip connection options already included in the connection URI. - if (item.Key == "server" || item.Key == "database" || item.Key == "port") - continue; - - // Skip CertificateFile if it has already been included. - if ((item.Key == "certificatefile" || item.Key == "sslca") && certificateFileAdded) - continue; - - try - { - var value = Settings[item.Key]; - // Get the default value of the connection option. - var option = MySqlXConnectionStringBuilder.Options.Values.First( - o => o.Keyword == item.Key || - (o.Synonyms != null && o.Synonyms.Contains(item.Key))); - var defaultValue = option.DefaultValue; - // If the default value has been changed then include it in the connection URI. - if (value != null && (defaultValue == null || (value.ToString() != defaultValue.ToString()))) - { - if (!firstItemAdded) - firstItemAdded = true; - else - builder.Append("&"); - - if (item.Key == "certificatefile" || item.Key == "sslca") - { - certificateFileAdded = true; - builder.Append("sslca"); - } - else - builder.Append(item.Key); - builder.Append("="); - builder.Append(value is bool ? value.ToString().ToLower() : value.ToString()); - } - } - // Dismiss any not supported exceptions since they are expected. - catch (NotSupportedException) { } - catch (ArgumentException) { } - } - - return builder.ToString(); - } - } - - /// - /// Initializes a new instance of the BaseSession class based on the specified connection string. - /// - /// The connection used to create the session. - /// A object. - /// is null. - /// Unable to parse the when - /// in URI format. - /// - /// When using Unix sockets the protocol=unix or protocol=unixsocket connection option is required. - /// This will enable elements passed in the server connection option to be treated as Unix sockets. The user is also required - /// to explicitly set sslmode to none since X Plugin does not support SSL when using Unix sockets. Note that - /// protocol=unix and protocol=unixsocket are synonyms. - ///   - /// Multiple hosts can be specified as part of the , - /// which enables client-side failover when trying to establish a connection. - ///   - /// Connection URI examples: - /// - mysqlx://test:test@[192.1.10.10,localhost] - /// - mysqlx://test:test@[192.1.10.10,127.0.0.1] - /// - mysqlx://root:@[../tmp/mysqlx.sock,/tmp/mysqld.sock]?protocol=unix&sslmode=none - /// - mysqlx://test:test@[192.1.10.10:33060,127.0.0.1:33060] - /// - mysqlx://test:test@[192.1.10.10,120.0.0.2:22000,[::1]:33060]/test?connectiontimeout=10 - /// - mysqlx://test:test@[(address=server.example,priority=20),(address=127.0.0.1,priority=100)] - /// - mysqlx://test:test@[(address=server.example,priority=100),(address=127.0.0.1,priority=75),(address=192.0.10.56,priority=25)] - /// - ///   - /// Connection string examples: - /// - server=10.10.10.10,localhost;port=33060;uid=test;password=test; - /// - host=10.10.10.10,192.101.10.2,localhost;port=5202;uid=test;password=test; - /// - host=./tmp/mysqld.sock,/var/run/mysqldx.sock;port=5202;uid=root;protocol=unix;sslmode=none; - /// - server=(address=server.example,priority=20),(address=127.0.0.1,priority=100);port=33060;uid=test;password=test; - /// - server=(address=server.example,priority=100),(address=127.0.0.1,priority=75),(address=192.0.10.56,priority=25);port=33060;uid=test;password=test; - /// - ///   - /// Failover methods - /// - Sequential: Connection attempts will be performed in a sequential order, that is, one after another until - /// a connection is successful or all the elements from the list have been tried. - /// - /// - Priority based: If a priority is provided, the connection attemps will be performed in descending order, starting - /// with the host with the highest priority. Priority must be a value between 0 and 100. Additionally, it is required to either - /// give a priority for every host or no priority to any host. - /// - /// - internal BaseSession(string connectionString, Client client = null) : this() - { - if (string.IsNullOrWhiteSpace(connectionString)) - throw new ArgumentNullException("connectionString"); - - _client = client; - this._connectionString = ParseConnectionData(connectionString, client); - - // Multiple hosts were specified. - if (FailoverManager.FailoverGroup != null && FailoverManager.FailoverGroup.Hosts?.Count > 1) - { - _internalSession = FailoverManager.AttemptConnectionXProtocol(this._connectionString, out this._connectionString, _isDefaultPort, client); - Settings.ConnectionString = this._connectionString; - Settings.AnalyzeConnectionString(this._connectionString, true, _isDefaultPort); - } - // A single host was specified. - else - { - Settings.ConnectionString = _connectionString; - if (!(_connectionString.Contains("sslmode") || _connectionString.Contains("ssl mode") || _connectionString.Contains("ssl-mode"))) - Settings.SslMode = MySqlSslMode.Required; - Settings.AnalyzeConnectionString(this._connectionString, true, _isDefaultPort); - - if (Settings.DnsSrv) - { - var dnsSrvRecords = DnsSrv.GetDnsSrvRecords(Settings.Server); - FailoverManager.SetHostList(dnsSrvRecords.ConvertAll(r => new FailoverServer(r.Target, r.Port, r.Priority)), - FailoverMethod.Sequential); - _internalSession = FailoverManager.AttemptConnectionXProtocol(this._connectionString, out this._connectionString, _isDefaultPort, client); - Settings.ConnectionString = this._connectionString; - } - else - _internalSession = InternalSession.GetSession(Settings); - } - - // Set the default schema if provided by the user. - if (!string.IsNullOrWhiteSpace(Settings.Database)) - DefaultSchema = GetSchema(Settings.Database); - } - - /// - /// Initializes a new instance of the BaseSession class based on the specified anonymous type object. - /// - /// The connection data as an anonymous type used to create the session. - /// A object. - /// is null. - /// - /// Multiple hosts can be specified as part of the , which enables client-side failover when trying to - /// establish a connection. - ///   - /// To assign multiple hosts, create a property similar to the connection string examples shown in - /// . Note that the value of the property must be a string. - /// - /// - internal BaseSession(object connectionData, Client client = null) : this() - { - if (connectionData == null) - throw new ArgumentNullException("connectionData"); - - _client = client; - if (client == null) - FailoverManager.Reset(); - - var values = Tools.GetDictionaryFromAnonymous(connectionData); - if (!values.Keys.Any(s => s.ToLowerInvariant() == PORT_CONNECTION_OPTION_KEYWORD)) - values.Add(PORT_CONNECTION_OPTION_KEYWORD, X_PROTOCOL_DEFAULT_PORT); - - bool hostsParsed = false; - foreach (var value in values) - { - if (!Settings.ContainsKey(value.Key)) - throw new KeyNotFoundException(string.Format(ResourcesX.InvalidConnectionStringAttribute, value.Key)); - - Settings.SetValue(value.Key, value.Value); - if (!hostsParsed && !string.IsNullOrEmpty(Settings[SERVER_CONNECTION_OPTION_KEYWORD].ToString())) - { - var server = value.Value.ToString(); - if (IsUnixSocket(server)) - Settings.SetValue(value.Key, server = NormalizeUnixSocket(server)); - - FailoverManager.ParseHostList(server, true, false); - if (FailoverManager.FailoverGroup != null && FailoverManager.FailoverGroup.Hosts?.Count > 1) - Settings[SERVER_CONNECTION_OPTION_KEYWORD] = null; - else if (FailoverManager.FailoverGroup != null) - Settings[SERVER_CONNECTION_OPTION_KEYWORD] = FailoverManager.FailoverGroup.Hosts[0].Host; - - hostsParsed = true; - } - } - this._connectionString = Settings.ToString(); - - Settings.AnalyzeConnectionString(this._connectionString, true, _isDefaultPort); - if (FailoverManager.FailoverGroup != null && FailoverManager.FailoverGroup.Hosts?.Count > 1) - { - // Multiple hosts were specified. - _internalSession = FailoverManager.AttemptConnectionXProtocol(this._connectionString, out this._connectionString, _isDefaultPort, client); - Settings.ConnectionString = _connectionString; - } - else - { - if (Settings.DnsSrv) - { - var dnsSrvRecords = DnsSrv.GetDnsSrvRecords(Settings.Server); - FailoverManager.SetHostList(dnsSrvRecords.ConvertAll(r => new FailoverServer(r.Target, r.Port, null)), - FailoverMethod.Sequential); - _internalSession = FailoverManager.AttemptConnectionXProtocol(this._connectionString, out this._connectionString, _isDefaultPort, client); - Settings.ConnectionString = this._connectionString; - } - else - _internalSession = InternalSession.GetSession(Settings); - } - - if (!string.IsNullOrWhiteSpace(Settings.Database)) - DefaultSchema = GetSchema(Settings.Database); - } - - internal BaseSession(InternalSession internalSession, Client client) - { - _internalSession = internalSession; - Settings = internalSession.Settings; - _client = client; - } - - // Constructor used exclusively to parse connection string or connection data - internal BaseSession() - { - Settings = new MySqlXConnectionStringBuilder(); - } - - /// - /// Drops the database/schema with the given name. - /// - /// The name of the schema. - /// is null. - public void DropSchema(string schema) - { - if (string.IsNullOrWhiteSpace(schema)) throw new ArgumentNullException(nameof(schema)); - Schema s = this.GetSchema(schema); - if (!s.ExistsInDatabase()) return; - InternalSession.ExecuteSqlNonQuery("DROP DATABASE `" + schema + "`"); - } - - /// - /// Creates a schema/database with the given name. - /// - /// The name of the schema/database. - /// A object that matches the recently created schema/database. - public Schema CreateSchema(string schema) - { - InternalSession.ExecuteSqlNonQuery("CREATE DATABASE `" + schema + "`"); - return new Schema(this, schema); - } - - /// - /// Gets the schema with the given name. - /// - /// The name of the schema. - /// A object set with the provided schema name. - public Schema GetSchema(string schema) - { - this.Schema = new Schema(this, schema); - return this.Schema; - } - - /// - /// Gets a list of schemas (or databases) in this session. - /// - /// A list containing all existing schemas (or databases). - public List GetSchemas() - { - RowResult result = XSession.GetSqlRowResult("select * from information_schema.schemata"); - result.FetchAll(); - var query = from row in result.Rows - select new Schema(this, row.GetString("schema_name")); - return query.ToList(); - } - - /// - /// Starts a new transaction. - /// - public void StartTransaction() - { - InternalSession.ExecuteSqlNonQuery("START TRANSACTION"); - } - - /// - /// Commits the current transaction. - /// - /// A object containing the results of the commit operation. - public void Commit() - { - InternalSession.ExecuteSqlNonQuery("COMMIT"); - } - - /// - /// Rolls back the current transaction. - /// - public void Rollback() - { - InternalSession.ExecuteSqlNonQuery("ROLLBACK"); - } - - /// - /// Closes this session or releases it to the pool. - /// - public void Close() - { - if (XSession.SessionState != SessionState.Closed) - { - if (_client == null) - CloseFully(); - else - { - _client.ReleaseSession(this); - XSession.SetState(SessionState.Closed, false); - _internalSession = null; - } - } - } - - /// - /// Closes this session - /// - internal void CloseFully() - { - XSession.Close(); - } - - internal void Reset() - { - XSession.ResetSession(); - } - - #region Savepoints - - /// - /// Sets a transaction savepoint with an autogenerated name. - /// - /// The autogenerated name of the transaction savepoint. - public string SetSavepoint() - { - // Autogenerate the name of the savepoint. - return SetSavepoint($"savepoint_{Guid.NewGuid().ToString().Replace("-", "_")}"); - } - - /// - /// Sets a named transaction savepoint. - /// - /// The name of the transaction savepoint. - /// The name of the transaction savepoint. - public string SetSavepoint(string name) - { - InternalSession.ExecuteSqlNonQuery($"SAVEPOINT {name}"); - return name; - } - - /// - /// Removes the named savepoint from the set of savepoints within the current transaction. - /// - /// The name of the transaction savepoint. - public void ReleaseSavepoint(string name) - { - InternalSession.ExecuteSqlNonQuery($"RELEASE SAVEPOINT {name}"); - } - - /// - /// Rolls back a transaction to the named savepoint without terminating the transaction. - /// - /// The name of the transaction savepoint. - public void RollbackTo(string name) - { - InternalSession.ExecuteSqlNonQuery($"ROLLBACK TO {name}"); - } - - #endregion - - /// - /// Parses the connection data. - /// - /// The connection string or connection URI. - /// A object. - /// An updated connection string representation of the provided connection string or connection URI. - protected internal string ParseConnectionData(string connectionData, Client client = null) - { - if (client == null) - FailoverManager.Reset(); - - if (Regex.IsMatch(connectionData, @"^mysqlx(\+\w+)?://.*", RegexOptions.IgnoreCase)) - { - return ParseConnectionUri(connectionData); - } - else - return ParseConnectionString(connectionData); - } - - /// - /// Parses a connection URI. - /// - /// The connection URI to parse. - /// The connection string representation of the provided . - private string ParseConnectionUri(string connectionUri) - { - Uri uri = null; - string updatedUri = null; - bool parseServerAsUnixSocket = false; - string hierPart = null; - try - { - uri = new Uri(connectionUri); - } - catch (UriFormatException ex) - { - if (ex.Message != "Invalid URI: The hostname could not be parsed.") - throw; - - // Identify if multiple hosts were specified. - string[] splitUri = connectionUri.Split('@', '?'); - if (splitUri.Length == 1) throw; - - hierPart = splitUri[1]; - var schema = string.Empty; - parseServerAsUnixSocket = IsUnixSocket(hierPart); - bool isArray = hierPart.StartsWith("[") && hierPart.Contains("]"); - - // Remove schema. - if ((!parseServerAsUnixSocket && hierPart.Contains("/")) && !isArray || - (parseServerAsUnixSocket && hierPart.Contains(")/")) || - (hierPart.StartsWith("[") && hierPart.Contains("]/") && isArray)) - { - schema = hierPart.Substring(hierPart.LastIndexOf('/') + 1); - hierPart = hierPart.Substring(0, hierPart.Length - schema.Length - 1); - } - - if (parseServerAsUnixSocket) - { - updatedUri = splitUri[0] + "@localhost" + - (schema != string.Empty ? "/" + schema : string.Empty) + - (splitUri.Length > 2 ? "?" + splitUri[2] : string.Empty); - } - else if (isArray) - { - hierPart = hierPart.Substring(1, hierPart.Length - 2); - int hostCount = FailoverManager.ParseHostList(hierPart, true, true); - if (FailoverManager.FailoverGroup != null) - { - hierPart = FailoverManager.FailoverGroup.ActiveHost.Host; - parseServerAsUnixSocket = IsUnixSocket(FailoverManager.FailoverGroup.ActiveHost.Host); - updatedUri = splitUri[0] + "@" + - (parseServerAsUnixSocket ? "localhost" : hierPart) + - (FailoverManager.FailoverGroup.ActiveHost.Port != -1 ? ":" + FailoverManager.FailoverGroup.ActiveHost.Port : string.Empty) + - (schema != string.Empty ? "/" + schema : string.Empty) + - (splitUri.Length == 3 ? "?" + splitUri[2] : string.Empty); - } - else if (hostCount == 1) - updatedUri = splitUri[0] + "@" + hierPart + - (schema != string.Empty ? "/" + schema : string.Empty) + - (splitUri.Length == 3 ? "?" + splitUri[2] : string.Empty); - else - throw; - } - } - - if (uri == null) - uri = updatedUri == null ? new Uri(connectionUri) : new Uri(updatedUri); - - if (uri.Scheme == DNS_SRV_URI_SCHEME) - { - if (FailoverManager.FailoverGroup != null && FailoverManager.FailoverGroup.Hosts?.Count > 1) - throw new ArgumentException(Resources.DnsSrvInvalidConnOptionMultihost); - if (!uri.IsDefaultPort) - throw new ArgumentException(Resources.DnsSrvInvalidConnOptionPort); - if (parseServerAsUnixSocket) - throw new ArgumentException(Resources.DnsSrvInvalidConnOptionUnixSocket); - } - else if (uri.Scheme != MYSQLX_URI_SCHEME) - throw new ArgumentException(string.Format(ResourcesX.DnsSrvInvalidScheme, uri.Scheme)); - - return ConvertToConnectionString(uri, hierPart, parseServerAsUnixSocket, uri.Scheme == DNS_SRV_URI_SCHEME); - } - - /// - /// Validates if the string provided is a Unix socket file. - /// - /// The Unix socket to evaluate. - /// true if is a valid Unix socket; otherwise, false. - internal static bool IsUnixSocket(string unixSocket) - { - if (unixSocket.StartsWith(".") || - unixSocket.StartsWith("/") || - unixSocket.StartsWith("(.") || - unixSocket.StartsWith("(/") || - unixSocket.StartsWith("%2") || - unixSocket.StartsWith("(%2")) - return true; - - return false; - } - - /// - /// Converts the URI object into a connection string. - /// - /// An instance with the values for the provided connection options. - /// The path of the Unix socket file. - /// If true the replaces the value for the server connection option; otherwise, false - /// Flag indicating if this is a connection using DNS SRV. - /// A connection string. - private string ConvertToConnectionString(Uri uri, string unixSocketPath, bool parseServerAsUnixSocket, bool isDnsSrvScheme) - { - List connectionParts = new List(); - - if (string.IsNullOrWhiteSpace(uri.Host)) - throw new UriFormatException(ResourcesX.InvalidUriData + "host"); - connectionParts.Add("server=" + (parseServerAsUnixSocket ? - NormalizeUnixSocket(unixSocketPath) : - uri.Host)); - connectionParts.Add("port=" + (uri.Port == -1 ? 33060 : uri.Port)); - _isDefaultPort = uri.IsDefaultPort; - if (uri.Scheme == DNS_SRV_URI_SCHEME) - connectionParts.Add("dns-srv=true"); - - if (!string.IsNullOrWhiteSpace(uri.UserInfo)) - { - string[] userData = uri.UserInfo.Split(':'); - if (userData.Length > 2) - throw new UriFormatException(ResourcesX.InvalidUriData + "user info"); - connectionParts.Add("uid=" + System.Uri.UnescapeDataString(userData[0])); - if (userData.Length > 1) - connectionParts.Add("password=" + System.Uri.UnescapeDataString(userData[1])); - } - if (uri.Segments.Length > 2) - throw new UriFormatException(ResourcesX.InvalidUriData + "segments"); - if (uri.Segments.Length > 1) - { - connectionParts.Add("database=" + System.Uri.UnescapeDataString(uri.Segments[1])); - } - if (!string.IsNullOrWhiteSpace(uri.Query)) - { - string[] queries = System.Uri.UnescapeDataString(uri.Query).Substring(1).Split(new char[] { '&' }, StringSplitOptions.RemoveEmptyEntries); - foreach (string query in queries) - { - string[] keyValue = query.Replace(";", string.Empty).Split('='); - string part; - var connectionAttributesOption = MySqlXConnectionStringBuilder.Options.Options.First(item => item.Keyword == CONNECTION_ATTRIBUTES_CONNECTION_OPTION_KEYWORD); - var dnsSrvOption = MySqlXConnectionStringBuilder.Options.Options.First(item => item.Keyword == DNS_SRV_CONNECTION_OPTION_KEYWORD); - - if (!((connectionAttributesOption.Keyword == keyValue[0]) || connectionAttributesOption.Synonyms.Contains(keyValue[0]) && keyValue.Count() > 2)) - { - if (keyValue.Length > 2) - throw new ArgumentException(ResourcesX.InvalidUriQuery + ":" + keyValue[0]); - var connecttimeoutOption = MySqlXConnectionStringBuilder.Options.Options.First(item => item.Keyword == CONNECT_TIMEOUT_CONNECTION_OPTION_KEYWORD); - if ((connecttimeoutOption.Keyword == keyValue[0] || connecttimeoutOption.Synonyms.Contains(keyValue[0])) && - String.IsNullOrWhiteSpace(keyValue[1])) - throw new FormatException(ResourcesX.InvalidConnectionTimeoutValue); - part = keyValue[0] + "=" + (keyValue.Length == 2 ? keyValue[1] : "true").Replace("(", string.Empty).Replace(")", string.Empty); - } - else if (keyValue[1] == string.Empty) - throw new MySqlException(ResourcesX.InvalidUriQuery + ": " + keyValue[0]); - else - part = keyValue[0] + "=" + query.Replace(keyValue[0] + "=", string.Empty); - - if (isDnsSrvScheme && (dnsSrvOption.Keyword == keyValue[0] || dnsSrvOption.Synonyms.Contains(keyValue[0])) && !Convert.ToBoolean(keyValue[1])) - throw new ArgumentException(string.Format(ResourcesX.DnsSrvConflictingOptions, dnsSrvOption.Keyword)); - else if (isDnsSrvScheme && (dnsSrvOption.Keyword == keyValue[0] || dnsSrvOption.Synonyms.Contains(keyValue[0]))) - continue; - - connectionParts.Add(part); - } - } - - return string.Join("; ", connectionParts); - } - - /// - /// Parses a connection string. - /// - /// The connection string to parse. - /// The parsed connection string. - private string ParseConnectionString(string connectionString) - { - var updatedConnectionString = string.Empty; - bool portProvided = false; - bool isDnsSrv = false; - var connectionOptionsDictionary = connectionString.Split(CONNECTION_DATA_KEY_SEPARATOR) - .Select(item => item.Split(new char[] { CONNECTION_DATA_VALUE_SEPARATOR }, 2)) - .Where(item => item.Length == 2) - .ToDictionary(item => item[0], item => item[1]); - var serverOption = MySqlXConnectionStringBuilder.Options.Options.First(item => item.Keyword == SERVER_CONNECTION_OPTION_KEYWORD); - var connecttimeoutOption = MySqlXConnectionStringBuilder.Options.Options.First(item => item.Keyword == CONNECT_TIMEOUT_CONNECTION_OPTION_KEYWORD); - foreach (KeyValuePair keyValuePair in connectionOptionsDictionary) - { - // Value is an equal or a semicolon - if (keyValuePair.Value == "=" || keyValuePair.Value == "\"") - throw new MySqlException(string.Format(Resources.InvalidConnectionStringValue, (keyValuePair.Value == "\"" ? ";" : "="), keyValuePair.Key)); - - // Key is not server or any of its synonyms. - if (keyValuePair.Key != serverOption.Keyword && !serverOption.Synonyms.Contains(keyValuePair.Key)) - { - if ((connecttimeoutOption.Keyword == keyValuePair.Key || connecttimeoutOption.Synonyms.Contains(keyValuePair.Key)) && - String.IsNullOrWhiteSpace(keyValuePair.Value)) - throw new FormatException(ResourcesX.InvalidConnectionTimeoutValue); - if (keyValuePair.Key == PORT_CONNECTION_OPTION_KEYWORD) - portProvided = true; - if (keyValuePair.Key == DNS_SRV_CONNECTION_OPTION_KEYWORD) - isDnsSrv = Convert.ToBoolean(keyValuePair.Value); - - updatedConnectionString += $"{keyValuePair.Key}{CONNECTION_DATA_VALUE_SEPARATOR}{keyValuePair.Value}{CONNECTION_DATA_KEY_SEPARATOR}"; - continue; - } - - // Key is server or one of its synonyms. - var updatedValue = keyValuePair.Value; - if (IsUnixSocket(keyValuePair.Value)) - updatedValue = NormalizeUnixSocket(keyValuePair.Value); - - // The value for the server connection option doesn't have a server list format. - if (FailoverManager.ParseHostList(updatedValue, true, false) == 1 && FailoverManager.FailoverGroup == null) - updatedConnectionString = $"{SERVER_CONNECTION_OPTION_KEYWORD}{CONNECTION_DATA_VALUE_SEPARATOR}{updatedValue}{CONNECTION_DATA_KEY_SEPARATOR}{updatedConnectionString}"; - } - - // DNS SRV Validation - Port cannot be provided by the user and multihost is not allowed if dns-srv is true - if (isDnsSrv) - { - if (portProvided) - throw new ArgumentException(Resources.DnsSrvInvalidConnOptionPort); - if (FailoverManager.FailoverGroup != null) - throw new ArgumentException(Resources.DnsSrvInvalidConnOptionMultihost); - } - - // Default port must be added if not provided by the user. - if (FailoverManager.FailoverGroup == null) - return portProvided ? updatedConnectionString : $"{updatedConnectionString}{CONNECTION_DATA_KEY_SEPARATOR}{PORT_CONNECTION_OPTION_KEYWORD}{CONNECTION_DATA_VALUE_SEPARATOR}{X_PROTOCOL_DEFAULT_PORT}"; - - return $"{SERVER_CONNECTION_OPTION_KEYWORD}{CONNECTION_DATA_VALUE_SEPARATOR}{FailoverManager.FailoverGroup.ActiveHost.Host}{CONNECTION_DATA_KEY_SEPARATOR}" + - (!portProvided ? $"{PORT_CONNECTION_OPTION_KEYWORD}{CONNECTION_DATA_VALUE_SEPARATOR}{X_PROTOCOL_DEFAULT_PORT}{CONNECTION_DATA_KEY_SEPARATOR}" : string.Empty) + - updatedConnectionString; - } - - /// - /// Normalizes the Unix socket by removing leading and ending parenthesis as well as removing special characters. - /// - /// The Unix socket to normalize. - /// A normalized Unix socket. - internal static string NormalizeUnixSocket(string unixSocket) - { - unixSocket = unixSocket.Replace("%2F", "/"); - if (unixSocket.StartsWith("(") && unixSocket.EndsWith(")")) - unixSocket = unixSocket.Substring(1, unixSocket.Length - 2); - - return unixSocket; - } - - #region IDisposable Support - private bool disposedValue = false; // To detect redundant calls - - /// - /// Disposes the current object. Disposes of the managed state if the flag is set to true. - /// - /// Flag to indicate if the managed state is to be disposed. - protected virtual void Dispose(bool disposing) - { - if (!disposedValue) - { - if (disposing) - { - // dispose managed state (managed objects). - Close(); - } - - // free unmanaged resources (unmanaged objects) and override a finalizer below. - // set large fields to null. - - disposedValue = true; - } - } - - // override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources. - // ~BaseSession() { - // // Do not change this code. Put cleanup code in Dispose(bool disposing) above. - // Dispose(false); - // } - - /// - /// Disposes the current object. Code added to correctly implement the disposable pattern. - /// - public void Dispose() - { - // Do not change this code. Put cleanup code in Dispose(bool disposing) above. - Dispose(true); - // uncomment the following line if the finalizer is overridden above. - // GC.SuppressFinalize(this); - } - #endregion - } - - /// - /// Describes the state of the session. - /// - public enum SessionState - { - /// - /// The session is closed. - /// - Closed = 0, - /// - /// The session is open. - /// - Open = 1, - /// - /// The session object is connecting to the data source. - /// - Connecting = 2, - /// - /// The session object is executing a command. - /// - Executing = 4, - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data; +using MySql.Data.Common; +using MySql.Data.Failover; +using MySql.Data.MySqlClient; +using MySqlX.Common; +using MySqlX.Sessions; +using MySqlX.XDevAPI.Relational; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; + +namespace MySqlX.XDevAPI +{ + /// + /// Represents a base class for a Session. + /// + public abstract class BaseSession : IDisposable + { + private InternalSession _internalSession; + private string _connectionString; + private bool _isDefaultPort = true; + private const uint X_PROTOCOL_DEFAULT_PORT = 33060; + private const char CONNECTION_DATA_KEY_SEPARATOR = ';'; + private const char CONNECTION_DATA_VALUE_SEPARATOR = '='; + private const string PORT_CONNECTION_OPTION_KEYWORD = "port"; + private const string SERVER_CONNECTION_OPTION_KEYWORD = "server"; + private const string CONNECT_TIMEOUT_CONNECTION_OPTION_KEYWORD = "connect-timeout"; + private const string CONNECTION_ATTRIBUTES_CONNECTION_OPTION_KEYWORD = "connection-attributes"; + private const string DNS_SRV_CONNECTION_OPTION_KEYWORD = "dns-srv"; + private const string DNS_SRV_URI_SCHEME = "mysqlx+srv"; + private const string MYSQLX_URI_SCHEME = "mysqlx"; + internal QueueTaskScheduler _scheduler = new QueueTaskScheduler(); + protected readonly Client _client; + + internal InternalSession InternalSession + { + get + { + if (_internalSession == null) + throw new MySqlException(ResourcesX.InvalidSession); + return _internalSession; + } + } + + internal XInternalSession XSession + { + get { return InternalSession as XInternalSession; } + } + + internal DateTime IdleSince { get; set; } + + #region Session status properties + + private DBVersion? _version = null; + + internal DBVersion Version => _version ?? (_version = XSession.GetServerVersion()).Value; + + private int? _threadId = null; + internal int ThreadId => _threadId ?? (_threadId = XSession.GetThreadId()).Value; + + /// + /// Flag to set if prepared statements are supported. + /// + internal bool SupportsPreparedStatements { get; set; } = true; + + #endregion + + /// + /// Gets the connection settings for this session. + /// + public MySqlXConnectionStringBuilder Settings { get; private set; } + + /// + /// Gets the currently active schema. + /// + public Schema Schema { get; protected set; } + + /// + /// Gets the default schema provided when creating the session. + /// + public Schema DefaultSchema { get; private set; } + + /// + /// Gets the connection uri representation of the connection options provided during the creation of the session. + /// + public String Uri + { + get + { + var builder = new StringBuilder(string.Format("mysqlx://{0}:{1}{2}?", + Settings.Server, + Settings.Port, + string.IsNullOrEmpty(Settings.Database) ? + string.Empty : + "/" + Settings.Database)); + var firstItemAdded = false; + var certificateFileAdded = false; + foreach (var item in Settings.values) + { + // Skip connection options already included in the connection URI. + if (item.Key == "server" || item.Key == "database" || item.Key == "port") + continue; + + // Skip CertificateFile if it has already been included. + if ((item.Key == "certificatefile" || item.Key == "sslca") && certificateFileAdded) + continue; + + try + { + var value = Settings[item.Key]; + // Get the default value of the connection option. + var option = MySqlXConnectionStringBuilder.Options.Values.First( + o => o.Keyword == item.Key || + (o.Synonyms != null && o.Synonyms.Contains(item.Key))); + var defaultValue = option.DefaultValue; + // If the default value has been changed then include it in the connection URI. + if (value != null && (defaultValue == null || (value.ToString() != defaultValue.ToString()))) + { + if (!firstItemAdded) + firstItemAdded = true; + else + builder.Append("&"); + + if (item.Key == "certificatefile" || item.Key == "sslca") + { + certificateFileAdded = true; + builder.Append("sslca"); + } + else + builder.Append(item.Key); + builder.Append("="); + builder.Append(value is bool ? value.ToString().ToLower() : value.ToString()); + } + } + // Dismiss any not supported exceptions since they are expected. + catch (NotSupportedException) { } + catch (ArgumentException) { } + } + + return builder.ToString(); + } + } + + /// + /// Initializes a new instance of the BaseSession class based on the specified connection string. + /// + /// The connection used to create the session. + /// A object. + /// is null. + /// Unable to parse the when + /// in URI format. + /// + /// When using Unix sockets the protocol=unix or protocol=unixsocket connection option is required. + /// This will enable elements passed in the server connection option to be treated as Unix sockets. The user is also required + /// to explicitly set sslmode to none since X Plugin does not support SSL when using Unix sockets. Note that + /// protocol=unix and protocol=unixsocket are synonyms. + ///   + /// Multiple hosts can be specified as part of the , + /// which enables client-side failover when trying to establish a connection. + ///   + /// Connection URI examples: + /// - mysqlx://test:test@[192.1.10.10,localhost] + /// - mysqlx://test:test@[192.1.10.10,127.0.0.1] + /// - mysqlx://root:@[../tmp/mysqlx.sock,/tmp/mysqld.sock]?protocol=unix&sslmode=none + /// - mysqlx://test:test@[192.1.10.10:33060,127.0.0.1:33060] + /// - mysqlx://test:test@[192.1.10.10,120.0.0.2:22000,[::1]:33060]/test?connectiontimeout=10 + /// - mysqlx://test:test@[(address=server.example,priority=20),(address=127.0.0.1,priority=100)] + /// - mysqlx://test:test@[(address=server.example,priority=100),(address=127.0.0.1,priority=75),(address=192.0.10.56,priority=25)] + /// + ///   + /// Connection string examples: + /// - server=10.10.10.10,localhost;port=33060;uid=test;password=test; + /// - host=10.10.10.10,192.101.10.2,localhost;port=5202;uid=test;password=test; + /// - host=./tmp/mysqld.sock,/var/run/mysqldx.sock;port=5202;uid=root;protocol=unix;sslmode=none; + /// - server=(address=server.example,priority=20),(address=127.0.0.1,priority=100);port=33060;uid=test;password=test; + /// - server=(address=server.example,priority=100),(address=127.0.0.1,priority=75),(address=192.0.10.56,priority=25);port=33060;uid=test;password=test; + /// + ///   + /// Failover methods + /// - Sequential: Connection attempts will be performed in a sequential order, that is, one after another until + /// a connection is successful or all the elements from the list have been tried. + /// + /// - Priority based: If a priority is provided, the connection attemps will be performed in descending order, starting + /// with the host with the highest priority. Priority must be a value between 0 and 100. Additionally, it is required to either + /// give a priority for every host or no priority to any host. + /// + /// + internal BaseSession(string connectionString, Client client = null) : this() + { + if (string.IsNullOrWhiteSpace(connectionString)) + throw new ArgumentNullException("connectionString"); + + _client = client; + this._connectionString = ParseConnectionData(connectionString, client); + + // Multiple hosts were specified. + if (FailoverManager.FailoverGroup != null && FailoverManager.FailoverGroup.Hosts?.Count > 1) + { + _internalSession = FailoverManager.AttemptConnectionXProtocol(this._connectionString, out this._connectionString, _isDefaultPort, client); + Settings.ConnectionString = this._connectionString; + Settings.AnalyzeConnectionString(this._connectionString, true, _isDefaultPort); + } + // A single host was specified. + else + { + Settings.ConnectionString = _connectionString; + if (!(_connectionString.Contains("sslmode") || _connectionString.Contains("ssl mode") || _connectionString.Contains("ssl-mode"))) + Settings.SslMode = MySqlSslMode.Required; + Settings.AnalyzeConnectionString(this._connectionString, true, _isDefaultPort); + + if (Settings.DnsSrv) + { + var dnsSrvRecords = DnsSrv.GetDnsSrvRecords(Settings.Server); + FailoverManager.SetHostList(dnsSrvRecords.ConvertAll(r => new FailoverServer(r.Target, r.Port, r.Priority)), + FailoverMethod.Sequential); + _internalSession = FailoverManager.AttemptConnectionXProtocol(this._connectionString, out this._connectionString, _isDefaultPort, client); + Settings.ConnectionString = this._connectionString; + } + else + _internalSession = InternalSession.GetSession(Settings); + } + + // Set the default schema if provided by the user. + if (!string.IsNullOrWhiteSpace(Settings.Database)) + DefaultSchema = GetSchema(Settings.Database); + } + + /// + /// Initializes a new instance of the BaseSession class based on the specified anonymous type object. + /// + /// The connection data as an anonymous type used to create the session. + /// A object. + /// is null. + /// + /// Multiple hosts can be specified as part of the , which enables client-side failover when trying to + /// establish a connection. + ///   + /// To assign multiple hosts, create a property similar to the connection string examples shown in + /// . Note that the value of the property must be a string. + /// + /// + internal BaseSession(object connectionData, Client client = null) : this() + { + if (connectionData == null) + throw new ArgumentNullException("connectionData"); + + _client = client; + if (client == null) + FailoverManager.Reset(); + + var values = Tools.GetDictionaryFromAnonymous(connectionData); + if (!values.Keys.Any(s => s.ToLowerInvariant() == PORT_CONNECTION_OPTION_KEYWORD)) + values.Add(PORT_CONNECTION_OPTION_KEYWORD, X_PROTOCOL_DEFAULT_PORT); + + bool hostsParsed = false; + foreach (var value in values) + { + if (!Settings.ContainsKey(value.Key)) + throw new KeyNotFoundException(string.Format(ResourcesX.InvalidConnectionStringAttribute, value.Key)); + + Settings.SetValue(value.Key, value.Value); + if (!hostsParsed && !string.IsNullOrEmpty(Settings[SERVER_CONNECTION_OPTION_KEYWORD].ToString())) + { + var server = value.Value.ToString(); + if (IsUnixSocket(server)) + Settings.SetValue(value.Key, server = NormalizeUnixSocket(server)); + + FailoverManager.ParseHostList(server, true, false); + if (FailoverManager.FailoverGroup != null && FailoverManager.FailoverGroup.Hosts?.Count > 1) + Settings[SERVER_CONNECTION_OPTION_KEYWORD] = null; + else if (FailoverManager.FailoverGroup != null) + Settings[SERVER_CONNECTION_OPTION_KEYWORD] = FailoverManager.FailoverGroup.Hosts[0].Host; + + hostsParsed = true; + } + } + this._connectionString = Settings.ToString(); + + Settings.AnalyzeConnectionString(this._connectionString, true, _isDefaultPort); + if (FailoverManager.FailoverGroup != null && FailoverManager.FailoverGroup.Hosts?.Count > 1) + { + // Multiple hosts were specified. + _internalSession = FailoverManager.AttemptConnectionXProtocol(this._connectionString, out this._connectionString, _isDefaultPort, client); + Settings.ConnectionString = _connectionString; + } + else + { + if (Settings.DnsSrv) + { + var dnsSrvRecords = DnsSrv.GetDnsSrvRecords(Settings.Server); + FailoverManager.SetHostList(dnsSrvRecords.ConvertAll(r => new FailoverServer(r.Target, r.Port, null)), + FailoverMethod.Sequential); + _internalSession = FailoverManager.AttemptConnectionXProtocol(this._connectionString, out this._connectionString, _isDefaultPort, client); + Settings.ConnectionString = this._connectionString; + } + else + _internalSession = InternalSession.GetSession(Settings); + } + + if (!string.IsNullOrWhiteSpace(Settings.Database)) + DefaultSchema = GetSchema(Settings.Database); + } + + internal BaseSession(InternalSession internalSession, Client client) + { + _internalSession = internalSession; + Settings = internalSession.Settings; + _client = client; + } + + // Constructor used exclusively to parse connection string or connection data + internal BaseSession() + { + Settings = new MySqlXConnectionStringBuilder(); + } + + /// + /// Drops the database/schema with the given name. + /// + /// The name of the schema. + /// is null. + public void DropSchema(string schema) + { + if (string.IsNullOrWhiteSpace(schema)) throw new ArgumentNullException(nameof(schema)); + Schema s = this.GetSchema(schema); + if (!s.ExistsInDatabase()) return; + InternalSession.ExecuteSqlNonQuery("DROP DATABASE `" + schema + "`"); + } + + /// + /// Creates a schema/database with the given name. + /// + /// The name of the schema/database. + /// A object that matches the recently created schema/database. + public Schema CreateSchema(string schema) + { + InternalSession.ExecuteSqlNonQuery("CREATE DATABASE `" + schema + "`"); + return new Schema(this, schema); + } + + /// + /// Gets the schema with the given name. + /// + /// The name of the schema. + /// A object set with the provided schema name. + public Schema GetSchema(string schema) + { + this.Schema = new Schema(this, schema); + return this.Schema; + } + + /// + /// Gets a list of schemas (or databases) in this session. + /// + /// A list containing all existing schemas (or databases). + public List GetSchemas() + { + RowResult result = XSession.GetSqlRowResult("select * from information_schema.schemata"); + result.FetchAll(); + var query = from row in result.Rows + select new Schema(this, row.GetString("schema_name")); + return query.ToList(); + } + + /// + /// Starts a new transaction. + /// + public void StartTransaction() + { + InternalSession.ExecuteSqlNonQuery("START TRANSACTION"); + } + + /// + /// Commits the current transaction. + /// + /// A object containing the results of the commit operation. + public void Commit() + { + InternalSession.ExecuteSqlNonQuery("COMMIT"); + } + + /// + /// Rolls back the current transaction. + /// + public void Rollback() + { + InternalSession.ExecuteSqlNonQuery("ROLLBACK"); + } + + /// + /// Closes this session or releases it to the pool. + /// + public void Close() + { + if (XSession.SessionState != SessionState.Closed) + { + if (_client == null) + CloseFully(); + else + { + _client.ReleaseSession(this); + XSession.SetState(SessionState.Closed, false); + _internalSession = null; + } + } + } + + /// + /// Closes this session + /// + internal void CloseFully() + { + XSession.Close(); + } + + internal void Reset() + { + XSession.ResetSession(); + } + + #region Savepoints + + /// + /// Sets a transaction savepoint with an autogenerated name. + /// + /// The autogenerated name of the transaction savepoint. + public string SetSavepoint() + { + // Autogenerate the name of the savepoint. + return SetSavepoint($"savepoint_{Guid.NewGuid().ToString().Replace("-", "_")}"); + } + + /// + /// Sets a named transaction savepoint. + /// + /// The name of the transaction savepoint. + /// The name of the transaction savepoint. + public string SetSavepoint(string name) + { + InternalSession.ExecuteSqlNonQuery($"SAVEPOINT {name}"); + return name; + } + + /// + /// Removes the named savepoint from the set of savepoints within the current transaction. + /// + /// The name of the transaction savepoint. + public void ReleaseSavepoint(string name) + { + InternalSession.ExecuteSqlNonQuery($"RELEASE SAVEPOINT {name}"); + } + + /// + /// Rolls back a transaction to the named savepoint without terminating the transaction. + /// + /// The name of the transaction savepoint. + public void RollbackTo(string name) + { + InternalSession.ExecuteSqlNonQuery($"ROLLBACK TO {name}"); + } + + #endregion + + /// + /// Parses the connection data. + /// + /// The connection string or connection URI. + /// A object. + /// An updated connection string representation of the provided connection string or connection URI. + protected internal string ParseConnectionData(string connectionData, Client client = null) + { + if (client == null) + FailoverManager.Reset(); + + if (Regex.IsMatch(connectionData, @"^mysqlx(\+\w+)?://.*", RegexOptions.IgnoreCase)) + { + return ParseConnectionUri(connectionData); + } + else + return ParseConnectionString(connectionData); + } + + /// + /// Parses a connection URI. + /// + /// The connection URI to parse. + /// The connection string representation of the provided . + private string ParseConnectionUri(string connectionUri) + { + Uri uri = null; + string updatedUri = null; + bool parseServerAsUnixSocket = false; + string hierPart = null; + try + { + uri = new Uri(connectionUri); + } + catch (UriFormatException ex) + { + if (ex.Message != "Invalid URI: The hostname could not be parsed.") + throw; + + // Identify if multiple hosts were specified. + string[] splitUri = connectionUri.Split('@', '?'); + if (splitUri.Length == 1) throw; + + hierPart = splitUri[1]; + var schema = string.Empty; + parseServerAsUnixSocket = IsUnixSocket(hierPart); + bool isArray = hierPart.StartsWith("[") && hierPart.Contains("]"); + + // Remove schema. + if ((!parseServerAsUnixSocket && hierPart.Contains("/")) && !isArray || + (parseServerAsUnixSocket && hierPart.Contains(")/")) || + (hierPart.StartsWith("[") && hierPart.Contains("]/") && isArray)) + { + schema = hierPart.Substring(hierPart.LastIndexOf('/') + 1); + hierPart = hierPart.Substring(0, hierPart.Length - schema.Length - 1); + } + + if (parseServerAsUnixSocket) + { + updatedUri = splitUri[0] + "@localhost" + + (schema != string.Empty ? "/" + schema : string.Empty) + + (splitUri.Length > 2 ? "?" + splitUri[2] : string.Empty); + } + else if (isArray) + { + hierPart = hierPart.Substring(1, hierPart.Length - 2); + int hostCount = FailoverManager.ParseHostList(hierPart, true, true); + if (FailoverManager.FailoverGroup != null) + { + hierPart = FailoverManager.FailoverGroup.ActiveHost.Host; + parseServerAsUnixSocket = IsUnixSocket(FailoverManager.FailoverGroup.ActiveHost.Host); + updatedUri = splitUri[0] + "@" + + (parseServerAsUnixSocket ? "localhost" : hierPart) + + (FailoverManager.FailoverGroup.ActiveHost.Port != -1 ? ":" + FailoverManager.FailoverGroup.ActiveHost.Port : string.Empty) + + (schema != string.Empty ? "/" + schema : string.Empty) + + (splitUri.Length == 3 ? "?" + splitUri[2] : string.Empty); + } + else if (hostCount == 1) + updatedUri = splitUri[0] + "@" + hierPart + + (schema != string.Empty ? "/" + schema : string.Empty) + + (splitUri.Length == 3 ? "?" + splitUri[2] : string.Empty); + else + throw; + } + } + + if (uri == null) + uri = updatedUri == null ? new Uri(connectionUri) : new Uri(updatedUri); + + if (uri.Scheme == DNS_SRV_URI_SCHEME) + { + if (FailoverManager.FailoverGroup != null && FailoverManager.FailoverGroup.Hosts?.Count > 1) + throw new ArgumentException(Resources.DnsSrvInvalidConnOptionMultihost); + if (!uri.IsDefaultPort) + throw new ArgumentException(Resources.DnsSrvInvalidConnOptionPort); + if (parseServerAsUnixSocket) + throw new ArgumentException(Resources.DnsSrvInvalidConnOptionUnixSocket); + } + else if (uri.Scheme != MYSQLX_URI_SCHEME) + throw new ArgumentException(string.Format(ResourcesX.DnsSrvInvalidScheme, uri.Scheme)); + + return ConvertToConnectionString(uri, hierPart, parseServerAsUnixSocket, uri.Scheme == DNS_SRV_URI_SCHEME); + } + + /// + /// Validates if the string provided is a Unix socket file. + /// + /// The Unix socket to evaluate. + /// true if is a valid Unix socket; otherwise, false. + internal static bool IsUnixSocket(string unixSocket) + { + if (unixSocket.StartsWith(".") || + unixSocket.StartsWith("/") || + unixSocket.StartsWith("(.") || + unixSocket.StartsWith("(/") || + unixSocket.StartsWith("%2") || + unixSocket.StartsWith("(%2")) + return true; + + return false; + } + + /// + /// Converts the URI object into a connection string. + /// + /// An instance with the values for the provided connection options. + /// The path of the Unix socket file. + /// If true the replaces the value for the server connection option; otherwise, false + /// Flag indicating if this is a connection using DNS SRV. + /// A connection string. + private string ConvertToConnectionString(Uri uri, string unixSocketPath, bool parseServerAsUnixSocket, bool isDnsSrvScheme) + { + List connectionParts = new List(); + + if (string.IsNullOrWhiteSpace(uri.Host)) + throw new UriFormatException(ResourcesX.InvalidUriData + "host"); + connectionParts.Add("server=" + (parseServerAsUnixSocket ? + NormalizeUnixSocket(unixSocketPath) : + uri.Host)); + connectionParts.Add("port=" + (uri.Port == -1 ? 33060 : uri.Port)); + _isDefaultPort = uri.IsDefaultPort; + if (uri.Scheme == DNS_SRV_URI_SCHEME) + connectionParts.Add("dns-srv=true"); + + if (!string.IsNullOrWhiteSpace(uri.UserInfo)) + { + string[] userData = uri.UserInfo.Split(':'); + if (userData.Length > 2) + throw new UriFormatException(ResourcesX.InvalidUriData + "user info"); + connectionParts.Add("uid=" + System.Uri.UnescapeDataString(userData[0])); + if (userData.Length > 1) + connectionParts.Add("password=" + System.Uri.UnescapeDataString(userData[1])); + } + if (uri.Segments.Length > 2) + throw new UriFormatException(ResourcesX.InvalidUriData + "segments"); + if (uri.Segments.Length > 1) + { + connectionParts.Add("database=" + System.Uri.UnescapeDataString(uri.Segments[1])); + } + if (!string.IsNullOrWhiteSpace(uri.Query)) + { + string[] queries = System.Uri.UnescapeDataString(uri.Query).Substring(1).Split(new char[] { '&' }, StringSplitOptions.RemoveEmptyEntries); + foreach (string query in queries) + { + string[] keyValue = query.Replace(";", string.Empty).Split('='); + string part; + var connectionAttributesOption = MySqlXConnectionStringBuilder.Options.Options.First(item => item.Keyword == CONNECTION_ATTRIBUTES_CONNECTION_OPTION_KEYWORD); + var dnsSrvOption = MySqlXConnectionStringBuilder.Options.Options.First(item => item.Keyword == DNS_SRV_CONNECTION_OPTION_KEYWORD); + + if (!((connectionAttributesOption.Keyword == keyValue[0]) || connectionAttributesOption.Synonyms.Contains(keyValue[0]) && keyValue.Count() > 2)) + { + if (keyValue.Length > 2) + throw new ArgumentException(ResourcesX.InvalidUriQuery + ":" + keyValue[0]); + var connecttimeoutOption = MySqlXConnectionStringBuilder.Options.Options.First(item => item.Keyword == CONNECT_TIMEOUT_CONNECTION_OPTION_KEYWORD); + if ((connecttimeoutOption.Keyword == keyValue[0] || connecttimeoutOption.Synonyms.Contains(keyValue[0])) && + String.IsNullOrWhiteSpace(keyValue[1])) + throw new FormatException(ResourcesX.InvalidConnectionTimeoutValue); + part = keyValue[0] + "=" + (keyValue.Length == 2 ? keyValue[1] : "true").Replace("(", string.Empty).Replace(")", string.Empty); + } + else if (keyValue[1] == string.Empty) + throw new MySqlException(ResourcesX.InvalidUriQuery + ": " + keyValue[0]); + else + part = keyValue[0] + "=" + query.Replace(keyValue[0] + "=", string.Empty); + + if (isDnsSrvScheme && (dnsSrvOption.Keyword == keyValue[0] || dnsSrvOption.Synonyms.Contains(keyValue[0])) && !Convert.ToBoolean(keyValue[1])) + throw new ArgumentException(string.Format(ResourcesX.DnsSrvConflictingOptions, dnsSrvOption.Keyword)); + else if (isDnsSrvScheme && (dnsSrvOption.Keyword == keyValue[0] || dnsSrvOption.Synonyms.Contains(keyValue[0]))) + continue; + + connectionParts.Add(part); + } + } + + return string.Join("; ", connectionParts); + } + + /// + /// Parses a connection string. + /// + /// The connection string to parse. + /// The parsed connection string. + private string ParseConnectionString(string connectionString) + { + var updatedConnectionString = string.Empty; + bool portProvided = false; + bool isDnsSrv = false; + var connectionOptionsDictionary = connectionString.Split(CONNECTION_DATA_KEY_SEPARATOR) + .Select(item => item.Split(new char[] { CONNECTION_DATA_VALUE_SEPARATOR }, 2)) + .Where(item => item.Length == 2) + .ToDictionary(item => item[0], item => item[1]); + var serverOption = MySqlXConnectionStringBuilder.Options.Options.First(item => item.Keyword == SERVER_CONNECTION_OPTION_KEYWORD); + var connecttimeoutOption = MySqlXConnectionStringBuilder.Options.Options.First(item => item.Keyword == CONNECT_TIMEOUT_CONNECTION_OPTION_KEYWORD); + foreach (KeyValuePair keyValuePair in connectionOptionsDictionary) + { + // Value is an equal or a semicolon + if (keyValuePair.Value == "=" || keyValuePair.Value == "\"") + throw new MySqlException(string.Format(Resources.InvalidConnectionStringValue, (keyValuePair.Value == "\"" ? ";" : "="), keyValuePair.Key)); + + // Key is not server or any of its synonyms. + if (keyValuePair.Key != serverOption.Keyword && !serverOption.Synonyms.Contains(keyValuePair.Key)) + { + if ((connecttimeoutOption.Keyword == keyValuePair.Key || connecttimeoutOption.Synonyms.Contains(keyValuePair.Key)) && + String.IsNullOrWhiteSpace(keyValuePair.Value)) + throw new FormatException(ResourcesX.InvalidConnectionTimeoutValue); + if (keyValuePair.Key == PORT_CONNECTION_OPTION_KEYWORD) + portProvided = true; + if (keyValuePair.Key == DNS_SRV_CONNECTION_OPTION_KEYWORD) + isDnsSrv = Convert.ToBoolean(keyValuePair.Value); + + updatedConnectionString += $"{keyValuePair.Key}{CONNECTION_DATA_VALUE_SEPARATOR}{keyValuePair.Value}{CONNECTION_DATA_KEY_SEPARATOR}"; + continue; + } + + // Key is server or one of its synonyms. + var updatedValue = keyValuePair.Value; + if (IsUnixSocket(keyValuePair.Value)) + updatedValue = NormalizeUnixSocket(keyValuePair.Value); + + // The value for the server connection option doesn't have a server list format. + if (FailoverManager.ParseHostList(updatedValue, true, false) == 1 && FailoverManager.FailoverGroup == null) + updatedConnectionString = $"{SERVER_CONNECTION_OPTION_KEYWORD}{CONNECTION_DATA_VALUE_SEPARATOR}{updatedValue}{CONNECTION_DATA_KEY_SEPARATOR}{updatedConnectionString}"; + } + + // DNS SRV Validation - Port cannot be provided by the user and multihost is not allowed if dns-srv is true + if (isDnsSrv) + { + if (portProvided) + throw new ArgumentException(Resources.DnsSrvInvalidConnOptionPort); + if (FailoverManager.FailoverGroup != null) + throw new ArgumentException(Resources.DnsSrvInvalidConnOptionMultihost); + } + + // Default port must be added if not provided by the user. + if (FailoverManager.FailoverGroup == null) + return portProvided ? updatedConnectionString : $"{updatedConnectionString}{CONNECTION_DATA_KEY_SEPARATOR}{PORT_CONNECTION_OPTION_KEYWORD}{CONNECTION_DATA_VALUE_SEPARATOR}{X_PROTOCOL_DEFAULT_PORT}"; + + return $"{SERVER_CONNECTION_OPTION_KEYWORD}{CONNECTION_DATA_VALUE_SEPARATOR}{FailoverManager.FailoverGroup.ActiveHost.Host}{CONNECTION_DATA_KEY_SEPARATOR}" + + (!portProvided ? $"{PORT_CONNECTION_OPTION_KEYWORD}{CONNECTION_DATA_VALUE_SEPARATOR}{X_PROTOCOL_DEFAULT_PORT}{CONNECTION_DATA_KEY_SEPARATOR}" : string.Empty) + + updatedConnectionString; + } + + /// + /// Normalizes the Unix socket by removing leading and ending parenthesis as well as removing special characters. + /// + /// The Unix socket to normalize. + /// A normalized Unix socket. + internal static string NormalizeUnixSocket(string unixSocket) + { + unixSocket = unixSocket.Replace("%2F", "/"); + if (unixSocket.StartsWith("(") && unixSocket.EndsWith(")")) + unixSocket = unixSocket.Substring(1, unixSocket.Length - 2); + + return unixSocket; + } + + #region IDisposable Support + private bool disposedValue = false; // To detect redundant calls + + /// + /// Disposes the current object. Disposes of the managed state if the flag is set to true. + /// + /// Flag to indicate if the managed state is to be disposed. + protected virtual void Dispose(bool disposing) + { + if (!disposedValue) + { + if (disposing) + { + // dispose managed state (managed objects). + Close(); + } + + // free unmanaged resources (unmanaged objects) and override a finalizer below. + // set large fields to null. + + disposedValue = true; + } + } + + // override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources. + // ~BaseSession() { + // // Do not change this code. Put cleanup code in Dispose(bool disposing) above. + // Dispose(false); + // } + + /// + /// Disposes the current object. Code added to correctly implement the disposable pattern. + /// + public void Dispose() + { + // Do not change this code. Put cleanup code in Dispose(bool disposing) above. + Dispose(true); + // uncomment the following line if the finalizer is overridden above. + // GC.SuppressFinalize(this); + } + #endregion + } + + /// + /// Describes the state of the session. + /// + public enum SessionState + { + /// + /// The session is closed. + /// + Closed = 0, + /// + /// The session is open. + /// + Open = 1, + /// + /// The session object is connecting to the data source. + /// + Connecting = 2, + /// + /// The session object is executing a command. + /// + Executing = 4, + } +} diff --git a/MySQL.Data/src/X/XDevAPI/CRUD/AddStatement.cs b/MySQL.Data/src/X/XDevAPI/CRUD/AddStatement.cs index 01111c516..4b0a12ebe 100644 --- a/MySQL.Data/src/X/XDevAPI/CRUD/AddStatement.cs +++ b/MySQL.Data/src/X/XDevAPI/CRUD/AddStatement.cs @@ -1,76 +1,76 @@ -// Copyright (c) 2015, 2023, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySqlX.XDevAPI.Common; -using System; -using System.Collections.Generic; -using System.Linq; - -namespace MySqlX.XDevAPI.CRUD -{ - /// - /// Represents a chaining collection insert statement. - /// - /// - public class AddStatement : CrudStatement - { - private List _Docs = new List(); - internal bool upsert; - - internal AddStatement(Collection collection) : base(collection) { } - - /// - /// Adds documents to the collection. - /// - /// The documents to add. - /// This object. - /// The array is null. - public AddStatement Add(params object[] items) - { - if (items == null) - throw new ArgumentNullException(); - - _Docs.AddRange(GetDocs(items)); - return this; - } - - /// - /// Executes the Add statement. - /// - /// A object containing the results of the execution. - public override Result Execute() - { - ValidateOpenSession(); - if (_Docs.Count == 0) - return new Result(null); - - //List newIds = AssignIds(); - return Target.Session.XSession.Insert(Target, _Docs.Cast().ToArray(), null, upsert); - } - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySqlX.XDevAPI.Common; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace MySqlX.XDevAPI.CRUD +{ + /// + /// Represents a chaining collection insert statement. + /// + /// + public class AddStatement : CrudStatement + { + private List _Docs = new List(); + internal bool upsert; + + internal AddStatement(Collection collection) : base(collection) { } + + /// + /// Adds documents to the collection. + /// + /// The documents to add. + /// This object. + /// The array is null. + public AddStatement Add(params object[] items) + { + if (items == null) + throw new ArgumentNullException(); + + _Docs.AddRange(GetDocs(items)); + return this; + } + + /// + /// Executes the Add statement. + /// + /// A object containing the results of the execution. + public override Result Execute() + { + ValidateOpenSession(); + if (_Docs.Count == 0) + return new Result(null); + + //List newIds = AssignIds(); + return Target.Session.XSession.Insert(Target, _Docs.Cast().ToArray(), null, upsert); + } + } +} diff --git a/MySQL.Data/src/X/XDevAPI/CRUD/CreateCollectionIndexStatement.cs b/MySQL.Data/src/X/XDevAPI/CRUD/CreateCollectionIndexStatement.cs index c96b3b445..b30f144c1 100644 --- a/MySQL.Data/src/X/XDevAPI/CRUD/CreateCollectionIndexStatement.cs +++ b/MySQL.Data/src/X/XDevAPI/CRUD/CreateCollectionIndexStatement.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2015, 2023, Oracle and/or its affiliates. +// Copyright © 2015, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/X/XDevAPI/CRUD/CreateIndexParams.cs b/MySQL.Data/src/X/XDevAPI/CRUD/CreateIndexParams.cs index 75a467837..af518edb6 100644 --- a/MySQL.Data/src/X/XDevAPI/CRUD/CreateIndexParams.cs +++ b/MySQL.Data/src/X/XDevAPI/CRUD/CreateIndexParams.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2015, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/X/XDevAPI/CRUD/CrudStatement.cs b/MySQL.Data/src/X/XDevAPI/CRUD/CrudStatement.cs index 71f24b5af..df71f408e 100644 --- a/MySQL.Data/src/X/XDevAPI/CRUD/CrudStatement.cs +++ b/MySQL.Data/src/X/XDevAPI/CRUD/CrudStatement.cs @@ -1,69 +1,69 @@ -// Copyright (c) 2015, 2023, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using System; -using System.Collections.Generic; -#if !NETFRAMEWORK -using System.Text.Json; -#endif -using MySqlX.XDevAPI.Common; - -namespace MySqlX.XDevAPI.CRUD -{ - /// - /// Represents a collection statement. - /// - /// Type of - /// Type of object - public abstract class CrudStatement : TargetedBaseStatement, TResult, T> - where TResult : Result - { - internal CrudStatement(Collection collection) : base(collection) - { - } - - /// - /// Converts base s into objects. - /// - /// Array of objects to be converted to objects. - /// An enumerable collection of objects. - protected IEnumerable GetDocs(object[] items) - { - foreach (object item in items) - { - if (typeof(T).Name == "DbDoc") - { - DbDoc d = item is DbDoc ? item as DbDoc : new DbDoc(item); - yield return (T)Convert.ChangeType(d, typeof(T)); - } - else - yield return (T)item; - } - } - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using System; +using System.Collections.Generic; +#if !NETFRAMEWORK +using System.Text.Json; +#endif +using MySqlX.XDevAPI.Common; + +namespace MySqlX.XDevAPI.CRUD +{ + /// + /// Represents a collection statement. + /// + /// Type of + /// Type of object + public abstract class CrudStatement : TargetedBaseStatement, TResult, T> + where TResult : Result + { + internal CrudStatement(Collection collection) : base(collection) + { + } + + /// + /// Converts base s into objects. + /// + /// Array of objects to be converted to objects. + /// An enumerable collection of objects. + protected IEnumerable GetDocs(object[] items) + { + foreach (object item in items) + { + if (typeof(T).Name == "DbDoc") + { + DbDoc d = item is DbDoc ? item as DbDoc : new DbDoc(item); + yield return (T)Convert.ChangeType(d, typeof(T)); + } + else + yield return (T)item; + } + } + } +} diff --git a/MySQL.Data/src/X/XDevAPI/CRUD/DocResult.cs b/MySQL.Data/src/X/XDevAPI/CRUD/DocResult.cs index cb6b0c068..1808659a6 100644 --- a/MySQL.Data/src/X/XDevAPI/CRUD/DocResult.cs +++ b/MySQL.Data/src/X/XDevAPI/CRUD/DocResult.cs @@ -1,74 +1,74 @@ -// Copyright (c) 2015, 2023, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using System.Collections.Generic; -using System.Diagnostics; -using MySqlX.XDevAPI.Common; -using MySqlX.Sessions; -using System; -using MySql.Data.MySqlClient; -#if !NETFRAMEWORK -using System.Text.Json; -#endif - -namespace MySqlX.XDevAPI.CRUD -{ - /// - /// Represents the result of an operation that includes a collection of documents. - /// - /// - public class DocResult : BufferingResult - { - System.Text.Encoding _encoding = System.Text.Encoding.UTF8; - - internal DocResult(InternalSession session) : base(session) - { - // this is just a single column "doc" - Debug.Assert(_columns.Count == 1); - } - - protected override T ReadItem(bool dumping) - { - List values = Protocol.ReadRow(this); - if (values == null) return default; - - Debug.Assert(values.Count == 1); - - if (typeof(T).Name == "DbDoc") - return (T)Convert.ChangeType(new DbDoc(_encoding.GetString(values[0]).TrimEnd('\0')), typeof(T)); - else - { -#if !NETFRAMEWORK - return JsonSerializer.Deserialize(_encoding.GetString(values[0]).TrimEnd('\0')); -#else - throw new MySqlException("Custom type mapping is only supported from .NET Core 3.1."); -#endif - } - } - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using System.Collections.Generic; +using System.Diagnostics; +using MySqlX.XDevAPI.Common; +using MySqlX.Sessions; +using System; +using MySql.Data.MySqlClient; +#if !NETFRAMEWORK +using System.Text.Json; +#endif + +namespace MySqlX.XDevAPI.CRUD +{ + /// + /// Represents the result of an operation that includes a collection of documents. + /// + /// + public class DocResult : BufferingResult + { + System.Text.Encoding _encoding = System.Text.Encoding.UTF8; + + internal DocResult(InternalSession session) : base(session) + { + // this is just a single column "doc" + Debug.Assert(_columns.Count == 1); + } + + protected override T ReadItem(bool dumping) + { + List values = Protocol.ReadRow(this); + if (values == null) return default; + + Debug.Assert(values.Count == 1); + + if (typeof(T).Name == "DbDoc") + return (T)Convert.ChangeType(new DbDoc(_encoding.GetString(values[0]).TrimEnd('\0')), typeof(T)); + else + { +#if !NETFRAMEWORK + return JsonSerializer.Deserialize(_encoding.GetString(values[0]).TrimEnd('\0')); +#else + throw new MySqlException("Custom type mapping is only supported from .NET Core 3.1."); +#endif + } + } + } +} diff --git a/MySQL.Data/src/X/XDevAPI/CRUD/FindParams.cs b/MySQL.Data/src/X/XDevAPI/CRUD/FindParams.cs index 7617f17db..3616ca7fb 100644 --- a/MySQL.Data/src/X/XDevAPI/CRUD/FindParams.cs +++ b/MySQL.Data/src/X/XDevAPI/CRUD/FindParams.cs @@ -1,43 +1,43 @@ -// Copyright © 2015, 2018, Oracle and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data.MySqlClient; -using MySqlX.Protocol.X; -using MySqlX.XDevAPI.Common; - -namespace MySqlX.XDevAPI.CRUD -{ - internal class FindParams : FilterParams - { - public string[] GroupBy; - public string GroupByCritieria; - public string[] Projection; - public RowLock Locking; - public LockContention LockingOption; - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data.MySqlClient; +using MySqlX.Protocol.X; +using MySqlX.XDevAPI.Common; + +namespace MySqlX.XDevAPI.CRUD +{ + internal class FindParams : FilterParams + { + public string[] GroupBy; + public string GroupByCritieria; + public string[] Projection; + public RowLock Locking; + public LockContention LockingOption; + } +} diff --git a/MySQL.Data/src/X/XDevAPI/CRUD/FindStatement.cs b/MySQL.Data/src/X/XDevAPI/CRUD/FindStatement.cs index fb92bcbb5..7df9b0714 100644 --- a/MySQL.Data/src/X/XDevAPI/CRUD/FindStatement.cs +++ b/MySQL.Data/src/X/XDevAPI/CRUD/FindStatement.cs @@ -1,172 +1,172 @@ -// Copyright (c) 2015, 2023, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data; -using MySql.Data.MySqlClient; -using MySqlX.XDevAPI.Common; -using System; -using System.Collections.Generic; - -namespace MySqlX.XDevAPI.CRUD -{ - /// - /// Represents a chaining collection find statement. - /// - /// - public class FindStatement : FilterableStatement, Collection, DocResult, T> - { - internal FindParams findParams = new FindParams(); - - internal FindStatement(Collection c, string condition) : base(c, condition) - { - } - - /// - /// List of column projections that shall be returned. - /// - /// List of columns. - /// This object set with the specified columns or fields. - public FindStatement Fields(params string[] columns) - { - if (columns == null) - return this; - - var projectionList = new List(); - foreach (var item in columns) - { - if (item != null) - projectionList.Add(item); - } - - findParams.Projection = projectionList.Count > 0 ? projectionList.ToArray() : null; - SetChanged(); - return this; - } - - /// - /// Executes the Find statement. - /// - /// A object containing the results of execution and data. - public override DocResult Execute() - { - return Execute(Target.Session.XSession.FindDocs, this); - } - - /// - /// Locks matching rows against updates. - /// - /// Optional row lock option to use. - /// This same object set with the lock shared option. - /// The server version is lower than 8.0.3. - public FindStatement LockShared(LockContention lockOption = LockContention.Default) - { - if (!this.Session.InternalSession.GetServerVersion().isAtLeast(8, 0, 3)) - throw new MySqlException(string.Format(ResourcesX.FunctionalityNotSupported, "8.0.3")); - - findParams.Locking = Protocol.X.RowLock.SharedLock; - findParams.LockingOption = lockOption; - SetChanged(); - return this; - } - - /// - /// Locks matching rows so no other transaction can read or write to it. - /// - /// Optional row lock option to use. - /// This same object set with the lock exclusive option. - /// The server version is lower than 8.0.3. - public FindStatement LockExclusive(LockContention lockOption = LockContention.Default) - { - if (!this.Session.InternalSession.GetServerVersion().isAtLeast(8, 0, 3)) - throw new MySqlException(string.Format(ResourcesX.FunctionalityNotSupported, "8.0.3")); - - findParams.Locking = Protocol.X.RowLock.ExclusiveLock; - findParams.LockingOption = lockOption; - SetChanged(); - return this; - } - - /// - /// Sets the collection aggregation. - /// - /// The field list for aggregation. - /// This same object set with the specified group-by criteria. - public FindStatement GroupBy(params string[] groupBy) - { - if (groupBy == null) - return this; - - var groupByList = new List(); - foreach (var item in groupBy) - { - if (item != null) - groupByList.Add(item); - } - - findParams.GroupBy = groupByList.Count > 0 ? groupByList.ToArray() : null; - SetChanged(); - return this; - } - - /// - /// Filters criteria for aggregated groups. - /// - /// The filter criteria for aggregated groups. - /// This same object set with the specified filter criteria. - public FindStatement Having(string having) - { - findParams.GroupByCritieria = having; - SetChanged(); - return this; - } - - /// - /// Sets user-defined sorting criteria for the operation. The strings use normal SQL syntax like - /// "order ASC" or "pages DESC, age ASC". - /// - /// The order criteria. - /// This same object set with the specified order criteria. - public FindStatement Sort(params string[] order) - { - FilterData.OrderBy = order; - SetChanged(); - return this; - } - - /// - /// Enables the setting of Where condition for this operation. - /// - /// The Where condition. - /// This same object set with the specified condition criteria. - [Obsolete("Where(string condition) has been deprecated since version 8.0.17.")] - public new FindStatement Where(string condition) - { - return base.Where(condition); - } - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data; +using MySql.Data.MySqlClient; +using MySqlX.XDevAPI.Common; +using System; +using System.Collections.Generic; + +namespace MySqlX.XDevAPI.CRUD +{ + /// + /// Represents a chaining collection find statement. + /// + /// + public class FindStatement : FilterableStatement, Collection, DocResult, T> + { + internal FindParams findParams = new FindParams(); + + internal FindStatement(Collection c, string condition) : base(c, condition) + { + } + + /// + /// List of column projections that shall be returned. + /// + /// List of columns. + /// This object set with the specified columns or fields. + public FindStatement Fields(params string[] columns) + { + if (columns == null) + return this; + + var projectionList = new List(); + foreach (var item in columns) + { + if (item != null) + projectionList.Add(item); + } + + findParams.Projection = projectionList.Count > 0 ? projectionList.ToArray() : null; + SetChanged(); + return this; + } + + /// + /// Executes the Find statement. + /// + /// A object containing the results of execution and data. + public override DocResult Execute() + { + return Execute(Target.Session.XSession.FindDocs, this); + } + + /// + /// Locks matching rows against updates. + /// + /// Optional row lock option to use. + /// This same object set with the lock shared option. + /// The server version is lower than 8.0.3. + public FindStatement LockShared(LockContention lockOption = LockContention.Default) + { + if (!this.Session.InternalSession.GetServerVersion().isAtLeast(8, 0, 3)) + throw new MySqlException(string.Format(ResourcesX.FunctionalityNotSupported, "8.0.3")); + + findParams.Locking = Protocol.X.RowLock.SharedLock; + findParams.LockingOption = lockOption; + SetChanged(); + return this; + } + + /// + /// Locks matching rows so no other transaction can read or write to it. + /// + /// Optional row lock option to use. + /// This same object set with the lock exclusive option. + /// The server version is lower than 8.0.3. + public FindStatement LockExclusive(LockContention lockOption = LockContention.Default) + { + if (!this.Session.InternalSession.GetServerVersion().isAtLeast(8, 0, 3)) + throw new MySqlException(string.Format(ResourcesX.FunctionalityNotSupported, "8.0.3")); + + findParams.Locking = Protocol.X.RowLock.ExclusiveLock; + findParams.LockingOption = lockOption; + SetChanged(); + return this; + } + + /// + /// Sets the collection aggregation. + /// + /// The field list for aggregation. + /// This same object set with the specified group-by criteria. + public FindStatement GroupBy(params string[] groupBy) + { + if (groupBy == null) + return this; + + var groupByList = new List(); + foreach (var item in groupBy) + { + if (item != null) + groupByList.Add(item); + } + + findParams.GroupBy = groupByList.Count > 0 ? groupByList.ToArray() : null; + SetChanged(); + return this; + } + + /// + /// Filters criteria for aggregated groups. + /// + /// The filter criteria for aggregated groups. + /// This same object set with the specified filter criteria. + public FindStatement Having(string having) + { + findParams.GroupByCritieria = having; + SetChanged(); + return this; + } + + /// + /// Sets user-defined sorting criteria for the operation. The strings use normal SQL syntax like + /// "order ASC" or "pages DESC, age ASC". + /// + /// The order criteria. + /// This same object set with the specified order criteria. + public FindStatement Sort(params string[] order) + { + FilterData.OrderBy = order; + SetChanged(); + return this; + } + + /// + /// Enables the setting of Where condition for this operation. + /// + /// The Where condition. + /// This same object set with the specified condition criteria. + [Obsolete("Where(string condition) has been deprecated since version 8.0.17.")] + public new FindStatement Where(string condition) + { + return base.Where(condition); + } + } +} diff --git a/MySQL.Data/src/X/XDevAPI/CRUD/ModifyStatement.cs b/MySQL.Data/src/X/XDevAPI/CRUD/ModifyStatement.cs index 6be178191..4e6265476 100644 --- a/MySQL.Data/src/X/XDevAPI/CRUD/ModifyStatement.cs +++ b/MySQL.Data/src/X/XDevAPI/CRUD/ModifyStatement.cs @@ -1,199 +1,199 @@ -// Copyright (c) 2015, 2023, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data; -using MySql.Data.MySqlClient; -using Mysqlx.Crud; -using MySqlX.XDevAPI.Common; -using System; -using System.Collections.Generic; -#if !NETFRAMEWORK -using System.Text.Json; -#endif - -namespace MySqlX.XDevAPI.CRUD -{ - /// - /// Represents a chaining collection modify statement. - /// - /// - public class ModifyStatement : FilterableStatement, Collection, Result, T> - { - internal ModifyStatement(Collection collection, string condition) : base(collection, condition) - { - Updates = new List(); - } - - internal List Updates; - - /// - /// Sets key and value. - /// - /// The document path key. - /// The new value. - /// This object. - public ModifyStatement Set(string docPath, object value) - { - Updates.Add(new UpdateSpec(UpdateOperation.Types.UpdateType.ItemSet, docPath).SetValue(value)); - SetChanged(); - return this; - } - - /// - /// Changes value for a key. - /// - /// The document path key. - /// The new value. - /// This object. - public ModifyStatement Change(string docPath, object value) - { - Updates.Add(new UpdateSpec(UpdateOperation.Types.UpdateType.ItemReplace, docPath).SetValue(value)); - SetChanged(); - return this; - } - - /// - /// Removes keys or values from a document. - /// - /// An array of document paths representing the keys to be removed. - /// This object. - public ModifyStatement Unset(params string[] docPath) - { - if (docPath == null) - return this; - - foreach (var item in docPath) - { - if (item != null) - Updates.Add(new UpdateSpec(UpdateOperation.Types.UpdateType.ItemRemove, item)); - } - - SetChanged(); - return this; - } - - /// - /// Creates a object set with the changes to be applied to all matching documents. - /// - /// The JSON-formatted object describing the set of changes. - /// A object set with the changes described in . - /// can be a object, an anonymous object, a JSON string or a custom type object. - /// is null. - /// is null or white space. - public ModifyStatement Patch(object document) - { - if (document == null) - throw new ArgumentNullException(nameof(document)); - - if (document is string && string.IsNullOrWhiteSpace((string)document)) - throw new ArgumentNullException(nameof(document), Resources.ParameterNullOrEmpty); - - DbDoc dbDocument = document is DbDoc ? document as DbDoc : new DbDoc(document); - - if (dbDocument.values.Count == 0) - { -#if !NETFRAMEWORK - var customObject = JsonSerializer.Serialize(document); - Updates.Add(new UpdateSpec(UpdateOperation.Types.UpdateType.MergePatch, string.Empty).SetValue(customObject)); -#else - throw new MySqlException(ResourcesX.CustomTypeNotSupported); -#endif - } - else - Updates.Add(new UpdateSpec(UpdateOperation.Types.UpdateType.MergePatch, string.Empty).SetValue(dbDocument.values)); - - SetChanged(); - return this; - } - - /// - /// Inserts an item into the specified array. - /// - /// The document path key including the index on which the item will be inserted. - /// The value to insert into the array. - /// A object containing the updated array. - public ModifyStatement ArrayInsert(string field, object value) - { - if (value is string && value.ToString() == string.Empty) - throw new ArgumentException(nameof(value), Resources.StringEmpty); - - Updates.Add(new UpdateSpec(UpdateOperation.Types.UpdateType.ArrayInsert, field).SetValue(value)); - SetChanged(); - return this; - } - - /// - /// Appends an item to the specified array. - /// - /// The document path key. - /// The value to append to the array. - /// A object containing the updated array. - public ModifyStatement ArrayAppend(string docPath, object value) - { - if (value is string && value.ToString() == string.Empty) - throw new ArgumentException(nameof(value), Resources.StringEmpty); - - Updates.Add(new UpdateSpec(UpdateOperation.Types.UpdateType.ArrayAppend, docPath).SetValue(value)); - SetChanged(); - return this; - } - - /// - /// Allows the user to set the sorting criteria for the operation. The strings use normal SQL syntax like - /// "order ASC" or "pages DESC, age ASC". - /// - /// The order criteria. - /// A generic object representing the implementing statement type. - public ModifyStatement Sort(params string[] order) - { - FilterData.OrderBy = order; - SetChanged(); - return this; - } - - /// - /// Enables the setting of Where condition for this operation. - /// - /// The Where condition. - /// The implementing statement type. - [Obsolete("Where(string condition) has been deprecated since version 8.0.17.")] - public new ModifyStatement Where(string condition) - { - return base.Where(condition); - } - - /// - /// Executes the modify statement. - /// - /// A object containing the results of the execution. - public override Result Execute() - { - return Execute(Target.Session.XSession.ModifyDocs, this); - } - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data; +using MySql.Data.MySqlClient; +using Mysqlx.Crud; +using MySqlX.XDevAPI.Common; +using System; +using System.Collections.Generic; +#if !NETFRAMEWORK +using System.Text.Json; +#endif + +namespace MySqlX.XDevAPI.CRUD +{ + /// + /// Represents a chaining collection modify statement. + /// + /// + public class ModifyStatement : FilterableStatement, Collection, Result, T> + { + internal ModifyStatement(Collection collection, string condition) : base(collection, condition) + { + Updates = new List(); + } + + internal List Updates; + + /// + /// Sets key and value. + /// + /// The document path key. + /// The new value. + /// This object. + public ModifyStatement Set(string docPath, object value) + { + Updates.Add(new UpdateSpec(UpdateOperation.Types.UpdateType.ItemSet, docPath).SetValue(value)); + SetChanged(); + return this; + } + + /// + /// Changes value for a key. + /// + /// The document path key. + /// The new value. + /// This object. + public ModifyStatement Change(string docPath, object value) + { + Updates.Add(new UpdateSpec(UpdateOperation.Types.UpdateType.ItemReplace, docPath).SetValue(value)); + SetChanged(); + return this; + } + + /// + /// Removes keys or values from a document. + /// + /// An array of document paths representing the keys to be removed. + /// This object. + public ModifyStatement Unset(params string[] docPath) + { + if (docPath == null) + return this; + + foreach (var item in docPath) + { + if (item != null) + Updates.Add(new UpdateSpec(UpdateOperation.Types.UpdateType.ItemRemove, item)); + } + + SetChanged(); + return this; + } + + /// + /// Creates a object set with the changes to be applied to all matching documents. + /// + /// The JSON-formatted object describing the set of changes. + /// A object set with the changes described in . + /// can be a object, an anonymous object, a JSON string or a custom type object. + /// is null. + /// is null or white space. + public ModifyStatement Patch(object document) + { + if (document == null) + throw new ArgumentNullException(nameof(document)); + + if (document is string && string.IsNullOrWhiteSpace((string)document)) + throw new ArgumentNullException(nameof(document), Resources.ParameterNullOrEmpty); + + DbDoc dbDocument = document is DbDoc ? document as DbDoc : new DbDoc(document); + + if (dbDocument.values.Count == 0) + { +#if !NETFRAMEWORK + var customObject = JsonSerializer.Serialize(document); + Updates.Add(new UpdateSpec(UpdateOperation.Types.UpdateType.MergePatch, string.Empty).SetValue(customObject)); +#else + throw new MySqlException(ResourcesX.CustomTypeNotSupported); +#endif + } + else + Updates.Add(new UpdateSpec(UpdateOperation.Types.UpdateType.MergePatch, string.Empty).SetValue(dbDocument.values)); + + SetChanged(); + return this; + } + + /// + /// Inserts an item into the specified array. + /// + /// The document path key including the index on which the item will be inserted. + /// The value to insert into the array. + /// A object containing the updated array. + public ModifyStatement ArrayInsert(string field, object value) + { + if (value is string && value.ToString() == string.Empty) + throw new ArgumentException(nameof(value), Resources.StringEmpty); + + Updates.Add(new UpdateSpec(UpdateOperation.Types.UpdateType.ArrayInsert, field).SetValue(value)); + SetChanged(); + return this; + } + + /// + /// Appends an item to the specified array. + /// + /// The document path key. + /// The value to append to the array. + /// A object containing the updated array. + public ModifyStatement ArrayAppend(string docPath, object value) + { + if (value is string && value.ToString() == string.Empty) + throw new ArgumentException(nameof(value), Resources.StringEmpty); + + Updates.Add(new UpdateSpec(UpdateOperation.Types.UpdateType.ArrayAppend, docPath).SetValue(value)); + SetChanged(); + return this; + } + + /// + /// Allows the user to set the sorting criteria for the operation. The strings use normal SQL syntax like + /// "order ASC" or "pages DESC, age ASC". + /// + /// The order criteria. + /// A generic object representing the implementing statement type. + public ModifyStatement Sort(params string[] order) + { + FilterData.OrderBy = order; + SetChanged(); + return this; + } + + /// + /// Enables the setting of Where condition for this operation. + /// + /// The Where condition. + /// The implementing statement type. + [Obsolete("Where(string condition) has been deprecated since version 8.0.17.")] + public new ModifyStatement Where(string condition) + { + return base.Where(condition); + } + + /// + /// Executes the modify statement. + /// + /// A object containing the results of the execution. + public override Result Execute() + { + return Execute(Target.Session.XSession.ModifyDocs, this); + } + } +} diff --git a/MySQL.Data/src/X/XDevAPI/CRUD/RemoveStatement.cs b/MySQL.Data/src/X/XDevAPI/CRUD/RemoveStatement.cs index f7d4210a3..4d9867384 100644 --- a/MySQL.Data/src/X/XDevAPI/CRUD/RemoveStatement.cs +++ b/MySQL.Data/src/X/XDevAPI/CRUD/RemoveStatement.cs @@ -1,77 +1,77 @@ -// Copyright (c) 2015, 2023, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySqlX.XDevAPI.Common; -using System; - -namespace MySqlX.XDevAPI.CRUD -{ - /// - /// Represents a chaining collection remove statement. - /// - /// - public class RemoveStatement : FilterableStatement, Collection, Result, T> - { - internal RemoveStatement(Collection collection, string condition) : base(collection, condition) - { - } - - /// - /// Sets user-defined sorting criteria for the operation. The strings use normal SQL syntax like - /// "order ASC" or "pages DESC, age ASC". - /// - /// The order criteria. - /// A generic object representing the implementing statement type. - public RemoveStatement Sort(params string[] order) - { - FilterData.OrderBy = order; - SetChanged(); - return this; - } - - /// - /// Enables the setting of Where condition for this operation. - /// - /// The Where condition. - /// The implementing statement type. - [Obsolete("Where(string condition) has been deprecated since version 8.0.17.")] - public new RemoveStatement Where(string condition) - { - return base.Where(condition); - } - - /// - /// Executes the remove statement. - /// - /// A object containing the results of the execution. - public override Result Execute() - { - return Execute(Target.Session.XSession.DeleteDocs, this); - } - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySqlX.XDevAPI.Common; +using System; + +namespace MySqlX.XDevAPI.CRUD +{ + /// + /// Represents a chaining collection remove statement. + /// + /// + public class RemoveStatement : FilterableStatement, Collection, Result, T> + { + internal RemoveStatement(Collection collection, string condition) : base(collection, condition) + { + } + + /// + /// Sets user-defined sorting criteria for the operation. The strings use normal SQL syntax like + /// "order ASC" or "pages DESC, age ASC". + /// + /// The order criteria. + /// A generic object representing the implementing statement type. + public RemoveStatement Sort(params string[] order) + { + FilterData.OrderBy = order; + SetChanged(); + return this; + } + + /// + /// Enables the setting of Where condition for this operation. + /// + /// The Where condition. + /// The implementing statement type. + [Obsolete("Where(string condition) has been deprecated since version 8.0.17.")] + public new RemoveStatement Where(string condition) + { + return base.Where(condition); + } + + /// + /// Executes the remove statement. + /// + /// A object containing the results of the execution. + public override Result Execute() + { + return Execute(Target.Session.XSession.DeleteDocs, this); + } + } +} diff --git a/MySQL.Data/src/X/XDevAPI/CRUD/UpdateSpec.cs b/MySQL.Data/src/X/XDevAPI/CRUD/UpdateSpec.cs index d338cc29d..86e127bd2 100644 --- a/MySQL.Data/src/X/XDevAPI/CRUD/UpdateSpec.cs +++ b/MySQL.Data/src/X/XDevAPI/CRUD/UpdateSpec.cs @@ -1,109 +1,109 @@ -// Copyright (c) 2015, 2022, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data; -using Mysqlx.Crud; -using Mysqlx.Expr; -using MySqlX.Protocol.X; -using MySqlX.Serialization; -using System; -using static Mysqlx.Crud.UpdateOperation.Types; - -namespace MySqlX.XDevAPI.CRUD -{ - internal class UpdateSpec - { - public UpdateSpec(UpdateOperation.Types.UpdateType updateType, string docPath) - { - if (updateType is not UpdateOperation.Types.UpdateType.MergePatch && string.IsNullOrWhiteSpace(docPath)) - throw new ArgumentException(ResourcesX.DocPathNullOrEmpty); - - Type = updateType; - Path = docPath; - } - - public string Path { get; private set; } - public UpdateOperation.Types.UpdateType Type { get; private set; } - public object Value { get; private set; } - - public bool HasValue - { - get { return Value != null; } - } - - public Expr GetValue(UpdateType operationType) - { - bool evaluateStringExpression = true; - if (operationType == UpdateType.ArrayAppend || operationType == UpdateType.ArrayInsert || operationType == UpdateType.ItemSet) - { - Value = ExprUtil.ParseAnonymousObject(Value) ?? Value; - if (Value is string) - { - try - { - JsonParser.Parse(Value as string); - } - catch (Exception) - { - evaluateStringExpression = false; - } - } - } - - return ExprUtil.ArgObjectToExpr(Value, false, evaluateStringExpression); - } - - public ColumnIdentifier GetSource(bool isRelational) - { - var source = Path; - - // accomodate parser's documentField() handling by removing "@" - if (source.Length > 0 && source[0] == '@') - source = source.Substring(1); - - ExprParser p = new ExprParser(source, false); - ColumnIdentifier identifier; - - if (isRelational) - identifier = p.ParseTableUpdateField(); - else - identifier = p.DocumentField().Identifier; - - if (p.tokenPos < p.tokens.Count) - throw new ArgumentException("Invalid document path."); - - return identifier; - } - - public UpdateSpec SetValue(object o) - { - Value = o; - return this; - } - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data; +using Mysqlx.Crud; +using Mysqlx.Expr; +using MySqlX.Protocol.X; +using MySqlX.Serialization; +using System; +using static Mysqlx.Crud.UpdateOperation.Types; + +namespace MySqlX.XDevAPI.CRUD +{ + internal class UpdateSpec + { + public UpdateSpec(UpdateOperation.Types.UpdateType updateType, string docPath) + { + if (updateType is not UpdateOperation.Types.UpdateType.MergePatch && string.IsNullOrWhiteSpace(docPath)) + throw new ArgumentException(ResourcesX.DocPathNullOrEmpty); + + Type = updateType; + Path = docPath; + } + + public string Path { get; private set; } + public UpdateOperation.Types.UpdateType Type { get; private set; } + public object Value { get; private set; } + + public bool HasValue + { + get { return Value != null; } + } + + public Expr GetValue(UpdateType operationType) + { + bool evaluateStringExpression = true; + if (operationType == UpdateType.ArrayAppend || operationType == UpdateType.ArrayInsert || operationType == UpdateType.ItemSet) + { + Value = ExprUtil.ParseAnonymousObject(Value) ?? Value; + if (Value is string) + { + try + { + JsonParser.Parse(Value as string); + } + catch (Exception) + { + evaluateStringExpression = false; + } + } + } + + return ExprUtil.ArgObjectToExpr(Value, false, evaluateStringExpression); + } + + public ColumnIdentifier GetSource(bool isRelational) + { + var source = Path; + + // accomodate parser's documentField() handling by removing "@" + if (source.Length > 0 && source[0] == '@') + source = source.Substring(1); + + ExprParser p = new ExprParser(source, false); + ColumnIdentifier identifier; + + if (isRelational) + identifier = p.ParseTableUpdateField(); + else + identifier = p.DocumentField().Identifier; + + if (p.tokenPos < p.tokens.Count) + throw new ArgumentException("Invalid document path."); + + return identifier; + } + + public UpdateSpec SetValue(object o) + { + Value = o; + return this; + } + } +} diff --git a/MySQL.Data/src/X/XDevAPI/Client.cs b/MySQL.Data/src/X/XDevAPI/Client.cs index bb69ed047..fc4518dfb 100644 --- a/MySQL.Data/src/X/XDevAPI/Client.cs +++ b/MySQL.Data/src/X/XDevAPI/Client.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2018, 2022, Oracle and/or its affiliates. +// Copyright © 2018, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/X/XDevAPI/Collection.cs b/MySQL.Data/src/X/XDevAPI/Collection.cs index 9c612b916..34afde110 100644 --- a/MySQL.Data/src/X/XDevAPI/Collection.cs +++ b/MySQL.Data/src/X/XDevAPI/Collection.cs @@ -1,191 +1,191 @@ -// Copyright (c) 2015, 2023, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data; -using MySql.Data.MySqlClient; -using MySqlX.XDevAPI.Common; -using MySqlX.XDevAPI.CRUD; -using System; - -namespace MySqlX.XDevAPI -{ - /// - /// Represents a collection of documents. - /// - public class Collection : Collection - { - internal Collection(Schema schema, string name) - : base(schema, name) - { - } - - #region Add Operations - - /// - /// Creates an containing the provided objects that can be used to add - /// one or more items to a collection. - /// - /// The objects to add. - /// An object containing the objects to add. - /// is null. - /// This method can take anonymous objects, domain objects, or just plain JSON strings. - /// The statement can be further modified before execution. - public new AddStatement Add(params object[] items) => base.Add(items); - - #endregion - - #region Remove Operations - - /// - /// Creates a with the given condition that can be used to remove - /// one or more documents from a collection.The statement can then be further modified before execution. - /// - /// The condition to match documents. - /// A object set with the given condition. - /// is null or white space. - /// The statement can then be further modified before execution. - public new RemoveStatement Remove(string condition) => base.Remove(condition); - - #endregion - - #region Modify Operations - - /// - /// Creates a with the given condition that can be used to modify one or more - /// documents from a collection. - /// - /// The condition to match documents. - /// A object set with the given condition. - /// is null or white space. - /// The statement can then be further modified before execution. - public new ModifyStatement Modify(string condition) => base.Modify(condition); - - /// - /// Replaces the document matching the given identifier. - /// - /// The unique identifier of the document to replace. - /// The document to replace the matching document. - /// A object containing the results of the execution. - /// is null or whitespace. - /// is null. - /// This is a direct execution method. Operation succeeds even if no matching document was found; - /// in which case, the Result.RecordsAffected property is zero. If the new document contains an identifier, the value - /// is ignored. - public Result ReplaceOne(object id, object doc) - { - if (id == null) - throw new ArgumentNullException(nameof(id)); - string stringId = id.ToString(); - if (string.IsNullOrWhiteSpace(stringId)) - throw new ArgumentNullException(nameof(id), Resources.ParameterNullOrEmpty); - if (doc == null) - throw new ArgumentNullException(nameof(doc)); - - DbDoc currentDocument = GetOne(id); - var modify = Modify("_id = :id").Bind("id", stringId); - DbDoc newDocument = doc is DbDoc ? doc as DbDoc : new DbDoc(doc); - - if (currentDocument != null) - { - // check for not matching id's - if (newDocument.HasId && !newDocument.Id.Equals(currentDocument.Id)) - throw new MySqlException(ResourcesX.ReplaceWithNoMatchingId); - - // Unset all properties - foreach (var dictionary in currentDocument.values) - if (dictionary.Key != "_id") modify.Unset(dictionary.Key); - } - - // Set new properties - foreach (var dictionary in newDocument.values) - if (dictionary.Key != "_id") modify.Set(dictionary.Key, dictionary.Value); - - return modify.Execute(); - } - #endregion - - #region Add-Modify Operations - - /// - /// Adds the given document to the collection unless the identifier or any other field that has a unique index - /// already exists, in which case it will update the matching document. - /// - /// The unique identifier of the document to replace. - /// The document to replace the matching document. - /// A object containing the results of the execution. - /// The server version is lower than 8.0.3. - /// is null or white space. - /// is null. - /// The is different from the one in . - /// This is a direct execution method. - public Result AddOrReplaceOne(object id, object doc) - { - if (!this.Session.InternalSession.GetServerVersion().isAtLeast(8, 0, 3)) - throw new MySqlException(string.Format(ResourcesX.FunctionalityNotSupported, "8.0.3")); - if (id == null) - throw new ArgumentNullException(nameof(id)); - string stringId = id.ToString(); - if (string.IsNullOrWhiteSpace(stringId)) - throw new ArgumentNullException(nameof(id), Resources.ParameterNullOrEmpty); - if (doc == null) - throw new ArgumentNullException(nameof(doc)); - - DbDoc currentDocument = GetOne(id); - DbDoc newDocument = doc is DbDoc ? doc as DbDoc : new DbDoc(doc); - - // check for not matching id's - if (currentDocument != null && newDocument.HasId - && !newDocument.Id.Equals(currentDocument.Id)) - throw new MySqlException(ResourcesX.ReplaceWithNoMatchingId); - - newDocument.Id = id; - AddStatement stmt = Add(newDocument); - stmt.upsert = true; - return stmt.Execute(); - } - #endregion - - /// - /// Creates a with the given condition, which can be used to find documents in a - /// collection. - /// - /// An optional condition to match documents. - /// A object set with the given condition. - /// The statement can then be further modified before execution. - public new FindStatement Find(string condition = null) => base.Find(condition); - - /// - /// Returns the document with the given identifier. - /// - /// The unique identifier of the document to replace. - /// A object if a document matching given identifier exists; otherwise, null. - /// is null or white space. - /// This is a direct execution method. - public new DbDoc GetOne(object id) => base.GetOne(id); - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data; +using MySql.Data.MySqlClient; +using MySqlX.XDevAPI.Common; +using MySqlX.XDevAPI.CRUD; +using System; + +namespace MySqlX.XDevAPI +{ + /// + /// Represents a collection of documents. + /// + public class Collection : Collection + { + internal Collection(Schema schema, string name) + : base(schema, name) + { + } + + #region Add Operations + + /// + /// Creates an containing the provided objects that can be used to add + /// one or more items to a collection. + /// + /// The objects to add. + /// An object containing the objects to add. + /// is null. + /// This method can take anonymous objects, domain objects, or just plain JSON strings. + /// The statement can be further modified before execution. + public new AddStatement Add(params object[] items) => base.Add(items); + + #endregion + + #region Remove Operations + + /// + /// Creates a with the given condition that can be used to remove + /// one or more documents from a collection.The statement can then be further modified before execution. + /// + /// The condition to match documents. + /// A object set with the given condition. + /// is null or white space. + /// The statement can then be further modified before execution. + public new RemoveStatement Remove(string condition) => base.Remove(condition); + + #endregion + + #region Modify Operations + + /// + /// Creates a with the given condition that can be used to modify one or more + /// documents from a collection. + /// + /// The condition to match documents. + /// A object set with the given condition. + /// is null or white space. + /// The statement can then be further modified before execution. + public new ModifyStatement Modify(string condition) => base.Modify(condition); + + /// + /// Replaces the document matching the given identifier. + /// + /// The unique identifier of the document to replace. + /// The document to replace the matching document. + /// A object containing the results of the execution. + /// is null or whitespace. + /// is null. + /// This is a direct execution method. Operation succeeds even if no matching document was found; + /// in which case, the Result.RecordsAffected property is zero. If the new document contains an identifier, the value + /// is ignored. + public Result ReplaceOne(object id, object doc) + { + if (id == null) + throw new ArgumentNullException(nameof(id)); + string stringId = id.ToString(); + if (string.IsNullOrWhiteSpace(stringId)) + throw new ArgumentNullException(nameof(id), Resources.ParameterNullOrEmpty); + if (doc == null) + throw new ArgumentNullException(nameof(doc)); + + DbDoc currentDocument = GetOne(id); + var modify = Modify("_id = :id").Bind("id", stringId); + DbDoc newDocument = doc is DbDoc ? doc as DbDoc : new DbDoc(doc); + + if (currentDocument != null) + { + // check for not matching id's + if (newDocument.HasId && !newDocument.Id.Equals(currentDocument.Id)) + throw new MySqlException(ResourcesX.ReplaceWithNoMatchingId); + + // Unset all properties + foreach (var dictionary in currentDocument.values) + if (dictionary.Key != "_id") modify.Unset(dictionary.Key); + } + + // Set new properties + foreach (var dictionary in newDocument.values) + if (dictionary.Key != "_id") modify.Set(dictionary.Key, dictionary.Value); + + return modify.Execute(); + } + #endregion + + #region Add-Modify Operations + + /// + /// Adds the given document to the collection unless the identifier or any other field that has a unique index + /// already exists, in which case it will update the matching document. + /// + /// The unique identifier of the document to replace. + /// The document to replace the matching document. + /// A object containing the results of the execution. + /// The server version is lower than 8.0.3. + /// is null or white space. + /// is null. + /// The is different from the one in . + /// This is a direct execution method. + public Result AddOrReplaceOne(object id, object doc) + { + if (!this.Session.InternalSession.GetServerVersion().isAtLeast(8, 0, 3)) + throw new MySqlException(string.Format(ResourcesX.FunctionalityNotSupported, "8.0.3")); + if (id == null) + throw new ArgumentNullException(nameof(id)); + string stringId = id.ToString(); + if (string.IsNullOrWhiteSpace(stringId)) + throw new ArgumentNullException(nameof(id), Resources.ParameterNullOrEmpty); + if (doc == null) + throw new ArgumentNullException(nameof(doc)); + + DbDoc currentDocument = GetOne(id); + DbDoc newDocument = doc is DbDoc ? doc as DbDoc : new DbDoc(doc); + + // check for not matching id's + if (currentDocument != null && newDocument.HasId + && !newDocument.Id.Equals(currentDocument.Id)) + throw new MySqlException(ResourcesX.ReplaceWithNoMatchingId); + + newDocument.Id = id; + AddStatement stmt = Add(newDocument); + stmt.upsert = true; + return stmt.Execute(); + } + #endregion + + /// + /// Creates a with the given condition, which can be used to find documents in a + /// collection. + /// + /// An optional condition to match documents. + /// A object set with the given condition. + /// The statement can then be further modified before execution. + public new FindStatement Find(string condition = null) => base.Find(condition); + + /// + /// Returns the document with the given identifier. + /// + /// The unique identifier of the document to replace. + /// A object if a document matching given identifier exists; otherwise, null. + /// is null or white space. + /// This is a direct execution method. + public new DbDoc GetOne(object id) => base.GetOne(id); + } +} diff --git a/MySQL.Data/src/X/XDevAPI/Common/BaseResult.cs b/MySQL.Data/src/X/XDevAPI/Common/BaseResult.cs index e79e2bf4d..7d13a8193 100644 --- a/MySQL.Data/src/X/XDevAPI/Common/BaseResult.cs +++ b/MySQL.Data/src/X/XDevAPI/Common/BaseResult.cs @@ -1,114 +1,114 @@ -// Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using System.Collections.Generic; -using MySqlX.Protocol; -using MySqlX.Sessions; -using System.Collections.ObjectModel; -using System; - -namespace MySqlX.XDevAPI.Common -{ - /// - /// Base abstract class that defines elements inherited by all result types. - /// - public abstract class BaseResult - { - private List _warnings = new List(); - internal ulong _recordsAffected; - internal ulong _affectedItemsCount; - internal ulong _autoIncrementValue; - internal InternalSession _session; - internal bool _hasData; - internal bool _hasMoreResults = false; - internal List _documentIds = new List(); - - /// - /// Gets the number of records affected by the statement that generated this result. - /// - public UInt64 AffectedItemsCount - { - get { return _affectedItemsCount; } - } - - internal BaseResult(InternalSession session) - { - if (session == null) return; - _session = session; - - // if we have an active resultset then we must buffer it entirely - if (session.ActiveResult != null) - { - session.ActiveResult.Buffer(); - session.ActiveResult = null; - } - - _hasData = Protocol.HasData(this); - if (_hasData) - session.ActiveResult = this; - } - - /// - /// Gets the object of the session. - /// - protected ProtocolBase Protocol - { - get { return _session?.GetProtocol(); } - } - - internal void AddWarning(WarningInfo w) - { - _warnings.Add(w); - } - - /// - /// Gets a read-only collection of objects derived from statement execution. - /// -#if NET_45_OR_GREATER - public IReadOnlyList Warnings -#else - public ReadOnlyCollection Warnings -#endif - { - get { return _warnings.AsReadOnly(); } - } - - /// - /// Gets the number of warnings in the collection derived from statement execution. - /// - public Int32 WarningsCount - { - get { return _warnings.Count; } - } - - /// - /// No action is performed by this method. It is intended to be overriden by child classes if required. - /// - protected virtual void Buffer() { } - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using System.Collections.Generic; +using MySqlX.Protocol; +using MySqlX.Sessions; +using System.Collections.ObjectModel; +using System; + +namespace MySqlX.XDevAPI.Common +{ + /// + /// Base abstract class that defines elements inherited by all result types. + /// + public abstract class BaseResult + { + private List _warnings = new List(); + internal ulong _recordsAffected; + internal ulong _affectedItemsCount; + internal ulong _autoIncrementValue; + internal InternalSession _session; + internal bool _hasData; + internal bool _hasMoreResults = false; + internal List _documentIds = new List(); + + /// + /// Gets the number of records affected by the statement that generated this result. + /// + public UInt64 AffectedItemsCount + { + get { return _affectedItemsCount; } + } + + internal BaseResult(InternalSession session) + { + if (session == null) return; + _session = session; + + // if we have an active resultset then we must buffer it entirely + if (session.ActiveResult != null) + { + session.ActiveResult.Buffer(); + session.ActiveResult = null; + } + + _hasData = Protocol.HasData(this); + if (_hasData) + session.ActiveResult = this; + } + + /// + /// Gets the object of the session. + /// + protected ProtocolBase Protocol + { + get { return _session?.GetProtocol(); } + } + + internal void AddWarning(WarningInfo w) + { + _warnings.Add(w); + } + + /// + /// Gets a read-only collection of objects derived from statement execution. + /// +#if NET_45_OR_GREATER + public IReadOnlyList Warnings +#else + public ReadOnlyCollection Warnings +#endif + { + get { return _warnings.AsReadOnly(); } + } + + /// + /// Gets the number of warnings in the collection derived from statement execution. + /// + public Int32 WarningsCount + { + get { return _warnings.Count; } + } + + /// + /// No action is performed by this method. It is intended to be overriden by child classes if required. + /// + protected virtual void Buffer() { } + } +} diff --git a/MySQL.Data/src/X/XDevAPI/Common/BaseStatement.cs b/MySQL.Data/src/X/XDevAPI/Common/BaseStatement.cs index f28f811b9..a56018d88 100644 --- a/MySQL.Data/src/X/XDevAPI/Common/BaseStatement.cs +++ b/MySQL.Data/src/X/XDevAPI/Common/BaseStatement.cs @@ -1,163 +1,163 @@ -// Copyright (c) 2015, 2023, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data; -using MySql.Data.MySqlClient; -using MySqlX.XDevAPI.Relational; -using System; -using System.Collections; -using System.Threading; -using System.Threading.Tasks; - -namespace MySqlX.XDevAPI.Common -{ - /// - /// Base abstract class for API statement. - /// - /// - /// - public abstract class BaseStatement where TResult : BaseResult - { - // Prepared statements flags - internal bool _hasChanged, _isPrepared; - protected int _stmtId; - - /// - /// Initializes a new instance of the BaseStatement class based on the specified session. - /// - /// The session where the statement will be executed. - public BaseStatement(BaseSession session) - { - Session = session; - _hasChanged = true; - } - - /// - /// Gets the that owns the statement. - /// - public BaseSession Session { get; private set; } - - /// - /// Executes the base statements. This method is intended to be defined by child classes. - /// - /// A result object containing the details of the execution. - public abstract TResult Execute(); - - /// - /// Executes a statement asynchronously. - /// - /// A result object containing the details of the execution. - public async Task ExecuteAsync() - { - return await Task.Factory.StartNew(() => - { - var result = Execute(); - if (result is BufferingResult) - { - (result as BufferingResult).FetchAll(); - } - else if (result is BufferingResult) - { - (result as BufferingResult).FetchAll(); - } - return result; - }, - CancellationToken.None, - TaskCreationOptions.None, - Session._scheduler); - } - - /// - /// Validates if the session is open and valid. - /// - protected void ValidateOpenSession() - { - if (Session.XSession.SessionState != SessionState.Open) - throw new MySqlException(ResourcesX.InvalidSession); - } - - /// - /// Sets the status as Changed for prepared statement validation. - /// - protected void SetChanged() - { - _hasChanged = true; - } - - /// - /// Converts a statement to prepared statement for a second execution - /// without any change but Bind, Limit, or Offset. - /// - protected virtual TResult ConvertToPreparedStatement(Func executeFunc, T t, IEnumerable args) - //where T : FilterableStatement - { - if (!Session.SupportsPreparedStatements) - { - // Normal execution - return executeFunc(t); - } - - if (_hasChanged) - { - if (_isPrepared) - { - // Deallocate prepared statement - Session.XSession.DeallocatePreparedStatement(_stmtId); - _isPrepared = false; - } - // Normal execution - return executeFunc(t); - } - else - { - if (!_isPrepared) - { - // Create prepared statement - try - { - _stmtId = Session.XSession.PrepareStatement(this); - _isPrepared = true; - } - catch (MySqlException ex) - when (ex.Code == 1461 // Can't create more than max_prepared_stmt_count statements - || ex.Code == 1047) // Unexpected message received - { - // Set prepared statements not supported to avoid trying it - // on following executions. - Session.SupportsPreparedStatements = false; - _isPrepared = false; - // Normal execution - return executeFunc(t); - } - } - // Execute prepared statement - return Session.XSession.ExecutePreparedStatement(_stmtId, args); - } - } - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data; +using MySql.Data.MySqlClient; +using MySqlX.XDevAPI.Relational; +using System; +using System.Collections; +using System.Threading; +using System.Threading.Tasks; + +namespace MySqlX.XDevAPI.Common +{ + /// + /// Base abstract class for API statement. + /// + /// + /// + public abstract class BaseStatement where TResult : BaseResult + { + // Prepared statements flags + internal bool _hasChanged, _isPrepared; + protected int _stmtId; + + /// + /// Initializes a new instance of the BaseStatement class based on the specified session. + /// + /// The session where the statement will be executed. + public BaseStatement(BaseSession session) + { + Session = session; + _hasChanged = true; + } + + /// + /// Gets the that owns the statement. + /// + public BaseSession Session { get; private set; } + + /// + /// Executes the base statements. This method is intended to be defined by child classes. + /// + /// A result object containing the details of the execution. + public abstract TResult Execute(); + + /// + /// Executes a statement asynchronously. + /// + /// A result object containing the details of the execution. + public async Task ExecuteAsync() + { + return await Task.Factory.StartNew(() => + { + var result = Execute(); + if (result is BufferingResult) + { + (result as BufferingResult).FetchAll(); + } + else if (result is BufferingResult) + { + (result as BufferingResult).FetchAll(); + } + return result; + }, + CancellationToken.None, + TaskCreationOptions.None, + Session._scheduler).ConfigureAwait(false); + } + + /// + /// Validates if the session is open and valid. + /// + protected void ValidateOpenSession() + { + if (Session.XSession.SessionState != SessionState.Open) + throw new MySqlException(ResourcesX.InvalidSession); + } + + /// + /// Sets the status as Changed for prepared statement validation. + /// + protected void SetChanged() + { + _hasChanged = true; + } + + /// + /// Converts a statement to prepared statement for a second execution + /// without any change but Bind, Limit, or Offset. + /// + protected virtual TResult ConvertToPreparedStatement(Func executeFunc, T t, IEnumerable args) + //where T : FilterableStatement + { + if (!Session.SupportsPreparedStatements) + { + // Normal execution + return executeFunc(t); + } + + if (_hasChanged) + { + if (_isPrepared) + { + // Deallocate prepared statement + Session.XSession.DeallocatePreparedStatement(_stmtId); + _isPrepared = false; + } + // Normal execution + return executeFunc(t); + } + else + { + if (!_isPrepared) + { + // Create prepared statement + try + { + _stmtId = Session.XSession.PrepareStatement(this); + _isPrepared = true; + } + catch (MySqlException ex) + when (ex.Code == 1461 // Can't create more than max_prepared_stmt_count statements + || ex.Code == 1047) // Unexpected message received + { + // Set prepared statements not supported to avoid trying it + // on following executions. + Session.SupportsPreparedStatements = false; + _isPrepared = false; + // Normal execution + return executeFunc(t); + } + } + // Execute prepared statement + return Session.XSession.ExecutePreparedStatement(_stmtId, args); + } + } + } +} diff --git a/MySQL.Data/src/X/XDevAPI/Common/BufferingResult.cs b/MySQL.Data/src/X/XDevAPI/Common/BufferingResult.cs index 74637c2b1..58a206a8d 100644 --- a/MySQL.Data/src/X/XDevAPI/Common/BufferingResult.cs +++ b/MySQL.Data/src/X/XDevAPI/Common/BufferingResult.cs @@ -1,242 +1,242 @@ -// Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using System; -using System.Collections; -using System.Collections.Generic; -using MySqlX.XDevAPI.Relational; -using MySqlX.Sessions; -using System.Collections.ObjectModel; -using MySql.Data; -using MySqlX; -using MySql.Data.MySqlClient; - -namespace MySqlX.XDevAPI.Common -{ - /// - /// Abstract class for buffered results. - /// - /// Generic result type. - public abstract class BufferingResult : BaseResult, IEnumerable, IEnumerator - { - /// - /// Index of the current item. - /// - protected int _position; - /// - /// List of generic items in this buffered result. - /// - protected List _items = new List(); - /// - /// Flag that indicates if all items have been read. - /// - protected bool _isComplete; - Dictionary _nameMap = new Dictionary(StringComparer.OrdinalIgnoreCase); - internal List _columns = null; - - - internal BufferingResult(InternalSession session) : base(session) - { - LoadColumnData(); - PageSize = 20; - _position = -1; - } - - /// - /// Gets a dictionary containing the column names and their index. - /// - protected Dictionary NameMap - { - get { return _nameMap; } - } - - /// - /// Gets the page size set for this buffered result. - /// - public int PageSize { get; private set; } - - /// - /// Loads the column data into the field. - /// - protected void LoadColumnData() - { - _columns = new List(); - if (_hasData) - { - _columns = Protocol.LoadColumnMetadata(); - if (_columns.Count == 0) - _hasData = false; - for (int i = 0; i < _columns.Count; i++) - _nameMap.Add(_columns[i].ColumnLabel ?? _columns[i].ColumnName, i); - } - else - Protocol.CloseResult(this); - } - - /// - /// Retrieves a read-only list of the generic items associated to this buffered result. - /// - /// A generic list representing items in this buffered result. - public ReadOnlyCollection FetchAll() - { - while (PageInItems()) ; - return _items.AsReadOnly(); - } - - internal void Dump() - { - if (_isComplete) return; - while (true) - { - if (ReadItem(true) == null) break; - } - _isComplete = true; - } - - /// - /// Retrieves one element from the generic items associated to this buffered result. - /// - /// A generic object that corresponds to the current or default item. - public T FetchOne() - { - if (!Next()) - return default(T); - return Current; - } - - /// - /// Determines if all items have already been read. - /// - /// True if all items have been retrived, false otherwise. - public bool Next() - { - _position++; - if (_position >= _items.Count) - { - if (_isComplete) return false; - if (!PageInItems()) - { - _isComplete = true; - return false; - } - } - return true; - } - - protected abstract T ReadItem(bool dumping); - - private bool PageInItems() - { - if (_isComplete) return false; - int count = 0; - for (int i = 0; i < PageSize; i++) - { - T item = ReadItem(false); - if (item == null) - { - _isComplete = !_hasData; - _session.ActiveResult = null; - break; - } - _items.Add(item); - count++; - } - return count > 0; - } - - /// - /// Gets the current item. - /// - /// All items have already been read. - public T Current - { - get - { - if (_position == _items.Count) - throw new InvalidOperationException(String.Format(ResourcesX.NoDataAtIndex, _position)); - return _items[_position]; - } - } - - object IEnumerator.Current - { - get { return this.Current; } - } - - /// - /// Determines if all items have already been read. - /// - /// True if all items have been retrived, false otherwise. - public bool MoveNext() - { - return Next(); - } - - /// - /// Resets the value of the field to zero. - /// - public void Reset() - { - _position = 0; - } - - /// - /// Gets an representation of this object. - /// - /// An representation of this object. - public IEnumerator GetEnumerator() - { - return this; - } - - /// - /// Gets an representation of this object. - /// - /// An representation of this object. - IEnumerator IEnumerable.GetEnumerator() - { - return this; - } - - /// - /// Retrieves a read-only list of the generic items associated to this buffered result. - /// - /// A generic list representing items in this buffered result. - protected override void Buffer() - { - FetchAll(); - } - - /// - /// No body has been defined for this method. - /// - public void Dispose() - { - } - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using System; +using System.Collections; +using System.Collections.Generic; +using MySqlX.XDevAPI.Relational; +using MySqlX.Sessions; +using System.Collections.ObjectModel; +using MySql.Data; +using MySqlX; +using MySql.Data.MySqlClient; + +namespace MySqlX.XDevAPI.Common +{ + /// + /// Abstract class for buffered results. + /// + /// Generic result type. + public abstract class BufferingResult : BaseResult, IEnumerable, IEnumerator + { + /// + /// Index of the current item. + /// + protected int _position; + /// + /// List of generic items in this buffered result. + /// + protected List _items = new List(); + /// + /// Flag that indicates if all items have been read. + /// + protected bool _isComplete; + Dictionary _nameMap = new Dictionary(StringComparer.OrdinalIgnoreCase); + internal List _columns = null; + + + internal BufferingResult(InternalSession session) : base(session) + { + LoadColumnData(); + PageSize = 20; + _position = -1; + } + + /// + /// Gets a dictionary containing the column names and their index. + /// + protected Dictionary NameMap + { + get { return _nameMap; } + } + + /// + /// Gets the page size set for this buffered result. + /// + public int PageSize { get; private set; } + + /// + /// Loads the column data into the field. + /// + protected void LoadColumnData() + { + _columns = new List(); + if (_hasData) + { + _columns = Protocol.LoadColumnMetadata(); + if (_columns.Count == 0) + _hasData = false; + for (int i = 0; i < _columns.Count; i++) + _nameMap.Add(_columns[i].ColumnLabel ?? _columns[i].ColumnName, i); + } + else + Protocol.CloseResult(this); + } + + /// + /// Retrieves a read-only list of the generic items associated to this buffered result. + /// + /// A generic list representing items in this buffered result. + public ReadOnlyCollection FetchAll() + { + while (PageInItems()) ; + return _items.AsReadOnly(); + } + + internal void Dump() + { + if (_isComplete) return; + while (true) + { + if (ReadItem(true) == null) break; + } + _isComplete = true; + } + + /// + /// Retrieves one element from the generic items associated to this buffered result. + /// + /// A generic object that corresponds to the current or default item. + public T FetchOne() + { + if (!Next()) + return default(T); + return Current; + } + + /// + /// Determines if all items have already been read. + /// + /// True if all items have been retrived, false otherwise. + public bool Next() + { + _position++; + if (_position >= _items.Count) + { + if (_isComplete) return false; + if (!PageInItems()) + { + _isComplete = true; + return false; + } + } + return true; + } + + protected abstract T ReadItem(bool dumping); + + private bool PageInItems() + { + if (_isComplete) return false; + int count = 0; + for (int i = 0; i < PageSize; i++) + { + T item = ReadItem(false); + if (item == null) + { + _isComplete = !_hasData; + _session.ActiveResult = null; + break; + } + _items.Add(item); + count++; + } + return count > 0; + } + + /// + /// Gets the current item. + /// + /// All items have already been read. + public T Current + { + get + { + if (_position == _items.Count) + throw new InvalidOperationException(String.Format(ResourcesX.NoDataAtIndex, _position)); + return _items[_position]; + } + } + + object IEnumerator.Current + { + get { return this.Current; } + } + + /// + /// Determines if all items have already been read. + /// + /// True if all items have been retrived, false otherwise. + public bool MoveNext() + { + return Next(); + } + + /// + /// Resets the value of the field to zero. + /// + public void Reset() + { + _position = 0; + } + + /// + /// Gets an representation of this object. + /// + /// An representation of this object. + public IEnumerator GetEnumerator() + { + return this; + } + + /// + /// Gets an representation of this object. + /// + /// An representation of this object. + IEnumerator IEnumerable.GetEnumerator() + { + return this; + } + + /// + /// Retrieves a read-only list of the generic items associated to this buffered result. + /// + /// A generic list representing items in this buffered result. + protected override void Buffer() + { + FetchAll(); + } + + /// + /// No body has been defined for this method. + /// + public void Dispose() + { + } + } +} diff --git a/MySQL.Data/src/X/XDevAPI/Common/CollectionOptions.cs b/MySQL.Data/src/X/XDevAPI/Common/CollectionOptions.cs index d15fa54e5..845ae395d 100644 --- a/MySQL.Data/src/X/XDevAPI/Common/CollectionOptions.cs +++ b/MySQL.Data/src/X/XDevAPI/Common/CollectionOptions.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2019, 2020 Oracle and/or its affiliates. +// Copyright © 2019, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -79,4 +79,4 @@ public enum ValidationLevel //Enable schema validation STRICT } -} \ No newline at end of file +} diff --git a/MySQL.Data/src/X/XDevAPI/Common/ColumnType.cs b/MySQL.Data/src/X/XDevAPI/Common/ColumnType.cs index 279c045b2..ddd964286 100644 --- a/MySQL.Data/src/X/XDevAPI/Common/ColumnType.cs +++ b/MySQL.Data/src/X/XDevAPI/Common/ColumnType.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2016, 2021, Oracle and/or its affiliates. +// Copyright © 2016, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/X/XDevAPI/Common/ErrorInfo.cs b/MySQL.Data/src/X/XDevAPI/Common/ErrorInfo.cs index 834289273..ca31f42fb 100644 --- a/MySQL.Data/src/X/XDevAPI/Common/ErrorInfo.cs +++ b/MySQL.Data/src/X/XDevAPI/Common/ErrorInfo.cs @@ -1,57 +1,57 @@ -// Copyright © 2015, 2017, Oracle and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using System; - -namespace MySqlX.XDevAPI.Common -{ - /// - /// Class to represent an error in this result. - /// - public class ErrorInfo - { - /// - /// Numeric code. - /// - public UInt32 Code; - /// - /// Return code indicating the outcome of the executed SQL statement. - /// - public string SqlState; - /// - /// Error message. - /// - public string Message; - - /// - /// Initializes a new instance of the ErrorInfo class. - /// - public ErrorInfo() - {} - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using System; + +namespace MySqlX.XDevAPI.Common +{ + /// + /// Class to represent an error in this result. + /// + public class ErrorInfo + { + /// + /// Numeric code. + /// + public UInt32 Code; + /// + /// Return code indicating the outcome of the executed SQL statement. + /// + public string SqlState; + /// + /// Error message. + /// + public string Message; + + /// + /// Initializes a new instance of the ErrorInfo class. + /// + public ErrorInfo() + {} + } +} diff --git a/MySQL.Data/src/X/XDevAPI/Common/FilterParams.cs b/MySQL.Data/src/X/XDevAPI/Common/FilterParams.cs index 0d2c30abc..35348362e 100644 --- a/MySQL.Data/src/X/XDevAPI/Common/FilterParams.cs +++ b/MySQL.Data/src/X/XDevAPI/Common/FilterParams.cs @@ -1,94 +1,94 @@ -// Copyright © 2015, 2019, Oracle and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySqlX.Protocol.X; -using Mysqlx.Crud; -using Mysqlx.Expr; -using System.Collections.Generic; -using Mysqlx.Datatypes; -using System; -using MySqlX; -using MySql.Data; - -namespace MySqlX.XDevAPI.Common -{ - internal class FilterParams - { - public long Limit = -1; - public long Offset = -1; - public string Condition; - public Dictionary Parameters = new Dictionary(); - public Dictionary placeholderNameToPosition; - public bool IsRelational; - public string[] OrderBy; - public bool hadLimit = false; - public bool hadOffset = false; - - public bool HasLimit - { - get { return Limit != -1; } - } - - public List GetOrderByExpressions(bool allowRelational) - { - return new ExprParser(ExprUtil.JoinString(OrderBy), allowRelational).ParseOrderSpec(); - } - - public Expr GetConditionExpression(bool allowRelational) - { - ExprParser parser = new ExprParser(Condition, allowRelational); - Expr expr = parser.Parse(); - if (parser.GetPositionalPlaceholderCount() > 0) - { - this.placeholderNameToPosition = parser.GetPlaceholderNameToPositionMap(); - } - return expr; - } - - public IEnumerable GetArgsExpression(Dictionary parameters) - { - if (placeholderNameToPosition == null || placeholderNameToPosition.Count == 0) - throw new ArgumentException(ResourcesX.NoPlaceholders); - - Scalar[] paramsList = new Scalar[placeholderNameToPosition.Count]; - foreach (var param in parameters) - { - if (!placeholderNameToPosition.ContainsKey(param.Key.ToLowerInvariant())) - throw new ArgumentNullException(string.Format(ResourcesX.UnknownPlaceholder, param.Key)); - paramsList[placeholderNameToPosition[param.Key.ToLowerInvariant()]] = ExprUtil.ArgObjectToScalar(param.Value) - ?? throw new ArgumentException(param.Key); - } - return paramsList; - } - - public FilterParams Clone() - { - return (FilterParams)this.MemberwiseClone(); - } - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySqlX.Protocol.X; +using Mysqlx.Crud; +using Mysqlx.Expr; +using System.Collections.Generic; +using Mysqlx.Datatypes; +using System; +using MySqlX; +using MySql.Data; + +namespace MySqlX.XDevAPI.Common +{ + internal class FilterParams + { + public long Limit = -1; + public long Offset = -1; + public string Condition; + public Dictionary Parameters = new Dictionary(); + public Dictionary placeholderNameToPosition; + public bool IsRelational; + public string[] OrderBy; + public bool hadLimit = false; + public bool hadOffset = false; + + public bool HasLimit + { + get { return Limit != -1; } + } + + public List GetOrderByExpressions(bool allowRelational) + { + return new ExprParser(ExprUtil.JoinString(OrderBy), allowRelational).ParseOrderSpec(); + } + + public Expr GetConditionExpression(bool allowRelational) + { + ExprParser parser = new ExprParser(Condition, allowRelational); + Expr expr = parser.Parse(); + if (parser.GetPositionalPlaceholderCount() > 0) + { + this.placeholderNameToPosition = parser.GetPlaceholderNameToPositionMap(); + } + return expr; + } + + public IEnumerable GetArgsExpression(Dictionary parameters) + { + if (placeholderNameToPosition == null || placeholderNameToPosition.Count == 0) + throw new ArgumentException(ResourcesX.NoPlaceholders); + + Scalar[] paramsList = new Scalar[placeholderNameToPosition.Count]; + foreach (var param in parameters) + { + if (!placeholderNameToPosition.ContainsKey(param.Key.ToLowerInvariant())) + throw new ArgumentNullException(string.Format(ResourcesX.UnknownPlaceholder, param.Key)); + paramsList[placeholderNameToPosition[param.Key.ToLowerInvariant()]] = ExprUtil.ArgObjectToScalar(param.Value) + ?? throw new ArgumentException(param.Key); + } + return paramsList; + } + + public FilterParams Clone() + { + return (FilterParams)this.MemberwiseClone(); + } + } +} diff --git a/MySQL.Data/src/X/XDevAPI/Common/FilterableStatement.cs b/MySQL.Data/src/X/XDevAPI/Common/FilterableStatement.cs index 88ff3e5bb..fa80d991a 100644 --- a/MySQL.Data/src/X/XDevAPI/Common/FilterableStatement.cs +++ b/MySQL.Data/src/X/XDevAPI/Common/FilterableStatement.cs @@ -1,202 +1,202 @@ -// Copyright (c) 2015, 2023, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data; -using MySqlX.Serialization; -using System; -using System.Collections.Generic; - -namespace MySqlX.XDevAPI.Common -{ - /// - /// Abstract class for filterable statements. - /// - /// The filterable statement. - /// The database object. - /// The type of result. - /// The type of the implemented object. - public abstract class FilterableStatement : TargetedBaseStatement - where T : FilterableStatement - where TTarget : DatabaseObject - where TResult : BaseResult - { - private FilterParams filter = new FilterParams(); - - /// - /// Initializes a new instance of the FiltarableStatement class based on the target and condition. - /// - /// The database object. - /// The optional filter condition. - public FilterableStatement(TTarget target, string condition = null) : base(target) - { - if (condition != null) - Where(condition); - } - - internal FilterParams FilterData - { - get { return filter; } - } - - /// - /// Enables the setting of Where condition for this operation. - /// - /// The Where condition. - /// The implementing statement type. - public T Where(string condition) - { - filter.Condition = condition; - SetChanged(); - return (T)this; - } - - /// - /// Sets the number of items to be returned by the operation. - /// - /// The number of items to be returned. - /// The implementing statement type. - /// is equal or lower than 0. - public T Limit(long rows) - { - if (rows <= 0) throw new ArgumentOutOfRangeException(nameof(rows), string.Format(ResourcesX.NumberNotGreaterThanZero, nameof(rows))); - filter.Limit = rows; - return (T)this; - } - - /// - /// Sets the number of items to be skipped before including them into the result. - /// - /// The number of items to be skipped. - /// The implementing statement type. - public T Offset(long rows) - { - filter.Offset = rows; - return (T)this; - } - - /// - /// Binds the parameter values in filter expression. - /// - /// The parameter name. - /// The value of the parameter. - /// A generic object representing the implementing statement type. - public T Bind(string parameterName, object value) - { - FilterData.Parameters[parameterName.ToLowerInvariant()] = value is string ? QuoteString((string)value) : value; - return (T)this; - } - - /// - /// Binds the parameter values in filter expression. - /// - /// The parameters as a DbDoc object. - /// A generic object representing the implementing statement type. - public T Bind(DbDoc dbDocParams) - { - return Bind(dbDocParams.ToString()); - } - - /// - /// Binds the parameter values in filter expression. - /// - /// The parameters as a JSON string. - /// The implementing statement type. - public T Bind(string jsonParams) - { - foreach (var item in JsonParser.Parse(jsonParams)) - { - Bind(item.Key, item.Value); - } - return (T)this; - } - - /// - /// Binds the parameter values in filter expression. - /// - /// The parameters as an anonymous object: new { param1 = value1, param2 = value2, ... }. - /// The implementing statement type. - public T Bind(object jsonParams) - { - return Bind(new DbDoc(jsonParams)); - } - - /// - /// Executes the statement. - /// - /// The function to execute. - /// The generic object to use. - /// A generic result object containing the results of the execution. - protected virtual TResult Execute(Func executeFunc, T t) - { - try - { - ValidateOpenSession(); - List parameters = new List(FilterData.Parameters.Values); - if (_isPrepared && FilterData.hadLimit != FilterData.HasLimit) - { - SetChanged(); - } - // Add the prepared statement placeholder values for limit and offset - if (!_hasChanged) - { - // Limit and offset placeholder values - if (FilterData.HasLimit) - { - parameters.Add(FilterData.Limit); - parameters.Add(FilterData.Offset == -1 ? 0 : FilterData.Offset); - } - } - var result = ConvertToPreparedStatement(executeFunc, t, parameters); - _hasChanged = false; - return result; - } - finally - { - FilterData.hadLimit = FilterData.HasLimit; - FilterData.hadOffset = FilterData.Offset != -1; - } - } - - /// - /// Clones the filterable data but Session and Target remain the - /// same. - /// - /// A clone of this filterable statement. - public virtual T Clone() - { - var t = (T)this.MemberwiseClone(); - t.filter = t.FilterData.Clone(); - return t; - } - - private static string QuoteString(string value) - { - return "'" + value.Trim().Replace("'", "\\'") + "'"; - } - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data; +using MySqlX.Serialization; +using System; +using System.Collections.Generic; + +namespace MySqlX.XDevAPI.Common +{ + /// + /// Abstract class for filterable statements. + /// + /// The filterable statement. + /// The database object. + /// The type of result. + /// The type of the implemented object. + public abstract class FilterableStatement : TargetedBaseStatement + where T : FilterableStatement + where TTarget : DatabaseObject + where TResult : BaseResult + { + private FilterParams filter = new FilterParams(); + + /// + /// Initializes a new instance of the FiltarableStatement class based on the target and condition. + /// + /// The database object. + /// The optional filter condition. + public FilterableStatement(TTarget target, string condition = null) : base(target) + { + if (condition != null) + Where(condition); + } + + internal FilterParams FilterData + { + get { return filter; } + } + + /// + /// Enables the setting of Where condition for this operation. + /// + /// The Where condition. + /// The implementing statement type. + public T Where(string condition) + { + filter.Condition = condition; + SetChanged(); + return (T)this; + } + + /// + /// Sets the number of items to be returned by the operation. + /// + /// The number of items to be returned. + /// The implementing statement type. + /// is equal or lower than 0. + public T Limit(long rows) + { + if (rows <= 0) throw new ArgumentOutOfRangeException(nameof(rows), string.Format(ResourcesX.NumberNotGreaterThanZero, nameof(rows))); + filter.Limit = rows; + return (T)this; + } + + /// + /// Sets the number of items to be skipped before including them into the result. + /// + /// The number of items to be skipped. + /// The implementing statement type. + public T Offset(long rows) + { + filter.Offset = rows; + return (T)this; + } + + /// + /// Binds the parameter values in filter expression. + /// + /// The parameter name. + /// The value of the parameter. + /// A generic object representing the implementing statement type. + public T Bind(string parameterName, object value) + { + FilterData.Parameters[parameterName.ToLowerInvariant()] = value is string ? QuoteString((string)value) : value; + return (T)this; + } + + /// + /// Binds the parameter values in filter expression. + /// + /// The parameters as a DbDoc object. + /// A generic object representing the implementing statement type. + public T Bind(DbDoc dbDocParams) + { + return Bind(dbDocParams.ToString()); + } + + /// + /// Binds the parameter values in filter expression. + /// + /// The parameters as a JSON string. + /// The implementing statement type. + public T Bind(string jsonParams) + { + foreach (var item in JsonParser.Parse(jsonParams)) + { + Bind(item.Key, item.Value); + } + return (T)this; + } + + /// + /// Binds the parameter values in filter expression. + /// + /// The parameters as an anonymous object: new { param1 = value1, param2 = value2, ... }. + /// The implementing statement type. + public T Bind(object jsonParams) + { + return Bind(new DbDoc(jsonParams)); + } + + /// + /// Executes the statement. + /// + /// The function to execute. + /// The generic object to use. + /// A generic result object containing the results of the execution. + protected virtual TResult Execute(Func executeFunc, T t) + { + try + { + ValidateOpenSession(); + List parameters = new List(FilterData.Parameters.Values); + if (_isPrepared && FilterData.hadLimit != FilterData.HasLimit) + { + SetChanged(); + } + // Add the prepared statement placeholder values for limit and offset + if (!_hasChanged) + { + // Limit and offset placeholder values + if (FilterData.HasLimit) + { + parameters.Add(FilterData.Limit); + parameters.Add(FilterData.Offset == -1 ? 0 : FilterData.Offset); + } + } + var result = ConvertToPreparedStatement(executeFunc, t, parameters); + _hasChanged = false; + return result; + } + finally + { + FilterData.hadLimit = FilterData.HasLimit; + FilterData.hadOffset = FilterData.Offset != -1; + } + } + + /// + /// Clones the filterable data but Session and Target remain the + /// same. + /// + /// A clone of this filterable statement. + public virtual T Clone() + { + var t = (T)this.MemberwiseClone(); + t.filter = t.FilterData.Clone(); + return t; + } + + private static string QuoteString(string value) + { + return "'" + value.Trim().Replace("'", "\\'") + "'"; + } + } +} diff --git a/MySQL.Data/src/X/XDevAPI/Common/QueryStatement.cs b/MySQL.Data/src/X/XDevAPI/Common/QueryStatement.cs index a8eb00f82..9286523f7 100644 --- a/MySQL.Data/src/X/XDevAPI/Common/QueryStatement.cs +++ b/MySQL.Data/src/X/XDevAPI/Common/QueryStatement.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2017, 2023, Oracle and/or its affiliates. +// Copyright © 2017, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/X/XDevAPI/Common/Result.cs b/MySQL.Data/src/X/XDevAPI/Common/Result.cs index 44d74f476..50ce51f96 100644 --- a/MySQL.Data/src/X/XDevAPI/Common/Result.cs +++ b/MySQL.Data/src/X/XDevAPI/Common/Result.cs @@ -1,60 +1,60 @@ -// Copyright (c) 2015, 2022, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySqlX.Sessions; -using System; -using System.Collections.ObjectModel; - -namespace MySqlX.XDevAPI.Common -{ - /// - /// Represents a general statement result. - /// - public class Result : BaseResult - { - internal Result(InternalSession session) : base(session) - { - if (session == null) return; - GeneratedIds = new ReadOnlyCollection(_documentIds); - session.GetProtocol().CloseResult(this); - } - - /// - /// Gets the last inserted identifier (if there is one) by the statement that generated this result. - /// - public UInt64 AutoIncrementValue - { - get { return _autoIncrementValue; } - } - - /// - /// Gets the list of generated identifiers in the order of the Add() calls. - /// - public ReadOnlyCollection GeneratedIds { get; } - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySqlX.Sessions; +using System; +using System.Collections.ObjectModel; + +namespace MySqlX.XDevAPI.Common +{ + /// + /// Represents a general statement result. + /// + public class Result : BaseResult + { + internal Result(InternalSession session) : base(session) + { + if (session == null) return; + GeneratedIds = new ReadOnlyCollection(_documentIds); + session.GetProtocol().CloseResult(this); + } + + /// + /// Gets the last inserted identifier (if there is one) by the statement that generated this result. + /// + public UInt64 AutoIncrementValue + { + get { return _autoIncrementValue; } + } + + /// + /// Gets the list of generated identifiers in the order of the Add() calls. + /// + public ReadOnlyCollection GeneratedIds { get; } + } +} diff --git a/MySQL.Data/src/X/XDevAPI/Common/TargetedBaseStatement.cs b/MySQL.Data/src/X/XDevAPI/Common/TargetedBaseStatement.cs index 27bd6308f..ec83f3dd9 100644 --- a/MySQL.Data/src/X/XDevAPI/Common/TargetedBaseStatement.cs +++ b/MySQL.Data/src/X/XDevAPI/Common/TargetedBaseStatement.cs @@ -1,55 +1,55 @@ -// Copyright (c) 2015, 2023, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -namespace MySqlX.XDevAPI.Common -{ - /// - /// Abstract class to select a database object target. - /// - /// The database object. - /// The execution result. - /// The type of the implemented object. - public abstract class TargetedBaseStatement : BaseStatement - where TTarget : DatabaseObject - where TResult : BaseResult - { - /// - /// Initializes a new instance of the TargetedBaseStatement class based on the provided target. - /// - /// The database object. - public TargetedBaseStatement(TTarget target) : base(target.Schema.Session) - { - Target = target; - } - - /// - /// Gets the database target. - /// - public TTarget Target { get; private set; } - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +namespace MySqlX.XDevAPI.Common +{ + /// + /// Abstract class to select a database object target. + /// + /// The database object. + /// The execution result. + /// The type of the implemented object. + public abstract class TargetedBaseStatement : BaseStatement + where TTarget : DatabaseObject + where TResult : BaseResult + { + /// + /// Initializes a new instance of the TargetedBaseStatement class based on the provided target. + /// + /// The database object. + public TargetedBaseStatement(TTarget target) : base(target.Schema.Session) + { + Target = target; + } + + /// + /// Gets the database target. + /// + public TTarget Target { get; private set; } + } +} diff --git a/MySQL.Data/src/X/XDevAPI/Common/WarningInfo.cs b/MySQL.Data/src/X/XDevAPI/Common/WarningInfo.cs index 6acbf8aeb..2e6877358 100644 --- a/MySQL.Data/src/X/XDevAPI/Common/WarningInfo.cs +++ b/MySQL.Data/src/X/XDevAPI/Common/WarningInfo.cs @@ -1,62 +1,62 @@ -// Copyright © 2015, 2017, Oracle and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -namespace MySqlX.XDevAPI.Common -{ - /// - /// Represents a warning in this result. - /// - public class WarningInfo - { - /// - /// Numeric value associated to the warning message. - /// - public uint Code; - - /// - /// Error message. - /// - public string Message; - - /// - /// Strict level for the warning. - /// - public uint Level; - - /// - /// Initializes a new instance of the WarningInfo class based on the code and msg. - /// - /// The code for the warning. - /// The error message for the warning. - public WarningInfo(uint code, string msg) - { - Code = code; - Message = msg; - } - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +namespace MySqlX.XDevAPI.Common +{ + /// + /// Represents a warning in this result. + /// + public class WarningInfo + { + /// + /// Numeric value associated to the warning message. + /// + public uint Code; + + /// + /// Error message. + /// + public string Message; + + /// + /// Strict level for the warning. + /// + public uint Level; + + /// + /// Initializes a new instance of the WarningInfo class based on the code and msg. + /// + /// The code for the warning. + /// The error message for the warning. + public WarningInfo(uint code, string msg) + { + Code = code; + Message = msg; + } + } +} diff --git a/MySQL.Data/src/X/XDevAPI/DatabaseObject.cs b/MySQL.Data/src/X/XDevAPI/DatabaseObject.cs index 69b59ba70..8d550665e 100644 --- a/MySQL.Data/src/X/XDevAPI/DatabaseObject.cs +++ b/MySQL.Data/src/X/XDevAPI/DatabaseObject.cs @@ -1,76 +1,76 @@ -// Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - - -using MySql.Data; -using MySql.Data.MySqlClient; - -namespace MySqlX.XDevAPI -{ - /// - /// Represents a database object. - /// - public abstract class DatabaseObject - { - internal DatabaseObject(Schema schema, string name) - { - Schema = schema; - Name = name; - } - - /// - /// Gets the session that owns the database object. - /// - public BaseSession Session - { - get { return Schema.Session; } - } - - /// - /// Gets the schema that owns the database object. - /// - public Schema Schema { get; internal set; } - - /// - /// Gets the database object name. - /// - public string Name { get; internal set; } - - /// - /// Verifies that the database object exists in the database. - /// - /// True if the object exists in database, false otherwise. - public abstract bool ExistsInDatabase(); - - protected void ValidateOpenSession() - { - if (Session.XSession.SessionState != SessionState.Open) - throw new MySqlException(ResourcesX.InvalidSession); - } - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +using MySql.Data; +using MySql.Data.MySqlClient; + +namespace MySqlX.XDevAPI +{ + /// + /// Represents a database object. + /// + public abstract class DatabaseObject + { + internal DatabaseObject(Schema schema, string name) + { + Schema = schema; + Name = name; + } + + /// + /// Gets the session that owns the database object. + /// + public BaseSession Session + { + get { return Schema.Session; } + } + + /// + /// Gets the schema that owns the database object. + /// + public Schema Schema { get; internal set; } + + /// + /// Gets the database object name. + /// + public string Name { get; internal set; } + + /// + /// Verifies that the database object exists in the database. + /// + /// True if the object exists in database, false otherwise. + public abstract bool ExistsInDatabase(); + + protected void ValidateOpenSession() + { + if (Session.XSession.SessionState != SessionState.Open) + throw new MySqlException(ResourcesX.InvalidSession); + } + } +} diff --git a/MySQL.Data/src/X/XDevAPI/DbDoc.cs b/MySQL.Data/src/X/XDevAPI/DbDoc.cs index aa8be6783..fe5fbc16b 100644 --- a/MySQL.Data/src/X/XDevAPI/DbDoc.cs +++ b/MySQL.Data/src/X/XDevAPI/DbDoc.cs @@ -1,303 +1,303 @@ -// Copyright (c) 2015, 2023, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data; -using MySqlX.Serialization; -using System; -using System.Collections; -using System.Collections.Generic; -using System.Reflection; -using System.Text; - -namespace MySqlX.XDevAPI -{ - /// - /// Represents a generic document in JSON format. - /// - public class DbDoc - { - internal Dictionary values = new Dictionary(); - - /// - /// Initializes a new instance of the DbDoc class based on the object provided. The value can be a domain object, anonymous object, or JSON string. - /// - /// The value for this DbDoc. - public DbDoc(object val = null) - { - if (val == null) - { - return; - } - - try - { - if (val is string) - values = JsonParser.Parse(val as string); - else if (val is Dictionary) - values = JsonParser.Parse(DictToString(val as Dictionary, 2)); - else if (val is DbDoc) - values = JsonParser.Parse(DictToString((val as DbDoc).values, 2)); - else - values = ParseObject(val); - } - catch (Exception exception) - { - // Throw message indicating the format of the Json document is invalid and append the message - // returned by the Json parser. - throw (new Exception(string.Format(ResourcesX.InvalidJsonDocument, exception.Message))); - } - } - - /// - /// Gets the value of a document property. - /// - /// The key path for the property. - /// - public object this[string path] - { - get { return GetValue(path); } - } - - /// - /// Gets the identifier of the document. - /// - public object Id - { - get { return values["_id"]; } - internal set { SetValue("_id", value); } - } - - /// - /// Gets a value indicating if this document has an identifier (property named _id with a value). - /// - public bool HasId - { - get { return values.ContainsKey("_id"); } - } - - //internal void EnsureId() - //{ - // if (!HasId) - // { - // char separatorChar = '-'; - // string[] token = Guid.NewGuid().ToString().Split(separatorChar); - // string guid = string.Empty; - // for (int i = token.Length-1; i >= 0; i--) - // { - // guid += token[i]; - // if (i != 0) guid += separatorChar; - // } - - // SetValue("_id", guid.Replace(separatorChar.ToString(), string.Empty)); - // } - //} - - private object GetValue(string path) - { - string[] levels = path.Split('.'); - Dictionary dic = values; - object returnValue = null; - foreach (string level in levels) - { - if (!dic.ContainsKey(level)) - throw new InvalidOperationException( - String.Format(ResourcesX.PathNotFound, path)); - if (dic[level] is Dictionary) - returnValue = dic = dic[level] as Dictionary; - else if (dic[level] == null) return null; - else if (dic[level].GetType().GetTypeInfo().IsGenericType) - returnValue = dic = ParseObject(dic[level]); - else - returnValue = dic[level]; - } - - return returnValue; - } - - /// - /// Sets a property on this document. - /// - /// The key of the property. - /// The new property value. - public void SetValue(string key, object val) - { - IList e = val as IList; - - if (e != null) - values[key] = GetArrayValues(e); - else if (val is DbDoc) - values[key] = (val as DbDoc).values; - else if (val is Dictionary) - values[key] = val; - else if (val != null && val.GetType().Namespace != "System") - values[key] = ParseObject(val); - else - values[key] = val; - } - - private Dictionary[] GetArrayValues(IEnumerable value) - { - List> values = new List>(); - foreach (object o in value) - values.Add(ParseObject(o)); - return values.ToArray(); - } - - /// - /// Returns this document in Json format. - /// - /// A Json formatted string. - public override string ToString() - { - return DictToString(values, 2); - } - - private string DictToString(Dictionary vals, int ident) - { - StringBuilder json = new StringBuilder("{"); - string delimiter = ""; - foreach (string key in vals.Keys) - { - json.Append(delimiter); - json.AppendLine(); - json.Append(' ', ident); - json.AppendFormat("\"{0}\": {1}", key, GetValue(vals[key], ident) ?? "null"); - delimiter = ", "; - } - json.AppendLine(); - json.Append(' ', ident - 2); - json.Append("}"); - return json.ToString(); - } - - private string GetValue(object val, int ident) - { - if (val == null) return null; - - if (val.GetType().IsArray) - { - - StringBuilder values = new StringBuilder("["); - string separator = string.Empty; - foreach (var item in (Array)val) - { - values.Append(separator); - values.AppendLine(); - values.Append(' ', ident + 2); - values.Append(GetValue(item, ident + 2)); - separator = ", "; - } - values.AppendLine(); - values.Append(' ', ident); - values.Append("]"); - return values.ToString(); - } - if (val is Dictionary) - return DictToString(val as Dictionary, ident + 2); - else if (val is MySqlExpression) - { - var expression = (MySqlExpression)val; - return expression.value; - } - - string quoteChar = ""; - if (val is string || val is DateTime) - { - quoteChar = "\""; - } - - return quoteChar + ( - val is bool ? - val.ToString().ToLowerInvariant() : - val is double ? - ((double)val).ToString(System.Globalization.CultureInfo.InvariantCulture) : - val.ToString() - ) + quoteChar; - } - - private bool CompareDictionaries(Dictionary dict1, Dictionary dict2) - { - IEqualityComparer valueComparer = EqualityComparer.Default; - if (dict1.Count != dict2.Count) return false; - foreach (TKey key in dict1.Keys) - { - if (!dict2.ContainsKey(key)) return false; - object val = dict1[key]; - object val2 = dict2[key]; - if (val is Dictionary[] && val2 is Dictionary[]) - { - Dictionary[] valArray1 = (Dictionary[])val; - Dictionary[] valArray2 = (Dictionary[])val2; - if (valArray1.Length != valArray2.Length) return false; - for (int i = 0; i < valArray1.Length; i++) - { - if (!CompareDictionaries(valArray1[i], valArray2[i])) return false; - } - } - else if (val is Dictionary && val2 is Dictionary) - return CompareDictionaries((Dictionary)val, (Dictionary)val2); - else if (!val.Equals(val2)) return false; - } - return true; - } - - /// - /// Compares this DbDoc with another one. - /// - /// The DbDoc to compare to. - /// True if they are equal, false otherwise. - public override bool Equals(object obj) - { - if (!(obj is DbDoc)) - throw new InvalidOperationException("DbDoc can only be compared with another DbDoc"); - DbDoc toCompare = obj as DbDoc; - return CompareDictionaries(values, toCompare.values); - } - - /// - /// Gets a value that serves as a hash function for a particular type. - /// - /// A hash code for the current object. - public override int GetHashCode() - { - return base.GetHashCode(); - } - - private Dictionary ParseObject(object val) - { - Type t = val.GetType(); - bool allProps = t.Name.Contains("Anonymous"); - Dictionary vals = new Dictionary(); - - PropertyInfo[] props = allProps ? t.GetProperties() : t.GetProperties(BindingFlags.Public); - foreach (PropertyInfo prop in props) - vals.Add(prop.Name, prop.GetValue(val, null)); - return vals; - } - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data; +using MySqlX.Serialization; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; +using System.Text; + +namespace MySqlX.XDevAPI +{ + /// + /// Represents a generic document in JSON format. + /// + public class DbDoc + { + internal Dictionary values = new Dictionary(); + + /// + /// Initializes a new instance of the DbDoc class based on the object provided. The value can be a domain object, anonymous object, or JSON string. + /// + /// The value for this DbDoc. + public DbDoc(object val = null) + { + if (val == null) + { + return; + } + + try + { + if (val is string) + values = JsonParser.Parse(val as string); + else if (val is Dictionary) + values = JsonParser.Parse(DictToString(val as Dictionary, 2)); + else if (val is DbDoc) + values = JsonParser.Parse(DictToString((val as DbDoc).values, 2)); + else + values = ParseObject(val); + } + catch (Exception exception) + { + // Throw message indicating the format of the Json document is invalid and append the message + // returned by the Json parser. + throw (new Exception(string.Format(ResourcesX.InvalidJsonDocument, exception.Message))); + } + } + + /// + /// Gets the value of a document property. + /// + /// The key path for the property. + /// + public object this[string path] + { + get { return GetValue(path); } + } + + /// + /// Gets the identifier of the document. + /// + public object Id + { + get { return values["_id"]; } + internal set { SetValue("_id", value); } + } + + /// + /// Gets a value indicating if this document has an identifier (property named _id with a value). + /// + public bool HasId + { + get { return values.ContainsKey("_id"); } + } + + //internal void EnsureId() + //{ + // if (!HasId) + // { + // char separatorChar = '-'; + // string[] token = Guid.NewGuid().ToString().Split(separatorChar); + // string guid = string.Empty; + // for (int i = token.Length-1; i >= 0; i--) + // { + // guid += token[i]; + // if (i != 0) guid += separatorChar; + // } + + // SetValue("_id", guid.Replace(separatorChar.ToString(), string.Empty)); + // } + //} + + private object GetValue(string path) + { + string[] levels = path.Split('.'); + Dictionary dic = values; + object returnValue = null; + foreach (string level in levels) + { + if (!dic.ContainsKey(level)) + throw new InvalidOperationException( + String.Format(ResourcesX.PathNotFound, path)); + if (dic[level] is Dictionary) + returnValue = dic = dic[level] as Dictionary; + else if (dic[level] == null) return null; + else if (dic[level].GetType().GetTypeInfo().IsGenericType) + returnValue = dic = ParseObject(dic[level]); + else + returnValue = dic[level]; + } + + return returnValue; + } + + /// + /// Sets a property on this document. + /// + /// The key of the property. + /// The new property value. + public void SetValue(string key, object val) + { + IList e = val as IList; + + if (e != null) + values[key] = GetArrayValues(e); + else if (val is DbDoc) + values[key] = (val as DbDoc).values; + else if (val is Dictionary) + values[key] = val; + else if (val != null && val.GetType().Namespace != "System") + values[key] = ParseObject(val); + else + values[key] = val; + } + + private Dictionary[] GetArrayValues(IEnumerable value) + { + List> values = new List>(); + foreach (object o in value) + values.Add(ParseObject(o)); + return values.ToArray(); + } + + /// + /// Returns this document in Json format. + /// + /// A Json formatted string. + public override string ToString() + { + return DictToString(values, 2); + } + + private string DictToString(Dictionary vals, int ident) + { + StringBuilder json = new StringBuilder("{"); + string delimiter = ""; + foreach (string key in vals.Keys) + { + json.Append(delimiter); + json.AppendLine(); + json.Append(' ', ident); + json.AppendFormat("\"{0}\": {1}", key, GetValue(vals[key], ident) ?? "null"); + delimiter = ", "; + } + json.AppendLine(); + json.Append(' ', ident - 2); + json.Append("}"); + return json.ToString(); + } + + private string GetValue(object val, int ident) + { + if (val == null) return null; + + if (val.GetType().IsArray) + { + + StringBuilder values = new StringBuilder("["); + string separator = string.Empty; + foreach (var item in (Array)val) + { + values.Append(separator); + values.AppendLine(); + values.Append(' ', ident + 2); + values.Append(GetValue(item, ident + 2)); + separator = ", "; + } + values.AppendLine(); + values.Append(' ', ident); + values.Append("]"); + return values.ToString(); + } + if (val is Dictionary) + return DictToString(val as Dictionary, ident + 2); + else if (val is MySqlExpression) + { + var expression = (MySqlExpression)val; + return expression.value; + } + + string quoteChar = ""; + if (val is string || val is DateTime) + { + quoteChar = "\""; + } + + return quoteChar + ( + val is bool ? + val.ToString().ToLowerInvariant() : + val is double ? + ((double)val).ToString(System.Globalization.CultureInfo.InvariantCulture) : + val.ToString() + ) + quoteChar; + } + + private bool CompareDictionaries(Dictionary dict1, Dictionary dict2) + { + IEqualityComparer valueComparer = EqualityComparer.Default; + if (dict1.Count != dict2.Count) return false; + foreach (TKey key in dict1.Keys) + { + if (!dict2.ContainsKey(key)) return false; + object val = dict1[key]; + object val2 = dict2[key]; + if (val is Dictionary[] && val2 is Dictionary[]) + { + Dictionary[] valArray1 = (Dictionary[])val; + Dictionary[] valArray2 = (Dictionary[])val2; + if (valArray1.Length != valArray2.Length) return false; + for (int i = 0; i < valArray1.Length; i++) + { + if (!CompareDictionaries(valArray1[i], valArray2[i])) return false; + } + } + else if (val is Dictionary && val2 is Dictionary) + return CompareDictionaries((Dictionary)val, (Dictionary)val2); + else if (!val.Equals(val2)) return false; + } + return true; + } + + /// + /// Compares this DbDoc with another one. + /// + /// The DbDoc to compare to. + /// True if they are equal, false otherwise. + public override bool Equals(object obj) + { + if (!(obj is DbDoc)) + throw new InvalidOperationException("DbDoc can only be compared with another DbDoc"); + DbDoc toCompare = obj as DbDoc; + return CompareDictionaries(values, toCompare.values); + } + + /// + /// Gets a value that serves as a hash function for a particular type. + /// + /// A hash code for the current object. + public override int GetHashCode() + { + return base.GetHashCode(); + } + + private Dictionary ParseObject(object val) + { + Type t = val.GetType(); + bool allProps = t.Name.Contains("Anonymous"); + Dictionary vals = new Dictionary(); + + PropertyInfo[] props = allProps ? t.GetProperties() : t.GetProperties(BindingFlags.Public); + foreach (PropertyInfo prop in props) + vals.Add(prop.Name, prop.GetValue(val, null)); + return vals; + } + } +} diff --git a/MySQL.Data/src/X/XDevAPI/GenericCollection.cs b/MySQL.Data/src/X/XDevAPI/GenericCollection.cs index d4e839c42..16443acfc 100644 --- a/MySQL.Data/src/X/XDevAPI/GenericCollection.cs +++ b/MySQL.Data/src/X/XDevAPI/GenericCollection.cs @@ -1,301 +1,301 @@ -// Copyright (c) 2015, 2023, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data; -using MySql.Data.MySqlClient; -using MySqlX.XDevAPI.Common; -using MySqlX.XDevAPI.CRUD; -using System; - -namespace MySqlX.XDevAPI -{ - /// - /// Represents a collection of documents with a generic type. - /// - /// - public class Collection : DatabaseObject - { - /// - /// Initializes a new instance of the generic Collection class based on the specified schema - /// and name. - /// - /// The object associated to this collection. - /// The name of the collection. - public Collection(Schema s, string name) : base(s, name) { } - - /// - /// Creates an containing the provided generic object. The add - /// statement can be further modified before execution. - /// - /// The generic object to add. - /// An object containing the object to add. - public AddStatement Add(params object[] items) - { - if (items == null) - throw new ArgumentNullException(); - - AddStatement stmt = new AddStatement(this); - stmt.Add(items); - return stmt; - } - - #region Remove Operations - - /// - /// Creates a with the given condition that can be used to remove - /// one or more documents from a collection.The statement can then be further modified before execution. - /// - /// The condition to match documents. - /// A object set with the given condition. - /// is null or white space. - /// The statement can then be further modified before execution. - public RemoveStatement Remove(string condition) - { - if (string.IsNullOrWhiteSpace(condition)) - throw new ArgumentNullException(nameof(condition), Resources.ParameterNullOrEmpty); - - RemoveStatement stmt = new RemoveStatement(this, condition); - return stmt; - } - - /// - /// Removes the document with the given identifier. - /// - /// The unique identifier of the document to replace. - /// A object containing the results of the execution. - /// is null or white space. - /// This is a direct execution method. - public Result RemoveOne(object id) - { - if (id == null) - throw new ArgumentNullException(nameof(id)); - string stringId = id.ToString(); - if (string.IsNullOrWhiteSpace(stringId)) - throw new ArgumentNullException(nameof(id), Resources.ParameterNullOrEmpty); - - return Remove("_id = :id").Bind("id", id).Execute(); - } - - #endregion - - #region Modify Operations - - /// - /// Creates a with the given condition that can be used to modify one or more - /// documents from a collection. - /// - /// The condition to match documents. - /// A object set with the given condition. - /// is null or white space. - /// The statement can then be further modified before execution. - public ModifyStatement Modify(string condition) - { - if (string.IsNullOrWhiteSpace(condition)) - throw new ArgumentNullException(nameof(condition), Resources.ParameterNullOrEmpty); - - ModifyStatement stmt = new ModifyStatement(this, condition); - return stmt; - } - #endregion - - /// - /// Returns the number of documents in this collection on the server. - /// - /// The number of documents found. - public long Count() - { - long result = 0; - try - { - ValidateOpenSession(); - result = Session.XSession.TableCount(Schema, Name, "Collection"); - } - catch (MySqlException ex) - { - switch (ex.Number) - { - case (int)CloseNotification.IDLE: - case (int)CloseNotification.KILLED: - case (int)CloseNotification.SHUTDOWN: - XDevAPI.Session.ThrowSessionClosedByServerException(ex, Session); - break; - default: - throw; - } - } - return result; - } - - /// - /// Creates a with the given condition which can be used to find documents in a - /// collection. - /// - /// An optional condition to match documents. - /// A object set with the given condition. - /// The statement can then be further modified before execution. - public FindStatement Find(string condition = null) - { - FindStatement stmt = new FindStatement(this, condition); - return stmt; - } - - /// - /// Creates an index based on the properties provided in the JSON document. - /// - /// The index name. - /// JSON document describing the index to be created. - /// - /// is a JSON document with the following fields: - /// - /// - fields: array of IndexField objects, each describing a single document member to be - /// included in the index (see below). - /// - type: string, (optional) the type of index. One of INDEX or SPATIAL. Default is INDEX and may - /// be omitted. - /// - ///   - /// A single IndexField description consists of the following fields: - /// - /// - field: string, the full document path to the document member or field to be indexed. - /// - type: string, one of the supported SQL column types to map the field into (see the following list). - /// For numeric types, the optional UNSIGNED keyword may follow. For the TEXT type, the length to consider for - /// indexing may be added. - /// - required: bool, (optional) true if the field is required to exist in the document. defaults to - /// false, except for GEOJSON where it defaults to true. - /// - options: int, (optional) special option flags for use when decoding GEOJSON data. - /// - srid: int, (optional) srid value for use when decoding GEOJSON data. - /// - ///   - /// Supported SQL column types: - /// - /// - INT [UNSIGNED] - /// - TINYINT [UNSIGNED] - /// - SMALLINT[UNSIGNED] - /// - MEDIUMINT [UNSIGNED] - /// - INTEGER [UNSIGNED] - /// - BIGINT [UNSIGNED] - /// - REAL [UNSIGNED] - /// - FLOAT [UNSIGNED] - /// - DOUBLE [UNSIGNED] - /// - DECIMAL [UNSIGNED] - /// - NUMERIC [UNSIGNED] - /// - DATE - /// - TIME - /// - TIMESTAMP - /// - DATETIME - /// - TEXT[(length)] - /// - CHAR[(lenght)] - /// - GEOJSON (extra options: options, srid) - /// - /// - public void CreateIndex(string indexName, object indexDefinition) - { - new CreateCollectionIndexStatement(this, indexName, new DbDoc(indexDefinition)).Execute(); - } - - /// - /// Drops a collection index. - /// - /// The index name. - /// is null or white space. - public void DropIndex(string indexName) - { - if (string.IsNullOrWhiteSpace(indexName)) throw new ArgumentNullException(nameof(indexName)); - - ValidateOpenSession(); - - try - { - bool indexExists = Convert.ToInt32(Session.XSession.ExecuteQueryAsScalar( - string.Format("SELECT COUNT(*)>0 FROM information_schema.statistics WHERE table_schema = '{0}' AND table_name = '{1}' AND index_name = '{2}'", - this.Schema.Name, this.Name, indexName))) == 1; - if (!indexExists) return; - - Session.XSession.DropCollectionIndex(this.Schema.Name, this.Name, indexName); - } - catch (MySqlException ex) - { - switch (ex.Number) - { - case (int)CloseNotification.IDLE: - case (int)CloseNotification.KILLED: - case (int)CloseNotification.SHUTDOWN: - XDevAPI.Session.ThrowSessionClosedByServerException(ex, Session); - break; - default: - throw; - } - } - } - - /// - /// Verifies if the current collection exists in the server schema. - /// - /// true if the collection exists; otherwise, false. - public override bool ExistsInDatabase() - { - bool result = false; - try - { - ValidateOpenSession(); - result = Session.XSession.TableExists(Schema, Name); - } - catch (MySqlException ex) - { - switch (ex.Number) - { - case (int)CloseNotification.IDLE: - case (int)CloseNotification.KILLED: - case (int)CloseNotification.SHUTDOWN: - XDevAPI.Session.ThrowSessionClosedByServerException(ex, Session); - break; - default: - throw; - } - } - return result; - } - - /// - /// Returns the document with the given identifier. - /// - /// The unique identifier of the document to replace. - /// A object if a document matching given identifier exists; otherwise, null. - /// is null or white space. - /// This is a direct execution method. - public T GetOne(object id) - { - if (id == null) - throw new ArgumentNullException(nameof(id)); - string stringId = id.ToString(); - if (string.IsNullOrWhiteSpace(stringId)) - throw new ArgumentNullException(nameof(id), Resources.ParameterNullOrEmpty); - - return Find("_id = :id").Bind("id", id).Execute().FetchOne(); - } - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data; +using MySql.Data.MySqlClient; +using MySqlX.XDevAPI.Common; +using MySqlX.XDevAPI.CRUD; +using System; + +namespace MySqlX.XDevAPI +{ + /// + /// Represents a collection of documents with a generic type. + /// + /// + public class Collection : DatabaseObject + { + /// + /// Initializes a new instance of the generic Collection class based on the specified schema + /// and name. + /// + /// The object associated to this collection. + /// The name of the collection. + public Collection(Schema s, string name) : base(s, name) { } + + /// + /// Creates an containing the provided generic object. The add + /// statement can be further modified before execution. + /// + /// The generic object to add. + /// An object containing the object to add. + public AddStatement Add(params object[] items) + { + if (items == null) + throw new ArgumentNullException(); + + AddStatement stmt = new AddStatement(this); + stmt.Add(items); + return stmt; + } + + #region Remove Operations + + /// + /// Creates a with the given condition that can be used to remove + /// one or more documents from a collection.The statement can then be further modified before execution. + /// + /// The condition to match documents. + /// A object set with the given condition. + /// is null or white space. + /// The statement can then be further modified before execution. + public RemoveStatement Remove(string condition) + { + if (string.IsNullOrWhiteSpace(condition)) + throw new ArgumentNullException(nameof(condition), Resources.ParameterNullOrEmpty); + + RemoveStatement stmt = new RemoveStatement(this, condition); + return stmt; + } + + /// + /// Removes the document with the given identifier. + /// + /// The unique identifier of the document to replace. + /// A object containing the results of the execution. + /// is null or white space. + /// This is a direct execution method. + public Result RemoveOne(object id) + { + if (id == null) + throw new ArgumentNullException(nameof(id)); + string stringId = id.ToString(); + if (string.IsNullOrWhiteSpace(stringId)) + throw new ArgumentNullException(nameof(id), Resources.ParameterNullOrEmpty); + + return Remove("_id = :id").Bind("id", id).Execute(); + } + + #endregion + + #region Modify Operations + + /// + /// Creates a with the given condition that can be used to modify one or more + /// documents from a collection. + /// + /// The condition to match documents. + /// A object set with the given condition. + /// is null or white space. + /// The statement can then be further modified before execution. + public ModifyStatement Modify(string condition) + { + if (string.IsNullOrWhiteSpace(condition)) + throw new ArgumentNullException(nameof(condition), Resources.ParameterNullOrEmpty); + + ModifyStatement stmt = new ModifyStatement(this, condition); + return stmt; + } + #endregion + + /// + /// Returns the number of documents in this collection on the server. + /// + /// The number of documents found. + public long Count() + { + long result = 0; + try + { + ValidateOpenSession(); + result = Session.XSession.TableCount(Schema, Name, "Collection"); + } + catch (MySqlException ex) + { + switch (ex.Number) + { + case (int)CloseNotification.IDLE: + case (int)CloseNotification.KILLED: + case (int)CloseNotification.SHUTDOWN: + XDevAPI.Session.ThrowSessionClosedByServerException(ex, Session); + break; + default: + throw; + } + } + return result; + } + + /// + /// Creates a with the given condition which can be used to find documents in a + /// collection. + /// + /// An optional condition to match documents. + /// A object set with the given condition. + /// The statement can then be further modified before execution. + public FindStatement Find(string condition = null) + { + FindStatement stmt = new FindStatement(this, condition); + return stmt; + } + + /// + /// Creates an index based on the properties provided in the JSON document. + /// + /// The index name. + /// JSON document describing the index to be created. + /// + /// is a JSON document with the following fields: + /// + /// - fields: array of IndexField objects, each describing a single document member to be + /// included in the index (see below). + /// - type: string, (optional) the type of index. One of INDEX or SPATIAL. Default is INDEX and may + /// be omitted. + /// + ///   + /// A single IndexField description consists of the following fields: + /// + /// - field: string, the full document path to the document member or field to be indexed. + /// - type: string, one of the supported SQL column types to map the field into (see the following list). + /// For numeric types, the optional UNSIGNED keyword may follow. For the TEXT type, the length to consider for + /// indexing may be added. + /// - required: bool, (optional) true if the field is required to exist in the document. defaults to + /// false, except for GEOJSON where it defaults to true. + /// - options: int, (optional) special option flags for use when decoding GEOJSON data. + /// - srid: int, (optional) srid value for use when decoding GEOJSON data. + /// + ///   + /// Supported SQL column types: + /// + /// - INT [UNSIGNED] + /// - TINYINT [UNSIGNED] + /// - SMALLINT[UNSIGNED] + /// - MEDIUMINT [UNSIGNED] + /// - INTEGER [UNSIGNED] + /// - BIGINT [UNSIGNED] + /// - REAL [UNSIGNED] + /// - FLOAT [UNSIGNED] + /// - DOUBLE [UNSIGNED] + /// - DECIMAL [UNSIGNED] + /// - NUMERIC [UNSIGNED] + /// - DATE + /// - TIME + /// - TIMESTAMP + /// - DATETIME + /// - TEXT[(length)] + /// - CHAR[(lenght)] + /// - GEOJSON (extra options: options, srid) + /// + /// + public void CreateIndex(string indexName, object indexDefinition) + { + new CreateCollectionIndexStatement(this, indexName, new DbDoc(indexDefinition)).Execute(); + } + + /// + /// Drops a collection index. + /// + /// The index name. + /// is null or white space. + public void DropIndex(string indexName) + { + if (string.IsNullOrWhiteSpace(indexName)) throw new ArgumentNullException(nameof(indexName)); + + ValidateOpenSession(); + + try + { + bool indexExists = Convert.ToInt32(Session.XSession.ExecuteQueryAsScalar( + string.Format("SELECT COUNT(*)>0 FROM information_schema.statistics WHERE table_schema = '{0}' AND table_name = '{1}' AND index_name = '{2}'", + this.Schema.Name, this.Name, indexName))) == 1; + if (!indexExists) return; + + Session.XSession.DropCollectionIndex(this.Schema.Name, this.Name, indexName); + } + catch (MySqlException ex) + { + switch (ex.Number) + { + case (int)CloseNotification.IDLE: + case (int)CloseNotification.KILLED: + case (int)CloseNotification.SHUTDOWN: + XDevAPI.Session.ThrowSessionClosedByServerException(ex, Session); + break; + default: + throw; + } + } + } + + /// + /// Verifies if the current collection exists in the server schema. + /// + /// true if the collection exists; otherwise, false. + public override bool ExistsInDatabase() + { + bool result = false; + try + { + ValidateOpenSession(); + result = Session.XSession.TableExists(Schema, Name); + } + catch (MySqlException ex) + { + switch (ex.Number) + { + case (int)CloseNotification.IDLE: + case (int)CloseNotification.KILLED: + case (int)CloseNotification.SHUTDOWN: + XDevAPI.Session.ThrowSessionClosedByServerException(ex, Session); + break; + default: + throw; + } + } + return result; + } + + /// + /// Returns the document with the given identifier. + /// + /// The unique identifier of the document to replace. + /// A object if a document matching given identifier exists; otherwise, null. + /// is null or white space. + /// This is a direct execution method. + public T GetOne(object id) + { + if (id == null) + throw new ArgumentNullException(nameof(id)); + string stringId = id.ToString(); + if (string.IsNullOrWhiteSpace(stringId)) + throw new ArgumentNullException(nameof(id), Resources.ParameterNullOrEmpty); + + return Find("_id = :id").Bind("id", id).Execute().FetchOne(); + } + } +} diff --git a/MySQL.Data/src/X/XDevAPI/Iterator.cs b/MySQL.Data/src/X/XDevAPI/Iterator.cs index 81a6c1443..e4b2d1fd8 100644 --- a/MySQL.Data/src/X/XDevAPI/Iterator.cs +++ b/MySQL.Data/src/X/XDevAPI/Iterator.cs @@ -1,16 +1,16 @@ -// Copyright © 2015, 2017, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2015, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/X/XDevAPI/MySqlExpression.cs b/MySQL.Data/src/X/XDevAPI/MySqlExpression.cs index dc740c116..0b7167c0f 100644 --- a/MySQL.Data/src/X/XDevAPI/MySqlExpression.cs +++ b/MySQL.Data/src/X/XDevAPI/MySqlExpression.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2017, 2021, Oracle and/or its affiliates. +// Copyright © 2017, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/X/XDevAPI/MySqlX.cs b/MySQL.Data/src/X/XDevAPI/MySqlX.cs index aab91be04..a395cf4a0 100644 --- a/MySQL.Data/src/X/XDevAPI/MySqlX.cs +++ b/MySQL.Data/src/X/XDevAPI/MySqlX.cs @@ -1,147 +1,147 @@ -// Copyright (c) 2015, 2022, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -namespace MySqlX.XDevAPI -{ - - /// - /// Main class for session operations related to Connector/NET implementation of the X DevAPI. - /// - - public class MySQLX - { - /// - /// Opens a session to the server given or to the first available server if multiple servers were specified. - /// - /// The connection string or URI string format. - /// - /// A object representing the established session. - /// Multiple hosts can be specified as part of the which - /// will enable client side failover when trying to establish a connection. For additional details and syntax - /// examples refer to the remarks section. - public static Session GetSession(string connectionString) - { - return new Session(connectionString); - } - - /// - /// Opens a session to the server given. - /// - /// The connection data for the server. - /// - /// A object representing the established session. - public static Session GetSession(object connectionData) - { - return new Session(connectionData); - } - - /// - /// Creates a new instance. - /// - /// The connection string or URI string format. - /// - /// The connection options in JSON string format. - /// A object representing a session pool. - public static Client GetClient(string connectionString, string connectionOptions) - { - return new Client(connectionString, connectionOptions); - } - - /// - /// Creates a new instance. - /// - /// The connection string or URI string format. - /// - /// The connection options in object format. - /// - /// - /// new { pooling = new - /// { - /// enabled = true, - /// maxSize = 15, - /// maxIdleTime = 60000, - /// queueTimeout = 60000 - /// } - /// } - /// - /// - /// - /// A object representing a session pool. - public static Client GetClient(string connectionString, object connectionOptions) - { - return new Client(connectionString, connectionOptions); - } - - /// - /// Creates a new instance. - /// - /// The connection data. - /// - /// The connection options in JSON string format. - /// A object representing a session pool. - public static Client GetClient(object connectionData, string connectionOptions) - { - return new Client(connectionData, connectionOptions); - } - - /// - /// Creates a new instance. - /// - /// The connection data. - /// - /// The connection options in object format. - /// - /// - /// new { pooling = new - /// { - /// enabled = true, - /// maxSize = 15, - /// maxIdleTime = 60000, - /// queueTimeout = 60000 - /// } - /// } - /// - /// - /// - /// A object representing a session pool. - public static Client GetClient(object connectionData, object connectionOptions) - { - return new Client(connectionData, connectionOptions); - } - - //public static Iterator CsvFileRowIterator() - //{ - // throw new NotImplementedException(); - //} - - //public static Iterator JsonFileDocIterator() - //{ - // throw new NotImplementedException(); - //} - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +namespace MySqlX.XDevAPI +{ + + /// + /// Main class for session operations related to Connector/NET implementation of the X DevAPI. + /// + + public class MySQLX + { + /// + /// Opens a session to the server given or to the first available server if multiple servers were specified. + /// + /// The connection string or URI string format. + /// + /// A object representing the established session. + /// Multiple hosts can be specified as part of the which + /// will enable client side failover when trying to establish a connection. For additional details and syntax + /// examples refer to the remarks section. + public static Session GetSession(string connectionString) + { + return new Session(connectionString); + } + + /// + /// Opens a session to the server given. + /// + /// The connection data for the server. + /// + /// A object representing the established session. + public static Session GetSession(object connectionData) + { + return new Session(connectionData); + } + + /// + /// Creates a new instance. + /// + /// The connection string or URI string format. + /// + /// The connection options in JSON string format. + /// A object representing a session pool. + public static Client GetClient(string connectionString, string connectionOptions) + { + return new Client(connectionString, connectionOptions); + } + + /// + /// Creates a new instance. + /// + /// The connection string or URI string format. + /// + /// The connection options in object format. + /// + /// + /// new { pooling = new + /// { + /// enabled = true, + /// maxSize = 15, + /// maxIdleTime = 60000, + /// queueTimeout = 60000 + /// } + /// } + /// + /// + /// + /// A object representing a session pool. + public static Client GetClient(string connectionString, object connectionOptions) + { + return new Client(connectionString, connectionOptions); + } + + /// + /// Creates a new instance. + /// + /// The connection data. + /// + /// The connection options in JSON string format. + /// A object representing a session pool. + public static Client GetClient(object connectionData, string connectionOptions) + { + return new Client(connectionData, connectionOptions); + } + + /// + /// Creates a new instance. + /// + /// The connection data. + /// + /// The connection options in object format. + /// + /// + /// new { pooling = new + /// { + /// enabled = true, + /// maxSize = 15, + /// maxIdleTime = 60000, + /// queueTimeout = 60000 + /// } + /// } + /// + /// + /// + /// A object representing a session pool. + public static Client GetClient(object connectionData, object connectionOptions) + { + return new Client(connectionData, connectionOptions); + } + + //public static Iterator CsvFileRowIterator() + //{ + // throw new NotImplementedException(); + //} + + //public static Iterator JsonFileDocIterator() + //{ + // throw new NotImplementedException(); + //} + } +} diff --git a/MySQL.Data/src/X/XDevAPI/MySqlXConnectionStringBuilder.cs b/MySQL.Data/src/X/XDevAPI/MySqlXConnectionStringBuilder.cs index 9ceeff51a..7e4177f2f 100644 --- a/MySQL.Data/src/X/XDevAPI/MySqlXConnectionStringBuilder.cs +++ b/MySQL.Data/src/X/XDevAPI/MySqlXConnectionStringBuilder.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2019, 2022, Oracle and/or its affiliates. +// Copyright © 2019, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/X/XDevAPI/Relational/Column.cs b/MySQL.Data/src/X/XDevAPI/Relational/Column.cs index 2aabe71cf..d9a550478 100644 --- a/MySQL.Data/src/X/XDevAPI/Relational/Column.cs +++ b/MySQL.Data/src/X/XDevAPI/Relational/Column.cs @@ -1,109 +1,109 @@ -// Copyright © 2015, 2017, Oracle and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using System; -using MySqlX.Protocol; -using MySqlX.Data; -using MySql.Data.MySqlClient; -using MySql.Data.MySqlClient.X.XDevAPI.Common; - -namespace MySqlX.XDevAPI.Relational -{ - /// - /// Represents a table column. - /// - public class Column - { - internal ValueDecoder _decoder; - internal UInt64 _collationNumber; - - /// - /// Gets the original column name. - /// - public string ColumnName { get; internal set; } - /// - /// Gets the alias of the column name. - /// - public string ColumnLabel { get; internal set; } - /// - /// Gets the table name the column orginates from. - /// - public string TableName { get; internal set; } - /// - /// Gets the alias of the table name . - /// - public string TableLabel { get; internal set; } - /// - /// Gets the schema name the column originates from. - /// - public string SchemaName { get; internal set; } - /// - /// Gets the catalog the schema originates from. - /// In MySQL protocol this is `def` by default. - /// - public string DatabaseName { get; internal set; } - /// - /// Gets the collation used for this column. - /// - public string CollationName { get; internal set; } - /// - /// Gets the character set used for this column. - /// - public string CharacterSetName { get; internal set; } - /// - /// Gets the column length. - /// - public UInt32 Length { get; internal set; } - /// - /// Gets the fractional decimal digits for floating point and fixed point numbers. - /// - public UInt32 FractionalDigits { get; internal set; } - /// - /// Gets the Mysql data type. - /// - public ColumnType Type { get; internal set; } - /// - /// Gets the .NET Clr data type. - /// - public Type ClrType { get; internal set; } - /// - /// True if it's a signed number. - /// - public bool IsNumberSigned { get; internal set; } - /// - /// True if column is UINT zerofill or BYTES rightpad. - /// - public bool IsPadded { get; internal set; } - - /// - /// Initializes a new instance of the Column class. - /// - public Column() - {} - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using System; +using MySqlX.Protocol; +using MySqlX.Data; +using MySql.Data.MySqlClient; +using MySql.Data.MySqlClient.X.XDevAPI.Common; + +namespace MySqlX.XDevAPI.Relational +{ + /// + /// Represents a table column. + /// + public class Column + { + internal ValueDecoder _decoder; + internal UInt64 _collationNumber; + + /// + /// Gets the original column name. + /// + public string ColumnName { get; internal set; } + /// + /// Gets the alias of the column name. + /// + public string ColumnLabel { get; internal set; } + /// + /// Gets the table name the column orginates from. + /// + public string TableName { get; internal set; } + /// + /// Gets the alias of the table name . + /// + public string TableLabel { get; internal set; } + /// + /// Gets the schema name the column originates from. + /// + public string SchemaName { get; internal set; } + /// + /// Gets the catalog the schema originates from. + /// In MySQL protocol this is `def` by default. + /// + public string DatabaseName { get; internal set; } + /// + /// Gets the collation used for this column. + /// + public string CollationName { get; internal set; } + /// + /// Gets the character set used for this column. + /// + public string CharacterSetName { get; internal set; } + /// + /// Gets the column length. + /// + public UInt32 Length { get; internal set; } + /// + /// Gets the fractional decimal digits for floating point and fixed point numbers. + /// + public UInt32 FractionalDigits { get; internal set; } + /// + /// Gets the Mysql data type. + /// + public ColumnType Type { get; internal set; } + /// + /// Gets the .NET Clr data type. + /// + public Type ClrType { get; internal set; } + /// + /// True if it's a signed number. + /// + public bool IsNumberSigned { get; internal set; } + /// + /// True if column is UINT zerofill or BYTES rightpad. + /// + public bool IsPadded { get; internal set; } + + /// + /// Initializes a new instance of the Column class. + /// + public Column() + {} + } +} diff --git a/MySQL.Data/src/X/XDevAPI/Relational/InternalRowResult.cs b/MySQL.Data/src/X/XDevAPI/Relational/InternalRowResult.cs index b689dff59..fe66dcf40 100644 --- a/MySQL.Data/src/X/XDevAPI/Relational/InternalRowResult.cs +++ b/MySQL.Data/src/X/XDevAPI/Relational/InternalRowResult.cs @@ -1,140 +1,140 @@ -// Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using MySqlX.XDevAPI.Common; -using MySqlX.Sessions; -using MySql.Data.MySqlClient; -using System.Collections.ObjectModel; -using System.Linq; - -namespace MySqlX.XDevAPI.Relational -{ - /// - /// Represents a resultset that contains rows of data. - /// - public class InternalRowResult : BufferingResult - { - internal InternalRowResult(InternalSession session) : base(session) - { - } - - /// - /// Gets the columns in this resultset. - /// -#if NET_45_OR_GREATER - public IReadOnlyList Columns -#else - public ReadOnlyCollection Columns -#endif - { - get { return _columns.AsReadOnly(); } - } - - /// - /// Gets the number of columns in this resultset. - /// - public Int32 ColumnCount - { - get { return _columns.Count; } - } - - /// - /// Gets a list containing the column names in this resultset. - /// - public List ColumnNames - { - get { return _columns.Select(o => o.ColumnLabel).ToList(); } - } - - /// - /// Gets the rows of this resultset. This collection will be incomplete unless all the rows have been read - /// either by using the Next method or the Buffer method. - /// -#if NET_45_OR_GREATER - public IReadOnlyList Rows -#else - public ReadOnlyCollection Rows -#endif - { - get { return _items.AsReadOnly(); } - } - - /// - /// Gets the value of the column value at the current index. - /// - /// The column index. - /// The CLR value at the column index. - public object this[int index] - { - get { return GetValue(index); } - } - - /// - /// Allows getting the value of the column value at the current index. - /// - /// The column index. - /// The CLR value at the column index. - private object GetValue(int index) - { - if (_position == _items.Count) - throw new InvalidOperationException("No data at position"); - return _items[_position][index]; - } - - /// - /// Returns the index of the given column name. - /// - /// The name of the column to find. - /// The numeric index of column. - public int IndexOf(string name) - { - if (!NameMap.ContainsKey(name)) - throw new MySqlException("Column not found '" + name + "'"); - return NameMap[name]; - } - - protected override Row ReadItem(bool dumping) - { - ///TODO: fix this - List values = Protocol.ReadRow(this); - if (values == null) return null; - if (dumping) return new Row(NameMap, null); - - Debug.Assert(values.Count == _columns.Count, "Value count does not equal column count"); - object[] clrValues = new object[values.Count]; - for (int i = 0; i < values.Count; i++) - clrValues[i] = Columns[i]._decoder.ClrValueDecoder(values[i]); - - Row row = new Row(NameMap, clrValues); - return row; - } - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using MySqlX.XDevAPI.Common; +using MySqlX.Sessions; +using MySql.Data.MySqlClient; +using System.Collections.ObjectModel; +using System.Linq; + +namespace MySqlX.XDevAPI.Relational +{ + /// + /// Represents a resultset that contains rows of data. + /// + public class InternalRowResult : BufferingResult + { + internal InternalRowResult(InternalSession session) : base(session) + { + } + + /// + /// Gets the columns in this resultset. + /// +#if NET_45_OR_GREATER + public IReadOnlyList Columns +#else + public ReadOnlyCollection Columns +#endif + { + get { return _columns.AsReadOnly(); } + } + + /// + /// Gets the number of columns in this resultset. + /// + public Int32 ColumnCount + { + get { return _columns.Count; } + } + + /// + /// Gets a list containing the column names in this resultset. + /// + public List ColumnNames + { + get { return _columns.Select(o => o.ColumnLabel).ToList(); } + } + + /// + /// Gets the rows of this resultset. This collection will be incomplete unless all the rows have been read + /// either by using the Next method or the Buffer method. + /// +#if NET_45_OR_GREATER + public IReadOnlyList Rows +#else + public ReadOnlyCollection Rows +#endif + { + get { return _items.AsReadOnly(); } + } + + /// + /// Gets the value of the column value at the current index. + /// + /// The column index. + /// The CLR value at the column index. + public object this[int index] + { + get { return GetValue(index); } + } + + /// + /// Allows getting the value of the column value at the current index. + /// + /// The column index. + /// The CLR value at the column index. + private object GetValue(int index) + { + if (_position == _items.Count) + throw new InvalidOperationException("No data at position"); + return _items[_position][index]; + } + + /// + /// Returns the index of the given column name. + /// + /// The name of the column to find. + /// The numeric index of column. + public int IndexOf(string name) + { + if (!NameMap.ContainsKey(name)) + throw new MySqlException("Column not found '" + name + "'"); + return NameMap[name]; + } + + protected override Row ReadItem(bool dumping) + { + ///TODO: fix this + List values = Protocol.ReadRow(this); + if (values == null) return null; + if (dumping) return new Row(NameMap, null); + + Debug.Assert(values.Count == _columns.Count, "Value count does not equal column count"); + object[] clrValues = new object[values.Count]; + for (int i = 0; i < values.Count; i++) + clrValues[i] = Columns[i]._decoder.ClrValueDecoder(values[i]); + + Row row = new Row(NameMap, clrValues); + return row; + } + } +} diff --git a/MySQL.Data/src/X/XDevAPI/Relational/Row.cs b/MySQL.Data/src/X/XDevAPI/Relational/Row.cs index 25c22d17a..f54157d5b 100644 --- a/MySQL.Data/src/X/XDevAPI/Relational/Row.cs +++ b/MySQL.Data/src/X/XDevAPI/Relational/Row.cs @@ -1,97 +1,97 @@ -// Copyright © 2015, 2017, Oracle and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data; -using MySqlX; -using System; -using System.Collections.Generic; - -namespace MySqlX.XDevAPI.Relational -{ - /// - /// Represents a single row of data in a table. - /// - public class Row - { - private object[] _values; - private Dictionary _nameMap; - - internal Row(Dictionary nameMap, object[] values) - { - _values = values; - _nameMap = nameMap; - } - - /// - /// Gets the value of the row at the given index. - /// - /// The column index to retrieve the value. - /// The value at the index. - public object this[int index] - { - get { return GetValue(index); } - } - - /// - /// Gets the value of the column as a string. - /// - /// The name of the column. - /// The value of the column as a string. - public string GetString(string name) - { - return GetValue(name).ToString(); - } - - /// - /// Gets a string based indexer into the row. Returns the value as a CLR type. - /// - /// The column index to get. - /// The CLR value for the column. - public object this[string name] - { - get - { - return GetValue(name); - } - } - - private object GetValue(int index) - { - if (index < 0 || index >= _values.Length) - throw new IndexOutOfRangeException(String.Format(ResourcesX.InvalidRowIndex, index)); - return _values[index]; - } - - private object GetValue(string name) - { - if (!_nameMap.ContainsKey(name)) - throw new InvalidOperationException(String.Format(ResourcesX.InvalidNameIndex, name)); - return GetValue(_nameMap[name]); - } - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data; +using MySqlX; +using System; +using System.Collections.Generic; + +namespace MySqlX.XDevAPI.Relational +{ + /// + /// Represents a single row of data in a table. + /// + public class Row + { + private object[] _values; + private Dictionary _nameMap; + + internal Row(Dictionary nameMap, object[] values) + { + _values = values; + _nameMap = nameMap; + } + + /// + /// Gets the value of the row at the given index. + /// + /// The column index to retrieve the value. + /// The value at the index. + public object this[int index] + { + get { return GetValue(index); } + } + + /// + /// Gets the value of the column as a string. + /// + /// The name of the column. + /// The value of the column as a string. + public string GetString(string name) + { + return GetValue(name).ToString(); + } + + /// + /// Gets a string based indexer into the row. Returns the value as a CLR type. + /// + /// The column index to get. + /// The CLR value for the column. + public object this[string name] + { + get + { + return GetValue(name); + } + } + + private object GetValue(int index) + { + if (index < 0 || index >= _values.Length) + throw new IndexOutOfRangeException(String.Format(ResourcesX.InvalidRowIndex, index)); + return _values[index]; + } + + private object GetValue(string name) + { + if (!_nameMap.ContainsKey(name)) + throw new InvalidOperationException(String.Format(ResourcesX.InvalidNameIndex, name)); + return GetValue(_nameMap[name]); + } + } +} diff --git a/MySQL.Data/src/X/XDevAPI/Relational/RowResult.cs b/MySQL.Data/src/X/XDevAPI/Relational/RowResult.cs index a59af481d..968307fa1 100644 --- a/MySQL.Data/src/X/XDevAPI/Relational/RowResult.cs +++ b/MySQL.Data/src/X/XDevAPI/Relational/RowResult.cs @@ -1,43 +1,43 @@ -// Copyright © 2015, 2017, Oracle and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySqlX.Sessions; - -namespace MySqlX.XDevAPI.Relational -{ - - /// - /// Inherits from . Creates a resultset that contains rows of data. - /// - public sealed class RowResult : InternalRowResult - { - internal RowResult(InternalSession session) : base(session) - { - } - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySqlX.Sessions; + +namespace MySqlX.XDevAPI.Relational +{ + + /// + /// Inherits from . Creates a resultset that contains rows of data. + /// + public sealed class RowResult : InternalRowResult + { + internal RowResult(InternalSession session) : base(session) + { + } + } +} diff --git a/MySQL.Data/src/X/XDevAPI/Relational/SqlResult.cs b/MySQL.Data/src/X/XDevAPI/Relational/SqlResult.cs index d4ca4f291..2e29f1255 100644 --- a/MySQL.Data/src/X/XDevAPI/Relational/SqlResult.cs +++ b/MySQL.Data/src/X/XDevAPI/Relational/SqlResult.cs @@ -1,68 +1,68 @@ -// Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using System; -using MySqlX.Sessions; - -namespace MySqlX.XDevAPI.Relational -{ - /// - /// Represents a resultset that contains rows of data for relational operations. - /// - public class SqlResult : InternalRowResult - { - internal SqlResult(InternalSession session) : base(session) - { - - } - - /// - /// Gets a boolean value indicating if this result has data. - /// - public bool HasData - { - get { return _hasData; } - } - - /// - /// Moves to next resultset. - /// - /// True if there is a new resultset, false otherwise. - public bool NextResult() - { - if (!_hasMoreResults) - return false; - _hasData = Protocol.HasData(this); - LoadColumnData(); - _isComplete = !_hasData; - _position = -1; - _items.Clear(); - return _hasData; - } - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using System; +using MySqlX.Sessions; + +namespace MySqlX.XDevAPI.Relational +{ + /// + /// Represents a resultset that contains rows of data for relational operations. + /// + public class SqlResult : InternalRowResult + { + internal SqlResult(InternalSession session) : base(session) + { + + } + + /// + /// Gets a boolean value indicating if this result has data. + /// + public bool HasData + { + get { return _hasData; } + } + + /// + /// Moves to next resultset. + /// + /// True if there is a new resultset, false otherwise. + public bool NextResult() + { + if (!_hasMoreResults) + return false; + _hasData = Protocol.HasData(this); + LoadColumnData(); + _isComplete = !_hasData; + _position = -1; + _items.Clear(); + return _hasData; + } + } +} diff --git a/MySQL.Data/src/X/XDevAPI/Relational/SqlStatement.cs b/MySQL.Data/src/X/XDevAPI/Relational/SqlStatement.cs index 8ce94b656..39b617ef9 100644 --- a/MySQL.Data/src/X/XDevAPI/Relational/SqlStatement.cs +++ b/MySQL.Data/src/X/XDevAPI/Relational/SqlStatement.cs @@ -1,108 +1,108 @@ -// Copyright (c) 2015, 2023, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data.MySqlClient; -using MySqlX.XDevAPI.Common; -using System; -using System.Collections.Generic; - -namespace MySqlX.XDevAPI.Relational -{ - /// - /// Represents a sql statement. - /// - public class SqlStatement : BaseStatement - { - /// - /// Initializes a new instance of the SqlStament class bassed on the session and sql statement. - /// - /// The session the Sql statement belongs to. - /// The Sql statement. - public SqlStatement(Session session, string sql) : base(session) - { - SQL = sql; - } - - /// - /// Gets the current Sql statement. - /// - public string SQL { get; private set; } - /// - /// Gets the list of parameters associated to this Sql statement. - /// - protected internal List parameters = new List(); - - /// - /// Executes the current Sql statement. - /// - /// A object with the resultset and execution status. - public override SqlResult Execute() - { - SqlResult result = null; - try - { - ValidateOpenSession(); - result = GetSQLResult(this); - } - catch (MySqlException ex) - { - switch (ex.Number) - { - case (int)CloseNotification.IDLE: - case (int)CloseNotification.KILLED: - case (int)CloseNotification.SHUTDOWN: - XDevAPI.Session.ThrowSessionClosedByServerException(ex, Session); - break; - default: - throw; - } - } - - return result; - } - - private SqlResult GetSQLResult(SqlStatement statement) - { - return Session.XSession.GetSQLResult(statement.SQL, parameters.ToArray()); - } - - /// - /// Binds the parameters values by position. - /// - /// The parameter values. - /// This set with the binded parameters. - public SqlStatement Bind(params object[] values) - { - if (values == null) - parameters.Add(null); - else - parameters.AddRange(values); - return this; - } - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data.MySqlClient; +using MySqlX.XDevAPI.Common; +using System; +using System.Collections.Generic; + +namespace MySqlX.XDevAPI.Relational +{ + /// + /// Represents a sql statement. + /// + public class SqlStatement : BaseStatement + { + /// + /// Initializes a new instance of the SqlStament class bassed on the session and sql statement. + /// + /// The session the Sql statement belongs to. + /// The Sql statement. + public SqlStatement(Session session, string sql) : base(session) + { + SQL = sql; + } + + /// + /// Gets the current Sql statement. + /// + public string SQL { get; private set; } + /// + /// Gets the list of parameters associated to this Sql statement. + /// + protected internal List parameters = new List(); + + /// + /// Executes the current Sql statement. + /// + /// A object with the resultset and execution status. + public override SqlResult Execute() + { + SqlResult result = null; + try + { + ValidateOpenSession(); + result = GetSQLResult(this); + } + catch (MySqlException ex) + { + switch (ex.Number) + { + case (int)CloseNotification.IDLE: + case (int)CloseNotification.KILLED: + case (int)CloseNotification.SHUTDOWN: + XDevAPI.Session.ThrowSessionClosedByServerException(ex, Session); + break; + default: + throw; + } + } + + return result; + } + + private SqlResult GetSQLResult(SqlStatement statement) + { + return Session.XSession.GetSQLResult(statement.SQL, parameters.ToArray()); + } + + /// + /// Binds the parameters values by position. + /// + /// The parameter values. + /// This set with the binded parameters. + public SqlStatement Bind(params object[] values) + { + if (values == null) + parameters.Add(null); + else + parameters.AddRange(values); + return this; + } + } +} diff --git a/MySQL.Data/src/X/XDevAPI/Relational/Table.cs b/MySQL.Data/src/X/XDevAPI/Relational/Table.cs index d9ff1be07..940ce10f0 100644 --- a/MySQL.Data/src/X/XDevAPI/Relational/Table.cs +++ b/MySQL.Data/src/X/XDevAPI/Relational/Table.cs @@ -1,172 +1,172 @@ -// Copyright (c) 2015, 2020, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using System; -using MySql.Data.MySqlClient; -using MySqlX.XDevAPI.Relational; - -namespace MySqlX.XDevAPI.Relational -{ - /// - /// Represents a server Table or View. - /// - public class Table : DatabaseObject - { - private bool? isView; - - /// - /// Gets a value indicating whether the object is - /// a View (True) or a Table (False). - /// - public bool IsView { - get - { - return CheckIsView(); - } - internal set - { - isView = value; - } - } - - private bool CheckIsView() - { - if (!isView.HasValue) - { - ValidateOpenSession(); - string type = Session.XSession.GetObjectType(Schema, Name).ToUpperInvariant(); - isView = (type == "VIEW"); - } - return isView.Value; - } - - internal Table(Schema schema, string name, bool isView) - : base(schema, name) - { - this.isView = isView; - } - - internal Table(Schema schema, string name) - : base(schema, name) - { - } - - internal Table() : base(null, null) { } - - /// - /// Creates a set with the columns to select. The table select - /// statement can be further modified before execution. This method is intended to select a set - /// of table rows. - /// - /// The optional column names to select. - /// A object for select chain operations. - public TableSelectStatement Select(params string[] columns) - { - return new TableSelectStatement(this, columns); - } - - /// - /// Creates a set with the fileds to insert to. The table - /// insert statement can be further modified before exeuction. This method is intended to - /// insert one or multiple rows into a table. - /// - /// The list of fields to insert. - /// A object for insert chain operations. - public TableInsertStatement Insert(params string[] fields) - { - return new TableInsertStatement(this, fields); - } - - /// - /// Creates a . This method is intended to update table rows - /// values. - /// - /// A object for update chain operations. - public TableUpdateStatement Update() - { - return new TableUpdateStatement(this); - } - - /// - /// Creates a . This method is intended to delete rows from a - /// table. - /// - /// A object for delete chain operations. - public TableDeleteStatement Delete() - { - return new TableDeleteStatement(this, null); - } - - /// - /// Returns the number of rows in the table on the server. - /// - /// The number of rows. - public long Count() - { - long result=0; - try - { - ValidateOpenSession(); - result = Session.XSession.TableCount(Schema, Name, "Table"); - } - catch (MySqlException ex) - { - switch (ex.Number) - { - case (int)CloseNotification.IDLE: - case (int)CloseNotification.KILLED: - case (int)CloseNotification.SHUTDOWN: - XDevAPI.Session.ThrowSessionClosedByServerException(ex, Session); - break; - default: - throw; - } - } - return result; - } - - /// - /// Verifies if the table exists in the database. - /// - /// true if the table exists; otherwise, false. - public override bool ExistsInDatabase() - { - bool result = false; - try - { - ValidateOpenSession(); - return Session.XSession.TableExists(Schema, Name); - } - catch (MySqlException e) - { - XDevAPI.Session.ThrowSessionClosedByServerException(e, Session); - } - return result; - } - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using System; +using MySql.Data.MySqlClient; +using MySqlX.XDevAPI.Relational; + +namespace MySqlX.XDevAPI.Relational +{ + /// + /// Represents a server Table or View. + /// + public class Table : DatabaseObject + { + private bool? isView; + + /// + /// Gets a value indicating whether the object is + /// a View (True) or a Table (False). + /// + public bool IsView { + get + { + return CheckIsView(); + } + internal set + { + isView = value; + } + } + + private bool CheckIsView() + { + if (!isView.HasValue) + { + ValidateOpenSession(); + string type = Session.XSession.GetObjectType(Schema, Name).ToUpperInvariant(); + isView = (type == "VIEW"); + } + return isView.Value; + } + + internal Table(Schema schema, string name, bool isView) + : base(schema, name) + { + this.isView = isView; + } + + internal Table(Schema schema, string name) + : base(schema, name) + { + } + + internal Table() : base(null, null) { } + + /// + /// Creates a set with the columns to select. The table select + /// statement can be further modified before execution. This method is intended to select a set + /// of table rows. + /// + /// The optional column names to select. + /// A object for select chain operations. + public TableSelectStatement Select(params string[] columns) + { + return new TableSelectStatement(this, columns); + } + + /// + /// Creates a set with the fileds to insert to. The table + /// insert statement can be further modified before exeuction. This method is intended to + /// insert one or multiple rows into a table. + /// + /// The list of fields to insert. + /// A object for insert chain operations. + public TableInsertStatement Insert(params string[] fields) + { + return new TableInsertStatement(this, fields); + } + + /// + /// Creates a . This method is intended to update table rows + /// values. + /// + /// A object for update chain operations. + public TableUpdateStatement Update() + { + return new TableUpdateStatement(this); + } + + /// + /// Creates a . This method is intended to delete rows from a + /// table. + /// + /// A object for delete chain operations. + public TableDeleteStatement Delete() + { + return new TableDeleteStatement(this, null); + } + + /// + /// Returns the number of rows in the table on the server. + /// + /// The number of rows. + public long Count() + { + long result=0; + try + { + ValidateOpenSession(); + result = Session.XSession.TableCount(Schema, Name, "Table"); + } + catch (MySqlException ex) + { + switch (ex.Number) + { + case (int)CloseNotification.IDLE: + case (int)CloseNotification.KILLED: + case (int)CloseNotification.SHUTDOWN: + XDevAPI.Session.ThrowSessionClosedByServerException(ex, Session); + break; + default: + throw; + } + } + return result; + } + + /// + /// Verifies if the table exists in the database. + /// + /// true if the table exists; otherwise, false. + public override bool ExistsInDatabase() + { + bool result = false; + try + { + ValidateOpenSession(); + return Session.XSession.TableExists(Schema, Name); + } + catch (MySqlException e) + { + XDevAPI.Session.ThrowSessionClosedByServerException(e, Session); + } + return result; + } + } +} diff --git a/MySQL.Data/src/X/XDevAPI/Relational/TableDeleteStatement.cs b/MySQL.Data/src/X/XDevAPI/Relational/TableDeleteStatement.cs index 2d3b5a9d3..bbfaef2cb 100644 --- a/MySQL.Data/src/X/XDevAPI/Relational/TableDeleteStatement.cs +++ b/MySQL.Data/src/X/XDevAPI/Relational/TableDeleteStatement.cs @@ -1,66 +1,66 @@ -// Copyright (c) 2015, 2023, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySqlX.XDevAPI.Common; -using System; - -namespace MySqlX.XDevAPI.Relational -{ - /// - /// Represents a chaining table delete statement. - /// - public class TableDeleteStatement : FilterableStatement - { - internal TableDeleteStatement(Table table, string condition) : base(table, condition) - { - FilterData.IsRelational = true; - } - - /// - /// Sets user-defined sorting criteria for the operation. The strings use normal SQL syntax like - /// "order ASC" or "pages DESC, age ASC". - /// - /// The order criteria. - /// A generic object representing the implementing statement type. - public TableDeleteStatement OrderBy(params string[] order) - { - FilterData.OrderBy = order; - SetChanged(); - return this; - } - - /// - /// Executes the delete statement. - /// - /// A object containing the results of the delete execution. - public override Result Execute() - { - return Execute(Target.Session.XSession.DeleteRows, this); - } - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySqlX.XDevAPI.Common; +using System; + +namespace MySqlX.XDevAPI.Relational +{ + /// + /// Represents a chaining table delete statement. + /// + public class TableDeleteStatement : FilterableStatement + { + internal TableDeleteStatement(Table table, string condition) : base(table, condition) + { + FilterData.IsRelational = true; + } + + /// + /// Sets user-defined sorting criteria for the operation. The strings use normal SQL syntax like + /// "order ASC" or "pages DESC, age ASC". + /// + /// The order criteria. + /// A generic object representing the implementing statement type. + public TableDeleteStatement OrderBy(params string[] order) + { + FilterData.OrderBy = order; + SetChanged(); + return this; + } + + /// + /// Executes the delete statement. + /// + /// A object containing the results of the delete execution. + public override Result Execute() + { + return Execute(Target.Session.XSession.DeleteRows, this); + } + } +} diff --git a/MySQL.Data/src/X/XDevAPI/Relational/TableInsertStatement.cs b/MySQL.Data/src/X/XDevAPI/Relational/TableInsertStatement.cs index 77eb84080..bfd63743d 100644 --- a/MySQL.Data/src/X/XDevAPI/Relational/TableInsertStatement.cs +++ b/MySQL.Data/src/X/XDevAPI/Relational/TableInsertStatement.cs @@ -1,71 +1,71 @@ -// Copyright (c) 2015, 2023, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySqlX.XDevAPI.Common; -using System; -using System.Collections.Generic; - -namespace MySqlX.XDevAPI.Relational -{ - /// - /// Represents a chaining table insert statement. - /// - public class TableInsertStatement : TargetedBaseStatement - { - internal string[] fields; - internal List values = new List(); - internal object[] parameters; - - internal TableInsertStatement(Table table, string[] fields) : base(table) - { - this.fields = fields; - } - - /// - /// Executes the insert statement. - /// - /// A object containing the results of the insert statement. - public override Result Execute() - { - ValidateOpenSession(); - return Target.Session.XSession.InsertRows(this); - } - - /// - /// Values to be inserted. - /// Multiple rows supported. - /// - /// The values to be inserted. - /// This same object. - public TableInsertStatement Values(params object[] values) - { - this.values.Add(values); - return this; - } - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySqlX.XDevAPI.Common; +using System; +using System.Collections.Generic; + +namespace MySqlX.XDevAPI.Relational +{ + /// + /// Represents a chaining table insert statement. + /// + public class TableInsertStatement : TargetedBaseStatement + { + internal string[] fields; + internal List values = new List(); + internal object[] parameters; + + internal TableInsertStatement(Table table, string[] fields) : base(table) + { + this.fields = fields; + } + + /// + /// Executes the insert statement. + /// + /// A object containing the results of the insert statement. + public override Result Execute() + { + ValidateOpenSession(); + return Target.Session.XSession.InsertRows(this); + } + + /// + /// Values to be inserted. + /// Multiple rows supported. + /// + /// The values to be inserted. + /// This same object. + public TableInsertStatement Values(params object[] values) + { + this.values.Add(values); + return this; + } + } +} diff --git a/MySQL.Data/src/X/XDevAPI/Relational/TableSelectStatement.cs b/MySQL.Data/src/X/XDevAPI/Relational/TableSelectStatement.cs index 41df41dfb..eabf3e900 100644 --- a/MySQL.Data/src/X/XDevAPI/Relational/TableSelectStatement.cs +++ b/MySQL.Data/src/X/XDevAPI/Relational/TableSelectStatement.cs @@ -1,141 +1,141 @@ -// Copyright (c) 2015, 2023, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data; -using MySql.Data.MySqlClient; -using MySqlX.XDevAPI.Common; -using MySqlX.XDevAPI.CRUD; -using System; -using System.Collections.Generic; - -namespace MySqlX.XDevAPI.Relational -{ - /// - /// Represents a chaining table select statement. - /// - public class TableSelectStatement : FilterableStatement - { - internal FindParams findParams = new FindParams(); - - internal TableSelectStatement(Table t, params string[] projection) : base(t) - { - findParams.Projection = projection; - FilterData.IsRelational = true; - } - - /// - /// Executes the select statement. - /// - /// A object containing the results of the execution and data. - public override RowResult Execute() - { - return Execute(Target.Session.XSession.FindRows, this); - } - - /// - /// Locks matching rows against updates. - /// - /// Optional row lock option to use. - /// This same object set with lock shared option. - /// The server version is lower than 8.0.3. - public TableSelectStatement LockShared(LockContention lockOption = LockContention.Default) - { - if (!this.Session.InternalSession.GetServerVersion().isAtLeast(8, 0, 3)) - throw new MySqlException(string.Format(ResourcesX.FunctionalityNotSupported, "8.0.3")); - - findParams.Locking = Protocol.X.RowLock.SharedLock; - findParams.LockingOption = lockOption; - SetChanged(); - return this; - } - - /// - /// Locks matching rows so no other transaction can read or write to it. - /// - /// Optional row lock option to use. - /// This same object set with the lock exclusive option. - /// The server version is lower than 8.0.3. - public TableSelectStatement LockExclusive(LockContention lockOption = LockContention.Default) - { - if (!this.Session.InternalSession.GetServerVersion().isAtLeast(8, 0, 3)) - throw new MySqlException(string.Format(ResourcesX.FunctionalityNotSupported, "8.0.3")); - - findParams.Locking = Protocol.X.RowLock.ExclusiveLock; - findParams.LockingOption = lockOption; - SetChanged(); - return this; - } - - /// - /// Sets the table aggregation. - /// - /// The column list for aggregation. - /// This same object set with the specified group-by criteria. - public TableSelectStatement GroupBy(params string[] groupBy) - { - if (groupBy == null) - return this; - - var groupByList = new List(); - foreach (var item in groupBy) - { - if (item != null) - groupByList.Add(item); - } - - findParams.GroupBy = groupByList.Count > 0 ? groupByList.ToArray() : null; - SetChanged(); - return this; - } - - /// - /// Filters criteria for aggregated groups. - /// - /// The filter criteria for aggregated groups. - /// This same object set with the specified filter criteria. - public TableSelectStatement Having(string having) - { - findParams.GroupByCritieria = having; - SetChanged(); - return this; - } - - /// - /// Sets user-defined sorting criteria for the operation. The strings use normal SQL syntax like - /// "order ASC" or "pages DESC, age ASC". - /// - /// The order criteria. - /// A generic object that represents the implementing statement type. - public TableSelectStatement OrderBy(params string[] order) - { - FilterData.OrderBy = order; - SetChanged(); - return this; - } - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data; +using MySql.Data.MySqlClient; +using MySqlX.XDevAPI.Common; +using MySqlX.XDevAPI.CRUD; +using System; +using System.Collections.Generic; + +namespace MySqlX.XDevAPI.Relational +{ + /// + /// Represents a chaining table select statement. + /// + public class TableSelectStatement : FilterableStatement + { + internal FindParams findParams = new FindParams(); + + internal TableSelectStatement(Table t, params string[] projection) : base(t) + { + findParams.Projection = projection; + FilterData.IsRelational = true; + } + + /// + /// Executes the select statement. + /// + /// A object containing the results of the execution and data. + public override RowResult Execute() + { + return Execute(Target.Session.XSession.FindRows, this); + } + + /// + /// Locks matching rows against updates. + /// + /// Optional row lock option to use. + /// This same object set with lock shared option. + /// The server version is lower than 8.0.3. + public TableSelectStatement LockShared(LockContention lockOption = LockContention.Default) + { + if (!this.Session.InternalSession.GetServerVersion().isAtLeast(8, 0, 3)) + throw new MySqlException(string.Format(ResourcesX.FunctionalityNotSupported, "8.0.3")); + + findParams.Locking = Protocol.X.RowLock.SharedLock; + findParams.LockingOption = lockOption; + SetChanged(); + return this; + } + + /// + /// Locks matching rows so no other transaction can read or write to it. + /// + /// Optional row lock option to use. + /// This same object set with the lock exclusive option. + /// The server version is lower than 8.0.3. + public TableSelectStatement LockExclusive(LockContention lockOption = LockContention.Default) + { + if (!this.Session.InternalSession.GetServerVersion().isAtLeast(8, 0, 3)) + throw new MySqlException(string.Format(ResourcesX.FunctionalityNotSupported, "8.0.3")); + + findParams.Locking = Protocol.X.RowLock.ExclusiveLock; + findParams.LockingOption = lockOption; + SetChanged(); + return this; + } + + /// + /// Sets the table aggregation. + /// + /// The column list for aggregation. + /// This same object set with the specified group-by criteria. + public TableSelectStatement GroupBy(params string[] groupBy) + { + if (groupBy == null) + return this; + + var groupByList = new List(); + foreach (var item in groupBy) + { + if (item != null) + groupByList.Add(item); + } + + findParams.GroupBy = groupByList.Count > 0 ? groupByList.ToArray() : null; + SetChanged(); + return this; + } + + /// + /// Filters criteria for aggregated groups. + /// + /// The filter criteria for aggregated groups. + /// This same object set with the specified filter criteria. + public TableSelectStatement Having(string having) + { + findParams.GroupByCritieria = having; + SetChanged(); + return this; + } + + /// + /// Sets user-defined sorting criteria for the operation. The strings use normal SQL syntax like + /// "order ASC" or "pages DESC, age ASC". + /// + /// The order criteria. + /// A generic object that represents the implementing statement type. + public TableSelectStatement OrderBy(params string[] order) + { + FilterData.OrderBy = order; + SetChanged(); + return this; + } + } +} diff --git a/MySQL.Data/src/X/XDevAPI/Relational/TableUpdateStatement.cs b/MySQL.Data/src/X/XDevAPI/Relational/TableUpdateStatement.cs index 643652b3a..f4aa6ecd1 100644 --- a/MySQL.Data/src/X/XDevAPI/Relational/TableUpdateStatement.cs +++ b/MySQL.Data/src/X/XDevAPI/Relational/TableUpdateStatement.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2015, 2023, Oracle and/or its affiliates. +// Copyright © 2015, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/X/XDevAPI/Schema.cs b/MySQL.Data/src/X/XDevAPI/Schema.cs index 4bec5525e..a09f782a3 100644 --- a/MySQL.Data/src/X/XDevAPI/Schema.cs +++ b/MySQL.Data/src/X/XDevAPI/Schema.cs @@ -1,349 +1,349 @@ -// Copyright (c) 2015, 2023, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data; -using MySql.Data.MySqlClient; -using MySqlX.XDevAPI.Common; -using MySqlX.XDevAPI.Relational; -using System; -using System.Collections.Generic; - -namespace MySqlX.XDevAPI -{ - /// - /// Represents a schema or database. - /// - public class Schema : DatabaseObject - { - internal Schema(BaseSession session, string name) : base(null, name) - { - Schema = this; - Session = session; - } - - /// - /// Session related to current schema. - /// - public new BaseSession Session { get; private set; } - - - #region Browse Functions - - /// - /// Returns a list of all collections in this schema. - /// - /// A list representing all found collections. - public List GetCollections() - { - List result = null; - try - { - ValidateOpenSession(); - result = Session.XSession.GetObjectList(this, "COLLECTION"); - } - catch (MySqlException ex) - { - switch (ex.Number) - { - case (int)CloseNotification.IDLE: - case (int)CloseNotification.KILLED: - case (int)CloseNotification.SHUTDOWN: - XDevAPI.Session.ThrowSessionClosedByServerException(ex, Session); - break; - default: - throw; - } - } - return result; - } - - /// - /// Returns a list of all tables in this schema. - /// - /// A list representing all found tables. - public List GetTables() - { - List
result = null; - try - { - ValidateOpenSession(); - result = Session.XSession.GetObjectList
(this, "TABLE", "VIEW"); - } - catch (MySqlException ex) - { - switch (ex.Number) - { - case (int)CloseNotification.IDLE: - case (int)CloseNotification.KILLED: - case (int)CloseNotification.SHUTDOWN: - XDevAPI.Session.ThrowSessionClosedByServerException(ex, Session); - break; - default: - throw; - } - } - return result; - } - - #endregion - - #region Instance Functions - - /// - /// Gets a collection by name. - /// - /// The name of the collection to get. - /// Ensures the collection exists in the schema. - /// A object matching the given name. - public Collection GetCollection(string name, bool ValidateExistence = false) - { - Collection c = new Collection(this, name); - if (ValidateExistence) - { - ValidateOpenSession(); - if (!c.ExistsInDatabase()) - throw new MySqlException(String.Format("Collection '{0}' does not exist.", name)); - } - return c; - } - - /// - /// Gets a typed collection object. This is useful for using domain objects. - /// - /// The name of collection to get. - /// Ensures the collection exists in the schema. - /// A generic object set with the given name. - public Collection GetCollection(string name, bool ValidateExistence = false) - { - Collection c = new Collection(this, name); - - if (ValidateExistence) - { - ValidateOpenSession(); - if (!c.ExistsInDatabase()) - throw new MySqlException(String.Format("Collection '{0}' does not exist.", name)); - } - return c; - } - - /// - /// Gets the given collection as a table. - /// - /// The name of the collection. - /// A object set with the given name. - public Table GetCollectionAsTable(string name) - { - return GetTable(name); - } - - /// - /// Gets a table object. Upon return the object may or may not be valid. - /// - /// The name of the table object. - /// A object set with the given name. - public Table GetTable(string name) - { - return new Table(this, name); - } - - #endregion - - #region Create Functions - - /// - /// Creates a . - /// - /// The name of the collection to create. - /// If false, throws an exception if the collection exists. - /// Collection referente. - public Collection CreateCollection(string collectionName, bool ReuseExisting = false) - { - ValidateOpenSession(); - Collection coll = new Collection(this, collectionName); - try - { - if (Session.Version.isAtLeast(8, 0, 19)) - { - CreateCollectionOptions options = new CreateCollectionOptions() { ReuseExisting = ReuseExisting }; - Session.XSession.CreateCollection(Name, collectionName, options); - } - else - { - Session.XSession.CreateCollection(Name, collectionName); - } - } - catch (MySqlException ex) when (ex.Number == (int)CloseNotification.IDLE || ex.Number == (int)CloseNotification.KILLED || ex.Number == (int)CloseNotification.SHUTDOWN) - { - XDevAPI.Session.ThrowSessionClosedByServerException(ex, Session); - } - catch (MySqlException ex) when (ex.Code == 1050) - { - if (ReuseExisting) - return coll; - throw; - } - return new Collection(this, collectionName); - } - - /// - /// Creates a including a schema validation. - /// - /// The name of the collection to create. - /// This object hold the parameters required to create the collection. - /// - /// Collection referente. - public Collection CreateCollection(string collectionName, CreateCollectionOptions options) - { - ValidateOpenSession(); - Collection coll = null; - - try - { - coll = new Collection(this, collectionName); - Session.XSession.CreateCollection(Name, collectionName, options); - } - catch (MySqlException ex) when (ex.Number == (int)CloseNotification.IDLE || ex.Number == (int)CloseNotification.KILLED || ex.Number == (int)CloseNotification.SHUTDOWN) - { - XDevAPI.Session.ThrowSessionClosedByServerException(ex, Session); - } - catch (MySqlException ex_1) when (ex_1.Code == 5015) - { - var msg = string.Format("{0}{1}{2}", ex_1.Message, ", ", ResourcesX.SchemaCreateCollectionMsg); - throw new MySqlException(msg); - } - catch (MySqlException ex) when (ex.Code == 1050) - { - if (options.ReuseExisting) - return coll; - throw; - } - catch (MySqlException) - { - throw; - } - return coll; - } - - /// - /// Modify a collection adding or removing schema validation parameters. - /// - /// The name of the collection to create. - /// This object encapsulate the Validation parameters level and schema. - /// Collection referente. - public Collection ModifyCollection(string collectionName, ModifyCollectionOptions? options) - { - ValidateOpenSession(); - Collection result = null; - try - { - Session.XSession.ModifyCollection(Name, collectionName, options); - result = new Collection(this, collectionName); - } - catch (MySqlException ex) when (ex.Number == (int)CloseNotification.IDLE || ex.Number == (int)CloseNotification.KILLED || ex.Number == (int)CloseNotification.SHUTDOWN) - { - XDevAPI.Session.ThrowSessionClosedByServerException(ex, Session); - } - catch (MySqlException ex_1) when (ex_1.Code == 5157) - { - var msg = string.Format("{0}{1}{2}", ex_1.Message, ", ", ResourcesX.SchemaCreateCollectionMsg); - throw new MySqlException(msg); - } - catch (MySqlException) - { - throw; - } - return result; - } - - #endregion - - /// - /// Drops the given collection. - /// - /// The name of the collection to drop. - /// is null. - public void DropCollection(string name) - { - if (string.IsNullOrWhiteSpace(name)) throw new ArgumentNullException(nameof(name)); - try - { - ValidateOpenSession(); - Collection c = GetCollection(name); - if (!c.ExistsInDatabase()) return; - Session.XSession.DropCollection(Name, name); - } - catch (MySqlException ex) - { - switch (ex.Number) - { - case (int)CloseNotification.IDLE: - case (int)CloseNotification.KILLED: - case (int)CloseNotification.SHUTDOWN: - XDevAPI.Session.ThrowSessionClosedByServerException(ex, Session); - break; - default: - throw; - } - } - } - - #region Base Class - - /// - /// Determines if this schema actually exists. - /// - /// True if exists, false otherwise. - public override bool ExistsInDatabase() - { - bool result = false; - try - { - ValidateOpenSession(); - string sql = String.Format("SELECT COUNT(*) FROM information_schema.schemata WHERE schema_name like '{0}'", Name); - long count = (long)Session.InternalSession.ExecuteQueryAsScalar(sql); - result = count > 0; - } - catch (MySqlException ex) - { - switch (ex.Number) - { - case (int)CloseNotification.IDLE: - case (int)CloseNotification.KILLED: - case (int)CloseNotification.SHUTDOWN: - XDevAPI.Session.ThrowSessionClosedByServerException(ex, Session); - break; - default: - throw; - } - } - return result; - } - - #endregion - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data; +using MySql.Data.MySqlClient; +using MySqlX.XDevAPI.Common; +using MySqlX.XDevAPI.Relational; +using System; +using System.Collections.Generic; + +namespace MySqlX.XDevAPI +{ + /// + /// Represents a schema or database. + /// + public class Schema : DatabaseObject + { + internal Schema(BaseSession session, string name) : base(null, name) + { + Schema = this; + Session = session; + } + + /// + /// Session related to current schema. + /// + public new BaseSession Session { get; private set; } + + + #region Browse Functions + + /// + /// Returns a list of all collections in this schema. + /// + /// A list representing all found collections. + public List GetCollections() + { + List result = null; + try + { + ValidateOpenSession(); + result = Session.XSession.GetObjectList(this, "COLLECTION"); + } + catch (MySqlException ex) + { + switch (ex.Number) + { + case (int)CloseNotification.IDLE: + case (int)CloseNotification.KILLED: + case (int)CloseNotification.SHUTDOWN: + XDevAPI.Session.ThrowSessionClosedByServerException(ex, Session); + break; + default: + throw; + } + } + return result; + } + + /// + /// Returns a list of all tables in this schema. + /// + /// A list representing all found tables. + public List
GetTables() + { + List
result = null; + try + { + ValidateOpenSession(); + result = Session.XSession.GetObjectList
(this, "TABLE", "VIEW"); + } + catch (MySqlException ex) + { + switch (ex.Number) + { + case (int)CloseNotification.IDLE: + case (int)CloseNotification.KILLED: + case (int)CloseNotification.SHUTDOWN: + XDevAPI.Session.ThrowSessionClosedByServerException(ex, Session); + break; + default: + throw; + } + } + return result; + } + + #endregion + + #region Instance Functions + + /// + /// Gets a collection by name. + /// + /// The name of the collection to get. + /// Ensures the collection exists in the schema. + /// A object matching the given name. + public Collection GetCollection(string name, bool ValidateExistence = false) + { + Collection c = new Collection(this, name); + if (ValidateExistence) + { + ValidateOpenSession(); + if (!c.ExistsInDatabase()) + throw new MySqlException(String.Format("Collection '{0}' does not exist.", name)); + } + return c; + } + + /// + /// Gets a typed collection object. This is useful for using domain objects. + /// + /// The name of collection to get. + /// Ensures the collection exists in the schema. + /// A generic object set with the given name. + public Collection GetCollection(string name, bool ValidateExistence = false) + { + Collection c = new Collection(this, name); + + if (ValidateExistence) + { + ValidateOpenSession(); + if (!c.ExistsInDatabase()) + throw new MySqlException(String.Format("Collection '{0}' does not exist.", name)); + } + return c; + } + + /// + /// Gets the given collection as a table. + /// + /// The name of the collection. + /// A object set with the given name. + public Table GetCollectionAsTable(string name) + { + return GetTable(name); + } + + /// + /// Gets a table object. Upon return the object may or may not be valid. + /// + /// The name of the table object. + /// A object set with the given name. + public Table GetTable(string name) + { + return new Table(this, name); + } + + #endregion + + #region Create Functions + + /// + /// Creates a . + /// + /// The name of the collection to create. + /// If false, throws an exception if the collection exists. + /// Collection referente. + public Collection CreateCollection(string collectionName, bool ReuseExisting = false) + { + ValidateOpenSession(); + Collection coll = new Collection(this, collectionName); + try + { + if (Session.Version.isAtLeast(8, 0, 19)) + { + CreateCollectionOptions options = new CreateCollectionOptions() { ReuseExisting = ReuseExisting }; + Session.XSession.CreateCollection(Name, collectionName, options); + } + else + { + Session.XSession.CreateCollection(Name, collectionName); + } + } + catch (MySqlException ex) when (ex.Number == (int)CloseNotification.IDLE || ex.Number == (int)CloseNotification.KILLED || ex.Number == (int)CloseNotification.SHUTDOWN) + { + XDevAPI.Session.ThrowSessionClosedByServerException(ex, Session); + } + catch (MySqlException ex) when (ex.Code == 1050) + { + if (ReuseExisting) + return coll; + throw; + } + return new Collection(this, collectionName); + } + + /// + /// Creates a including a schema validation. + /// + /// The name of the collection to create. + /// This object hold the parameters required to create the collection. + /// + /// Collection referente. + public Collection CreateCollection(string collectionName, CreateCollectionOptions options) + { + ValidateOpenSession(); + Collection coll = null; + + try + { + coll = new Collection(this, collectionName); + Session.XSession.CreateCollection(Name, collectionName, options); + } + catch (MySqlException ex) when (ex.Number == (int)CloseNotification.IDLE || ex.Number == (int)CloseNotification.KILLED || ex.Number == (int)CloseNotification.SHUTDOWN) + { + XDevAPI.Session.ThrowSessionClosedByServerException(ex, Session); + } + catch (MySqlException ex_1) when (ex_1.Code == 5015) + { + var msg = string.Format("{0}{1}{2}", ex_1.Message, ", ", ResourcesX.SchemaCreateCollectionMsg); + throw new MySqlException(msg); + } + catch (MySqlException ex) when (ex.Code == 1050) + { + if (options.ReuseExisting) + return coll; + throw; + } + catch (MySqlException) + { + throw; + } + return coll; + } + + /// + /// Modify a collection adding or removing schema validation parameters. + /// + /// The name of the collection to create. + /// This object encapsulate the Validation parameters level and schema. + /// Collection referente. + public Collection ModifyCollection(string collectionName, ModifyCollectionOptions? options) + { + ValidateOpenSession(); + Collection result = null; + try + { + Session.XSession.ModifyCollection(Name, collectionName, options); + result = new Collection(this, collectionName); + } + catch (MySqlException ex) when (ex.Number == (int)CloseNotification.IDLE || ex.Number == (int)CloseNotification.KILLED || ex.Number == (int)CloseNotification.SHUTDOWN) + { + XDevAPI.Session.ThrowSessionClosedByServerException(ex, Session); + } + catch (MySqlException ex_1) when (ex_1.Code == 5157) + { + var msg = string.Format("{0}{1}{2}", ex_1.Message, ", ", ResourcesX.SchemaCreateCollectionMsg); + throw new MySqlException(msg); + } + catch (MySqlException) + { + throw; + } + return result; + } + + #endregion + + /// + /// Drops the given collection. + /// + /// The name of the collection to drop. + /// is null. + public void DropCollection(string name) + { + if (string.IsNullOrWhiteSpace(name)) throw new ArgumentNullException(nameof(name)); + try + { + ValidateOpenSession(); + Collection c = GetCollection(name); + if (!c.ExistsInDatabase()) return; + Session.XSession.DropCollection(Name, name); + } + catch (MySqlException ex) + { + switch (ex.Number) + { + case (int)CloseNotification.IDLE: + case (int)CloseNotification.KILLED: + case (int)CloseNotification.SHUTDOWN: + XDevAPI.Session.ThrowSessionClosedByServerException(ex, Session); + break; + default: + throw; + } + } + } + + #region Base Class + + /// + /// Determines if this schema actually exists. + /// + /// True if exists, false otherwise. + public override bool ExistsInDatabase() + { + bool result = false; + try + { + ValidateOpenSession(); + string sql = String.Format("SELECT COUNT(*) FROM information_schema.schemata WHERE schema_name like '{0}'", Name); + long count = (long)Session.InternalSession.ExecuteQueryAsScalar(sql); + result = count > 0; + } + catch (MySqlException ex) + { + switch (ex.Number) + { + case (int)CloseNotification.IDLE: + case (int)CloseNotification.KILLED: + case (int)CloseNotification.SHUTDOWN: + XDevAPI.Session.ThrowSessionClosedByServerException(ex, Session); + break; + default: + throw; + } + } + return result; + } + + #endregion + } +} diff --git a/MySQL.Data/src/X/XDevAPI/Session.cs b/MySQL.Data/src/X/XDevAPI/Session.cs index 978e7de8a..784f2c9ad 100644 --- a/MySQL.Data/src/X/XDevAPI/Session.cs +++ b/MySQL.Data/src/X/XDevAPI/Session.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2015, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/common/Cache.cs b/MySQL.Data/src/common/Cache.cs index bd1494f8d..3535ece0c 100644 --- a/MySQL.Data/src/common/Cache.cs +++ b/MySQL.Data/src/common/Cache.cs @@ -1,83 +1,83 @@ -// Copyright (c) 2004, 2016, Oracle and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using System.Collections.Generic; - -namespace MySql.Data.Common -{ - internal class Cache - { - private readonly int _capacity; - private readonly Queue _keyQ; - private readonly Dictionary _contents; - - public Cache(int initialCapacity, int capacity) - { - _capacity = capacity; - _contents = new Dictionary(initialCapacity); - - if (capacity > 0) - _keyQ = new Queue(initialCapacity); - } - - public TValueType this[TKeyType key] - { - get - { - TValueType val; - if (_contents.TryGetValue(key, out val)) - return val; - else - return default(TValueType); - } - set { InternalAdd(key, value); } - } - - public void Add(TKeyType key, TValueType value) - { - InternalAdd(key, value); - } - - private void InternalAdd(TKeyType key, TValueType value) - { - if (!_contents.ContainsKey(key)) - { - - if (_capacity > 0) - { - _keyQ.Enqueue(key); - - if (_keyQ.Count > _capacity) - _contents.Remove(_keyQ.Dequeue()); - } - } - - _contents[key] = value; - } - } -} +// Copyright © 2004, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using System.Collections.Generic; + +namespace MySql.Data.Common +{ + internal class Cache + { + private readonly int _capacity; + private readonly Queue _keyQ; + private readonly Dictionary _contents; + + public Cache(int initialCapacity, int capacity) + { + _capacity = capacity; + _contents = new Dictionary(initialCapacity); + + if (capacity > 0) + _keyQ = new Queue(initialCapacity); + } + + public TValueType this[TKeyType key] + { + get + { + TValueType val; + if (_contents.TryGetValue(key, out val)) + return val; + else + return default(TValueType); + } + set { InternalAdd(key, value); } + } + + public void Add(TKeyType key, TValueType value) + { + InternalAdd(key, value); + } + + private void InternalAdd(TKeyType key, TValueType value) + { + if (!_contents.ContainsKey(key)) + { + + if (_capacity > 0) + { + _keyQ.Enqueue(key); + + if (_keyQ.Count > _capacity) + _contents.Remove(_keyQ.Dequeue()); + } + } + + _contents[key] = value; + } + } +} diff --git a/MySQL.Data/src/common/ContextString.cs b/MySQL.Data/src/common/ContextString.cs index cf57f4ca6..1108dc87b 100644 --- a/MySQL.Data/src/common/ContextString.cs +++ b/MySQL.Data/src/common/ContextString.cs @@ -1,171 +1,171 @@ -// Copyright (c) 2004, 2016, Oracle and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using System; -using System.Collections; -using System.Text; - -namespace MySql.Data.Common -{ - internal class ContextString - { - readonly bool _escapeBackslash; - - // Create a private ctor so the compiler doesn't give us a default one - public ContextString(string contextMarkers, bool escapeBackslash) - { - ContextMarkers = contextMarkers; - _escapeBackslash = escapeBackslash; - } - - public string ContextMarkers { get; set; } - - public int IndexOf(string src, string target) - { - return IndexOf(src, target, 0); - } - - public int IndexOf(string src, string target, int startIndex) - { - int index = src.IndexOf(target, startIndex); - while (index != -1) - { - if (!IndexInQuotes(src, index, startIndex)) break; - index = src.IndexOf(target, index + 1); - } - return index; - } - - private bool IndexInQuotes(string src, int index, int startIndex) - { - char contextMarker = Char.MinValue; - bool escaped = false; - - for (int i = startIndex; i < index; i++) - { - char c = src[i]; - - int contextIndex = ContextMarkers.IndexOf(c); - - // if we have found the closing marker for our open marker, then close the context - if (contextIndex > -1 && contextMarker == ContextMarkers[contextIndex] && !escaped) - contextMarker = Char.MinValue; - - // if we have found a context marker and we are not in a context yet, then start one - else if (contextMarker == Char.MinValue && contextIndex > -1 && !escaped) - contextMarker = c; - - else if (c == '\\' && _escapeBackslash) - escaped = !escaped; - } - return contextMarker != Char.MinValue || escaped; - } - - public int IndexOf(string src, char target) - { - char contextMarker = Char.MinValue; - bool escaped = false; - int pos = 0; - - foreach (char c in src) - { - int contextIndex = ContextMarkers.IndexOf(c); - - // if we have found the closing marker for our open marker, then close the context - if (contextIndex > -1 && contextMarker == ContextMarkers[contextIndex] && !escaped) - contextMarker = Char.MinValue; - - // if we have found a context marker and we are not in a context yet, then start one - else if (contextMarker == Char.MinValue && contextIndex > -1 && !escaped) - contextMarker = c; - - else if (contextMarker == Char.MinValue && c == target) - return pos; - else if (c == '\\' && _escapeBackslash) - escaped = !escaped; - pos++; - } - return -1; - } - - public string[] Split(string src, string delimiters) - { - ArrayList parts = new ArrayList(); - StringBuilder sb = new StringBuilder(); - bool escaped = false; - - char contextMarker = Char.MinValue; - - foreach (char c in src) - { - if (delimiters.IndexOf(c) != -1 && !escaped) - { - if (contextMarker != Char.MinValue) - sb.Append(c); - else - { - if (sb.Length <= 0) continue; - parts.Add(sb.ToString()); - sb.Remove(0, sb.Length); - } - } - else if (c == '\\' && _escapeBackslash) - escaped = !escaped; - else - { - int contextIndex = ContextMarkers.IndexOf(c); - if (!escaped && contextIndex != -1) - { - // if we have found the closing marker for our open - // marker, then close the context - if ((contextIndex % 2) == 1) - { - if (contextMarker == ContextMarkers[contextIndex - 1]) - contextMarker = Char.MinValue; - } - else - { - // if the opening and closing context markers are - // the same then we will always find the opening - // marker. - if (contextMarker == ContextMarkers[contextIndex + 1]) - contextMarker = Char.MinValue; - else if (contextMarker == Char.MinValue) - contextMarker = c; - } - } - - sb.Append(c); - } - } - if (sb.Length > 0) - parts.Add(sb.ToString()); - return (string[])parts.ToArray(typeof(string)); - } - } -} +// Copyright © 2004, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using System; +using System.Collections; +using System.Text; + +namespace MySql.Data.Common +{ + internal class ContextString + { + readonly bool _escapeBackslash; + + // Create a private ctor so the compiler doesn't give us a default one + public ContextString(string contextMarkers, bool escapeBackslash) + { + ContextMarkers = contextMarkers; + _escapeBackslash = escapeBackslash; + } + + public string ContextMarkers { get; set; } + + public int IndexOf(string src, string target) + { + return IndexOf(src, target, 0); + } + + public int IndexOf(string src, string target, int startIndex) + { + int index = src.IndexOf(target, startIndex); + while (index != -1) + { + if (!IndexInQuotes(src, index, startIndex)) break; + index = src.IndexOf(target, index + 1); + } + return index; + } + + private bool IndexInQuotes(string src, int index, int startIndex) + { + char contextMarker = Char.MinValue; + bool escaped = false; + + for (int i = startIndex; i < index; i++) + { + char c = src[i]; + + int contextIndex = ContextMarkers.IndexOf(c); + + // if we have found the closing marker for our open marker, then close the context + if (contextIndex > -1 && contextMarker == ContextMarkers[contextIndex] && !escaped) + contextMarker = Char.MinValue; + + // if we have found a context marker and we are not in a context yet, then start one + else if (contextMarker == Char.MinValue && contextIndex > -1 && !escaped) + contextMarker = c; + + else if (c == '\\' && _escapeBackslash) + escaped = !escaped; + } + return contextMarker != Char.MinValue || escaped; + } + + public int IndexOf(string src, char target) + { + char contextMarker = Char.MinValue; + bool escaped = false; + int pos = 0; + + foreach (char c in src) + { + int contextIndex = ContextMarkers.IndexOf(c); + + // if we have found the closing marker for our open marker, then close the context + if (contextIndex > -1 && contextMarker == ContextMarkers[contextIndex] && !escaped) + contextMarker = Char.MinValue; + + // if we have found a context marker and we are not in a context yet, then start one + else if (contextMarker == Char.MinValue && contextIndex > -1 && !escaped) + contextMarker = c; + + else if (contextMarker == Char.MinValue && c == target) + return pos; + else if (c == '\\' && _escapeBackslash) + escaped = !escaped; + pos++; + } + return -1; + } + + public string[] Split(string src, string delimiters) + { + ArrayList parts = new ArrayList(); + StringBuilder sb = new StringBuilder(); + bool escaped = false; + + char contextMarker = Char.MinValue; + + foreach (char c in src) + { + if (delimiters.IndexOf(c) != -1 && !escaped) + { + if (contextMarker != Char.MinValue) + sb.Append(c); + else + { + if (sb.Length <= 0) continue; + parts.Add(sb.ToString()); + sb.Remove(0, sb.Length); + } + } + else if (c == '\\' && _escapeBackslash) + escaped = !escaped; + else + { + int contextIndex = ContextMarkers.IndexOf(c); + if (!escaped && contextIndex != -1) + { + // if we have found the closing marker for our open + // marker, then close the context + if ((contextIndex % 2) == 1) + { + if (contextMarker == ContextMarkers[contextIndex - 1]) + contextMarker = Char.MinValue; + } + else + { + // if the opening and closing context markers are + // the same then we will always find the opening + // marker. + if (contextMarker == ContextMarkers[contextIndex + 1]) + contextMarker = Char.MinValue; + else if (contextMarker == Char.MinValue) + contextMarker = c; + } + } + + sb.Append(c); + } + } + if (sb.Length > 0) + parts.Add(sb.ToString()); + return (string[])parts.ToArray(typeof(string)); + } + } +} diff --git a/MySQL.Data/src/common/Dns/DnsEnums.cs b/MySQL.Data/src/common/Dns/DnsEnums.cs index 97a718c29..0291bda64 100644 --- a/MySQL.Data/src/common/Dns/DnsEnums.cs +++ b/MySQL.Data/src/common/Dns/DnsEnums.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2022, Oracle and/or its affiliates. +// Copyright © 2022, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/common/Dns/DnsQuestion.cs b/MySQL.Data/src/common/Dns/DnsQuestion.cs index d8f35d548..89861c146 100644 --- a/MySQL.Data/src/common/Dns/DnsQuestion.cs +++ b/MySQL.Data/src/common/Dns/DnsQuestion.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2022, Oracle and/or its affiliates. +// Copyright © 2022, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/common/Dns/DnsRecordHeader.cs b/MySQL.Data/src/common/Dns/DnsRecordHeader.cs index 198e23d61..8db53aa42 100644 --- a/MySQL.Data/src/common/Dns/DnsRecordHeader.cs +++ b/MySQL.Data/src/common/Dns/DnsRecordHeader.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2022, Oracle and/or its affiliates. +// Copyright © 2022, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/common/Dns/DnsRecordReader.cs b/MySQL.Data/src/common/Dns/DnsRecordReader.cs index 060ce10dc..2e35895bd 100644 --- a/MySQL.Data/src/common/Dns/DnsRecordReader.cs +++ b/MySQL.Data/src/common/Dns/DnsRecordReader.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2022, Oracle and/or its affiliates. +// Copyright © 2022, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/common/Dns/DnsRecordUnknown.cs b/MySQL.Data/src/common/Dns/DnsRecordUnknown.cs index 6cff373c3..8c2bfaf3f 100644 --- a/MySQL.Data/src/common/Dns/DnsRecordUnknown.cs +++ b/MySQL.Data/src/common/Dns/DnsRecordUnknown.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2022, Oracle and/or its affiliates. +// Copyright © 2022, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/common/Dns/DnsRequest.cs b/MySQL.Data/src/common/Dns/DnsRequest.cs index fa1c685a8..2a9372a40 100644 --- a/MySQL.Data/src/common/Dns/DnsRequest.cs +++ b/MySQL.Data/src/common/Dns/DnsRequest.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2022, Oracle and/or its affiliates. +// Copyright © 2022, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/common/Dns/DnsResolver.cs b/MySQL.Data/src/common/Dns/DnsResolver.cs index ab5063a74..a82d579a2 100644 --- a/MySQL.Data/src/common/Dns/DnsResolver.cs +++ b/MySQL.Data/src/common/Dns/DnsResolver.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2022, Oracle and/or its affiliates. +// Copyright © 2022, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/common/Dns/DnsResourceRecord.cs b/MySQL.Data/src/common/Dns/DnsResourceRecord.cs index 32754b722..a0b8dcafd 100644 --- a/MySQL.Data/src/common/Dns/DnsResourceRecord.cs +++ b/MySQL.Data/src/common/Dns/DnsResourceRecord.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2022, Oracle and/or its affiliates. +// Copyright © 2022, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/common/Dns/DnsResponse.cs b/MySQL.Data/src/common/Dns/DnsResponse.cs index ababab2d7..1667744e1 100644 --- a/MySQL.Data/src/common/Dns/DnsResponse.cs +++ b/MySQL.Data/src/common/Dns/DnsResponse.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2022, Oracle and/or its affiliates. +// Copyright © 2022, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/common/Dns/DnsSrvRecord.cs b/MySQL.Data/src/common/Dns/DnsSrvRecord.cs index 6c3fd39cf..3d8b1d62a 100644 --- a/MySQL.Data/src/common/Dns/DnsSrvRecord.cs +++ b/MySQL.Data/src/common/Dns/DnsSrvRecord.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2019, 2022, Oracle and/or its affiliates. +// Copyright © 2019, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -98,4 +98,4 @@ public int Compare(DnsSrvRecord x, DnsSrvRecord y) return priorityDiff == 0 ? y.Weight.CompareTo(x.Weight) : priorityDiff; } } -} \ No newline at end of file +} diff --git a/MySQL.Data/src/common/DnsSrv.cs b/MySQL.Data/src/common/DnsSrv.cs index 7d96dc7bf..429199688 100644 --- a/MySQL.Data/src/common/DnsSrv.cs +++ b/MySQL.Data/src/common/DnsSrv.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2019, 2022, Oracle and/or its affiliates. +// Copyright © 2019, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -119,4 +119,4 @@ internal static List SortSrvRecords(List srvRecords) /// private static void Reset() => _resolver = null; } -} \ No newline at end of file +} diff --git a/MySQL.Data/src/common/LowResolutionStopwatch.cs b/MySQL.Data/src/common/LowResolutionStopwatch.cs index 801adc1fa..11cddb077 100644 --- a/MySQL.Data/src/common/LowResolutionStopwatch.cs +++ b/MySQL.Data/src/common/LowResolutionStopwatch.cs @@ -1,101 +1,101 @@ -// Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using System; - -namespace MySql.Data.Common -{ - /// - /// This class is modeled after .NET Stopwatch. It provides better - /// performance (no system calls).It is however less precise than - /// .NET Stopwatch, measuring in milliseconds. It is adequate to use - /// when high-precision is not required (e.g for measuring IO timeouts), - /// but not for other tasks. - /// - internal class LowResolutionStopwatch - { - long _startTime; - public static readonly long Frequency = 1000; // measure in milliseconds - public static readonly bool IsHighResolution = false; - - public LowResolutionStopwatch() - { - ElapsedMilliseconds = 0; - } - public long ElapsedMilliseconds { get; private set; } - - public void Start() - { - _startTime = Environment.TickCount; - } - - public void Stop() - { - long now = Environment.TickCount; - long elapsed; - - // Calculate time different, handle possible overflow - if (now < _startTime) - { - if (now < 0) - elapsed = 1 + ((long)Int32.MaxValue - _startTime) + (now - (long)Int32.MinValue); - else - elapsed = Int32.MaxValue - _startTime + now; - } - else - elapsed = now - _startTime; - - ElapsedMilliseconds += elapsed; - } - - public void Reset() - { - ElapsedMilliseconds = 0; - _startTime = 0; - } - - public TimeSpan Elapsed => new TimeSpan(0, 0, 0, 0, (int)ElapsedMilliseconds); - - public static LowResolutionStopwatch StartNew() - { - LowResolutionStopwatch sw = new LowResolutionStopwatch(); - sw.Start(); - return sw; - } - - public static long GetTimestamp() - { - return Environment.TickCount; - } - - bool IsRunning() - { - return (_startTime != 0); - } - } -} +// Copyright © 2009, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using System; + +namespace MySql.Data.Common +{ + /// + /// This class is modeled after .NET Stopwatch. It provides better + /// performance (no system calls).It is however less precise than + /// .NET Stopwatch, measuring in milliseconds. It is adequate to use + /// when high-precision is not required (e.g for measuring IO timeouts), + /// but not for other tasks. + /// + internal class LowResolutionStopwatch + { + long _startTime; + public static readonly long Frequency = 1000; // measure in milliseconds + public static readonly bool IsHighResolution = false; + + public LowResolutionStopwatch() + { + ElapsedMilliseconds = 0; + } + public long ElapsedMilliseconds { get; private set; } + + public void Start() + { + _startTime = Environment.TickCount; + } + + public void Stop() + { + long now = Environment.TickCount; + long elapsed; + + // Calculate time different, handle possible overflow + if (now < _startTime) + { + if (now < 0) + elapsed = 1 + ((long)Int32.MaxValue - _startTime) + (now - (long)Int32.MinValue); + else + elapsed = Int32.MaxValue - _startTime + now; + } + else + elapsed = now - _startTime; + + ElapsedMilliseconds += elapsed; + } + + public void Reset() + { + ElapsedMilliseconds = 0; + _startTime = 0; + } + + public TimeSpan Elapsed => new TimeSpan(0, 0, 0, 0, (int)ElapsedMilliseconds); + + public static LowResolutionStopwatch StartNew() + { + LowResolutionStopwatch sw = new LowResolutionStopwatch(); + sw.Start(); + return sw; + } + + public static long GetTimestamp() + { + return Environment.TickCount; + } + + bool IsRunning() + { + return (_startTime != 0); + } + } +} diff --git a/MySQL.Data/src/common/MyNetworkStream.cs b/MySQL.Data/src/common/MyNetworkStream.cs index 7b69d4107..c8b5e2ed2 100644 --- a/MySQL.Data/src/common/MyNetworkStream.cs +++ b/MySQL.Data/src/common/MyNetworkStream.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2009, 2023, Oracle and/or its affiliates. +// Copyright © 2009, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -116,8 +116,7 @@ private void HandleOrRethrowException(Exception e) } if (IsTimeoutException(socketException)) { - return; - //throw new TimeoutException(socketException.Message, e); + throw new TimeoutException(socketException.Message, e); } } currentException = currentException.InnerException; @@ -137,16 +136,30 @@ private async Task ReadAsync(byte[] buffer, int offset, int count, Cancella { try { + //if (execAsync) + // return await base.ReadAsync(buffer, offset, count, cancellationToken).ConfigureAwait(false); + //else + // return base.Read(buffer, offset, count); + if (execAsync) - return await base.ReadAsync(buffer, offset, count, cancellationToken).ConfigureAwait(false); + { + int readasync= await base.ReadAsync(buffer, offset, count, cancellationToken).ConfigureAwait(false); + _socket.ReceiveTimeout = 0; + return readasync; + } else - return base.Read(buffer, offset, count); + { + int read = base.Read(buffer, offset, count); + _socket.ReceiveTimeout = 0; + return read; + } } catch (Exception e) { exception = e; HandleOrRethrowException(e); } + } while (++retry < MaxRetryCount); if (exception.GetBaseException() is SocketException @@ -296,6 +309,9 @@ private static MyNetworkStream CreateSocketStream(uint port, uint keepAlive, uin new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.IP) : new Socket(ip.AddressFamily, SocketType.Stream, ProtocolType.Tcp); + if (connectionTimeout > 0) + socket.ReceiveTimeout = (int)connectionTimeout; + socket.NoDelay = true; if (keepAlive > 0) @@ -385,4 +401,4 @@ private static void SetKeepAlive(Socket s, uint time) #endregion } -} \ No newline at end of file +} diff --git a/MySQL.Data/src/common/MySqlConnectionStringOption.cs b/MySQL.Data/src/common/MySqlConnectionStringOption.cs index 1fc3a7209..64ec4d6d5 100644 --- a/MySQL.Data/src/common/MySqlConnectionStringOption.cs +++ b/MySQL.Data/src/common/MySqlConnectionStringOption.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2019, 2021, Oracle and/or its affiliates. +// Copyright © 2019, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/common/MySqlConnectionStringOptionCollection.cs b/MySQL.Data/src/common/MySqlConnectionStringOptionCollection.cs index 3455a11f2..00609df8e 100644 --- a/MySQL.Data/src/common/MySqlConnectionStringOptionCollection.cs +++ b/MySQL.Data/src/common/MySqlConnectionStringOptionCollection.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2019, 2021, Oracle and/or its affiliates. +// Copyright © 2019, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/common/MySqlTokenizer.cs b/MySQL.Data/src/common/MySqlTokenizer.cs index 10ef3d74d..6bf9c226c 100644 --- a/MySQL.Data/src/common/MySqlTokenizer.cs +++ b/MySQL.Data/src/common/MySqlTokenizer.cs @@ -1,288 +1,288 @@ -// Copyright (c) 2004, 2021, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Text; - -namespace MySql.Data.Common -{ - internal class MySqlTokenizer - { - private string _sql; - - public MySqlTokenizer() - { - BackslashEscapes = true; - MultiLine = true; - Position = 0; - } - - public MySqlTokenizer(string input) - : this() - { - _sql = input; - } - - #region Properties - - public string Text - { - get { return _sql; } - set { _sql = value; Position = 0; } - } - - public bool AnsiQuotes { get; set; } - - public bool BackslashEscapes { get; set; } - - public bool MultiLine { get; set; } - - public bool SqlServerMode { get; set; } - - public bool Quoted { get; private set; } - - public bool IsComment { get; private set; } - - public int StartIndex { get; set; } - - public int StopIndex { get; set; } - - public int Position { get; set; } - - public bool ReturnComments { get; set; } - - #endregion - - public List GetAllTokens() - { - List tokens = new List(); - string token = NextToken(); - while (token != null) - { - tokens.Add(token); - token = NextToken(); - } - return tokens; - } - - public string NextToken() - { - while (FindToken()) - { - string token = _sql.Substring(StartIndex, StopIndex - StartIndex); - return token; - } - return null; - } - - public static bool IsParameter(string s) - { - if (String.IsNullOrEmpty(s)) return false; - if (s[0] == '?') return true; - return s.Length > 1 && s[0] == '@' && s[1] != '@'; - } - - public string NextParameter() - { - while (FindToken()) - { - if ((StopIndex - StartIndex) < 2) - { - if (IsParameter(_sql.Substring(StartIndex, 1))) return "?"; - else continue; - } - char c1 = _sql[StartIndex]; - char c2 = _sql[StartIndex + 1]; - if (c1 == '?' || - (c1 == '@' && c2 != '@')) - return _sql.Substring(StartIndex, StopIndex - StartIndex); - } - return null; - } - - public bool FindToken() - { - IsComment = Quoted = false; // reset our flags - StartIndex = StopIndex = -1; - - while (Position < _sql.Length) - { - char c = _sql[Position++]; - if (Char.IsWhiteSpace(c)) continue; - - if (c == '`' || c == '\'' || c == '"' || (c == '[' && SqlServerMode)) - ReadQuotedToken(c); - else if (c == '#' || c == '-' || c == '/') - { - if (!ReadComment(c)) - ReadSpecialToken(); - } - else - ReadUnquotedToken(); - if (StartIndex != -1) return true; - } - return false; - } - - public string ReadParenthesis() - { - StringBuilder sb = new StringBuilder("("); - int start = StartIndex; - string token = NextToken(); - while (true) - { - if (token == null) - throw new InvalidOperationException("Unable to parse SQL"); - sb.Append(token); - if (token == ")" && !Quoted) break; - token = NextToken(); - } - return sb.ToString(); - } - - private bool ReadComment(char c) - { - // make sure the comment starts correctly - if (c == '/' && (Position >= _sql.Length || _sql[Position] != '*')) return false; - if (c == '-' && ((Position + 1) >= _sql.Length || _sql[Position] != '-' || _sql[Position + 1] != ' ')) return false; - - string endingPattern = "\n"; - if (_sql[Position] == '*') - endingPattern = "*/"; - - int startingIndex = Position - 1; - - int index = _sql.IndexOf(endingPattern, Position); - if (endingPattern == "\n") - index = _sql.IndexOf('\n', Position); - if (index == -1) - index = _sql.Length - 1; - else - index += endingPattern.Length; - - Position = index; - if (ReturnComments) - { - StartIndex = startingIndex; - StopIndex = index; - IsComment = true; - } - return true; - } - - private void CalculatePosition(int start, int stop) - { - StartIndex = start; - StopIndex = stop; - if (!MultiLine) return; - } - - private void ReadUnquotedToken() - { - StartIndex = Position - 1; - - if (!IsSpecialCharacter(_sql[StartIndex])) - { - while (Position < _sql.Length) - { - char c = _sql[Position]; - if (Char.IsWhiteSpace(c)) break; - if (IsSpecialCharacter(c)) break; - Position++; - } - } - - Quoted = false; - StopIndex = Position; - } - - private void ReadSpecialToken() - { - StartIndex = Position - 1; - - Debug.Assert(IsSpecialCharacter(_sql[StartIndex])); - - StopIndex = Position; - Quoted = false; - } - - /// - /// Read a single quoted identifier from the stream - /// - /// - /// - private void ReadQuotedToken(char quoteChar) - { - if (quoteChar == '[') - quoteChar = ']'; - StartIndex = Position - 1; - bool escaped = false; - - bool found = false; - while (Position < _sql.Length) - { - char c = _sql[Position]; - - if (c == quoteChar && !escaped) - { - found = true; - break; - } - - if (escaped) - escaped = false; - else if (c == '\\' && BackslashEscapes) - escaped = true; - Position++; - } - if (found) Position++; - Quoted = found; - StopIndex = Position; - } - - private bool IsQuoteChar(char c) - { - return c == '`' || c == '\'' || c == '\"'; - } - - internal bool IsParameterMarker(char c) - { - return c == '@' || c == '?'; - } - - private bool IsSpecialCharacter(char c) - { - if (Char.IsLetterOrDigit(c) || - c == '$' || c == '_' || c == '.') return false; - if (IsParameterMarker(c)) return false; - return true; - } - } -} +// Copyright © 2004, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text; + +namespace MySql.Data.Common +{ + internal class MySqlTokenizer + { + private string _sql; + + public MySqlTokenizer() + { + BackslashEscapes = true; + MultiLine = true; + Position = 0; + } + + public MySqlTokenizer(string input) + : this() + { + _sql = input; + } + + #region Properties + + public string Text + { + get { return _sql; } + set { _sql = value; Position = 0; } + } + + public bool AnsiQuotes { get; set; } + + public bool BackslashEscapes { get; set; } + + public bool MultiLine { get; set; } + + public bool SqlServerMode { get; set; } + + public bool Quoted { get; private set; } + + public bool IsComment { get; private set; } + + public int StartIndex { get; set; } + + public int StopIndex { get; set; } + + public int Position { get; set; } + + public bool ReturnComments { get; set; } + + #endregion + + public List GetAllTokens() + { + List tokens = new List(); + string token = NextToken(); + while (token != null) + { + tokens.Add(token); + token = NextToken(); + } + return tokens; + } + + public string NextToken() + { + while (FindToken()) + { + string token = _sql.Substring(StartIndex, StopIndex - StartIndex); + return token; + } + return null; + } + + public static bool IsParameter(string s) + { + if (String.IsNullOrEmpty(s)) return false; + if (s[0] == '?') return true; + return s.Length > 1 && s[0] == '@' && s[1] != '@'; + } + + public string NextParameter() + { + while (FindToken()) + { + if ((StopIndex - StartIndex) < 2) + { + if (IsParameter(_sql.Substring(StartIndex, 1))) return "?"; + else continue; + } + char c1 = _sql[StartIndex]; + char c2 = _sql[StartIndex + 1]; + if (c1 == '?' || + (c1 == '@' && c2 != '@')) + return _sql.Substring(StartIndex, StopIndex - StartIndex); + } + return null; + } + + public bool FindToken() + { + IsComment = Quoted = false; // reset our flags + StartIndex = StopIndex = -1; + + while (Position < _sql.Length) + { + char c = _sql[Position++]; + if (Char.IsWhiteSpace(c)) continue; + + if (c == '`' || c == '\'' || c == '"' || (c == '[' && SqlServerMode)) + ReadQuotedToken(c); + else if (c == '#' || c == '-' || c == '/') + { + if (!ReadComment(c)) + ReadSpecialToken(); + } + else + ReadUnquotedToken(); + if (StartIndex != -1) return true; + } + return false; + } + + public string ReadParenthesis() + { + StringBuilder sb = new StringBuilder("("); + int start = StartIndex; + string token = NextToken(); + while (true) + { + if (token == null) + throw new InvalidOperationException("Unable to parse SQL"); + sb.Append(token); + if (token == ")" && !Quoted) break; + token = NextToken(); + } + return sb.ToString(); + } + + private bool ReadComment(char c) + { + // make sure the comment starts correctly + if (c == '/' && (Position >= _sql.Length || _sql[Position] != '*')) return false; + if (c == '-' && ((Position + 1) >= _sql.Length || _sql[Position] != '-' || _sql[Position + 1] != ' ')) return false; + + string endingPattern = "\n"; + if (_sql[Position] == '*') + endingPattern = "*/"; + + int startingIndex = Position - 1; + + int index = _sql.IndexOf(endingPattern, Position); + if (endingPattern == "\n") + index = _sql.IndexOf('\n', Position); + if (index == -1) + index = _sql.Length - 1; + else + index += endingPattern.Length; + + Position = index; + if (ReturnComments) + { + StartIndex = startingIndex; + StopIndex = index; + IsComment = true; + } + return true; + } + + private void CalculatePosition(int start, int stop) + { + StartIndex = start; + StopIndex = stop; + if (!MultiLine) return; + } + + private void ReadUnquotedToken() + { + StartIndex = Position - 1; + + if (!IsSpecialCharacter(_sql[StartIndex])) + { + while (Position < _sql.Length) + { + char c = _sql[Position]; + if (Char.IsWhiteSpace(c)) break; + if (IsSpecialCharacter(c)) break; + Position++; + } + } + + Quoted = false; + StopIndex = Position; + } + + private void ReadSpecialToken() + { + StartIndex = Position - 1; + + Debug.Assert(IsSpecialCharacter(_sql[StartIndex])); + + StopIndex = Position; + Quoted = false; + } + + /// + /// Read a single quoted identifier from the stream + /// + /// + /// + private void ReadQuotedToken(char quoteChar) + { + if (quoteChar == '[') + quoteChar = ']'; + StartIndex = Position - 1; + bool escaped = false; + + bool found = false; + while (Position < _sql.Length) + { + char c = _sql[Position]; + + if (c == quoteChar && !escaped) + { + found = true; + break; + } + + if (escaped) + escaped = false; + else if (c == '\\' && BackslashEscapes) + escaped = true; + Position++; + } + if (found) Position++; + Quoted = found; + StopIndex = Position; + } + + private bool IsQuoteChar(char c) + { + return c == '`' || c == '\'' || c == '\"'; + } + + internal bool IsParameterMarker(char c) + { + return c == '@' || c == '?'; + } + + private bool IsSpecialCharacter(char c) + { + if (Char.IsLetterOrDigit(c) || + c == '$' || c == '_' || c == '.') return false; + if (IsParameterMarker(c)) return false; + return true; + } + } +} diff --git a/MySQL.Data/src/common/NativeMethods.cs b/MySQL.Data/src/common/NativeMethods.cs index dd008747a..6501e7a41 100644 --- a/MySQL.Data/src/common/NativeMethods.cs +++ b/MySQL.Data/src/common/NativeMethods.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2009, 2022, Oracle and/or its affiliates. +// Copyright © 2009, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -68,7 +68,7 @@ public SecurityAttributes() public bool inheritHandle; } - [DllImport("Kernel32", CharSet = CharSet.Unicode)] + [DllImport("Kernel32", CharSet = CharSet.Unicode, SetLastError = true)] static extern public IntPtr CreateFile( String fileName, uint desiredAccess, diff --git a/MySQL.Data/src/common/Platform.cs b/MySQL.Data/src/common/Platform.cs index 4c0ec59ce..c4bed02dc 100644 --- a/MySQL.Data/src/common/Platform.cs +++ b/MySQL.Data/src/common/Platform.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2004, 2023, Oracle and/or its affiliates. +// Copyright © 2004, 2025, Oracle and/or its affiliates. // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/common/QueryNormalizer.cs b/MySQL.Data/src/common/QueryNormalizer.cs index f92d4d6ae..d99b23224 100644 --- a/MySQL.Data/src/common/QueryNormalizer.cs +++ b/MySQL.Data/src/common/QueryNormalizer.cs @@ -1,380 +1,380 @@ -// Copyright (c) 2009, 2020 Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data.MySqlClient; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace MySql.Data.Common -{ - internal class QueryNormalizer - { - private static readonly List Keywords = new List(); - private readonly List _tokens = new List(); - private int _pos; - private string _fullSql; - private string _queryType; - - static QueryNormalizer() - { - Keywords = SchemaProvider.GetReservedWords().AsDataTable(). - Select(). - Select(x => x[0].ToString()).ToList(); - } - - public string QueryType => _queryType; - - public string Normalize(string sql) - { - _tokens.Clear(); - StringBuilder newSql = new StringBuilder(); - _fullSql = sql; - - TokenizeSql(sql); - DetermineStatementType(_tokens); - ProcessMathSymbols(_tokens); - CollapseValueLists(_tokens); - CollapseInLists(_tokens); - CollapseWhitespace(_tokens); - - foreach (Token t in _tokens.Where(t => t.Output)) - newSql.Append(t.Text); - - return newSql.ToString(); - } - - private void DetermineStatementType(List tok) - { - foreach (Token t in tok.Where(t => t.Type == TokenType.Keyword)) - { - _queryType = t.Text.ToUpperInvariant(); - break; - } - } - - /// - /// Mark - or + signs that are unary ops as no output - /// - /// - private static void ProcessMathSymbols(List tok) - { - Token lastToken = null; - - foreach (Token t in tok) - { - if (t.Type == TokenType.Symbol && - (t.Text == "-" || t.Text == "+")) - { - if (lastToken != null && - lastToken.Type != TokenType.Number && - lastToken.Type != TokenType.Identifier && - (lastToken.Type != TokenType.Symbol || lastToken.Text != ")")) - t.Output = false; - } - if (t.IsRealToken) - lastToken = t; - } - } - - private static void CollapseWhitespace(List tok) - { - Token lastToken = null; - - foreach (Token t in tok) - { - if (t.Output && - t.Type == TokenType.Whitespace && - lastToken != null && - lastToken.Type == TokenType.Whitespace) - { - t.Output = false; - } - if (t.Output) - lastToken = t; - } - } - - private void CollapseValueLists(List tok) - { - int pos = -1; - while (++pos < tok.Count) - { - Token t = tok[pos]; - if (t.Type != TokenType.Keyword) continue; - if (!t.Text.StartsWith("VALUE", StringComparison.OrdinalIgnoreCase)) continue; - CollapseValueList(tok, ref pos); - } - } - - private void CollapseValueList(List tok, ref int pos) - { - List parenIndices = new List(); - - // this while loop will find all closing parens in this value list - while (true) - { - // find the close ')' - while (++pos < tok.Count) - { - if (tok[pos].Type == TokenType.Symbol && tok[pos].Text == ")") - break; - if (pos == tok.Count - 1) - break; - } - parenIndices.Add(pos); - - // now find the next "real" token - while (++pos < tok.Count) - if (tok[pos].IsRealToken) break; - if (pos == tok.Count) break; - - if (tok[pos].Text == ",") continue; - pos--; - break; - } - - // if we only have 1 value then we don't collapse - if (parenIndices.Count < 2) return; - int index = parenIndices[0]; - tok[++index] = new Token(TokenType.Whitespace, " "); - tok[++index] = new Token(TokenType.Comment, "/* , ... */"); - index++; - - // now mark all the other tokens as no output - while (index <= parenIndices[parenIndices.Count - 1]) - tok[index++].Output = false; - } - - private void CollapseInLists(List tok) - { - int pos = -1; - while (++pos < tok.Count) - { - Token t = tok[pos]; - if (t.Type != TokenType.Keyword) continue; - if (t.Text != "IN") continue; - CollapseInList(tok, ref pos); - } - } - - private static Token GetNextRealToken(List tok, ref int pos) - { - while (++pos < tok.Count) - { - if (tok[pos].IsRealToken) return tok[pos]; - } - return null; - } - - private static void CollapseInList(List tok, ref int pos) - { - Token t = GetNextRealToken(tok, ref pos); - // Debug.Assert(t.Text == "("); - if (t == null) - return; - - // if the first token is a keyword then we likely have a - // SELECT .. IN (SELECT ...) - t = GetNextRealToken(tok, ref pos); - if (t == null || t.Type == TokenType.Keyword) return; - - int start = pos; - // first find all the tokens that make up the in list - while (++pos < tok.Count) - { - t = tok[pos]; - if (t.Type == TokenType.CommandComment) return; - if (!t.IsRealToken) continue; - if (t.Text == "(") return; - if (t.Text == ")") break; - } - int stop = pos; - - for (int i = stop; i > start; i--) - tok.RemoveAt(i); - tok.Insert(++start, new Token(TokenType.Whitespace, " ")); - tok.Insert(++start, new Token(TokenType.Comment, "/* , ... */")); - tok.Insert(++start, new Token(TokenType.Whitespace, " ")); - tok.Insert(++start, new Token(TokenType.Symbol, ")")); - } - - private void TokenizeSql(string sql) - { - _pos = 0; - - while (_pos < sql.Length) - { - char c = sql[_pos]; - if (LetterStartsComment(c) && ConsumeComment()) - continue; - if (Char.IsWhiteSpace(c)) - ConsumeWhitespace(); - else if (c == '\'' || c == '\"' || c == '`') - ConsumeQuotedToken(c); - else if (!IsSpecialCharacter(c)) - ConsumeUnquotedToken(); - else - ConsumeSymbol(); - } - } - - private bool LetterStartsComment(char c) - { - return c == '#' || c == '/' || c == '-'; - } - - private bool IsSpecialCharacter(char c) - { - return !Char.IsLetterOrDigit(c) && c != '$' && c != '_' && c != '.'; - } - - private bool ConsumeComment() - { - char c = _fullSql[_pos]; - // make sure the comment starts correctly - if (c == '/' && ((_pos + 1) >= _fullSql.Length || _fullSql[_pos + 1] != '*')) return false; - if (c == '-' && ((_pos + 2) >= _fullSql.Length || _fullSql[_pos + 1] != '-' || _fullSql[_pos + 2] != ' ')) return false; - - string endingPattern = "\n"; - if (c == '/') - endingPattern = "*/"; - - int startingIndex = _pos; - - int index = _fullSql.IndexOf(endingPattern, _pos); - if (index == -1) - index = _fullSql.Length - 1; - else - index += endingPattern.Length; - string comment = _fullSql.Substring(_pos, index - _pos); - if (comment.StartsWith("/*!", StringComparison.Ordinal)) - _tokens.Add(new Token(TokenType.CommandComment, comment)); - _pos = index; - return true; - } - - private void ConsumeSymbol() - { - char c = _fullSql[_pos++]; - _tokens.Add(new Token(TokenType.Symbol, c.ToString())); - } - - private void ConsumeQuotedToken(char c) - { - bool escaped = false; - int start = _pos; - _pos++; - while (_pos < _fullSql.Length) - { - char x = _fullSql[_pos]; - - if (x == c && !escaped) break; - - if (escaped) - escaped = false; - else if (x == '\\') - escaped = true; - _pos++; - } - _pos++; - _tokens.Add(c == '\'' - ? new Token(TokenType.String, "?") - : new Token(TokenType.Identifier, _fullSql.Substring(start, _pos - start))); - } - - private void ConsumeUnquotedToken() - { - int startPos = _pos; - while (_pos < _fullSql.Length && !IsSpecialCharacter(_fullSql[_pos])) - _pos++; - string word = _fullSql.Substring(startPos, _pos - startPos); - double v; - if (double.TryParse( - word, - System.Globalization.NumberStyles.Any, - System.Globalization.CultureInfo.InvariantCulture, - out v)) - _tokens.Add(new Token(TokenType.Number, "?")); - else - { - Token t = new Token(TokenType.Identifier, word); - if (IsKeyword(word)) - { - t.Type = TokenType.Keyword; - t.Text = t.Text.ToUpperInvariant(); - } - _tokens.Add(t); - } - } - - private void ConsumeWhitespace() - { - _tokens.Add(new Token(TokenType.Whitespace, " ")); - while (_pos < _fullSql.Length && Char.IsWhiteSpace(_fullSql[_pos])) - _pos++; - } - - private static bool IsKeyword(string word) - { - return Keywords.Contains(word.ToUpperInvariant()); - } - } - - internal class Token - { - public TokenType Type; - public string Text; - public bool Output; - - public Token(TokenType type, string text) - { - Type = type; - Text = text; - Output = true; - } - - public bool IsRealToken => Type != TokenType.Comment && - Type != TokenType.CommandComment && - Type != TokenType.Whitespace && - Output; - } - - internal enum TokenType - { - Keyword, - String, - Number, - Symbol, - Identifier, - Comment, - CommandComment, - Whitespace - } -} \ No newline at end of file +// Copyright © 2009, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data.MySqlClient; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace MySql.Data.Common +{ + internal class QueryNormalizer + { + private static readonly List Keywords = new List(); + private readonly List _tokens = new List(); + private int _pos; + private string _fullSql; + private string _queryType; + + static QueryNormalizer() + { + Keywords = SchemaProvider.GetReservedWords().AsDataTable(). + Select(). + Select(x => x[0].ToString()).ToList(); + } + + public string QueryType => _queryType; + + public string Normalize(string sql) + { + _tokens.Clear(); + StringBuilder newSql = new StringBuilder(); + _fullSql = sql; + + TokenizeSql(sql); + DetermineStatementType(_tokens); + ProcessMathSymbols(_tokens); + CollapseValueLists(_tokens); + CollapseInLists(_tokens); + CollapseWhitespace(_tokens); + + foreach (Token t in _tokens.Where(t => t.Output)) + newSql.Append(t.Text); + + return newSql.ToString(); + } + + private void DetermineStatementType(List tok) + { + foreach (Token t in tok.Where(t => t.Type == TokenType.Keyword)) + { + _queryType = t.Text.ToUpperInvariant(); + break; + } + } + + /// + /// Mark - or + signs that are unary ops as no output + /// + /// + private static void ProcessMathSymbols(List tok) + { + Token lastToken = null; + + foreach (Token t in tok) + { + if (t.Type == TokenType.Symbol && + (t.Text == "-" || t.Text == "+")) + { + if (lastToken != null && + lastToken.Type != TokenType.Number && + lastToken.Type != TokenType.Identifier && + (lastToken.Type != TokenType.Symbol || lastToken.Text != ")")) + t.Output = false; + } + if (t.IsRealToken) + lastToken = t; + } + } + + private static void CollapseWhitespace(List tok) + { + Token lastToken = null; + + foreach (Token t in tok) + { + if (t.Output && + t.Type == TokenType.Whitespace && + lastToken != null && + lastToken.Type == TokenType.Whitespace) + { + t.Output = false; + } + if (t.Output) + lastToken = t; + } + } + + private void CollapseValueLists(List tok) + { + int pos = -1; + while (++pos < tok.Count) + { + Token t = tok[pos]; + if (t.Type != TokenType.Keyword) continue; + if (!t.Text.StartsWith("VALUE", StringComparison.OrdinalIgnoreCase)) continue; + CollapseValueList(tok, ref pos); + } + } + + private void CollapseValueList(List tok, ref int pos) + { + List parenIndices = new List(); + + // this while loop will find all closing parens in this value list + while (true) + { + // find the close ')' + while (++pos < tok.Count) + { + if (tok[pos].Type == TokenType.Symbol && tok[pos].Text == ")") + break; + if (pos == tok.Count - 1) + break; + } + parenIndices.Add(pos); + + // now find the next "real" token + while (++pos < tok.Count) + if (tok[pos].IsRealToken) break; + if (pos == tok.Count) break; + + if (tok[pos].Text == ",") continue; + pos--; + break; + } + + // if we only have 1 value then we don't collapse + if (parenIndices.Count < 2) return; + int index = parenIndices[0]; + tok[++index] = new Token(TokenType.Whitespace, " "); + tok[++index] = new Token(TokenType.Comment, "/* , ... */"); + index++; + + // now mark all the other tokens as no output + while (index <= parenIndices[parenIndices.Count - 1]) + tok[index++].Output = false; + } + + private void CollapseInLists(List tok) + { + int pos = -1; + while (++pos < tok.Count) + { + Token t = tok[pos]; + if (t.Type != TokenType.Keyword) continue; + if (t.Text != "IN") continue; + CollapseInList(tok, ref pos); + } + } + + private static Token GetNextRealToken(List tok, ref int pos) + { + while (++pos < tok.Count) + { + if (tok[pos].IsRealToken) return tok[pos]; + } + return null; + } + + private static void CollapseInList(List tok, ref int pos) + { + Token t = GetNextRealToken(tok, ref pos); + // Debug.Assert(t.Text == "("); + if (t == null) + return; + + // if the first token is a keyword then we likely have a + // SELECT .. IN (SELECT ...) + t = GetNextRealToken(tok, ref pos); + if (t == null || t.Type == TokenType.Keyword) return; + + int start = pos; + // first find all the tokens that make up the in list + while (++pos < tok.Count) + { + t = tok[pos]; + if (t.Type == TokenType.CommandComment) return; + if (!t.IsRealToken) continue; + if (t.Text == "(") return; + if (t.Text == ")") break; + } + int stop = pos; + + for (int i = stop; i > start; i--) + tok.RemoveAt(i); + tok.Insert(++start, new Token(TokenType.Whitespace, " ")); + tok.Insert(++start, new Token(TokenType.Comment, "/* , ... */")); + tok.Insert(++start, new Token(TokenType.Whitespace, " ")); + tok.Insert(++start, new Token(TokenType.Symbol, ")")); + } + + private void TokenizeSql(string sql) + { + _pos = 0; + + while (_pos < sql.Length) + { + char c = sql[_pos]; + if (LetterStartsComment(c) && ConsumeComment()) + continue; + if (Char.IsWhiteSpace(c)) + ConsumeWhitespace(); + else if (c == '\'' || c == '\"' || c == '`') + ConsumeQuotedToken(c); + else if (!IsSpecialCharacter(c)) + ConsumeUnquotedToken(); + else + ConsumeSymbol(); + } + } + + private bool LetterStartsComment(char c) + { + return c == '#' || c == '/' || c == '-'; + } + + private bool IsSpecialCharacter(char c) + { + return !Char.IsLetterOrDigit(c) && c != '$' && c != '_' && c != '.'; + } + + private bool ConsumeComment() + { + char c = _fullSql[_pos]; + // make sure the comment starts correctly + if (c == '/' && ((_pos + 1) >= _fullSql.Length || _fullSql[_pos + 1] != '*')) return false; + if (c == '-' && ((_pos + 2) >= _fullSql.Length || _fullSql[_pos + 1] != '-' || _fullSql[_pos + 2] != ' ')) return false; + + string endingPattern = "\n"; + if (c == '/') + endingPattern = "*/"; + + int startingIndex = _pos; + + int index = _fullSql.IndexOf(endingPattern, _pos); + if (index == -1) + index = _fullSql.Length - 1; + else + index += endingPattern.Length; + string comment = _fullSql.Substring(_pos, index - _pos); + if (comment.StartsWith("/*!", StringComparison.Ordinal)) + _tokens.Add(new Token(TokenType.CommandComment, comment)); + _pos = index; + return true; + } + + private void ConsumeSymbol() + { + char c = _fullSql[_pos++]; + _tokens.Add(new Token(TokenType.Symbol, c.ToString())); + } + + private void ConsumeQuotedToken(char c) + { + bool escaped = false; + int start = _pos; + _pos++; + while (_pos < _fullSql.Length) + { + char x = _fullSql[_pos]; + + if (x == c && !escaped) break; + + if (escaped) + escaped = false; + else if (x == '\\') + escaped = true; + _pos++; + } + _pos++; + _tokens.Add(c == '\'' + ? new Token(TokenType.String, "?") + : new Token(TokenType.Identifier, _fullSql.Substring(start, _pos - start))); + } + + private void ConsumeUnquotedToken() + { + int startPos = _pos; + while (_pos < _fullSql.Length && !IsSpecialCharacter(_fullSql[_pos])) + _pos++; + string word = _fullSql.Substring(startPos, _pos - startPos); + double v; + if (double.TryParse( + word, + System.Globalization.NumberStyles.Any, + System.Globalization.CultureInfo.InvariantCulture, + out v)) + _tokens.Add(new Token(TokenType.Number, "?")); + else + { + Token t = new Token(TokenType.Identifier, word); + if (IsKeyword(word)) + { + t.Type = TokenType.Keyword; + t.Text = t.Text.ToUpperInvariant(); + } + _tokens.Add(t); + } + } + + private void ConsumeWhitespace() + { + _tokens.Add(new Token(TokenType.Whitespace, " ")); + while (_pos < _fullSql.Length && Char.IsWhiteSpace(_fullSql[_pos])) + _pos++; + } + + private static bool IsKeyword(string word) + { + return Keywords.Contains(word.ToUpperInvariant()); + } + } + + internal class Token + { + public TokenType Type; + public string Text; + public bool Output; + + public Token(TokenType type, string text) + { + Type = type; + Text = text; + Output = true; + } + + public bool IsRealToken => Type != TokenType.Comment && + Type != TokenType.CommandComment && + Type != TokenType.Whitespace && + Output; + } + + internal enum TokenType + { + Keyword, + String, + Number, + Symbol, + Identifier, + Comment, + CommandComment, + Whitespace + } +} diff --git a/MySQL.Data/src/common/Ssl.cs b/MySQL.Data/src/common/Ssl.cs index 6db9f033a..394a7ac7e 100644 --- a/MySQL.Data/src/common/Ssl.cs +++ b/MySQL.Data/src/common/Ssl.cs @@ -1,356 +1,370 @@ -// Copyright (c) 2004, 2023, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data.common; -using MySql.Data.MySqlClient; -using Org.BouncyCastle.Crypto.Parameters; -using Org.BouncyCastle.Crypto; -using Org.BouncyCastle.Pkcs; -using System; -using System.Collections.Generic; -using System.IO; -using System.Net.Security; -using System.Security.Authentication; -using System.Security.Cryptography; -using System.Security.Cryptography.X509Certificates; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using Org.BouncyCastle.OpenSsl; -using Org.BouncyCastle.Utilities.IO.Pem; - -namespace MySql.Data.Common -{ - /// - /// Handles SSL connections for the Classic and X protocols. - /// - internal class Ssl - { - #region Fields - - /// - /// Contains the connection options provided by the user. - /// - private MySqlConnectionStringBuilder _settings; - - /// - /// A flag to establish how certificates are to be treated and validated. - /// - private bool _treatCertificatesAsPemFormat; - - /// - /// Defines the supported TLS protocols. - /// - private static SslProtocols[] tlsProtocols = new SslProtocols[] { SslProtocols.Tls12 }; - private static Dictionary tlsConnectionRef = new Dictionary(); - private static Dictionary tlsRetry = new Dictionary(); - private static Object thisLock = new Object(); - - #endregion - - public Ssl(MySqlConnectionStringBuilder settings) - { - this._settings = settings; - // Set default value to true since PEM files is the standard for MySQL SSL certificates. - _treatCertificatesAsPemFormat = true; - } - - public Ssl(string server, MySqlSslMode sslMode, string certificateFile, MySqlCertificateStoreLocation certificateStoreLocation, - string certificatePassword, string certificateThumbprint, string sslCa, string sslCert, string sslKey, string tlsVersion, uint connectionTimeout) - { - this._settings = new MySqlConnectionStringBuilder() - { - Server = server, - SslMode = sslMode, - CertificateFile = certificateFile, - CertificateStoreLocation = certificateStoreLocation, - CertificatePassword = certificatePassword, - CertificateThumbprint = certificateThumbprint, - SslCa = sslCa, - SslCert = sslCert, - SslKey = sslKey, - TlsVersion = tlsVersion, - ConnectionTimeout = connectionTimeout - }; - // Set default value to true since PEM files is the standard for MySQL SSL certificates. - _treatCertificatesAsPemFormat = true; - } - - /// - /// Retrieves a certificate from PEM file. - /// - private X509Certificate2 GetCertificateFromPEM(string certificatePath, string certificatePassword) - { - var certParser = new Org.BouncyCastle.X509.X509CertificateParser(); - var cert = certParser.ReadCertificate(File.ReadAllBytes(certificatePath)); - return new X509Certificate2(cert.GetEncoded(),certificatePassword); - } - - - /// - /// Retrieves a collection containing the client SSL PFX certificates. - /// - /// Dependent on connection string settings. - /// Either file or store based certificates are used. - private X509CertificateCollection GetPFXClientCertificates() - { - X509CertificateCollection certs = new X509CertificateCollection(); - - // Check for file-based certificate - if (_settings.CertificateFile != null) - { - if (_treatCertificatesAsPemFormat) - { - certs.Add(GetCertificateFromPEM(_settings.CertificateFile, _settings.CertificatePassword)); - return certs; - } - else - { - X509Certificate2 clientCert = new X509Certificate2(_settings.CertificateFile, - _settings.CertificatePassword); - certs.Add(clientCert); - return certs; - } - } - - if (_settings.CertificateStoreLocation == MySqlCertificateStoreLocation.None) - return certs; - - StoreLocation location = - (_settings.CertificateStoreLocation == MySqlCertificateStoreLocation.CurrentUser) ? - StoreLocation.CurrentUser : StoreLocation.LocalMachine; - - try - { - // Check for store-based certificate - X509Store store = new X509Store(StoreName.My, location); - store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly); - - - if (_settings.CertificateThumbprint == null) - { - // Return all certificates from the store. - certs.AddRange(store.Certificates); - - if (certs.Count == 0) - throw new MySqlException("No certificates were found in the certificate store"); - - return certs; - } - else - { - bool validateCert = _settings.SslMode == MySqlSslMode.VerifyCA || _settings.SslMode == MySqlSslMode.VerifyFull; - - // Find certificate with given thumbprint - certs.AddRange(store.Certificates.Find(X509FindType.FindByThumbprint, - _settings.CertificateThumbprint, validateCert)); - - if (certs.Count == 0) - throw new MySqlException(String.Format(Resources.InvalidCertificateThumbprint, _settings.CertificateThumbprint)); - - return certs; - } - } - catch (CryptographicException ex) - { - throw new MySqlException("Certificate couldn't be loaded from the CertificateStoreLocation", ex); - } - } - - /// - /// Initiates the SSL connection. - /// - /// The base stream. - /// The encoding used in the SSL connection. - /// The connection string used to establish the connection. - /// Boolean that indicates if the function will be executed asynchronously. - /// The cancellation token. - /// A instance ready to initiate an SSL connection. - public async Task> StartSSLAsync(Stream baseStream, Encoding encoding, string connectionString, CancellationToken cancellationToken, bool execAsync) - { - // If SslCa connection option was provided, check for the file extension as it can also be set as a PFX file. - if (_settings.SslCa != null) - { - var fileExtension = GetCertificateFileExtension(_settings.SslCa, true); - - if (fileExtension != null) - _treatCertificatesAsPemFormat = fileExtension != "pfx"; - } - - RemoteCertificateValidationCallback sslValidateCallback = new RemoteCertificateValidationCallback(ServerCheckValidation); - SslStream sslStream = new SslStream(baseStream, false, sslValidateCallback, null); - X509CertificateCollection certs = (_treatCertificatesAsPemFormat && - _settings.CertificateStoreLocation == MySqlCertificateStoreLocation.None) - ? new X509CertificateCollection() - : GetPFXClientCertificates(); - - string connectionId = connectionString.GetHashCode().ToString(); - SslProtocols tlsProtocol = SslProtocols.None; - - if (_settings.TlsVersion != null) - { -#if NET452 || NETSTANDARD2_0 - if (_settings.TlsVersion.Equals("Tls13", StringComparison.OrdinalIgnoreCase)) - throw new NotSupportedException(Resources.Tlsv13NotSupported); -#endif - - SslProtocols sslProtocolsToUse = (SslProtocols)Enum.Parse(typeof(SslProtocols), _settings.TlsVersion); - List listProtocols = new List(); - -#if NET48 || NETSTANDARD2_1 || NET5_0_OR_GREATER - if (sslProtocolsToUse.HasFlag((SslProtocols)12288)) - listProtocols.Add((SslProtocols)12288); -#endif - - if (sslProtocolsToUse.HasFlag(SslProtocols.Tls12)) - listProtocols.Add(SslProtocols.Tls12); - - tlsProtocols = listProtocols.ToArray(); - } - - if (tlsConnectionRef.ContainsKey(connectionId)) - { - tlsProtocol = tlsConnectionRef[connectionId]; - } - else - { - if (!tlsRetry.ContainsKey(connectionId)) - { - lock (tlsRetry) - { - tlsRetry[connectionId] = 0; - } - } - for (int i = tlsRetry[connectionId]; i < tlsProtocols.Length; i++) - { - tlsProtocol |= tlsProtocols[i]; - } - } - try - { - tlsProtocol = (tlsProtocol == SslProtocols.None) ? SslProtocols.Tls12 : tlsProtocol; - - if (execAsync) - { - using (cancellationToken.Register(() => throw new AggregateException($"Authentication to host '{_settings.Server}' failed.", new IOException()))) - await sslStream.AuthenticateAsClientAsync(_settings.Server, certs, tlsProtocol, false).ConfigureAwait(false); - } - else - { - using (cancellationToken.Register(() => throw new AggregateException($"Authentication to host '{_settings.Server}' failed.", new IOException()))) - sslStream.AuthenticateAsClientAsync(_settings.Server, certs, tlsProtocol, false).GetAwaiter().GetResult(); - } - - lock (tlsConnectionRef) - { - tlsConnectionRef[connectionId] = tlsProtocol; - } - tlsRetry.Remove(connectionId); - } - catch (AggregateException ex) - { - if (ex.GetBaseException() is IOException) - { - tlsConnectionRef.Remove(connectionId); - if (tlsRetry.ContainsKey(connectionId)) - { - if (tlsRetry[connectionId] > tlsProtocols.Length) - throw new MySqlException(Resources.SslConnectionError, ex); - tlsRetry[connectionId] += 1; - } - } - throw ex.GetBaseException(); - } - - baseStream = sslStream; - MySqlStream stream = new MySqlStream(sslStream, encoding, false); - stream.SequenceByte = 2; - - return new Tuple(stream, baseStream); - } - - /// - /// Verifies the SSL certificates used for authentication. - /// - /// An object that contains state information for this validation. - /// The MySQL server certificate used to authenticate the remote party. - /// The chain of certificate authorities associated with the remote certificate. - /// One or more errors associated with the remote certificate. - /// true if no errors were found based on the selected SSL mode; false, otherwise. - private bool ServerCheckValidation(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) - { - if (sslPolicyErrors == SslPolicyErrors.None) - return true; - - if (_settings.SslMode == MySqlSslMode.Required || - _settings.SslMode == MySqlSslMode.Preferred) - { - // Tolerate all certificate errors. - return true; - } - - // Validate PEM certificates using Bouncy Castle. - if (_treatCertificatesAsPemFormat) - { - SslPemCertificateValidator.ValidateCertificate(chain, _settings); - return true; - } - // Validate PFX certificate errors. - else if (_settings.SslMode == MySqlSslMode.VerifyCA && - sslPolicyErrors == SslPolicyErrors.RemoteCertificateNameMismatch) - { - // Tolerate name mismatch in certificate, if full validation is not requested. - return true; - } - - return false; - } - - /// - /// Gets the extension of the specified file. - /// - /// The path of the file. - /// Flag to indicate if the result should be converted to lower case. - /// The . character is ommited from the result. - /// - private string GetCertificateFileExtension(string filePath, bool toLowerCase) - { - if (filePath == null || !File.Exists(filePath)) - return null; - - var extension = Path.GetExtension(filePath); - extension = string.IsNullOrEmpty(extension) - ? null - : extension.Substring(extension.IndexOf(".") + 1); - - return toLowerCase - ? extension.ToLowerInvariant() - : extension; - } - } -} +// Copyright © 2004, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data.common; +using MySql.Data.MySqlClient; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Pkcs; +using System; +using System.Collections.Generic; +using System.IO; +using System.Net.Security; +using System.Security.Authentication; +using System.Security.Cryptography; +using System.Security.Cryptography.X509Certificates; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Org.BouncyCastle.OpenSsl; +using Org.BouncyCastle.Utilities.IO.Pem; + +namespace MySql.Data.Common +{ + /// + /// Handles SSL connections for the Classic and X protocols. + /// + internal class Ssl + { + #region Fields + + /// + /// Contains the connection options provided by the user. + /// + private MySqlConnectionStringBuilder _settings; + + /// + /// A flag to establish how certificates are to be treated and validated. + /// + private bool _treatCertificatesAsPemFormat; + + /// + /// Defines the supported TLS protocols. + /// + private static SslProtocols[] tlsProtocols = new SslProtocols[] { SslProtocols.Tls12}; + private static Dictionary tlsConnectionRef = new Dictionary(); + private static Dictionary tlsRetry = new Dictionary(); + private static SemaphoreSlim semaphoreSlim = new SemaphoreSlim(1, 1); + + #endregion + + public Ssl(MySqlConnectionStringBuilder settings) + { + this._settings = settings; + // Set default value to true since PEM files is the standard for MySQL SSL certificates. + _treatCertificatesAsPemFormat = true; + } + + public Ssl(string server, MySqlSslMode sslMode, string certificateFile, MySqlCertificateStoreLocation certificateStoreLocation, + string certificatePassword, string certificateThumbprint, string sslCa, string sslCert, string sslKey, string tlsVersion, uint connectionTimeout) + { + this._settings = new MySqlConnectionStringBuilder() + { + Server = server, + SslMode = sslMode, + CertificateFile = certificateFile, + CertificateStoreLocation = certificateStoreLocation, + CertificatePassword = certificatePassword, + CertificateThumbprint = certificateThumbprint, + SslCa = sslCa, + SslCert = sslCert, + SslKey = sslKey, + TlsVersion = tlsVersion, + ConnectionTimeout = connectionTimeout + }; + // Set default value to true since PEM files is the standard for MySQL SSL certificates. + _treatCertificatesAsPemFormat = true; + } + + /// + /// Retrieves a certificate from PEM file. + /// + private X509Certificate2 GetCertificateFromPEM(string certificatePath, string certificatePassword) + { + var certParser = new Org.BouncyCastle.X509.X509CertificateParser(); + var cert = certParser.ReadCertificate(File.ReadAllBytes(certificatePath)); + return new X509Certificate2(cert.GetEncoded(), certificatePassword); + } + + + /// + /// Retrieves a collection containing the client SSL PFX certificates. + /// + /// Dependent on connection string settings. + /// Either file or store based certificates are used. + private X509CertificateCollection GetPFXClientCertificates() + { + X509CertificateCollection certs = new X509CertificateCollection(); + + // Check for file-based certificate + if (_settings.CertificateFile != null) + { + if (_treatCertificatesAsPemFormat) + { + certs.Add(GetCertificateFromPEM(_settings.CertificateFile, _settings.CertificatePassword)); + return certs; + } + else + { + X509Certificate2 clientCert = new X509Certificate2(_settings.CertificateFile, + _settings.CertificatePassword); + certs.Add(clientCert); + return certs; + } + } + + if (_settings.CertificateStoreLocation == MySqlCertificateStoreLocation.None) + return certs; + + StoreLocation location = + (_settings.CertificateStoreLocation == MySqlCertificateStoreLocation.CurrentUser) ? + StoreLocation.CurrentUser : StoreLocation.LocalMachine; + + try + { + // Check for store-based certificate + X509Store store = new X509Store(StoreName.My, location); + store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly); + + + if (_settings.CertificateThumbprint == null) + { + // Return all certificates from the store. + certs.AddRange(store.Certificates); + + if (certs.Count == 0) + throw new MySqlException("No certificates were found in the certificate store"); + + return certs; + } + else + { + bool validateCert = _settings.SslMode == MySqlSslMode.VerifyCA || _settings.SslMode == MySqlSslMode.VerifyFull; + + // Find certificate with given thumbprint + certs.AddRange(store.Certificates.Find(X509FindType.FindByThumbprint, + _settings.CertificateThumbprint, validateCert)); + + if (certs.Count == 0) + throw new MySqlException(String.Format(Resources.InvalidCertificateThumbprint, _settings.CertificateThumbprint)); + + return certs; + } + } + catch (CryptographicException ex) + { + throw new MySqlException("Certificate couldn't be loaded from the CertificateStoreLocation", ex); + } + } + + /// + /// Initiates the SSL connection. + /// + /// The base stream. + /// The encoding used in the SSL connection. + /// The connection string used to establish the connection. + /// Boolean that indicates if the function will be executed asynchronously. + /// The cancellation token. + /// A instance ready to initiate an SSL connection. + public async Task> StartSSLAsync(Stream baseStream, Encoding encoding, string connectionString, CancellationToken cancellationToken, bool execAsync) + { + // If SslCa connection option was provided, check for the file extension as it can also be set as a PFX file. + if (_settings.SslCa != null) + { + var fileExtension = GetCertificateFileExtension(_settings.SslCa, true); + + if (fileExtension != null) + _treatCertificatesAsPemFormat = fileExtension != "pfx"; + } + + RemoteCertificateValidationCallback sslValidateCallback = new RemoteCertificateValidationCallback(ServerCheckValidation); + SslStream sslStream = new SslStream(baseStream, false, sslValidateCallback, null); + X509CertificateCollection certs = (_treatCertificatesAsPemFormat && + _settings.CertificateStoreLocation == MySqlCertificateStoreLocation.None) + ? new X509CertificateCollection() + : GetPFXClientCertificates(); + + string connectionId = connectionString.GetHashCode().ToString(); + SslProtocols tlsProtocol = SslProtocols.None; + + if (_settings.TlsVersion != null) + { + SslProtocols sslProtocolsToUse = (SslProtocols)Enum.Parse(typeof(SslProtocols), _settings.TlsVersion); + List listProtocols = new List(); + +#if NET5_0_OR_GREATER + if (sslProtocolsToUse.HasFlag(SslProtocols.Tls13)) + listProtocols.Add(SslProtocols.Tls13); +#else + // 12288 represents the numerical value of SslProtocols.Tls13 enum option. + if (sslProtocolsToUse.HasFlag((SslProtocols)12288)) + listProtocols.Add((SslProtocols)12288); +#endif + + if (sslProtocolsToUse.HasFlag(SslProtocols.Tls12)) + listProtocols.Add(SslProtocols.Tls12); + + tlsProtocols = listProtocols.ToArray(); + } + + if (execAsync) + await semaphoreSlim.WaitAsync(cancellationToken).ConfigureAwait(false); + else + semaphoreSlim.Wait(cancellationToken); + + + try + { + if (tlsConnectionRef.TryGetValue(connectionId, out var protocol)) + { + tlsProtocol = protocol; + } + else + { + if (!tlsRetry.ContainsKey(connectionId)) + { + lock (tlsRetry) + { + tlsRetry[connectionId] = 0; + } + } + for (int i = tlsRetry[connectionId]; i < tlsProtocols.Length; i++) + { + tlsProtocol |= tlsProtocols[i]; + } + } + } + finally + { + semaphoreSlim.Release(); + } + + + try + { + tlsProtocol = (tlsProtocol == SslProtocols.None) ? SslProtocols.Tls12 : tlsProtocol; + + if (execAsync) + { + using (cancellationToken.Register(() => throw new AggregateException($"Authentication to host '{_settings.Server}' failed.", new IOException()))) + await sslStream.AuthenticateAsClientAsync(_settings.Server, certs, tlsProtocol, false).ConfigureAwait(false); + } + else + { + using (cancellationToken.Register(() => throw new AggregateException($"Authentication to host '{_settings.Server}' failed.", new IOException()))) + sslStream.AuthenticateAsClientAsync(_settings.Server, certs, tlsProtocol, false).GetAwaiter().GetResult(); + } + + lock (tlsConnectionRef) + { + tlsConnectionRef[connectionId] = tlsProtocol; + } + tlsRetry.Remove(connectionId); + } + catch (AggregateException ex) + { + if (ex.GetBaseException() is IOException) + { + tlsConnectionRef.Remove(connectionId); + if (tlsRetry.ContainsKey(connectionId)) + { + if (tlsRetry[connectionId] > tlsProtocols.Length) + throw new MySqlException(Resources.SslConnectionError, ex); + tlsRetry[connectionId] += 1; + } + } + throw ex.GetBaseException(); + } + + baseStream = sslStream; + MySqlStream stream = new MySqlStream(sslStream, encoding, false); + stream.SequenceByte = 2; + + return new Tuple(stream, baseStream); + } + + /// + /// Verifies the SSL certificates used for authentication. + /// + /// An object that contains state information for this validation. + /// The MySQL server certificate used to authenticate the remote party. + /// The chain of certificate authorities associated with the remote certificate. + /// One or more errors associated with the remote certificate. + /// true if no errors were found based on the selected SSL mode; false, otherwise. + private bool ServerCheckValidation(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) + { + if (sslPolicyErrors == SslPolicyErrors.None) + return true; + + if (_settings.SslMode == MySqlSslMode.Required || + _settings.SslMode == MySqlSslMode.Preferred) + { + // Tolerate all certificate errors. + return true; + } + + // Validate PEM certificates using Bouncy Castle. + if (_treatCertificatesAsPemFormat) + { + SslPemCertificateValidator.ValidateCertificate(chain, _settings); + return true; + } + // Validate PFX certificate errors. + else if (_settings.SslMode == MySqlSslMode.VerifyCA && + sslPolicyErrors == SslPolicyErrors.RemoteCertificateNameMismatch) + { + // Tolerate name mismatch in certificate, if full validation is not requested. + return true; + } + + return false; + } + + /// + /// Gets the extension of the specified file. + /// + /// The path of the file. + /// Flag to indicate if the result should be converted to lower case. + /// The . character is ommited from the result. + /// + private string GetCertificateFileExtension(string filePath, bool toLowerCase) + { + if (filePath == null || !File.Exists(filePath)) + return null; + + var extension = Path.GetExtension(filePath); + extension = string.IsNullOrEmpty(extension) + ? null + : extension.Substring(extension.IndexOf(".") + 1); + + return toLowerCase + ? extension.ToLowerInvariant() + : extension; + } + } +} diff --git a/MySQL.Data/src/common/SslPemCertificateValidator.cs b/MySQL.Data/src/common/SslPemCertificateValidator.cs index c92005be8..8186ea6b6 100644 --- a/MySQL.Data/src/common/SslPemCertificateValidator.cs +++ b/MySQL.Data/src/common/SslPemCertificateValidator.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2019, 2022, Oracle and/or its affiliates. +// Copyright © 2019, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/common/StreamCreator.cs b/MySQL.Data/src/common/StreamCreator.cs index f1d9496cf..4b77c7c7b 100644 --- a/MySQL.Data/src/common/StreamCreator.cs +++ b/MySQL.Data/src/common/StreamCreator.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2004, 2022, Oracle and/or its affiliates. +// Copyright © 2004, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -33,6 +33,7 @@ using System.Linq; using System.Net; using System.Net.Sockets; +using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; @@ -108,11 +109,26 @@ private static async Task> GetTcpStreamAsync(MySq TcpClient tcpClient = new TcpClient(addr.AddressFamily); if (execAsync) - using (cancellationToken.Register(() => throw new MySqlException(Resources.Timeout, new TimeoutException()))) - await tcpClient.ConnectAsync(settings.Server, (int)settings.Port).ConfigureAwait(false); + { + try + { + using (cancellationToken.Register(() => tcpClient.Dispose())) + { +#if NETFRAMEWORK || NETSTANDARD2_1 || NETSTANDARD2_0 + await tcpClient.ConnectAsync(settings.Server, (int)settings.Port).ConfigureAwait(false); +#else + await tcpClient.ConnectAsync(settings.Server, (int)settings.Port, cancellationToken).ConfigureAwait(false); +#endif + } + } + catch (Exception ex) when (ex is SocketException or ObjectDisposedException && cancellationToken.IsCancellationRequested) + { + throw new MySqlException(Resources.Timeout, new TimeoutException()); + } + } else if (!tcpClient.ConnectAsync(settings.Server, (int)settings.Port).Wait((int)settings.ConnectionTimeout * 1000)) - throw new MySqlException(Resources.Timeout, new TimeoutException()); + throw new MySqlException(Resources.Timeout, new TimeoutException()); if (settings.Keepalive > 0) SetKeepAlive(tcpClient.Client, settings.Keepalive); diff --git a/MySQL.Data/src/common/StringUtility.cs b/MySQL.Data/src/common/StringUtility.cs index f8b8ad350..041397427 100644 --- a/MySQL.Data/src/common/StringUtility.cs +++ b/MySQL.Data/src/common/StringUtility.cs @@ -1,45 +1,45 @@ -// Copyright (c) 2014, 2021, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - - -namespace MySql.Data.Common -{ - internal class StringUtility - { - public static string ToUpperInvariant(string s) - { - return s.ToUpperInvariant(); - } - - public static string ToLowerInvariant(string s) - { - return s.ToLowerInvariant(); - } - - } -} +// Copyright © 2014, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +namespace MySql.Data.Common +{ + internal class StringUtility + { + public static string ToUpperInvariant(string s) + { + return s.ToUpperInvariant(); + } + + public static string ToLowerInvariant(string s) + { + return s.ToLowerInvariant(); + } + + } +} diff --git a/MySQL.Data/src/common/UnixEndPoint.cs b/MySQL.Data/src/common/UnixEndPoint.cs index 178986ad8..71ea2cba7 100644 --- a/MySQL.Data/src/common/UnixEndPoint.cs +++ b/MySQL.Data/src/common/UnixEndPoint.cs @@ -1,16 +1,16 @@ -// Copyright © 2017, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2017, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/src/common/Version.cs b/MySQL.Data/src/common/Version.cs index 1386be26c..e80dd3398 100644 --- a/MySQL.Data/src/common/Version.cs +++ b/MySQL.Data/src/common/Version.cs @@ -1,101 +1,101 @@ -// Copyright (c) 2004, 2016, Oracle and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using System; -using MySql.Data.MySqlClient; - -namespace MySql.Data.Common -{ - /// - /// Summary description for Version. - /// - internal struct DBVersion - { - private readonly string _srcString; - - public DBVersion(string s, int major, int minor, int build) - { - Major = major; - Minor = minor; - Build = build; - _srcString = s; - IsEnterprise = s.ToLowerInvariant().Contains("-enterprise-"); - } - - public int Major { get; } - - public int Minor { get; } - - public int Build { get; } - - public bool IsEnterprise - { - get; private set; - } - - public static DBVersion Parse(string versionString) - { - int start = 0; - int index = versionString.IndexOf('.', start); - if (index == -1) - throw new MySqlException(Resources.BadVersionFormat); - string val = versionString.Substring(start, index - start).Trim(); - int major = Convert.ToInt32(val, System.Globalization.NumberFormatInfo.InvariantInfo); - - start = index + 1; - index = versionString.IndexOf('.', start); - if (index == -1) - throw new MySqlException(Resources.BadVersionFormat); - val = versionString.Substring(start, index - start).Trim(); - int minor = Convert.ToInt32(val, System.Globalization.NumberFormatInfo.InvariantInfo); - - start = index + 1; - int i = start; - while (i < versionString.Length && Char.IsDigit(versionString, i)) - i++; - val = versionString.Substring(start, i - start).Trim(); - int build = Convert.ToInt32(val, System.Globalization.NumberFormatInfo.InvariantInfo); - - return new DBVersion(versionString, major, minor, build); - } - - public bool isAtLeast(int majorNum, int minorNum, int buildNum) - { - if (Major > majorNum) return true; - if (Major == majorNum && Minor > minorNum) return true; - if (Major == majorNum && Minor == minorNum && Build >= buildNum) return true; - return false; - } - - public override string ToString() - { - return _srcString; - } - - } -} +// Copyright © 2004, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using System; +using MySql.Data.MySqlClient; + +namespace MySql.Data.Common +{ + /// + /// Summary description for Version. + /// + internal struct DBVersion + { + private readonly string _srcString; + + public DBVersion(string s, int major, int minor, int build) + { + Major = major; + Minor = minor; + Build = build; + _srcString = s; + IsEnterprise = s.ToLowerInvariant().Contains("-enterprise-"); + } + + public int Major { get; } + + public int Minor { get; } + + public int Build { get; } + + public bool IsEnterprise + { + get; private set; + } + + public static DBVersion Parse(string versionString) + { + int start = 0; + int index = versionString.IndexOf('.', start); + if (index == -1) + throw new MySqlException(Resources.BadVersionFormat); + string val = versionString.Substring(start, index - start).Trim(); + int major = Convert.ToInt32(val, System.Globalization.NumberFormatInfo.InvariantInfo); + + start = index + 1; + index = versionString.IndexOf('.', start); + if (index == -1) + throw new MySqlException(Resources.BadVersionFormat); + val = versionString.Substring(start, index - start).Trim(); + int minor = Convert.ToInt32(val, System.Globalization.NumberFormatInfo.InvariantInfo); + + start = index + 1; + int i = start; + while (i < versionString.Length && Char.IsDigit(versionString, i)) + i++; + val = versionString.Substring(start, i - start).Trim(); + int build = Convert.ToInt32(val, System.Globalization.NumberFormatInfo.InvariantInfo); + + return new DBVersion(versionString, major, minor, build); + } + + public bool isAtLeast(int majorNum, int minorNum, int buildNum) + { + if (Major > majorNum) return true; + if (Major == majorNum && Minor > minorNum) return true; + if (Major == majorNum && Minor == minorNum && Build >= buildNum) return true; + return false; + } + + public override string ToString() + { + return _srcString; + } + + } +} diff --git a/MySQL.Data/src/common/netstandard2_0/NamedPipeStream.cs b/MySQL.Data/src/common/netstandard2_0/NamedPipeStream.cs index 46b3507c7..a3698477f 100644 --- a/MySQL.Data/src/common/netstandard2_0/NamedPipeStream.cs +++ b/MySQL.Data/src/common/netstandard2_0/NamedPipeStream.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2009, 2022, Oracle and/or its affiliates. +// Copyright © 2009, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -76,7 +76,8 @@ public void Open(string path, FileAccess mode, uint timeout) NativeMethods.FILE_WRITE_ATTRIBUTES | NativeMethods.FILE_WRITE_DATA, 0, security, NativeMethods.OPEN_EXISTING, NativeMethods.FILE_FLAG_OVERLAPPED, 0); - if (nativeHandle != IntPtr.Zero) + handle = new SafeFileHandle(nativeHandle, true); + if (!handle.IsInvalid) break; if (Marshal.GetLastWin32Error() != ERROR_PIPE_BUSY) @@ -102,7 +103,6 @@ public void Open(string path, FileAccess mode, uint timeout) } timeout -= (uint)sw.ElapsedMilliseconds; } - handle = new SafeFileHandle(nativeHandle, true); fileStream = new FileStream(handle, mode, 4096, true); } diff --git a/MySQL.Data/src/common/netstandard2_0/SharedMemoryStream.cs b/MySQL.Data/src/common/netstandard2_0/SharedMemoryStream.cs index 6cf1f5430..02431ca56 100644 --- a/MySQL.Data/src/common/netstandard2_0/SharedMemoryStream.cs +++ b/MySQL.Data/src/common/netstandard2_0/SharedMemoryStream.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2014, 2021, Oracle and/or its affiliates. +// Copyright © 2014, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -160,34 +160,52 @@ public override void Close() private void GetConnectNumber(uint timeOut) { - EventWaitHandle connectRequest; + Mutex connectNamedMutex = null; try { - connectRequest = - EventWaitHandle.OpenExisting(memoryName + "_CONNECT_REQUEST"); - + connectNamedMutex = Mutex.OpenExisting(memoryName + "_CONNECT_NAMED_MUTEX"); } - catch (Exception) + catch { - // If server runs as service, its shared memory is global - // And if connector runs in user session, it needs to prefix - // shared memory name with "Global\" - string prefixedMemoryName = @"Global\" + memoryName; - connectRequest = - EventWaitHandle.OpenExisting(prefixedMemoryName + "_CONNECT_REQUEST"); - memoryName = prefixedMemoryName; + throw new MySqlException("Failed to open shared memory connection mutex"); + } + if (!connectNamedMutex.WaitOne(checked((int)timeOut) * 1000, false)) + throw new MySqlException("Mutex timeout during connection"); + try + { + EventWaitHandle connectRequest; + try + { + connectRequest = + EventWaitHandle.OpenExisting(memoryName + "_CONNECT_REQUEST"); + } + catch (Exception) + { + // If server runs as service, its shared memory is global + // And if connector runs in user session, it needs to prefix + // shared memory name with "Global\" + string prefixedMemoryName = @"Global\" + memoryName; + connectRequest = + EventWaitHandle.OpenExisting(prefixedMemoryName + "_CONNECT_REQUEST"); + memoryName = prefixedMemoryName; + } + EventWaitHandle connectAnswer = + EventWaitHandle.OpenExisting(memoryName + "_CONNECT_ANSWER"); + using (SharedMemory connectData = + new SharedMemory(memoryName + "_CONNECT_DATA", (IntPtr)4)) + { + // now start the connection + if (!connectRequest.Set()) + throw new MySqlException("Failed to open shared memory connection"); + if (!connectAnswer.WaitOne((int)(timeOut * 1000), false)) + throw new MySqlException("Timeout during connection"); + connectNumber = Marshal.ReadInt32(connectData.View); + } } - EventWaitHandle connectAnswer = - EventWaitHandle.OpenExisting(memoryName + "_CONNECT_ANSWER"); - using (SharedMemory connectData = - new SharedMemory(memoryName + "_CONNECT_DATA", (IntPtr)4)) + finally { - // now start the connection - if (!connectRequest.Set()) - throw new MySqlException("Failed to open shared memory connection"); - if (!connectAnswer.WaitOne((int)(timeOut * 1000), false)) - throw new MySqlException("Timeout during connection"); - connectNumber = Marshal.ReadInt32(connectData.View); + connectNamedMutex.ReleaseMutex(); + connectNamedMutex.Dispose(); } } diff --git a/MySQL.Data/tests/MySql.Data.Tests/AttributeTests.cs b/MySQL.Data/tests/MySql.Data.Tests/AttributeTests.cs index 4ca6a3cc7..c6f69757d 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/AttributeTests.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/AttributeTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2022, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -27,6 +27,7 @@ // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA using NUnit.Framework; +using NUnit.Framework.Legacy; using System; namespace MySql.Data.MySqlClient.Tests @@ -47,7 +48,7 @@ public void SetUp() [TestCase(false)] public void SetAttributesWithoutParams(bool prepare) { - if (!Connection.driver.SupportsQueryAttributes) Assert.Ignore("MySQL Server version does not support query attributes."); + Assume.That(Connection.driver.SupportsQueryAttributes, "MySQL Server version does not support query attributes."); using MySqlCommand cmd = new MySqlCommand(); cmd.Connection = Connection; @@ -56,15 +57,15 @@ public void SetAttributesWithoutParams(bool prepare) if (prepare) cmd.Prepare(); var result = cmd.ExecuteScalar(); - if (Version >= new Version(8, 0, 26) || !prepare) StringAssert.AreEqualIgnoringCase("v1", result.ToString()); - else Assert.IsEmpty(result.ToString()); + if (Version >= new Version(8, 0, 26) || !prepare) Assert.That(result.ToString(), Is.EqualTo("v1").IgnoreCase); + else Assert.That(result.ToString(), Is.Empty); cmd.Attributes.SetAttribute("n2", 123); cmd.CommandText = "SELECT mysql_query_attribute_string('n2')"; if (prepare) cmd.Prepare(); result = cmd.ExecuteScalar(); - if (Version >= new Version(8, 0, 26) || !prepare) StringAssert.AreEqualIgnoringCase("123", result.ToString()); - else Assert.IsEmpty(result.ToString()); + if (Version >= new Version(8, 0, 26) || !prepare) Assert.That(result.ToString(), Is.EqualTo("123").IgnoreCase); + else Assert.That(result.ToString(), Is.Empty); MySqlAttribute attr = new MySqlAttribute(); attr.AttributeName = "n3"; @@ -73,8 +74,8 @@ public void SetAttributesWithoutParams(bool prepare) cmd.CommandText = "SELECT mysql_query_attribute_string('n3')"; if (prepare) cmd.Prepare(); result = cmd.ExecuteScalar(); - if (Version >= new Version(8, 0, 26) || !prepare) StringAssert.AreEqualIgnoringCase("v3", result.ToString()); - else Assert.IsEmpty(result.ToString()); + if (Version >= new Version(8, 0, 26) || !prepare) Assert.That(result.ToString(), Is.EqualTo("v3").IgnoreCase); + else Assert.That(result.ToString(), Is.Empty); } [TestCase("StringType", "value1")] @@ -85,20 +86,20 @@ public void SetAttributesWithoutParams(bool prepare) [TestCase("DoubleType", 1234.567)] public void ValueTypes(string name, object value) { - if (!Connection.driver.SupportsQueryAttributes) Assert.Ignore("MySQL Server version does not support query attributes."); + Assume.That(Connection.driver.SupportsQueryAttributes, "MySQL Server version does not support query attributes."); using MySqlCommand cmd = new MySqlCommand(); cmd.Connection = Connection; cmd.Attributes.SetAttribute(name, value); cmd.CommandText = $"SELECT mysql_query_attribute_string('{name}')"; var result = cmd.ExecuteScalar(); - StringAssert.AreEqualIgnoringCase(value.ToString(), result.ToString()); + Assert.That(result.ToString(), Is.EqualTo(value.ToString()).IgnoreCase); } [Test] public void TimeSpanValueType() { - if (!Connection.driver.SupportsQueryAttributes) Assert.Ignore("MySQL Server version does not support query attributes."); + Assume.That(Connection.driver.SupportsQueryAttributes, "MySQL Server version does not support query attributes."); TimeSpan time = new TimeSpan(01, 19, 25); @@ -107,13 +108,13 @@ public void TimeSpanValueType() cmd.Attributes.SetAttribute("TimeSpan", time); cmd.CommandText = "SELECT mysql_query_attribute_string('TimeSpan')"; var result = cmd.ExecuteScalar(); - StringAssert.StartsWith(time.ToString(), result.ToString()); + Assert.That(result.ToString(), Does.StartWith(time.ToString())); } [Test] public void DateTimeValueType() { - if (!Connection.driver.SupportsQueryAttributes) Assert.Ignore("MySQL Server version does not support query attributes."); + Assume.That(Connection.driver.SupportsQueryAttributes, "MySQL Server version does not support query attributes."); DateTime dateTime = DateTime.Now; @@ -122,7 +123,7 @@ public void DateTimeValueType() cmd.Attributes.SetAttribute("DateTime", dateTime); cmd.CommandText = "SELECT mysql_query_attribute_string('DateTime')"; var result = cmd.ExecuteScalar(); - Assert.AreEqual(dateTime.ToString("yyyy-MM-dd HH:mm:ss.ffffff"), result.ToString()); + Assert.That(result.ToString(), Is.EqualTo(dateTime.ToString("yyyy-MM-dd HH:mm:ss.ffffff"))); } [Test] @@ -130,19 +131,19 @@ public void ClearAttributes() { using MySqlCommand cmd = new MySqlCommand(); cmd.Attributes.SetAttribute("foo", "bar"); - Assert.AreEqual(1, cmd.Attributes.Count); + Assert.That(cmd.Attributes.Count, Is.EqualTo(1)); cmd.Attributes.SetAttribute("bar", "foo"); - Assert.AreEqual(2, cmd.Attributes.Count); + Assert.That(cmd.Attributes.Count, Is.EqualTo(2)); cmd.Attributes.Clear(); - Assert.AreEqual(0, cmd.Attributes.Count); + Assert.That(cmd.Attributes.Count, Is.EqualTo(0)); } [Test] public void SameNameAttribute() { - if (!Connection.driver.SupportsQueryAttributes) Assert.Ignore("MySQL Server version does not support query attributes."); + Assume.That(Connection.driver.SupportsQueryAttributes, "MySQL Server version does not support query attributes."); using MySqlCommand cmd = new MySqlCommand(); cmd.Connection = Connection; @@ -152,14 +153,14 @@ public void SameNameAttribute() cmd.CommandText = "SELECT mysql_query_attribute_string('foo')"; var result = cmd.ExecuteScalar(); - StringAssert.AreEqualIgnoringCase("bar", result.ToString()); + Assert.That(result.ToString(), Is.EqualTo("bar").IgnoreCase); } [TestCase(true)] [TestCase(false)] public void QueryAttributesNotSupported(bool prepare) { - if (Connection.driver.SupportsQueryAttributes) Assert.Ignore("Query attributes supported."); + Assume.That(!Connection.driver.SupportsQueryAttributes,"Query attributes supported."); MySqlTrace.Listeners.Clear(); MySqlTrace.Switch.Level = System.Diagnostics.SourceLevels.Warning; @@ -176,15 +177,15 @@ public void QueryAttributesNotSupported(bool prepare) if (prepare) cmd.Prepare(); var result = cmd.ExecuteScalar(); - StringAssert.AreEqualIgnoringCase("test", result.ToString()); - StringAssert.Contains(string.Format(Resources.QueryAttributesNotSupported, Version), listener.Strings[0]); + Assert.That(result.ToString(), Is.EqualTo("test").IgnoreCase); + Assert.That(listener.Strings[0], Does.Contain(string.Format(Resources.QueryAttributesNotSupported, Version))); } [TestCase(true)] [TestCase(false)] public void AttributesAndParameters(bool prepare) { - if (!Connection.driver.SupportsQueryAttributes) Assert.Ignore("MySQL Server version does not support query attributes."); + Assume.That(Connection.driver.SupportsQueryAttributes, "MySQL Server version does not support query attributes."); using MySqlCommand cmd = new MySqlCommand(); cmd.Connection = Connection; @@ -198,9 +199,9 @@ public void AttributesAndParameters(bool prepare) { while (reader.Read()) { - StringAssert.AreEqualIgnoringCase("Hello World", reader.GetString(0)); - StringAssert.AreEqualIgnoringCase("Goodbye World", reader.GetString(1)); - if (Version >= new Version(8, 0, 26) || !prepare) StringAssert.AreEqualIgnoringCase("bar", reader.GetString(2)); + Assert.That(reader.GetString(0), Is.EqualTo("Hello World").IgnoreCase); + Assert.That(reader.GetString(1), Is.EqualTo("Goodbye World").IgnoreCase); + if (Version >= new Version(8, 0, 26) || !prepare) Assert.That(reader.GetString(2), Is.EqualTo("bar").IgnoreCase); } } } @@ -221,7 +222,7 @@ public void InvalidValues() [TestCase(false)] public void ParameterOverridesAttributeValue(bool prepare) { - if (!Connection.driver.SupportsQueryAttributes) Assert.Ignore("MySQL Server version does not support query attributes."); + Assume.That(Connection.driver.SupportsQueryAttributes, "MySQL Server version does not support query attributes."); using var cmd = new MySqlCommand("select mysql_query_attribute_string('name') as attribute, mysql_query_attribute_string('name2') as attribute2, @name as parameter, @name2 as parameter2, mysql_query_attribute_string('attr') as attribute3", Connection); cmd.Attributes.SetAttribute("name", "attribute"); @@ -235,11 +236,11 @@ public void ParameterOverridesAttributeValue(bool prepare) using var reader = cmd.ExecuteReader(); while (reader.Read()) { - StringAssert.AreEqualIgnoringCase("attribute", reader.GetValue(0).ToString()); - StringAssert.AreEqualIgnoringCase("attribute2", reader.GetValue(1).ToString()); - StringAssert.AreEqualIgnoringCase("parameter", reader.GetValue(2).ToString()); - StringAssert.AreEqualIgnoringCase("parameter2", reader.GetValue(3).ToString()); - StringAssert.AreEqualIgnoringCase("attribute3", reader.GetValue(4).ToString()); + Assert.That(reader.GetValue(0).ToString(), Is.EqualTo("attribute").IgnoreCase); + Assert.That(reader.GetValue(1).ToString(), Is.EqualTo("attribute2").IgnoreCase); + Assert.That(reader.GetValue(2).ToString(), Is.EqualTo("parameter").IgnoreCase); + Assert.That(reader.GetValue(3).ToString(), Is.EqualTo("parameter2").IgnoreCase); + Assert.That(reader.GetValue(4).ToString(), Is.EqualTo("attribute3").IgnoreCase); } } } diff --git a/MySQL.Data/tests/MySql.Data.Tests/AuthTests.cs b/MySQL.Data/tests/MySql.Data.Tests/AuthTests.cs index 82bff80be..952e044db 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/AuthTests.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/AuthTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2016, 2023, Oracle and/or its affiliates. +// Copyright © 2016, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -26,15 +26,15 @@ // along with this program; if not, write to the Free Software Foundation, Inc., // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -using Microsoft.Win32; -using MySql.Data.Authentication.FIDO.Utility; + using MySql.Data.Common; using MySql.Data.MySqlClient.Authentication; using NUnit.Framework; +using NUnit.Framework.Legacy; using System; using System.Collections.Generic; using System.Data; -using System.Numerics; +using System.Linq; using System.Reflection; using System.Text; @@ -203,18 +203,18 @@ private void TestIntegratedSecurityWithoutProxy(string user, bool pooling) threadId = c.ServerThread; MySqlCommand command = new MySqlCommand("SELECT 1", c); long ret = (long)command.ExecuteScalar(); - Assert.AreEqual(1, ret); + Assert.That(ret, Is.EqualTo(1)); command.CommandText = "select user()"; string myUser = (string)command.ExecuteScalar(); // Check if proxy user is correct - StringAssert.StartsWith(UserName + "@", myUser); + Assert.That(myUser, Does.StartWith(UserName + "@")); // check if mysql user is correct // (foo_user is mapped to current OS user) command.CommandText = "select current_user()"; string currentUser = (string)command.ExecuteScalar(); - StringAssert.StartsWith(UserName, currentUser); + Assert.That(currentUser, Does.StartWith(UserName)); } } @@ -330,18 +330,18 @@ private void TestIntegratedSecurityWithUser(string user, bool pooling) threadId = c.ServerThread; MySqlCommand command = new MySqlCommand("SELECT 1", c); long ret = (long)command.ExecuteScalar(); - Assert.AreEqual(1, ret); + Assert.That(ret, Is.EqualTo(1)); command.CommandText = "select user()"; string myUser = (string)command.ExecuteScalar(); // Check if proxy user is correct - StringAssert.StartsWith(UserName + "@", myUser); + Assert.That(myUser, Does.StartWith(UserName + "@")); // check if mysql user is correct // (foo_user is mapped to current OS user) command.CommandText = "select current_user()"; string currentUser = (string)command.ExecuteScalar(); - StringAssert.StartsWith("foo_user@", currentUser); + Assert.That(currentUser, Does.StartWith("foo_user@")); } } @@ -359,6 +359,8 @@ private void TestIntegratedSecurityWithUser(string user, bool pooling) [Property("Category", "Security")] public void ConnectUsingMySqlNativePasswordPlugin() { + Assume.That(Check_Plugin_Enabled("mysql_native_password"), "mysql_native_password plugin must be enabled on the server to run this test"); + string userName = "testNtvPass"; string password = "mysql"; string pluginName = "mysql_native_password"; @@ -375,16 +377,16 @@ public void ConnectUsingMySqlNativePasswordPlugin() MySqlCommand command = new MySqlCommand("SHOW SESSION STATUS LIKE 'Ssl_version';", connection); using (MySqlDataReader reader = command.ExecuteReader()) { - Assert.True(reader.Read()); - StringAssert.StartsWith("TLSv1", reader.GetString(1)); + Assert.That(reader.Read(), Is.True); + Assert.That(reader.GetString(1), Does.StartWith("TLSv1")); } command.CommandText = String.Format("SELECT `User`, `plugin` FROM `mysql`.`user` WHERE `User` = '{0}';", userName); using (MySqlDataReader reader = command.ExecuteReader()) { - Assert.True(reader.Read()); - Assert.AreEqual(userName, reader.GetString(0)); - Assert.AreEqual(pluginName, reader.GetString(1)); + Assert.That(reader.Read(), Is.True); + Assert.That(reader.GetString(0), Is.EqualTo(userName)); + Assert.That(reader.GetString(1), Is.EqualTo(pluginName)); } connection.Close(); @@ -425,16 +427,16 @@ public void ConnectUsingSha256PasswordPlugin() MySqlCommand command = new MySqlCommand("SHOW SESSION STATUS LIKE 'Ssl_version';", connection); using (MySqlDataReader reader = command.ExecuteReader()) { - Assert.True(reader.Read()); - StringAssert.StartsWith("TLSv1", reader.GetString(1)); + Assert.That(reader.Read(), Is.True); + Assert.That(reader.GetString(1), Does.StartWith("TLSv1")); } command.CommandText = String.Format("SELECT `User`, `plugin` FROM `mysql`.`user` WHERE `User` = '{0}';", userName); using (MySqlDataReader reader = command.ExecuteReader()) { - Assert.True(reader.Read()); - Assert.AreEqual(userName, reader.GetString(0)); - Assert.AreEqual(pluginName, reader.GetString(1)); + Assert.That(reader.Read(), Is.True); + Assert.That(reader.GetString(0), Is.EqualTo(userName)); + Assert.That(reader.GetString(1), Is.EqualTo(pluginName)); } connection.Close(); @@ -462,7 +464,7 @@ public void ConnectUsingSha256PasswordPlugin() if (serverCompiledUsingOpenSsl) { Exception ex = Assert.Throws(() => connection.Open()); - Assert.AreEqual("Retrieval of the RSA public key is not enabled for insecure connections.", ex.Message); + Assert.That(ex.Message, Is.EqualTo(Resources.RSAPublicKeyRetrievalNotEnabled)); } else Assert.Throws(() => connection.Open()); } @@ -489,16 +491,16 @@ public void ConnectUsingSha256PasswordPlugin() MySqlCommand command = new MySqlCommand("SHOW SESSION STATUS LIKE 'Ssl_version';", connection); using (MySqlDataReader reader = command.ExecuteReader()) { - Assert.True(reader.Read()); - StringAssert.StartsWith("TLSv1", reader.GetString(1)); + Assert.That(reader.Read(), Is.True); + Assert.That(reader.GetString(1), Does.StartWith("TLSv1")); } command.CommandText = String.Format("SELECT `User`, `plugin` FROM `mysql`.`user` WHERE `User` = '{0}';", userName); using (MySqlDataReader reader = command.ExecuteReader()) { - Assert.True(reader.Read()); - Assert.AreEqual(userName, reader.GetString(0)); - Assert.AreEqual(pluginName, reader.GetString(1)); + Assert.That(reader.Read(), Is.True); + Assert.That(reader.GetString(0), Is.EqualTo(userName)); + Assert.That(reader.GetString(1), Is.EqualTo(pluginName)); } connection.Close(); @@ -540,9 +542,9 @@ public void AllowPublicKeyRetrievalForSha256PasswordPlugin() { Exception ex = Assert.Throws(() => connection.Open()); ; if (serverCompiledUsingOpenSsl) - Assert.AreEqual("Retrieval of the RSA public key is not enabled for insecure connections.", ex.Message); + Assert.That(ex.Message, Is.EqualTo(Resources.RSAPublicKeyRetrievalNotEnabled)); else - StringAssert.StartsWith("Authentication to host", ex.Message); + Assert.That(ex.Message, Does.StartWith("Authentication to host")); } if (serverCompiledUsingOpenSsl) @@ -604,8 +606,8 @@ public void ConnectUsingCachingSha2Plugin() using (MySqlConnection connection = new MySqlConnection(builder.ConnectionString)) { connection.Open(); - Assert.AreEqual(ConnectionState.Open, connection.connectionState); - Assert.AreEqual(AuthStage.FULL_AUTH, CachingSha2AuthenticationPlugin._authStage); + Assert.That(connection.connectionState, Is.EqualTo(ConnectionState.Open)); + Assert.That(CachingSha2AuthenticationPlugin._authStage, Is.EqualTo(AuthStage.FULL_AUTH)); connection.Close(); } @@ -613,8 +615,8 @@ public void ConnectUsingCachingSha2Plugin() using (MySqlConnection connection = new MySqlConnection(builder.ConnectionString)) { connection.Open(); - Assert.AreEqual(ConnectionState.Open, connection.connectionState); - Assert.AreEqual(AuthStage.FAST_AUTH, CachingSha2AuthenticationPlugin._authStage); + Assert.That(connection.connectionState, Is.EqualTo(ConnectionState.Open)); + Assert.That(CachingSha2AuthenticationPlugin._authStage, Is.EqualTo(AuthStage.FAST_AUTH)); connection.Close(); } @@ -623,14 +625,14 @@ public void ConnectUsingCachingSha2Plugin() using (MySqlConnection connection = new MySqlConnection(builder.ConnectionString)) { connection.Open(); - Assert.AreEqual(AuthStage.FULL_AUTH, CachingSha2AuthenticationPlugin._authStage); + Assert.That(CachingSha2AuthenticationPlugin._authStage, Is.EqualTo(AuthStage.FULL_AUTH)); connection.Close(); } // Authentication failure - TLS connection. builder.Password = "incorrectPassword"; Exception ex = Assert.Throws(() => new MySqlConnection(builder.ConnectionString).Open()); - StringAssert.StartsWith("Access denied for user", ex.InnerException.Message); + Assert.That(ex.InnerException.Message, Does.StartWith("Access denied for user")); // Authentication success with empty password – Any connection. builder.UserID = "testCachingSha2NoPassword"; @@ -641,8 +643,8 @@ public void ConnectUsingCachingSha2Plugin() using (MySqlConnection connection = new MySqlConnection(builder.ConnectionString)) { connection.Open(); - Assert.AreEqual(ConnectionState.Open, connection.connectionState); - Assert.AreEqual(AuthStage.GENERATE_SCRAMBLE, CachingSha2AuthenticationPlugin._authStage); + Assert.That(connection.connectionState, Is.EqualTo(ConnectionState.Open)); + Assert.That(CachingSha2AuthenticationPlugin._authStage, Is.EqualTo(AuthStage.GENERATE_SCRAMBLE)); connection.Close(); } @@ -651,8 +653,8 @@ public void ConnectUsingCachingSha2Plugin() using (MySqlConnection connection = new MySqlConnection(builder.ConnectionString)) { connection.Open(); - Assert.AreEqual(ConnectionState.Open, connection.connectionState); - Assert.AreEqual(AuthStage.GENERATE_SCRAMBLE, CachingSha2AuthenticationPlugin._authStage); + Assert.That(connection.connectionState, Is.EqualTo(ConnectionState.Open)); + Assert.That(CachingSha2AuthenticationPlugin._authStage, Is.EqualTo(AuthStage.GENERATE_SCRAMBLE)); connection.Close(); } @@ -661,12 +663,12 @@ public void ConnectUsingCachingSha2Plugin() builder.UserID = "testCachingSha2"; builder.SslMode = MySqlSslMode.Required; ex = Assert.Throws(() => new MySqlConnection(builder.ConnectionString).Open()); - StringAssert.StartsWith("Access denied for user", ex.InnerException.Message); + Assert.That(ex.InnerException.Message, Does.StartWith("Access denied for user")); // TLS not enabled. builder.SslMode = MySqlSslMode.Disabled; ex = Assert.Throws(() => new MySqlConnection(builder.ConnectionString).Open()); - StringAssert.StartsWith("Access denied for user", ex.InnerException.Message); + Assert.That(ex.InnerException.Message, Does.StartWith("Access denied for user")); // Authentication using RSA keys. Only available in servers compiled with OpenSSL (E.g. Commercial). bool serverCompiledUsingOpenSsl = false; @@ -693,21 +695,21 @@ public void ConnectUsingCachingSha2Plugin() using (MySqlConnection connection = new MySqlConnection(builder.ConnectionString)) { ex = Assert.Throws(() => connection.Open()); - Assert.AreEqual("Retrieval of the RSA public key is not enabled for insecure connections.", ex.Message); + Assert.That(ex.Message, Is.EqualTo(Resources.RSAPublicKeyRetrievalNotEnabled)); } builder.AllowPublicKeyRetrieval = true; using (MySqlConnection connection = new MySqlConnection(builder.ConnectionString)) { connection.Open(); - Assert.AreEqual(AuthStage.FULL_AUTH, CachingSha2AuthenticationPlugin._authStage); + Assert.That(CachingSha2AuthenticationPlugin._authStage, Is.EqualTo(AuthStage.FULL_AUTH)); connection.Close(); } using (MySqlConnection connection = new MySqlConnection(builder.ConnectionString)) { connection.Open(); - Assert.AreEqual(AuthStage.FAST_AUTH, CachingSha2AuthenticationPlugin._authStage); + Assert.That(CachingSha2AuthenticationPlugin._authStage, Is.EqualTo(AuthStage.FAST_AUTH)); connection.Close(); } @@ -716,13 +718,13 @@ public void ConnectUsingCachingSha2Plugin() using (MySqlConnection connection = new MySqlConnection(builder.ConnectionString)) { connection.Open(); - Assert.AreEqual(AuthStage.FULL_AUTH, CachingSha2AuthenticationPlugin._authStage); + Assert.That(CachingSha2AuthenticationPlugin._authStage, Is.EqualTo(AuthStage.FULL_AUTH)); connection.Close(); } builder.Password = "incorrectPassword"; ex = Assert.Throws(() => new MySqlConnection(builder.ConnectionString).Open()); - StringAssert.StartsWith("Access denied for user", ex.InnerException.Message); + Assert.That(ex.InnerException.Message, Does.StartWith("Access denied for user")); } } @@ -761,9 +763,9 @@ public void AllowPublicKeyRetrievalForCachingSha2PasswordPlugin() { Exception ex = Assert.Throws(() => connection.Open()); if (serverCompiledUsingOpenSsl) - Assert.AreEqual("Retrieval of the RSA public key is not enabled for insecure connections.", ex.Message); + Assert.That(ex.Message, Is.EqualTo(Resources.RSAPublicKeyRetrievalNotEnabled)); else - StringAssert.StartsWith("Authentication to host", ex.Message); + Assert.That(ex.Message, Does.StartWith("Authentication to host")); } if (serverCompiledUsingOpenSsl) @@ -811,7 +813,7 @@ public void CachingSha2AuthFailsAfterFlushPrivileges() using (MySqlConnection connection = new MySqlConnection(settings.ConnectionString)) { connection.Open(); - Assert.True(connection.State == ConnectionState.Open); + Assert.That(connection.State == ConnectionState.Open, Is.True); connection.Close(); } @@ -820,7 +822,7 @@ public void CachingSha2AuthFailsAfterFlushPrivileges() using (MySqlConnection connection = new MySqlConnection(settings.ConnectionString)) { connection.Open(); - Assert.True(connection.State == ConnectionState.Open); + Assert.That(connection.State == ConnectionState.Open, Is.True); connection.Close(); } @@ -832,9 +834,9 @@ public void CachingSha2AuthFailsAfterFlushPrivileges() { ex = Assert.Throws(() => connection.Open()); if (serverCompiledUsingOpenSsl) - Assert.AreEqual("Retrieval of the RSA public key is not enabled for insecure connections.", ex.Message); + Assert.That(ex.Message, Is.EqualTo(Resources.RSAPublicKeyRetrievalNotEnabled)); else - StringAssert.StartsWith("Authentication to host", ex.Message); + Assert.That(ex.Message, Does.StartWith("Authentication to host")); } settings.AllowPublicKeyRetrieval = true; @@ -844,14 +846,14 @@ public void CachingSha2AuthFailsAfterFlushPrivileges() if (serverCompiledUsingOpenSsl) { connection.Open(); - Assert.True(connection.State == ConnectionState.Open); + Assert.That(connection.State == ConnectionState.Open); connection.Close(); } // Fail since AllowPublicKeyRetrieval is ignored in gpl servers. else { ex = Assert.Throws(() => connection.Open()); - StringAssert.StartsWith("Authentication to host", ex.Message); + Assert.That(ex.Message, Does.StartWith("Authentication to host")); } } } @@ -887,7 +889,7 @@ public void CheckAllowPublicKeyRetrievalOptionIsAvailable() using (MySqlConnection connection = new MySqlConnection(connectionString)) { connection.Open(); - Assert.True(connection.Settings.AllowPublicKeyRetrieval); + Assert.That(connection.Settings.AllowPublicKeyRetrieval, Is.True); connection.Close(); } } @@ -918,14 +920,14 @@ public void ConnectUsingClearPasswordPlugin() using (MySqlConnection connection = new MySqlConnection(settings.ConnectionString)) { connection.Open(); - Assert.AreEqual(ConnectionState.Open, connection.connectionState); + Assert.That(connection.connectionState, Is.EqualTo(ConnectionState.Open)); var sql = string.Format("select user,plugin from mysql.user where user like '{0}'", settings.UserID); MySqlCommand command = new MySqlCommand(sql, connection); using (MySqlDataReader reader = command.ExecuteReader()) { - Assert.True(reader.Read()); - StringAssert.AreEqualIgnoringCase("test1@MYSQL.LOCAL", reader.GetString(0)); - StringAssert.AreEqualIgnoringCase("authentication_ldap_simple", reader.GetString(1)); + Assert.That(reader.Read(), Is.True); + Assert.That(reader.GetString(0), Is.EqualTo("test1@MYSQL.LOCAL").IgnoreCase); + Assert.That(reader.GetString(1), Is.EqualTo("authentication_ldap_simple").IgnoreCase); } //test the new user can execute sql statements FR1_1 sql = "create table testinserts( id int, name varchar(50),age int)"; @@ -940,13 +942,13 @@ public void ConnectUsingClearPasswordPlugin() sql = "select count(*) from testinserts"; command = new MySqlCommand(sql, connection); var counter = command.ExecuteScalar(); - Assert.AreEqual(4, counter); + Assert.That(counter, Is.EqualTo(4)); //check ssl command = new MySqlCommand("SHOW SESSION STATUS LIKE 'Ssl_version';", connection); using (MySqlDataReader reader = command.ExecuteReader()) { - Assert.True(reader.Read()); - StringAssert.StartsWith("TLSv1", reader.GetString(1)); + Assert.That(reader.Read(), Is.True); + Assert.That(reader.GetString(1), Does.StartWith("TLSv1")); } } @@ -958,13 +960,13 @@ public void ConnectUsingClearPasswordPlugin() using (MySqlConnection conn = new MySqlConnection(unixConnectionString)) { conn.Open(); - Assert.AreEqual(ConnectionState.Open, conn.State); + Assert.That(conn.State, Is.EqualTo(ConnectionState.Open)); } using (MySqlConnection connection = new MySqlConnection(unixConnectionString + "sslmode=none")) { connection.Open(); - Assert.AreEqual(ConnectionState.Open, connection.State); + Assert.That(connection.State, Is.EqualTo(ConnectionState.Open)); } } @@ -979,7 +981,7 @@ public void ConnectUsingClearPasswordPlugin() using (MySqlConnection connection = new MySqlConnection(settings.ConnectionString)) { Exception ex = Assert.Throws(() => connection.Open()); - StringAssert.StartsWith("Access denied for user", ex.InnerException.Message); + Assert.That(ex.InnerException.Message, Does.StartWith("Access denied for user")); } // Test connection for INVALID user in LDAP server, expected result FAIL @@ -993,7 +995,7 @@ public void ConnectUsingClearPasswordPlugin() using (MySqlConnection connection = new MySqlConnection(settings.ConnectionString)) { Exception ex = Assert.Throws(() => connection.Open()); - StringAssert.StartsWith("Access denied for user", ex.InnerException.Message); + Assert.That(ex.InnerException.Message, Does.StartWith("Access denied for user")); } // Test connection for VALID user in LDAP server with SSLMode=none, expected result FAIL @@ -1008,7 +1010,7 @@ public void ConnectUsingClearPasswordPlugin() using (MySqlConnection connection = new MySqlConnection(settings.ConnectionString)) { Exception ex = Assert.Throws(() => connection.Open()); - StringAssert.Contains("Clear-password authentication is not supported over insecure channels", ex.Message); + Assert.That(ex.Message, Is.EqualTo(Resources.ClearPasswordNotSupported)); } // Test connection for VALID user in LDAP server with different SSLMode values, expected result pass @@ -1028,7 +1030,7 @@ public void ConnectUsingClearPasswordPlugin() using (MySqlConnection connection = new MySqlConnection(settings.ConnectionString)) { connection.Open(); - Assert.AreEqual(ConnectionState.Open, connection.State); + Assert.That(connection.State, Is.EqualTo(ConnectionState.Open)); connection.Close(); } @@ -1037,7 +1039,7 @@ public void ConnectUsingClearPasswordPlugin() using (MySqlConnection connection = new MySqlConnection(settings.ConnectionString)) { connection.Open(); - Assert.AreEqual(ConnectionState.Open, connection.State); + Assert.That(connection.State, Is.EqualTo(ConnectionState.Open)); connection.Close(); } @@ -1048,7 +1050,7 @@ public void ConnectUsingClearPasswordPlugin() using (MySqlConnection connection = new MySqlConnection(settings.ConnectionString)) { connection.Open(); - Assert.AreEqual(ConnectionState.Open, connection.State); + Assert.That(connection.State, Is.EqualTo(ConnectionState.Open)); connection.Close(); } @@ -1093,11 +1095,11 @@ public void ConnectUsingMySqlSASLPluginSCRAMSHA(string userName, string password MySqlCommand command = new MySqlCommand($"SELECT `User`, `plugin` FROM `mysql`.`user` WHERE `User` = '{userName}';", connection); using (MySqlDataReader reader = command.ExecuteReader()) { - StringAssert.AreEqualIgnoringCase(mechanism, MySqlSASLPlugin.scramMechanism.MechanismName); - Assert.AreEqual(ScramBase.AuthState.VALIDATE, MySqlSASLPlugin.scramMechanism._state); - Assert.True(reader.Read()); - StringAssert.AreEqualIgnoringCase(userName, reader.GetString(0)); - StringAssert.AreEqualIgnoringCase(plugin, reader.GetString(1)); + Assert.That(MySqlSASLPlugin.scramMechanism.MechanismName, Is.EqualTo(mechanism).IgnoreCase); + Assert.That(MySqlSASLPlugin.scramMechanism._state, Is.EqualTo(ScramBase.AuthState.VALIDATE)); + Assert.That(reader.Read(), Is.True); + Assert.That(reader.GetString(0), Is.EqualTo(userName).IgnoreCase); + Assert.That(reader.GetString(1), Is.EqualTo(plugin).IgnoreCase); } } else @@ -1116,19 +1118,19 @@ public void AssertScramSha1() ScramSha1Mechanism scramSha1 = new ScramSha1Mechanism("user", "pencil", Host); scramSha1._cnonce = fixedNonce; - Assert.AreEqual(ScramBase.AuthState.INITIAL, scramSha1._state); + Assert.That(scramSha1._state, Is.EqualTo(ScramBase.AuthState.INITIAL)); var challenge = Encoding.UTF8.GetString(scramSha1.Challenge(null)); - Assert.AreEqual("n,a=user,n=user,r=" + fixedNonce, challenge); - Assert.AreEqual(ScramBase.AuthState.FINAL, scramSha1._state); + Assert.That(challenge, Is.EqualTo("n,a=user,n=user,r=" + fixedNonce)); + Assert.That(scramSha1._state, Is.EqualTo(ScramBase.AuthState.FINAL)); response = Encoding.UTF8.GetBytes(challenge1); challenge = Encoding.UTF8.GetString(scramSha1.Challenge(response)); - Assert.AreEqual(expected, challenge); - Assert.AreEqual(ScramBase.AuthState.VALIDATE, scramSha1._state); + Assert.That(challenge, Is.EqualTo(expected)); + Assert.That(scramSha1._state, Is.EqualTo(ScramBase.AuthState.VALIDATE)); response = Encoding.UTF8.GetBytes(challenge2); - Assert.IsNull(scramSha1.Challenge(response)); + Assert.That(scramSha1.Challenge(response), Is.Null); } [Test] @@ -1142,90 +1144,47 @@ public void AssertScramSha256() ScramSha256Mechanism scramSha256 = new ScramSha256Mechanism("user", "pencil", Host); scramSha256._cnonce = fixedNonce; - Assert.AreEqual(ScramBase.AuthState.INITIAL, scramSha256._state); + Assert.That(scramSha256._state, Is.EqualTo(ScramBase.AuthState.INITIAL)); var challenge = Encoding.UTF8.GetString(scramSha256.Challenge(null)); - Assert.AreEqual("n,a=user,n=user,r=" + fixedNonce, challenge); - Assert.AreEqual(ScramBase.AuthState.FINAL, scramSha256._state); + Assert.That(challenge, Is.EqualTo("n,a=user,n=user,r=" + fixedNonce)); + Assert.That(scramSha256._state, Is.EqualTo(ScramBase.AuthState.FINAL)); response = Encoding.UTF8.GetBytes(challenge1); challenge = Encoding.UTF8.GetString(scramSha256.Challenge(response)); - Assert.AreEqual(expected, challenge); - Assert.AreEqual(ScramBase.AuthState.VALIDATE, scramSha256._state); + Assert.That(challenge, Is.EqualTo(expected)); + Assert.That(scramSha256._state, Is.EqualTo(ScramBase.AuthState.VALIDATE)); response = Encoding.UTF8.GetBytes(challenge2); - Assert.IsNull(scramSha256.Challenge(response)); + Assert.That(scramSha256.Challenge(response), Is.Null); } #endregion - #region GSSAPI/Kerberos Mechanism - /// - /// WL14210 - [Classic] Add LDAP kerberos support (GSSAPI) - /// This test require to start MySQL Commercial Server with the configuration specified in file Resources/my.ini - /// It uses preconfigured LDAP servers present in the labs. - /// For configuration of the server, theres a quick guide in Resources/KerberosConfig.txt to setup the environment. - /// - [TestCase("test1@MYSQL.LOCAL", "Testpw1", "authentication_ldap_sasl", true)] - [TestCase("invalidUser@MYSQL.LOCAL", "Testpw1", "authentication_ldap_sasl", false)] - [TestCase("test1@MYSQL.LOCAL", "wrongPassword", "authentication_ldap_sasl", false)] - [Ignore("This test require to start MySQL Commercial Server with the configuration specified in file Resources/my.ini")] - [Property("Category", "Security")] - public void ConnectUsingMySqlSASLPluginGSSAPI(string userName, string password, string pluginName, bool shouldPass) - { - MySqlConnectionStringBuilder settings = new MySqlConnectionStringBuilder(Settings.ConnectionString) - { - UserID = userName, - Password = password, - Database = string.Empty, - SslMode = MySqlSslMode.Disabled - }; - - ExecuteSQL("CREATE USER 'test1@MYSQL.LOCAL' IDENTIFIED WITH authentication_ldap_sasl; GRANT ALL ON *.* to 'test1@MYSQL.LOCAL';", true); - - using (MySqlConnection connection = new MySqlConnection(settings.ConnectionString)) - { - if (shouldPass) - { - connection.Open(); - MySqlCommand command = new MySqlCommand($"SELECT user();", connection); - using (MySqlDataReader reader = command.ExecuteReader()) - { - StringAssert.AreEqualIgnoringCase("GSSAPI", MySqlSASLPlugin.gssapiMechanism.MechanismName); - Assert.True(reader.Read()); - StringAssert.Contains(userName, reader.GetString(0)); - } - } - else - Assert.Throws(() => connection.Open()); - } - } - #endregion - [Test] public void AssertSaslPrep() { // Valid String - Assert.AreEqual("my,0TEXT", MySqlSASLPlugin.SaslPrep("my,0TEXT")); - Assert.AreEqual("my,0 TEXT", MySqlSASLPlugin.SaslPrep("my,0 TEXT")); + Assert.That(MySqlSASLPlugin.SaslPrep("my,0TEXT"), Is.EqualTo("my,0TEXT")); + Assert.That(MySqlSASLPlugin.SaslPrep("my,0 TEXT"), Is.EqualTo("my,0 TEXT")); // Queries for matching strings MAY contain unassigned code points. - Assert.AreEqual("\u0888my,0TEXT", MySqlSASLPlugin.SaslPrep("\u0888my,0TEXT")); - Assert.AreEqual("my,0\u0890TEXT", MySqlSASLPlugin.SaslPrep("my,0\u0890TEXT")); - Assert.AreEqual("my,0TEXT\u089F", MySqlSASLPlugin.SaslPrep("my,0TEXT\u089F")); + Assert.That(MySqlSASLPlugin.SaslPrep("\u0888my,0TEXT"), Is.EqualTo("\u0888my,0TEXT")); + Assert.That(MySqlSASLPlugin.SaslPrep("my,0\u0890TEXT"), Is.EqualTo("my,0\u0890TEXT")); + Assert.That(MySqlSASLPlugin.SaslPrep("my,0TEXT\u089F"), Is.EqualTo("my,0TEXT\u089F")); // Mapping: non-ASCII space characters. - Assert.AreEqual("my,0 TEXT", MySqlSASLPlugin.SaslPrep("my,0\u1680TEXT")); - Assert.AreEqual("my,0 TEXT", MySqlSASLPlugin.SaslPrep("my,0\u200BTEXT")); - Assert.AreEqual(" my,0 TEXT ", MySqlSASLPlugin.SaslPrep("\u00A0my,0\u2000TEXT\u3000")); + Assert.That(MySqlSASLPlugin.SaslPrep("my,0\u1680TEXT"), Is.EqualTo("my,0 TEXT")); + Assert.That(MySqlSASLPlugin.SaslPrep("my,0\u200BTEXT"), Is.EqualTo("my,0 TEXT")); + Assert.That(MySqlSASLPlugin.SaslPrep("\u00A0my,0\u2000TEXT\u3000"), Is.EqualTo(" my,0 TEXT ")); // Mapping: the "commonly mapped to nothing" characters. - Assert.AreEqual("my,0TEXT", MySqlSASLPlugin.SaslPrep("my,0\u00ADTEXT")); - Assert.AreEqual("my,0TEXT", MySqlSASLPlugin.SaslPrep("my,0\uFE0ATEXT")); - Assert.AreEqual("my,0TEXT", MySqlSASLPlugin.SaslPrep("\u00ADmy,0\u1806TE\uFE0FXT\uFEFF")); + Assert.That(MySqlSASLPlugin.SaslPrep("my,0\u00ADTEXT"), Is.EqualTo("my,0TEXT")); + Assert.That(MySqlSASLPlugin.SaslPrep("my,0\uFE0ATEXT"), Is.EqualTo("my,0TEXT")); + Assert.That(MySqlSASLPlugin.SaslPrep("\u00ADmy,0\u1806TE\uFE0FXT\uFEFF"), Is.EqualTo("my,0TEXT")); // KC Normalization. - Assert.AreEqual("my,0 fi TEXT", MySqlSASLPlugin.SaslPrep("my,0 \uFB01 TEXT")); - Assert.AreEqual("my,0 fi TEXT", MySqlSASLPlugin.SaslPrep("my,0 \uFB01 TEXT")); + Assert.That(MySqlSASLPlugin.SaslPrep("my,0 \uFB01 TEXT"), Is.EqualTo("my,0 fi TEXT")); + Assert.That(MySqlSASLPlugin.SaslPrep("my,0 \uFB01 TEXT"), Is.EqualTo("my,0 fi TEXT")); // Prohibited Output: ASCII control characters. Assert.Throws(() => MySqlSASLPlugin.SaslPrep("\u007Fmy,0TEXT")); @@ -1277,120 +1236,6 @@ public void AssertSaslPrep() } #endregion - #region PureKerberos Mechanism - /// - /// WL14429 - [Classic] Support for authentication_kerberos_client authentication plugin - /// WL14654 - [Classic] Integrate new SSPI kerberos library - /// WL15341 - [Classic] Support MIT Kerberos library on Windows - /// These tests require to start MySQL Commercial Server with the configuration specified in file Resources/my.ini - /// It uses preconfigured LDAP servers present in the labs. - /// For configuration of the server, there's a quick guide in Resources/KerberosConfig.txt to setup the environment. - /// For SSPI, Windows client should be part of Windows server domain. - /// Please refer to the WLs to check the specifications for each case. - /// - - [TestCase(false, "invalidUser", "", "", null)] - [TestCase(false, "invalidUser", "fakePassword", "", null)] - [TestCase(false, "", "", "caching_sha2_password", null)] - [TestCase(true, "", "", "authentication_kerberos_client", KerberosAuthMode.GSSAPI)] // TRUE: if there's a TGT in cache or the login user is in KDC. 'AUTO' if logged-in user is properly configured - [TestCase(true, "", "falsePassword", "authentication_kerberos_client", KerberosAuthMode.GSSAPI)] - [TestCase(true, "", "Testpw1", "authentication_kerberos_client", KerberosAuthMode.GSSAPI)] - [TestCase(true, "test1", "Testpw1", "authentication_kerberos_client", KerberosAuthMode.AUTO)] - [TestCase(true, "test1", "Testpw1", "sha256_password", KerberosAuthMode.AUTO)] - [TestCase(true, "test1", "Testpw1", "", KerberosAuthMode.AUTO)] - [TestCase(true, "test1", "wrongPassword", "", KerberosAuthMode.GSSAPI)] // TRUE: if there's a TGT in cache. - [TestCase(true, "test1", "", "", KerberosAuthMode.GSSAPI)] - [Ignore("This test require to start MySQL Commercial Server with the configuration specified in file Resources/my.ini")] - [Property("Category", "Security")] - public void ConnectUsingMySqlPluginKerberosAUTO(bool shouldPass, string userName, string password, string pluginName, KerberosAuthMode mode) - { - MySqlConnectionStringBuilder settings = new MySqlConnectionStringBuilder(Settings.ConnectionString) - { - UserID = userName, - Password = password, - DefaultAuthenticationPlugin = pluginName - }; - - TestKerberosConnection(shouldPass, userName, settings, mode); - } - - [TestCase(false, "invalidUser", "", "", null)] - [TestCase(false, "invalidUser", "fakePassword", "", null)] - [TestCase(false, "", "", "caching_sha2_password", null)] - [TestCase(false, "", "", "authentication_kerberos_client", null)] // TRUE if logged-in user is properly configured in MySQL Server - [TestCase(false, "", "falsePassword", "authentication_kerberos_client", null)] // SSPI will use the logged-in user and the password provided - [TestCase(false, "test1", "wrongPassword", "", null)] - [TestCase(true, "", "Testpw1", "authentication_kerberos_client", KerberosAuthMode.SSPI)] // logged-in user should be properly configured in MySQL server - [TestCase(true, "test1", "Testpw1", "authentication_kerberos_client", KerberosAuthMode.SSPI)] - [TestCase(true, "test1", "Testpw1", "sha256_password", KerberosAuthMode.SSPI)] - [TestCase(true, "test1", "Testpw1", "", KerberosAuthMode.SSPI)] - [TestCase(true, "test1", "", "", KerberosAuthMode.SSPI)] // MySQL user should match with logged-in Windows user - [Ignore("This test require to start MySQL Commercial Server with the configuration specified in file Resources/my.ini")] - [Property("Category", "Security")] - public void ConnectUsingMySqlPluginKerberosSSPI(bool shouldPass, string userName, string password, string pluginName, KerberosAuthMode mode) - { - MySqlConnectionStringBuilder settings = new MySqlConnectionStringBuilder(Settings.ConnectionString) - { - UserID = userName, - Password = password, - DefaultAuthenticationPlugin = pluginName, - KerberosAuthMode = KerberosAuthMode.SSPI - }; - - TestKerberosConnection(shouldPass, userName, settings, mode); - } - - [TestCase(false, "invalidUser", "", "", null)] - [TestCase(false, "invalidUser", "fakePassword", "", null)] - [TestCase(false, "", "", "caching_sha2_password", null)] - [TestCase(true, "", "", "authentication_kerberos_client", KerberosAuthMode.GSSAPI)] // TRUE: if there's a TGT in cache or the login user is in KDC. - [TestCase(true, "", "falsePassword", "authentication_kerberos_client", KerberosAuthMode.GSSAPI)] // TRUE: if there's a TGT in cache or the login user is in KDC. - [TestCase(true, "", "Testpw1", "authentication_kerberos_client", KerberosAuthMode.GSSAPI)] // TRUE: if there's a TGT in cache or the login user is in KDC. - [TestCase(true, "test1", "Testpw1", "authentication_kerberos_client", KerberosAuthMode.GSSAPI)] - [TestCase(true, "test1", "Testpw1", "sha256_password", KerberosAuthMode.GSSAPI)] - [TestCase(true, "test1", "Testpw1", "", KerberosAuthMode.GSSAPI)] - [TestCase(true, "test1", "wrongPassword", "", KerberosAuthMode.GSSAPI)] // TRUE: if there's a TGT in cache - [TestCase(true, "test1", "", "", KerberosAuthMode.GSSAPI)] // TRUE: if there's a TGT in cache - [Ignore("This test require to start MySQL Commercial Server with the configuration specified in file Resources/my.ini")] - [Property("Category", "Security")] - public void ConnectUsingMySqlPluginKerberosGSSAPI(bool shouldPass, string userName, string password, string pluginName, KerberosAuthMode mode) - { - MySqlConnectionStringBuilder settings = new MySqlConnectionStringBuilder(Settings.ConnectionString) - { - UserID = userName, - Password = password, - DefaultAuthenticationPlugin = pluginName, - KerberosAuthMode = KerberosAuthMode.GSSAPI - }; - - TestKerberosConnection(shouldPass, userName, settings, mode); - } - - private void TestKerberosConnection(bool shouldPass, string username, MySqlConnectionStringBuilder settings, KerberosAuthMode mode) - { - ExecuteSQL("CREATE USER IF NOT EXISTS 'test1'@'%' IDENTIFIED WITH authentication_kerberos BY 'MYSQL.LOCAL'; " + - "GRANT ALL ON *.* to 'test1'@'%';", true); - - using (MySqlConnection conn = new MySqlConnection(settings.ConnectionString)) - { - if (shouldPass) - { - conn.Open(); - MySqlCommand command = new MySqlCommand($"SELECT user();", conn); - using (MySqlDataReader reader = command.ExecuteReader()) - { - Assert.True(reader.Read()); - StringAssert.Contains(username, reader.GetString(0)); - } - - Assert.True(conn.Settings.KerberosAuthMode == mode); - } - else - Assert.Throws(() => conn.Open()); - } - } - #endregion - #region OCI IAM Authentication /// /// WL14708 - Support OCI IAM authentication @@ -1423,9 +1268,9 @@ public void ConnectUsingOciIamAuthentication(string userName, string configFileP MySqlCommand command = new MySqlCommand($"SELECT user();", conn); using (MySqlDataReader reader = command.ExecuteReader()) { - Assert.True(reader.Read()); + Assert.That(reader.Read(), Is.True); userName = string.IsNullOrEmpty(userName) ? Environment.UserName : userName; - StringAssert.Contains(userName, reader.GetString(0)); + Assert.That(reader.GetString(0), Does.Contain(userName)); } } } @@ -1436,7 +1281,7 @@ public void NonExistingKeyFile() OciAuthenticationPlugin plugin = new OciAuthenticationPlugin(); string keyFileInvalidPath = "C:\\invalid\\Path"; string exMsg = Assert.Throws(() => OciAuthenticationPlugin.SignData(new byte[0], keyFileInvalidPath)).Message; - StringAssert.AreEqualIgnoringCase(Resources.OciKeyFileDoesNotExists, exMsg); + Assert.That(exMsg, Is.EqualTo(Resources.OciKeyFileDoesNotExists).IgnoreCase); } public struct Profiles @@ -1484,13 +1329,13 @@ public void ValidatesEntries(Profiles profiles) if (profiles.missingEntry) { exMsg = Assert.Throws(() => plugin.GetOciConfigValues(profiles.profiles, out string keyFile, out string fingerprint, out string securityTokenFilePath)).Message; - StringAssert.AreEqualIgnoringCase(Resources.OciEntryNotFound, exMsg); + Assert.That(exMsg, Is.EqualTo(Resources.OciEntryNotFound).IgnoreCase); } else { plugin.GetOciConfigValues(profiles.profiles, out string keyFile, out string fingerprint, out string securityTokenFilePath); exMsg = Assert.Throws(() => OciAuthenticationPlugin.SignData(new byte[0], keyFile)).Message; - StringAssert.AreEqualIgnoringCase(Resources.OciInvalidKeyFile, exMsg); + Assert.That(exMsg, Is.EqualTo(Resources.OciInvalidKeyFile).IgnoreCase); } } @@ -1507,9 +1352,9 @@ public void OtherThanDefaultProfile() plugin._ociConfigProfile = "TEST"; plugin.GetOciConfigValues(profiles, out string keyFilePath, out string fingerprint, out string securityTokenFilePath); - StringAssert.AreEqualIgnoringCase("keyFilePath", keyFilePath); - StringAssert.AreEqualIgnoringCase("66:55:44:33:22:11", fingerprint); - StringAssert.AreEqualIgnoringCase("securityTokenFilePath", securityTokenFilePath); + Assert.That(keyFilePath, Is.EqualTo("keyFilePath").IgnoreCase); + Assert.That(fingerprint, Is.EqualTo("66:55:44:33:22:11").IgnoreCase); + Assert.That(securityTokenFilePath, Is.EqualTo("securityTokenFilePath").IgnoreCase); } [DatapointSource] @@ -1539,7 +1384,7 @@ public void NonExistingConfigFile(string invalidPath) using (var conn = new MySqlConnection(connStringBuilder.ConnectionString)) { string exMsg = Assert.Throws(() => conn.Open()).Message; - StringAssert.AreEqualIgnoringCase(Resources.OciConfigFileNotFound, exMsg); + Assert.That(exMsg, Is.EqualTo(Resources.OciConfigFileNotFound).IgnoreCase); } } @@ -1549,7 +1394,7 @@ public void OciSdkNotInstalled() OciAuthenticationPlugin plugin = new OciAuthenticationPlugin(); string exMsg = Assert.Throws(() => plugin.AuthenticateAsync(false, false).GetAwaiter().GetResult()).Message; - StringAssert.AreEqualIgnoringCase(Resources.OciSDKNotFound, exMsg); + Assert.That(exMsg, Is.EqualTo(Resources.OciSDKNotFound).IgnoreCase); } [Test] @@ -1572,7 +1417,7 @@ public void NonExistingConfigProfile() using (var conn = new MySqlConnection(connStringBuilder.ConnectionString)) { string exMsg = Assert.Throws(() => conn.Open()).Message; - StringAssert.AreEqualIgnoringCase(Resources.OciConfigProfileNotFound, exMsg); + Assert.That(exMsg, Is.EqualTo(Resources.OciConfigProfileNotFound).IgnoreCase); } } @@ -1608,7 +1453,7 @@ public void ConnectUsing1FAuth() using var conn = new MySqlConnection(connStringBuilder.ConnectionString); conn.Open(); - Assert.AreEqual(ConnectionState.Open, conn.State); + Assert.That(conn.State, Is.EqualTo(ConnectionState.Open)); } [TestCase("user_2f", "password1", "password2", true)] @@ -1641,7 +1486,7 @@ public void ConnectUsing2FAuth(string user, string pwd, string pwd2, bool should else { conn.Open(); - Assert.AreEqual(ConnectionState.Open, conn.State); + Assert.That(conn.State, Is.EqualTo(ConnectionState.Open)); } } @@ -1675,152 +1520,11 @@ public void ConnectUsing3FAuth(string user, string pwd, string pwd2, string pwd3 else { conn.Open(); - Assert.AreEqual(ConnectionState.Open, conn.State); + Assert.That(conn.State, Is.EqualTo(ConnectionState.Open)); } } #endregion - #region FIDO Authentication - /// - /// WL14871 - Support FIDO authentication [classic] - /// - [Test] - [Ignore("This should be executed manually since it depends on libfido2 library")] - [Property("Category", "Security")] - public void FidoAuthentication1F() - { - // Install FIDO plugin - ExecuteSQL("INSTALL PLUGIN authentication_fido SONAME 'authentication_fido.so';", true); - // Create user - // The INITIAL AUTHENTICATION IDENTIFIED clause must be specified to set a random or a static password. - ExecuteSQL("CREATE USER 'user_f1'@'localhost' IDENTIFIED WITH authentication_fido INITIAL AUTHENTICATION IDENTIFIED BY 'bar';", true); - - // Register the authenticator - // $ mysql --user=user_f1 --fido-register-factor=1 - - var connStringBuilder = new MySqlConnectionStringBuilder() - { - UserID = "user_f1", - Server = Settings.Server, - Port = Settings.Port - }; - - using var conn = new MySqlConnection(connStringBuilder.ConnectionString); - conn.FidoActionRequested += Conn_FidoActionRequested; - conn.Open(); - Assert.AreEqual(ConnectionState.Open, conn.State); - } - - [Test] - [Ignore("This should be executed manually since it depends on libfido2 library")] - [Property("Category", "Security")] - public void FidoAuthentication2F() - { - // Install FIDO plugin - ExecuteSQL("INSTALL PLUGIN authentication_fido SONAME 'authentication_fido.so';", true); - // Create user - ExecuteSQL("CREATE USER 'user_f2'@'localhost' IDENTIFIED BY 'bar' AND IDENTIFIED WITH authentication_fido;", true); - - // Register the authenticator - // $ mysql --user=user_f2 --fido-register-factor=2 - - var connStringBuilder = new MySqlConnectionStringBuilder() - { - UserID = "user_f2", - Password = "bar", - Server = Settings.Server, - Port = Settings.Port - }; - - using var conn = new MySqlConnection(connStringBuilder.ConnectionString); - conn.FidoActionRequested += Conn_FidoActionRequested; - conn.Open(); - Assert.AreEqual(ConnectionState.Open, conn.State); - } - - [Test] - [Ignore("This should be executed manually since it depends on libfido2 library")] - [Property("Category", "Security")] - public void FidoAuthentication3F() - { - // Install FIDO plugin - ExecuteSQL("INSTALL PLUGIN authentication_fido SONAME 'authentication_fido.so';", true); - // Create user - ExecuteSQL("CREATE USER 'user_f3'@'localhost' IDENTIFIED BY 'bar' AND IDENTIFIED BY 'baz' AND IDENTIFIED WITH authentication_fido;", true); - - // Register the authenticator - // $ mysql --user=user_f3 --fido-register-factor=3 - - var connStringBuilder = new MySqlConnectionStringBuilder() - { - UserID = "user_f3", - Password = "bar", - Password2 = "baz", - Server = Settings.Server, - Port = Settings.Port - }; - - using var conn = new MySqlConnection(connStringBuilder.ConnectionString); - conn.FidoActionRequested += Conn_FidoActionRequested; - conn.Open(); - Assert.AreEqual(ConnectionState.Open, conn.State); - } - - [Test] - [Ignore("This should be executed manually since it depends on libfido2 library")] - [Property("Category", "Security")] - public void FidoAuthenticationNoUserGestureException() - { - // Install FIDO plugin - ExecuteSQL("INSTALL PLUGIN authentication_fido SONAME 'authentication_fido.so';", true); - // Create user - ExecuteSQL("CREATE USER 'user_f2'@'localhost' IDENTIFIED BY 'bar' AND IDENTIFIED WITH authentication_fido;", true); - - // Register the authenticator - // $ mysql --user=user_f2 --fido-register-factor=2 - - var connStringBuilder = new MySqlConnectionStringBuilder() - { - UserID = "user_f2", - Password = "bar", - Server = Settings.Server, - Port = Settings.Port - }; - - using var conn = new MySqlConnection(connStringBuilder.ConnectionString); - conn.FidoActionRequested += Conn_FidoActionRequested; - Assert.Throws(() => conn.Open()); - } - - [Test] - [Ignore("This should be executed manually since it depends on libfido2 library")] - [Property("Category", "Security")] - public void FidoAuthenticationUnregisteredUserException() - { - // Install FIDO plugin - ExecuteSQL("INSTALL PLUGIN authentication_fido SONAME 'authentication_fido.so';", true); - // Create user - ExecuteSQL("CREATE USER 'user_f2'@'localhost' IDENTIFIED BY 'bar' AND IDENTIFIED WITH authentication_fido;", true); - - var connStringBuilder = new MySqlConnectionStringBuilder() - { - UserID = "user_f2", - Password = "bar", - Server = Settings.Server, - Port = Settings.Port - }; - - using var conn = new MySqlConnection(connStringBuilder.ConnectionString); - conn.FidoActionRequested += Conn_FidoActionRequested; - Assert.Throws(() => conn.Open()); - } - - private static void Conn_FidoActionRequested() - { - Console.WriteLine("Please insert FIDO device and perform gesture action for authentication to complete."); - } - #endregion - #region WebAuthn Authentication /// /// WL15193 - Support WebauthN in fido authentication plugin [Classic] @@ -1848,7 +1552,7 @@ public void WebAuthnAuthenticationPasswordless() using var conn = new MySqlConnection(connStringBuilder.ConnectionString); conn.WebAuthnActionRequested += Conn_WebAuthnActionRequested; conn.Open(); - Assert.AreEqual(ConnectionState.Open, conn.State); + Assert.That(conn.State, Is.EqualTo(ConnectionState.Open)); } [Test] @@ -1874,7 +1578,7 @@ public void WebAuthnAuthentication2F() using var conn = new MySqlConnection(connStringBuilder.ConnectionString); conn.WebAuthnActionRequested += Conn_WebAuthnActionRequested; conn.Open(); - Assert.AreEqual(ConnectionState.Open, conn.State); + Assert.That(conn.State, Is.EqualTo(ConnectionState.Open)); } [Test] @@ -1901,7 +1605,7 @@ public void WebAuthnAuthentication3F() using var conn = new MySqlConnection(connStringBuilder.ConnectionString); conn.WebAuthnActionRequested += Conn_WebAuthnActionRequested; conn.Open(); - Assert.AreEqual(ConnectionState.Open, conn.State); + Assert.That(conn.State, Is.EqualTo(ConnectionState.Open)); } [Test] @@ -1958,6 +1662,101 @@ private static void Conn_WebAuthnActionRequested() } #endregion + #region OpenID Connect client + /// + /// WL16491 - OpenID Connect authentication support + /// + + private static string IdentityToken = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJteXN1YmoiLCJpc3MiOiJodHRw" + + "czovL215aXNzdWVyLmNvbSIsImV4cCI6MjEzNTE5ODEwNX0.kXjtDjcSYhpNP0IgSbQjPuOsd-nBDVulQKgZAq4HkgMPCNINh-EIMbuqvYKkE5a" + + "B6zicm6PHNvxDrS63NjQH7Nh7s29eN50DSK33zQsvdYr8O5eUTL2SrNRqpWgMQ0xlU9Hr4HCw10YmIcwjskANHJxXSgyUCKveeRCR-L-DoNFZDy" + + "UYyd3pu7M1zO-12LjebktMklCQBfiCAcqSNDZDE2s6OkxuoF7VOtK91Wsw17xOZVQDjCZkUDtUrRZs8uxJfbjBonQ7LVQQhg227z8lrUeXewVhx" + + "NKPrf-YUrdMmEfMBjwD9v1AU5onKlkHuW0DtvZmt707Kyd-ve-HgQj1xX-W6BfEPo-28FCcDvLGlXZ8cyB1wPODogKhtc7bq3TPuTkDkegO7AG1" + + "NaYXcbSNEpQQ5zdfbzS_spV2zzJawPK1awNUeT_UA7t4swY4JcrOFkPkXUTqWT9QWvXuxCE9gZUAWIa3FHdeWjzLTZEKB8-ZhPYmyPphkzds9sm" + + "TJi4gawmNtb8WvEpXZUUXIZzIRcunXEdIayr18E9XfFCOCQo8JQOSxY3HQGgzqYk4S0AMeR0BiBIKe9VySsykdAuhLvL51AZDXvKQ9fQDu4lAtk" + + "cXrKCZwA_2RXjLzOM7dkySQu66t-GIIZXxqCdcWf1"; + + private static string OpenId_server_config = "JSON://{\"myissuer\":\"{\\\\\"kty\\\\\": \\\\\"RSA\\\\\",\\\\\"n\\\\\":" + + " \\\\\"zpnGGekMZHmWtpcsBmJdUODRApNHU7_bijsn4E0MWhthfkyK1LilQp5-aemc6Id5yL978CMfn10LXsjGchZKIGAgk52nW7kI3Zt973npwzB2M" + + "YJ4FFqsHQSAM9kvd3iUz2aQG-nVVl9Ia8Yimcssav8sEjOlEqZ1n_JLXavWwI9z-_lkTcZBgsM9jke_tWa1yLjYce009yBmf-sJMDrXZ-3TALrNUDzGt" + + "9mQwDxjE0UGnQIQE7vXJ2O5-k1qXMKPTew32zvRD7Bxcsxe71LRaerEPmgnricajk5LJVsbonavecrvHDCGDvOgzueZrr15kUhXZxZbXmtx6dUYqJ-0A" + + "qbZ0Km3elrYnDFysJR5pJsjmDnH2wzHDQ_gZeC_Up_4d78pzLyXHhiOmyDTLyogmeN7xYunvgzu-B4tepSC9XCSu-WZDmJASFaxRzOJhQBKLX2Ly0XmS" + + "LMXEP-vOupwvEi-SpBOVw2WzxT9dJrK-vI6cBGewB-zHrwsLFBvt1OZVNV5YGpQ1kqFfFoWrtkINFwJc39UnboDqalhvim9K-ITRe6xYk_Dlf9f-BA5b" + + "sry8n3GBBXEjkirM_QFb_DcbBXj1OJX_B0BZAK0bupYgOpxDG_su1a8N3CqOOWJguVzuydl7uW_uicDkCua3cVWd-n8QtXDaM6qZLRTB7q0_ek\\\\\"" + + ",\\\\\"e\\\\\": \\\\\"AQAB\\\\\",\\\\\"alg\\\\\": \\\\\"RS256\\\\\",\\\\\"use\\\\\": \\\\\"sig\\\\\",\\\\\"name" + + "\\\\\": \\\\\"https://myissuer.com\\\\\"}\"}"; + + [Test] + [Ignore("This test requires a server version 9.1.0 or higher configured to use OpenID Connect authentication")] + public void OpenIdConnectClient() + { + Assume.That(Version >= new Version("9.1.0"), "This test is for MySQL 9.1.0 or higher"); + Assume.That(Check_Plugin_Enabled("authentication_openid_connect"), "authentication_openid_connect plugin must be enabled on the server to run this test"); + + ExecuteSQL("SET GLOBAL authentication_openid_connect_configuration = '" + OpenId_server_config + "'", true); + + ExecuteSQL("CREATE USER IF NOT EXISTS 'openid-testuser'@'%' IDENTIFIED WITH 'authentication_openid_connect' AS '{\"identity_provider\" : \"myissuer\", \"user\" : \"mysubj\"}'", true); + + var connStringBuilder1 = new MySqlConnectionStringBuilder() + { + UserID = "openid-testuser", + Server = Settings.Server, + Port = Settings.Port, + OpenIdIdentityToken = IdentityToken + }; + using (MySqlConnection conn = new MySqlConnection(connStringBuilder1.ConnectionString)) + { + conn.Open(); + Assert.That(conn.connectionState, Is.EqualTo(ConnectionState.Open)); + } + + var connStringBuilder2 = new MySqlConnectionStringBuilder() + { + UserID = "openid-testuser", + Server = Settings.Server, + Port = Settings.Port, + OpenIdIdentityToken = IdentityToken, + DefaultAuthenticationPlugin = "authentication_openid_connect_client" + }; + using (MySqlConnection conn = new MySqlConnection(connStringBuilder2.ConnectionString)) + { + conn.Open(); + Assert.That(conn.connectionState, Is.EqualTo(ConnectionState.Open)); + } + + var connStringBuilder3 = new MySqlConnectionStringBuilder() + { + UserID = "openid-testuser", + Server = Settings.Server, + Port = Settings.Port, + OpenIdIdentityToken = "", + DefaultAuthenticationPlugin = "authentication_openid_connect_client" + }; + using (MySqlConnection conn = new MySqlConnection(connStringBuilder3.ConnectionString)) + { + Assert.Throws(() => conn.Open()); + } + + char[] reversedIdentityToken = IdentityToken.ToCharArray(); + Array.Reverse(reversedIdentityToken); + + var connStringBuilder4 = new MySqlConnectionStringBuilder() + { + UserID = "openid-testuser", + Server = Settings.Server, + Port = Settings.Port, + OpenIdIdentityToken = new string(reversedIdentityToken), + DefaultAuthenticationPlugin = "authentication_openid_connect_client" + }; + using (MySqlConnection conn = new MySqlConnection(connStringBuilder4.ConnectionString)) + { + Assert.Throws(() => conn.Open()); + } + + ExecuteSQL("DROP USER IF EXISTS 'openid-testuser'@'%'", true); + } + #endregion + [Test, Description("Test User Authentication Fails with classic protocol")] public void AuthPlainAndMySql41() { @@ -1974,12 +1773,9 @@ public void AuthPlainAndMySql41() "with secure connections(classic connection).Server started with mysql native password plugin")] public void Sha256AndNativeWithCertificates() { - if (Version <= new Version("8.0.4")) Assert.Ignore("This test is for MySql 8.0.4 or higher"); - - using (var rdr = ExecuteReader("SELECT * FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME = 'caching_sha2_password'")) - { - if (!rdr.HasRows) Assert.Ignore("This test needs plugin caching_sha2_password"); - } + Assume.That(Version >= new Version("8.0.4"), "This test is for MySql 8.0.4 or higher"); + Assume.That(Check_Plugin_Enabled("mysql_native_password"), "mysql_native_password plugin must be enabled on the server to run this test"); + Assume.That(Check_Plugin_Enabled("caching_sha2_password"), "This test needs plugin caching_sha2_password"); // Test connection for VALID user in LDAP server with different SSLMode values, expected result pass string assemblyPath = Assembly.GetExecutingAssembly().Location.Replace(String.Format("{0}.dll", @@ -2241,4 +2037,4 @@ public void Sha256AndNativeWithCertificates() } } } -} \ No newline at end of file +} diff --git a/MySQL.Data/tests/MySql.Data.Tests/BlobTests.cs b/MySQL.Data/tests/MySql.Data.Tests/BlobTests.cs index a18f82a1a..31458255e 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/BlobTests.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/BlobTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2020 Oracle and/or its affiliates. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -29,6 +29,7 @@ using System; using System.Data; using NUnit.Framework; +using NUnit.Framework.Legacy; namespace MySql.Data.MySqlClient.Tests { @@ -48,11 +49,11 @@ public void InsertNullBinary() cmd.CommandText = "SELECT * FROM Test"; using (MySqlDataReader reader = cmd.ExecuteReader()) { - Assert.True(reader.HasRows == true, "Checking HasRows"); + Assert.That(reader.HasRows, Is.EqualTo(true), "Checking HasRows"); reader.Read(); var value = reader.GetValue(1) as string; - Assert.True(value == null); + Assert.That(value, Is.EqualTo(null)); } } @@ -75,23 +76,23 @@ public void InsertBinary() cmd.Parameters[1].Value = dataIn2; rows += cmd.ExecuteNonQuery(); - Assert.True(rows == 2, "Checking insert rowcount"); + Assert.That(rows == 2, "Checking insert rowcount"); cmd.CommandText = "SELECT * FROM InsertBinary"; using (MySqlDataReader reader = cmd.ExecuteReader()) { - Assert.True(reader.HasRows == true, "Checking HasRows"); + Assert.That(reader.HasRows, Is.EqualTo(true), "Checking HasRows"); reader.Read(); byte[] dataOut = new byte[lenIn]; long lenOut = reader.GetBytes(1, 0, dataOut, 0, lenIn); - Assert.True(lenIn == lenOut, "Checking length of binary data (row 1)"); + Assert.That(lenIn, Is.EqualTo(lenOut), "Checking length of binary data (row 1)"); // now see if the buffer is intact for (int x = 0; x < dataIn.Length; x++) - Assert.True(dataIn[x] == dataOut[x], "Checking first binary array at " + x); + Assert.That(dataIn[x], Is.EqualTo(dataOut[x]), "Checking first binary array at " + x); // now we test chunking int pos = 0; @@ -105,15 +106,15 @@ public void InsertBinary() } // now see if the buffer is intact for (int x = 0; x < dataIn.Length; x++) - Assert.True(dataIn[x] == dataOut[x], "Checking first binary array at " + x); + Assert.That(dataIn[x], Is.EqualTo(dataOut[x]), "Checking first binary array at " + x); reader.Read(); lenOut = reader.GetBytes(1, 0, dataOut, 0, lenIn); - Assert.True(lenIn == lenOut, "Checking length of binary data (row 2)"); + Assert.That(lenIn == lenOut, "Checking length of binary data (row 2)"); // now see if the buffer is intact for (int x = 0; x < dataIn2.Length; x++) - Assert.True(dataIn2[x] == dataOut[x], "Checking second binary array at " + x); + Assert.That(dataIn2[x], Is.EqualTo(dataOut[x]), "Checking second binary array at " + x); } } @@ -166,7 +167,7 @@ private void InternalGetChars(bool prepare) } // now see if the buffer is intact for (int x = 0; x < data.Length; x++) - Assert.True(data[x] == dataOut[x], "Checking first text array at " + x); + Assert.That(data[x], Is.EqualTo(dataOut[x]), "Checking first text array at " + x); } } @@ -197,7 +198,7 @@ private void InternalInsertText(bool prepare) cmd.Parameters.Add(new MySqlParameter("?b1", "This is my blob data")); if (prepare) cmd.Prepare(); int rows = cmd.ExecuteNonQuery(); - Assert.True(rows == 1, "Checking insert rowcount"); + Assert.That(rows, Is.EqualTo(1), "Checking insert rowcount"); cmd.CommandText = "INSERT INTO InsertText VALUES(2, ?b1, ?t1)"; cmd.Parameters.Clear(); @@ -207,24 +208,22 @@ private void InternalInsertText(bool prepare) cmd.Parameters.AddWithValue("?b1", str); rows = cmd.ExecuteNonQuery(); - Assert.True(rows == 1, "Checking insert rowcount"); + Assert.That(rows, Is.EqualTo(1), "Checking insert rowcount"); cmd.CommandText = "SELECT * FROM InsertText"; if (prepare) cmd.Prepare(); using (MySqlDataReader reader = cmd.ExecuteReader()) { - Assert.True(reader.HasRows, "Checking HasRows"); + Assert.That(reader.HasRows, "Checking HasRows"); - Assert.True(reader.Read()); + Assert.That(reader.Read()); - Assert.AreEqual("This is my blob data", reader.GetString(1)); string s = reader.GetString(2); - Assert.True(s.Length == 1024, "Checking length returned "); - Assert.True(s.Substring(0, 9) == "ABCDEFGHI", "Checking first few chars of string"); + Assert.That(s.Length, Is.EqualTo(1024), "Checking length returned "); + Assert.That(s.Substring(0, 9), Is.EqualTo("ABCDEFGHI"), "Checking first few chars of string"); - Assert.True(reader.Read()); - Assert.AreEqual(DBNull.Value, reader.GetValue(2)); - Assert.AreEqual("This is my text value", reader.GetString(1)); + Assert.That(reader.Read()); + Assert.That(reader.GetValue(2), Is.EqualTo(DBNull.Value)); } } @@ -241,8 +240,8 @@ public void GetCharsOnLongTextColumn() { reader.Read(); reader.GetChars(1, 0, buf, 0, 2); - Assert.AreEqual('T', buf[0]); - Assert.AreEqual('e', buf[1]); + Assert.That(buf[0], Is.EqualTo('T')); + Assert.That(buf[1], Is.EqualTo('e')); } } @@ -272,13 +271,13 @@ public void MediumIntBlobSize() { reader.Read(); uint actualsize = reader.GetUInt32(1); - Assert.AreEqual((uint)image.Length, actualsize); + Assert.That(actualsize, Is.EqualTo((uint)image.Length)); uint size = reader.GetUInt32(0); byte[] outImage = new byte[size]; long len = reader.GetBytes(reader.GetOrdinal("image"), 0, outImage, 0, (int)size); - Assert.AreEqual((uint)image.Length, size); - Assert.AreEqual((uint)image.Length, len); + Assert.That(size, Is.EqualTo((uint)image.Length)); + Assert.That(len, Is.EqualTo((uint)image.Length)); } } @@ -298,7 +297,7 @@ public void BlobBiggerThanMaxPacket() cmd.Parameters.AddWithValue("?image", image); Exception ex = Assert.Throws(() => cmd.ExecuteNonQuery()); - Assert.AreEqual(ex.Message, "Packets larger than max_allowed_packet are not allowed."); + Assert.That(ex.Message, Is.EqualTo(Resources.QueryTooLarge)); } } @@ -316,7 +315,7 @@ public void UpdateDataSet() MySqlCommandBuilder cb = new MySqlCommandBuilder(da); string s = (string)dt.Rows[0][2]; - Assert.AreEqual("Text field", s); + Assert.That(s, Is.EqualTo("Text field")); byte[] inBuf = Utils.CreateBlob(512); dt.Rows[0].BeginEdit(); @@ -331,10 +330,10 @@ public void UpdateDataSet() cb.Dispose(); byte[] outBuf = (byte[])dt.Rows[0]["blob1"]; - Assert.True(inBuf.Length == outBuf.Length, "checking length of updated buffer"); + Assert.That(inBuf.Length, Is.EqualTo(outBuf.Length), "checking length of updated buffer"); for (int y = 0; y < inBuf.Length; y++) - Assert.True(inBuf[y] == outBuf[y], "checking array data"); + Assert.That(inBuf[y] == outBuf[y], Is.True, "checking array data"); } } } diff --git a/MySQL.Data/tests/MySql.Data.Tests/BlobTestsCompressed.cs b/MySQL.Data/tests/MySql.Data.Tests/BlobTestsCompressed.cs index 4e9a8e7d5..b27875d3e 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/BlobTestsCompressed.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/BlobTestsCompressed.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -27,6 +27,7 @@ // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA using NUnit.Framework; +using NUnit.Framework.Legacy; namespace MySql.Data.MySqlClient.Tests { @@ -38,4 +39,4 @@ internal override void AdjustConnectionSettings(MySqlConnectionStringBuilder set settings.UseCompression = true; } } -} \ No newline at end of file +} diff --git a/MySQL.Data/tests/MySql.Data.Tests/CharSetTests.cs b/MySQL.Data/tests/MySql.Data.Tests/CharSetTests.cs index ecf9715e9..90c0db97c 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/CharSetTests.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/CharSetTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2022, Oracle and/or its affiliates. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -28,6 +28,7 @@ using MySql.Data.Common; using NUnit.Framework; +using NUnit.Framework.Legacy; using System; using System.Data; @@ -63,9 +64,9 @@ public void VarBinary() MySqlCommand cmd = new MySqlCommand("SELECT * FROM Test", Connection); using (MySqlDataReader reader = cmd.ExecuteReader()) { - Assert.True(reader.Read()); + Assert.That(reader.Read()); object o = reader.GetValue(1); - Assert.True(o is string); + Assert.That(o is string); } } @@ -81,7 +82,7 @@ public void Latin1Connection() MySqlCommand cmd = new MySqlCommand("SELECT id FROM Test WHERE name LIKE 'Test'", conn); object id = cmd.ExecuteScalar(); - Assert.AreEqual(1, id); + Assert.That(id, Is.EqualTo(1)); } } @@ -102,7 +103,7 @@ public void FunctionReturnsStringWithCharSet() using (MySqlDataReader reader = cmd.ExecuteReader()) { reader.Read(); - Assert.AreEqual("Trädgårdsvägen1", reader.GetString(0)); + Assert.That(reader.GetString(0), Is.EqualTo("Trädgårdsvägen1")); } } } @@ -125,7 +126,7 @@ public void Encoding() using (MySqlDataReader reader = cmd.ExecuteReader()) { reader.Read(); - Assert.AreEqual("äâáàç", reader.GetString(0)); + Assert.That(reader.GetString(0), Is.EqualTo("äâáàç")); } } } @@ -144,7 +145,7 @@ public void RespectBinaryFlags() "SELECT CONCAT('Trädgårdsvägen', 1)", c); DataTable dt = new DataTable(); da.Fill(dt); - Assert.True(dt.Rows[0][0] is byte[]); + Assert.That(dt.Rows[0][0] is byte[]); } connStr = Connection.ConnectionString + ";respect binary flags=false"; using (MySqlConnection c = new MySqlConnection(connStr)) @@ -155,8 +156,8 @@ public void RespectBinaryFlags() "SELECT CONCAT('Trädgårdsvägen', 1)", c); DataTable dt = new DataTable(); da.Fill(dt); - Assert.True(dt.Rows[0][0] is string); - Assert.AreEqual("Trädgårdsvägen1", dt.Rows[0][0]); + Assert.That(dt.Rows[0][0] is string); + Assert.That(dt.Rows[0][0], Is.EqualTo("Trädgårdsvägen1")); } } @@ -182,7 +183,7 @@ public void RussianErrorMessagesShowCorrectly() } catch (MySqlException e) { - Assert.AreEqual(expected, e.Message); + Assert.That(e.Message, Is.EqualTo(expected)); } } @@ -223,10 +224,10 @@ public void UsingUtf16() { for (int i = 0; i < reader.FieldCount; i++) { - Assert.True(j == reader.GetInt32(0)); - Assert.True(firstNames[j] == reader.GetString(1)); - Assert.True(lastNames[j] == reader.GetString(2)); - Assert.True(lastUpdates[j] == reader.GetDateTime(3)); + Assert.That(j, Is.EqualTo(reader.GetInt32(0))); + Assert.That(firstNames[j], Is.EqualTo(reader.GetString(1))); + Assert.That(lastNames[j], Is.EqualTo(reader.GetString(2))); + Assert.That(lastUpdates[j], Is.EqualTo(reader.GetDateTime(3))); } j++; } @@ -268,10 +269,10 @@ public void UsingUtf32() { for (int i = 0; i < reader.FieldCount; i++) { - Assert.True(j == reader.GetInt32(0)); - Assert.True(firstNames[j] == reader.GetString(1)); - Assert.True(lastNames[j] == reader.GetString(2)); - Assert.True(lastUpdates[j] == reader.GetDateTime(3)); + Assert.That(j, Is.EqualTo(reader.GetInt32(0))); + Assert.That(firstNames[j], Is.EqualTo(reader.GetString(1))); + Assert.That(lastNames[j], Is.EqualTo(reader.GetString(2))); + Assert.That(lastUpdates[j], Is.EqualTo(reader.GetDateTime(3))); } j++; } @@ -305,9 +306,9 @@ public void CanInsertChineseCharacterSetGB18030() while (reader.Read()) { if (reader.GetUInt32(0) == 1) - Assert.AreEqual("㭋玤䂜蚌", reader.GetString(1)); + Assert.That(reader.GetString(1), Is.EqualTo("㭋玤䂜蚌")); if (reader.GetUInt32(0) == 2) - Assert.AreEqual("念奴娇·赤壁怀古 ·苏东坡", reader.GetString(1)); + Assert.That(reader.GetString(1), Is.EqualTo("念奴娇·赤壁怀古 ·苏东坡")); } } } @@ -342,7 +343,7 @@ public void CanCreateDbUsingChineseCharacterSetGB18030() using (MySqlConnection conn = new MySqlConnection(rootSb.ConnectionString)) { conn.Open(); - Assert.AreEqual(database, conn.Database); + Assert.That(conn.Database, Is.EqualTo(database)); } } finally @@ -365,7 +366,7 @@ public void UTF16LETest() { while (reader.Read()) { - Assert.AreEqual("瑵ㅦ氶⁥整瑳", reader[0].ToString()); + Assert.That(reader[0].ToString(), Is.EqualTo("瑵ㅦ氶⁥整瑳")); } } } @@ -381,7 +382,7 @@ public void CP932() connection.Open(); MySqlCommand cmd = new MySqlCommand("SELECT '涯割晦叶角'", connection); string s = (string)cmd.ExecuteScalar(); - Assert.AreEqual("涯割晦叶角", s); + Assert.That(s, Is.EqualTo("涯割晦叶角")); } } @@ -427,7 +428,7 @@ public void ExtendedCharsetOnConnection() using (MySqlConnection conn = new MySqlConnection(sb.ToString())) { conn.Open(); - Assert.AreEqual(database, conn.Database); + Assert.That(conn.Database, Is.EqualTo(database)); } } finally @@ -452,9 +453,9 @@ public void DefaultCharSet() reader.Read(); if (Connection.driver.Version.isAtLeast(8, 0, 1)) - Assert.AreEqual("utf8mb4", reader.GetString("Value")); + Assert.That(reader.GetString("Value"), Is.EqualTo("utf8mb4")); else - Assert.AreEqual("latin1", reader.GetString("Value")); + Assert.That(reader.GetString("Value"), Is.EqualTo("latin1")); } } @@ -469,21 +470,21 @@ public void CharacterVariablesByDefault() MySqlCommand cmd = rootConnection.CreateCommand(); cmd.CommandText = "SELECT @@character_set_server"; string characterSet = cmd.ExecuteScalar().ToString(); - Assert.False(string.IsNullOrWhiteSpace(characterSet)); + Assert.That(string.IsNullOrWhiteSpace(characterSet), Is.False); cmd.CommandText = "SHOW VARIABLES LIKE 'character_set_c%'"; using (MySqlDataReader dr = cmd.ExecuteReader()) { - Assert.True(dr.HasRows); + Assert.That(dr.HasRows); while (dr.Read()) { switch (dr.GetString(0).ToLowerInvariant()) { case "character_set_client": - Assert.AreEqual(characterSet, dr.GetString(1)); + Assert.That(dr.GetString(1), Is.EqualTo(characterSet)); break; case "character_set_connection": - Assert.AreEqual(characterSet, dr.GetString(1)); + Assert.That(dr.GetString(1), Is.EqualTo(characterSet)); break; default: throw new InvalidOperationException(string.Format("Variable '{0}' not expected.", dr.GetString(0))); @@ -492,7 +493,7 @@ public void CharacterVariablesByDefault() } cmd.CommandText = "SELECT @@character_set_results"; - Assert.AreEqual(DBNull.Value, cmd.ExecuteScalar()); + Assert.That(cmd.ExecuteScalar(), Is.EqualTo(DBNull.Value)); } } @@ -502,8 +503,7 @@ public void CharacterVariablesByDefault() [Test] public void DatabaseCaseSentitive() { - if (Version >= new Version(8, 0, 0) || !Platform.IsWindows()) Assert.Ignore("This test is only for Windows OS and MySql higher than 8.0."); - + Assume.That(Version >= new Version(8, 0, 0) && Platform.IsWindows(), "This test is only for Windows OS and MySql higher than 8.0."); ExecuteSQL("DROP PROCEDURE IF EXISTS spTest"); ExecuteSQL(@"CREATE PROCEDURE spTest () BEGIN SELECT ""test""; END"); @@ -515,7 +515,7 @@ public void DatabaseCaseSentitive() { cmd.CommandType = CommandType.StoredProcedure; var result = cmd.ExecuteNonQuery(); - Assert.AreEqual(0, result); + Assert.That(result, Is.EqualTo(0)); } } } @@ -527,7 +527,7 @@ public void DatabaseCaseSentitive() [Test] public void PoundSymbolInJsonColumn() { - if (Version < new Version(5, 7, 0)) Assert.Ignore("JSON data type not available in MySQL Server v5.6"); + Assume.That(Version >= new Version(5, 7, 0), "JSON data type not available in MySQL Server v5.6"); ExecuteSQL("CREATE TABLE `PoundTable`(`TextColumn` VARCHAR(20) NULL, `JsonColumn` JSON);"); ExecuteSQL("INSERT INTO `PoundTable`(`TextColumn`, `JsonColumn`) VALUES('£', JSON_OBJECT('Value', '£'));"); @@ -537,8 +537,8 @@ public void PoundSymbolInJsonColumn() { while (reader.Read()) { - StringAssert.AreEqualIgnoringCase("£", reader[0].ToString()); - StringAssert.AreEqualIgnoringCase("{\"Value\": \"£\"}", reader[1].ToString()); + Assert.That(reader[0].ToString(), Is.EqualTo("£").IgnoreCase); + Assert.That(reader[1].ToString(), Is.EqualTo("{\"Value\": \"£\"}").IgnoreCase); } } } @@ -560,26 +560,26 @@ public void CharacterVariablesByDefaultServerDefault() var cmd = rootConnection.CreateCommand(); cmd.CommandText = "SELECT @@character_set_server"; var characterSet = cmd.ExecuteScalar().ToString(); - Assert.AreEqual(false, string.IsNullOrWhiteSpace(characterSet)); + Assert.That(string.IsNullOrWhiteSpace(characterSet), Is.EqualTo(false)); cmd.CommandText = "SHOW VARIABLES LIKE 'character_set_c%'"; using (var dr = cmd.ExecuteReader()) { - Assert.AreEqual(true, dr.HasRows); + Assert.That(dr.HasRows, Is.EqualTo(true)); while (dr.Read()) switch (dr.GetString(0).ToLowerInvariant()) { case "character_set_client": - Assert.AreEqual(characterSet, dr.GetString(1)); + Assert.That(dr.GetString(1), Is.EqualTo(characterSet)); break; case "character_set_connection": - Assert.AreEqual(characterSet, dr.GetString(1)); + Assert.That(dr.GetString(1), Is.EqualTo(characterSet)); break; } } cmd.CommandText = "SELECT @@character_set_results"; - Assert.AreEqual(DBNull.Value, cmd.ExecuteScalar()); + Assert.That(cmd.ExecuteScalar(), Is.EqualTo(DBNull.Value)); } } @@ -600,20 +600,20 @@ public void CharacterVariablesByAssignedServerDefault() var cmd = rootConnection.CreateCommand(); cmd.CommandText = "SELECT @@character_set_server"; var characterSet = cmd.ExecuteScalar().ToString(); - Assert.AreEqual(false, string.IsNullOrWhiteSpace(characterSet)); + Assert.That(string.IsNullOrWhiteSpace(characterSet), Is.EqualTo(false)); cmd.CommandText = "SHOW VARIABLES LIKE 'character_set_c%'"; using (var dr = cmd.ExecuteReader()) { - Assert.AreEqual(true, dr.HasRows); + Assert.That(dr.HasRows, Is.EqualTo(true)); while (dr.Read()) switch (dr.GetString(0).ToLowerInvariant()) { case "character_set_client": - StringAssert.StartsWith(expectedCharSet, dr.GetString(1)); + Assert.That(dr.GetString(1), Does.StartWith(expectedCharSet)); break; case "character_set_connection": - StringAssert.StartsWith(expectedCharSet, dr.GetString(1)); + Assert.That(dr.GetString(1), Does.StartWith(expectedCharSet)); break; default: Assert.Fail($"Variable {dr.GetString(0)} not expected."); break; @@ -621,11 +621,11 @@ public void CharacterVariablesByAssignedServerDefault() } cmd.CommandText = "SELECT @@character_set_results"; - Assert.AreEqual(DBNull.Value, cmd.ExecuteScalar()); + Assert.That(cmd.ExecuteScalar(), Is.EqualTo(DBNull.Value)); } } #endregion WL14389 } -} \ No newline at end of file +} diff --git a/MySQL.Data/tests/MySql.Data.Tests/CharSetUTF8Tests.cs b/MySQL.Data/tests/MySql.Data.Tests/CharSetUTF8Tests.cs index 695a469b6..2e34ef818 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/CharSetUTF8Tests.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/CharSetUTF8Tests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2022, Oracle and/or its affiliates. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -28,6 +28,7 @@ using MySql.Data.Common; using NUnit.Framework; +using NUnit.Framework.Legacy; using System; using System.Data; using System.Text; @@ -66,7 +67,7 @@ public void UTF8BlogsTruncating() { reader.Read(); string s = reader.GetString(0); - Assert.AreEqual(szParam, s); + Assert.That(s, Is.EqualTo(szParam)); } } @@ -77,7 +78,7 @@ public void UTF8BlogsTruncating() public void GetSchemaOnUTF8() { #if !NETFRAMEWORK - if (!Platform.IsWindows()) Assert.Ignore(); + Assume.That(Platform.IsWindows()); #endif ExecuteSQL("CREATE TABLE Test(name VARCHAR(40) NOT NULL, name2 VARCHAR(20)) " + "CHARACTER SET utf8"); @@ -87,8 +88,8 @@ public void GetSchemaOnUTF8() using (MySqlDataReader reader = cmd.ExecuteReader()) { DataTable dt = reader.GetSchemaTable(); - Assert.AreEqual(40, dt.Rows[0]["ColumnSize"]); - Assert.AreEqual(20, dt.Rows[1]["ColumnSize"]); + Assert.That(dt.Rows[0]["ColumnSize"], Is.EqualTo(40)); + Assert.That(dt.Rows[1]["ColumnSize"], Is.EqualTo(20)); } } @@ -102,7 +103,7 @@ public void NonLatin1Exception() MySqlCommand cmd = new MySqlCommand("select `Numéro` from Test", Connection); var exception = Assert.Throws(() => cmd.ExecuteScalar()); - Assert.AreEqual("Unknown column 'Numéro' in 'field list'", exception.Message); + Assert.That(exception.Message, Is.EqualTo("Unknown column 'Numéro' in 'field list'")); } /// @@ -120,8 +121,8 @@ public void GetCharLengthInUTF8() DataSet ds = new DataSet(); ad.Fill(ds); ad.FillSchema(ds, SchemaType.Mapped); - Assert.AreEqual(1, ds.Tables[0].Columns["name"].MaxLength); - Assert.AreEqual(20, ds.Tables[0].Columns["longname"].MaxLength); + Assert.That(ds.Tables[0].Columns["name"].MaxLength, Is.EqualTo(1)); + Assert.That(ds.Tables[0].Columns["longname"].MaxLength, Is.EqualTo(20)); } [Test] @@ -155,10 +156,10 @@ public void BlobAsUtf8() da.Fill(dt); foreach (DataColumn col in dt.Columns) { - Assert.AreEqual(typeof(string), col.DataType); + Assert.That(col.DataType, Is.EqualTo(typeof(string))); string s = (string)dt.Rows[0][0]; byte[] b = utf8.GetBytes(s); - Assert.AreEqual(utf8_string, dt.Rows[0][col.Ordinal].ToString()); + Assert.That(dt.Rows[0][col.Ordinal].ToString(), Is.EqualTo(utf8_string)); } } @@ -173,11 +174,11 @@ public void BlobAsUtf8() foreach (DataColumn col in dt.Columns) { if (col.ColumnName.StartsWith("exclude", StringComparison.OrdinalIgnoreCase)) - Assert.AreEqual(typeof(byte[]), col.DataType); + Assert.That(col.DataType, Is.EqualTo(typeof(byte[]))); else { - Assert.AreEqual(typeof(string), col.DataType); - Assert.AreEqual(utf8_string, dt.Rows[0][col.Ordinal].ToString()); + Assert.That(col.DataType, Is.EqualTo(typeof(string))); + Assert.That(dt.Rows[0][col.Ordinal].ToString(), Is.EqualTo(utf8_string)); } } } @@ -194,11 +195,11 @@ public void BlobAsUtf8() { if (col.ColumnName.StartsWith("include", StringComparison.OrdinalIgnoreCase)) { - Assert.AreEqual(typeof(string), col.DataType); - Assert.AreEqual(utf8_string, dt.Rows[0][col.Ordinal].ToString()); + Assert.That(col.DataType, Is.EqualTo(typeof(string))); + Assert.That(dt.Rows[0][col.Ordinal].ToString(), Is.EqualTo(utf8_string)); } else - Assert.AreEqual(typeof(byte[]), col.DataType); + Assert.That(col.DataType, Is.EqualTo(typeof(byte[]))); } } } @@ -219,13 +220,13 @@ public void UTF8AsColumnNames() DataTable dt = new DataTable(); da.Fill(dt); - Assert.AreEqual("Numéro", dt.Columns[0].ColumnName); + Assert.That(dt.Columns[0].ColumnName, Is.EqualTo("Numéro")); MySqlCommand cmd = new MySqlCommand("SELECT NOW() AS 'Numéro'", c); using (MySqlDataReader reader = cmd.ExecuteReader()) { int ord = reader.GetOrdinal("Numéro"); - Assert.AreEqual(0, ord); + Assert.That(ord, Is.EqualTo(0)); } } } @@ -241,7 +242,7 @@ public void Unicode() { reader.Read(); string s1 = reader.GetString(0); - Assert.AreEqual("困巫忘否役", s1); + Assert.That(s1, Is.EqualTo("困巫忘否役")); } } @@ -278,21 +279,21 @@ public void UTF8() using (MySqlDataReader reader = cmd.ExecuteReader()) { reader.Read(); - Assert.AreEqual("ЁЄЉҖҚ", reader.GetString(1)); + Assert.That(reader.GetString(1), Is.EqualTo("ЁЄЉҖҚ")); reader.Read(); - Assert.AreEqual("兣冘凥凷冋", reader.GetString(1)); + Assert.That(reader.GetString(1), Is.EqualTo("兣冘凥凷冋")); reader.Read(); - Assert.AreEqual("困巫忘否役", reader.GetString(1)); + Assert.That(reader.GetString(1), Is.EqualTo("困巫忘否役")); reader.Read(); - Assert.AreEqual("涯割晦叶角", reader.GetString(1)); + Assert.That(reader.GetString(1), Is.EqualTo("涯割晦叶角")); reader.Read(); - Assert.AreEqual("ברחפע", reader.GetString(1)); + Assert.That(reader.GetString(1), Is.EqualTo("ברחפע")); reader.Read(); - Assert.AreEqual("ψόβΩΞ", reader.GetString(1)); + Assert.That(reader.GetString(1), Is.EqualTo("ψόβΩΞ")); reader.Read(); - Assert.AreEqual("þðüçöÝÞÐÜÇÖ", reader.GetString(1)); + Assert.That(reader.GetString(1), Is.EqualTo("þðüçöÝÞÐÜÇÖ")); reader.Read(); - Assert.AreEqual("ฅๆษ", reader.GetString(1)); + Assert.That(reader.GetString(1), Is.EqualTo("ฅๆษ")); } } @@ -333,21 +334,21 @@ public void UTF8PreparedAndUsingParameters() using (MySqlDataReader reader = cmd.ExecuteReader()) { reader.Read(); - Assert.AreEqual("ЁЄЉҖҚ", reader.GetString(0)); + Assert.That(reader.GetString(0), Is.EqualTo("ЁЄЉҖҚ")); reader.Read(); - Assert.AreEqual("兣冘凥凷冋", reader.GetString(0)); + Assert.That(reader.GetString(0), Is.EqualTo("兣冘凥凷冋")); reader.Read(); - Assert.AreEqual("困巫忘否役", reader.GetString(0)); + Assert.That(reader.GetString(0), Is.EqualTo("困巫忘否役")); reader.Read(); - Assert.AreEqual("涯割晦叶角", reader.GetString(0)); + Assert.That(reader.GetString(0), Is.EqualTo("涯割晦叶角")); reader.Read(); - Assert.AreEqual("ברחפע", reader.GetString(0)); + Assert.That(reader.GetString(0), Is.EqualTo("ברחפע")); reader.Read(); - Assert.AreEqual("ψόβΩΞ", reader.GetString(0)); + Assert.That(reader.GetString(0), Is.EqualTo("ψόβΩΞ")); reader.Read(); - Assert.AreEqual("þðüçöÝÞÐÜÇÖ", reader.GetString(0)); + Assert.That(reader.GetString(0), Is.EqualTo("þðüçöÝÞÐÜÇÖ")); reader.Read(); - Assert.AreEqual("ฅๆษ", reader.GetString(0)); + Assert.That(reader.GetString(0), Is.EqualTo("ฅๆษ")); } } @@ -361,8 +362,8 @@ public void Chinese() using (MySqlDataReader reader = ExecuteReader("SELECT * FROM Test")) { reader.Read(); - Assert.AreEqual("困巫忘否役", reader.GetString(1)); - Assert.AreEqual("涝搞谷侪魍", reader.GetString(2)); + Assert.That(reader.GetString(1), Is.EqualTo("困巫忘否役")); + Assert.That(reader.GetString(2), Is.EqualTo("涝搞谷侪魍")); } } @@ -378,7 +379,7 @@ public void Russian() using (MySqlDataReader reader = cmd.ExecuteReader()) { reader.Read(); - Assert.AreEqual("щьеи", reader.GetString(1)); + Assert.That(reader.GetString(1), Is.EqualTo("щьеи")); } } @@ -399,7 +400,7 @@ public void UTF8Parameters() cmd.Parameters.Add("?parameter", MySqlDbType.VarString); cmd.Parameters[0].Value = "šđč枊ĐČĆŽ"; object o = cmd.ExecuteScalar(); - Assert.AreEqual(1, o); + Assert.That(o, Is.EqualTo(1)); } [Test] @@ -414,7 +415,7 @@ public void Turkish() using (MySqlDataReader reader = cmd.ExecuteReader()) { reader.Read(); - Assert.AreEqual("ĞËÇÄŞ", reader.GetString(1)); + Assert.That(reader.GetString(1), Is.EqualTo("ĞËÇÄŞ")); } } } diff --git a/MySQL.Data/tests/MySql.Data.Tests/ClientSideFailoverTests.cs b/MySQL.Data/tests/MySql.Data.Tests/ClientSideFailoverTests.cs index b4b251fd5..b5b95b247 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/ClientSideFailoverTests.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/ClientSideFailoverTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2019, 2022, Oracle and/or its affiliates. +// Copyright © 2019, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -28,6 +28,7 @@ using MySql.Data.Failover; using NUnit.Framework; +using NUnit.Framework.Legacy; using System; using System.Data; @@ -54,17 +55,17 @@ public void RandomMethod(string server, bool shouldPass = true) if (Settings.Server.Contains("::1")) { ipv6 = GetMySqlServerIp(true); - if (string.IsNullOrEmpty(ipv6)) Assert.Ignore("No IPv6 available."); + Assume.That(!string.IsNullOrEmpty(ipv6), "No IPv6 available."); Settings.Server = server.Replace("::1", ipv6); } if (!shouldPass) { Exception ex = Assert.Throws(() => TryConnection(Settings.ConnectionString)); - Assert.AreEqual("Unable to connect to any of the specified MySQL hosts.", ex.Message); + Assert.That(ex.Message, Is.EqualTo(Resources.UnableToConnectToHost)); } else - Assert.AreEqual(ConnectionState.Open, TryConnection(Settings.ConnectionString)); + Assert.That(TryConnection(Settings.ConnectionString), Is.EqualTo(ConnectionState.Open)); } private static ConnectionState TryConnection(string connString) @@ -82,7 +83,7 @@ private static ConnectionState TryConnection(string connString) public void PriorityMethod() { #if !NETFRAMEWORK - if (!System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows)) Assert.Ignore(); + Assume.That(System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows)); #endif // Multiple hosts and validate proper order assigned to hosts. Settings.Pooling = false; @@ -90,11 +91,11 @@ public void PriorityMethod() using (MySqlConnection conn = new MySqlConnection(Settings.ConnectionString)) { conn.Open(); - Assert.AreEqual(ConnectionState.Open, conn.State); - Assert.AreEqual(Host, conn.Settings.Server); - Assert.AreEqual("server.example", FailoverManager.FailoverGroup.Hosts[0].Host); - Assert.AreEqual("192.0.10.56", FailoverManager.FailoverGroup.Hosts[1].Host); - Assert.AreEqual(Host, FailoverManager.FailoverGroup.Hosts[2].Host); + Assert.That(conn.State, Is.EqualTo(ConnectionState.Open)); + Assert.That(conn.Settings.Server, Is.EqualTo(Host)); + Assert.That(FailoverManager.FailoverGroup.Hosts[0].Host, Is.EqualTo("server.example")); + Assert.That(FailoverManager.FailoverGroup.Hosts[1].Host, Is.EqualTo("192.0.10.56")); + Assert.That(FailoverManager.FailoverGroup.Hosts[2].Host, Is.EqualTo(Host)); } // Multiple hosts with IPv6 @@ -105,7 +106,7 @@ public void PriorityMethod() using (MySqlConnection conn = new MySqlConnection(Settings.ConnectionString)) { conn.Open(); - Assert.AreEqual(ConnectionState.Open, conn.State); + Assert.That(conn.State, Is.EqualTo(ConnectionState.Open)); } } @@ -123,20 +124,20 @@ public void PriorityMethod() using (MySqlConnection conn = new MySqlConnection(Settings.ConnectionString)) { conn.Open(); - Assert.AreEqual(ConnectionState.Open, conn.State); + Assert.That(conn.State, Is.EqualTo(ConnectionState.Open)); priority = 100; foreach (var host in FailoverManager.FailoverGroup.Hosts) { - Assert.AreEqual(priority != 0 ? priority-- : 0, host.Priority); + Assert.That(host.Priority, Is.EqualTo(priority != 0 ? priority-- : 0)); } } } - [TestCase("(address=server.example,priority=-20),(address=127.0.0.1,priority=100)", "The priority must be between 0 and 100.", "argument")] // Priority outside the 0-100 allowed range - [TestCase("(address=server.example,priority=-50),(address=127.0.0.1,priority=101)", "The priority must be between 0 and 100.", "argument")] // Priority outside the 0-100 allowed range - [TestCase("(address=server.example),(address=127.0.0.1,priority=100)", "You must either assign no priority to any of the hosts or give a priority for every host.", "argument")] // Set priority for a subset of the hosts. - [TestCase("(address=server.example,priority=50),(address=127.0.0.1,priority=100),(address=server.example)", "You must either assign no priority to any of the hosts or give a priority for every host.", "argument")] // Set priority for a subset of the hosts. - [TestCase("(address=server.example,priority=100),(address=10.10.10.10,priority=25),(address=192.0.10.56,priority=75)", "Unable to connect to any of the specified MySQL hosts.", "mysql")] // Multiple hosts. All attempts fail. + [TestCase("(address=server.example,priority=-20),(address=127.0.0.1,priority=100)", "The priority must be between 0 and 100", "argument")] // Priority outside the 0-100 allowed range + [TestCase("(address=server.example,priority=-50),(address=127.0.0.1,priority=101)", "The priority must be between 0 and 100", "argument")] // Priority outside the 0-100 allowed range + [TestCase("(address=server.example),(address=127.0.0.1,priority=100)", "You must either assign no priority to any of the hosts or give a priority for every host", "argument")] // Set priority for a subset of the hosts. + [TestCase("(address=server.example,priority=50),(address=127.0.0.1,priority=100),(address=server.example)", "You must either assign no priority to any of the hosts or give a priority for every host", "argument")] // Set priority for a subset of the hosts. + [TestCase("(address=server.example,priority=100),(address=10.10.10.10,priority=25),(address=192.0.10.56,priority=75)", "Unable to connect to any of the specified MySQL hosts", "mysql")] // Multiple hosts. All attempts fail. public void PriorityMethodConnectionFail(string server, string exceptionMessage, string exceptionType) { Settings.Server = server.Replace("127.0.0.1", Host); @@ -148,7 +149,7 @@ public void PriorityMethodConnectionFail(string server, string exceptionMessage, else ex = Assert.Throws(() => conn.Open()); - Assert.AreEqual(exceptionMessage, ex.Message); + Assert.That(ex.Message, Is.EqualTo(exceptionMessage)); } } @@ -165,7 +166,7 @@ public void Pooling(string server) { connArray[i] = new MySqlConnection(Settings.ConnectionString); connArray[i].Open(); - Assert.AreEqual(ConnectionState.Open, connArray[i].State); + Assert.That(connArray[i].State, Is.EqualTo(ConnectionState.Open)); } // now make sure all the server ids are different @@ -174,7 +175,7 @@ public void Pooling(string server) for (int j = 0; j < connArray.Length; j++) { if (i != j) - Assert.True(connArray[i].ServerThread != connArray[j].ServerThread); + Assert.That(connArray[i].ServerThread != connArray[j].ServerThread); } } @@ -197,4 +198,4 @@ public void FailWhenMySqlExceptionRaised() Assert.Throws(() => conn.Open()); } } -} \ No newline at end of file +} diff --git a/MySQL.Data/tests/MySql.Data.Tests/CmdTests.cs b/MySQL.Data/tests/MySql.Data.Tests/CmdTests.cs index 3522add9d..e932704e3 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/CmdTests.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/CmdTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2023, Oracle and/or its affiliates. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -27,6 +27,7 @@ // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA using NUnit.Framework; +using NUnit.Framework.Legacy; using System; using System.Data; using System.Diagnostics; @@ -82,7 +83,7 @@ public void InvalidCast() cmd.Parameters[1].Direction = ParameterDirection.ReturnValue; cmd.Parameters[0].Value = 20; cmd.ExecuteNonQuery(); - Assert.AreEqual(40, cmd.Parameters[1].Value); + Assert.That(cmd.Parameters[1].Value, Is.EqualTo(40)); cmd.CommandText = "spMyTwice"; cmd.CommandType = CommandType.StoredProcedure; @@ -92,7 +93,7 @@ public void InvalidCast() cmd.Parameters[0].Direction = ParameterDirection.Output; cmd.Parameters[1].Value = 20; cmd.ExecuteNonQuery(); - Assert.AreEqual(40, cmd.Parameters[0].Value); + Assert.That(cmd.Parameters[0].Value, Is.EqualTo(40)); } } @@ -103,25 +104,25 @@ public void InsertTest() // do the insert MySqlCommand cmd = new MySqlCommand("INSERT INTO Test (id,name) VALUES(10,'Test')", Connection); int cnt = cmd.ExecuteNonQuery(); - Assert.True(cnt == 1, "Insert Count"); + Assert.That(cnt == 1, "Insert Count"); // make sure we get the right value back out cmd.CommandText = "SELECT name FROM Test WHERE id=10"; string name = (string)cmd.ExecuteScalar(); - Assert.True(name == "Test", "Insert result"); + Assert.That(name == "Test", "Insert result"); // now do the insert with parameters cmd.CommandText = "INSERT INTO Test (id,name) VALUES(?id, ?name)"; cmd.Parameters.Add(new MySqlParameter("?id", 11)); cmd.Parameters.Add(new MySqlParameter("?name", "Test2")); cnt = cmd.ExecuteNonQuery(); - Assert.True(cnt == 1, "Insert with Parameters Count"); + Assert.That(cnt == 1, "Insert with Parameters Count"); // make sure we get the right value back out cmd.Parameters.Clear(); cmd.CommandText = "SELECT name FROM Test WHERE id=11"; name = (string)cmd.ExecuteScalar(); - Assert.True(name == "Test2", "Insert with parameters result"); + Assert.That(name == "Test2", "Insert with parameters result"); } [Test] @@ -134,29 +135,29 @@ public void UpdateTest() // do the update MySqlCommand cmd = new MySqlCommand("UPDATE test SET name='Test3' WHERE id=10 OR id=11", Connection); int cnt = cmd.ExecuteNonQuery(); - Assert.AreEqual(2, cnt); + Assert.That(cnt, Is.EqualTo(2)); // make sure we get the right value back out cmd.CommandText = "SELECT name FROM test WHERE id=10"; string name = (string)cmd.ExecuteScalar(); - Assert.AreEqual("Test3", name); + Assert.That(name, Is.EqualTo("Test3")); cmd.CommandText = "SELECT name FROM test WHERE id=11"; name = (string)cmd.ExecuteScalar(); - Assert.AreEqual("Test3", name); + Assert.That(name, Is.EqualTo("Test3")); // now do the update with parameters cmd.CommandText = "UPDATE test SET name=?name WHERE id=?id"; cmd.Parameters.Add(new MySqlParameter("?id", 11)); cmd.Parameters.Add(new MySqlParameter("?name", "Test5")); cnt = cmd.ExecuteNonQuery(); - Assert.True(cnt == 1, "Update with Parameters Count"); + Assert.That(cnt == 1, "Update with Parameters Count"); // make sure we get the right value back out cmd.Parameters.Clear(); cmd.CommandText = "SELECT name FROM test WHERE id=11"; name = (string)cmd.ExecuteScalar(); - Assert.AreEqual("Test5", name); + Assert.That(name, Is.EqualTo("Test5")); } @@ -170,14 +171,25 @@ public void DeleteTest() // make sure we get the right value back out MySqlCommand cmd = new MySqlCommand("DELETE FROM Test WHERE id=1 or id=2", Connection); int delcnt = cmd.ExecuteNonQuery(); - Assert.AreEqual(2, delcnt); + Assert.That(delcnt, Is.EqualTo(2)); // find out how many rows we have now cmd.CommandText = "SELECT COUNT(*) FROM Test"; object after_cnt = cmd.ExecuteScalar(); - Assert.AreEqual(0, Convert.ToInt32(after_cnt)); + Assert.That(Convert.ToInt32(after_cnt), Is.EqualTo(0)); } + #if !NETFRAMEWORK + [Test] + public void ActivityTest() + { + using var cmd = Connection.CreateCommand(); + cmd.CommandText = "SELECT 1;"; + using var _ = TestListener((activity) => Assert.That(BaseUserName+"0", Is.EqualTo(activity.GetTagItem("db.user")))); + cmd.ExecuteNonQuery(); + } + #endif + [Test] public void CtorTest() { @@ -308,9 +320,9 @@ public void PreparedInsertUsingReader() { ExecuteSQL("CREATE TABLE Test (id int NOT NULL, name VARCHAR(100))"); MySqlCommand cmd = new MySqlCommand("INSERT INTO Test VALUES(1, 'Test')", Connection); - Assert.False(cmd.IsPrepared); + Assert.That(cmd.IsPrepared, Is.False); cmd.Prepare(); - Assert.True(cmd.IsPrepared); + Assert.That(cmd.IsPrepared); using (MySqlDataReader reader = cmd.ExecuteReader()) { } @@ -318,9 +330,9 @@ public void PreparedInsertUsingReader() cmd.CommandText = "SELECT * FROM Test"; using (MySqlDataReader reader = cmd.ExecuteReader()) { - Assert.True(reader.Read()); - Assert.False(reader.Read()); - Assert.False(reader.NextResult()); + Assert.That(reader.Read()); + Assert.That(reader.Read(), Is.False); + Assert.That(reader.NextResult(), Is.False); } } @@ -395,31 +407,31 @@ public void DefaultCommandTimeout() { MySqlConnection c = new MySqlConnection($"server={Host}"); MySqlCommand cmd = new MySqlCommand("", c); - Assert.AreEqual(30, cmd.CommandTimeout); + Assert.That(cmd.CommandTimeout, Is.EqualTo(30)); c = new MySqlConnection($"server={Host};default command timeout=47"); cmd = new MySqlCommand("", c); - Assert.AreEqual(47, cmd.CommandTimeout); + Assert.That(cmd.CommandTimeout, Is.EqualTo(47)); cmd = new MySqlCommand(""); - Assert.AreEqual(30, cmd.CommandTimeout); + Assert.That(cmd.CommandTimeout, Is.EqualTo(30)); cmd.CommandTimeout = 66; cmd.Connection = c; - Assert.AreEqual(66, cmd.CommandTimeout); + Assert.That(cmd.CommandTimeout, Is.EqualTo(66)); cmd.CommandTimeout = 0; - Assert.AreEqual(0, cmd.CommandTimeout); + Assert.That(cmd.CommandTimeout, Is.EqualTo(0)); c = new MySqlConnection($"server={Host};default command timeout=0"); cmd = new MySqlCommand("", c); - Assert.AreEqual(0, cmd.CommandTimeout); + Assert.That(cmd.CommandTimeout, Is.EqualTo(0)); // Defaults to Int32.MaxValue/1000 when provided value is larger. c = new MySqlConnection(Connection.ConnectionString); cmd = new MySqlCommand("", c); c.Open(); cmd.CommandTimeout = Int32.MaxValue; - Assert.AreEqual(Int32.MaxValue / 1000, cmd.CommandTimeout); + Assert.That(cmd.CommandTimeout, Is.EqualTo(Int32.MaxValue / 1000)); c.Close(); } @@ -453,7 +465,7 @@ public void UseAffectedRows() ExecuteSQL("INSERT INTO Test VALUES (3, 'C')"); MySqlCommand cmd = new MySqlCommand("UPDATE Test SET name='C' WHERE id=3", Connection); - Assert.AreEqual(1, cmd.ExecuteNonQuery()); + Assert.That(cmd.ExecuteNonQuery(), Is.EqualTo(1)); MySqlConnectionStringBuilder connStr = new MySqlConnectionStringBuilder(Connection.ConnectionString); connStr.UseAffectedRows = true; @@ -461,7 +473,7 @@ public void UseAffectedRows() { c.Open(); cmd.Connection = c; - Assert.AreEqual(0, cmd.ExecuteNonQuery()); + Assert.That(cmd.ExecuteNonQuery(), Is.EqualTo(0)); } } @@ -495,10 +507,10 @@ public void TableCommandType() using (MySqlDataReader reader = cmd.ExecuteReader()) { reader.Read(); - Assert.AreEqual(1, reader.GetInt32(0)); - Assert.AreEqual("A", reader.GetString(1)); - Assert.AreEqual(2, reader.GetInt32(2)); - Assert.AreEqual("B", reader.GetString(3)); + Assert.That(reader.GetInt32(0), Is.EqualTo(1)); + Assert.That(reader.GetString(1), Is.EqualTo("A")); + Assert.That(reader.GetInt32(2), Is.EqualTo(2)); + Assert.That(reader.GetString(3), Is.EqualTo("B")); } } @@ -529,8 +541,8 @@ public void SyntaxErrorWithCloseConnection() c.Open(); MySqlCommand cmd = new MySqlCommand("SELE 1", c); var ex = Assert.Throws(() => cmd.ExecuteReader(CommandBehavior.CloseConnection)); - Assert.AreEqual("You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'SELE 1' at line 1", ex.Message); - Assert.True(c.State == ConnectionState.Closed); + Assert.That(ex.Message, Is.EqualTo("You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'SELE 1' at line 1")); + Assert.That(c.State == ConnectionState.Closed); } } @@ -544,7 +556,7 @@ public void EmptyOrJustSemiCommand() cmd.CommandText = ";"; MySqlException ex = Assert.Throws(() => cmd.ExecuteNonQuery()); // Error: 1065 Message: Query was empty - Assert.AreEqual(1065, ex.Number); + Assert.That(ex.Number, Is.EqualTo(1065)); } /// @@ -557,7 +569,7 @@ public void CommandTextIsNull() { MySqlCommand cmd = new MySqlCommand(null, Connection); Exception ex = Assert.Throws(() => cmd.ExecuteReader()); - Assert.True(ex.Message != String.Empty); + Assert.That(ex.Message != String.Empty); } /// @@ -576,7 +588,7 @@ public void LongLastInsertId() { cmd.CommandText = "INSERT INTO longids VALUES ();"; cmd.ExecuteNonQuery(); - Assert.AreEqual(seed++, cmd.LastInsertedId); + Assert.That(cmd.LastInsertedId, Is.EqualTo(seed++)); } } @@ -592,12 +604,12 @@ public async Task ExecuteNonQueryAsync() proc.CommandType = CommandType.StoredProcedure; int result = await proc.ExecuteNonQueryAsync(); - Assert.AreNotEqual(-1, result); + Assert.That(result, Is.Not.EqualTo(-1)); MySqlCommand cmd = new MySqlCommand("SELECT COUNT(*) FROM CMDNonQueryAsyncTest;", Connection); cmd.CommandType = CommandType.Text; object cnt = cmd.ExecuteScalar(); - Assert.AreEqual(100, Convert.ToInt32(cnt)); + Assert.That(Convert.ToInt32(cnt), Is.EqualTo(100)); } [Test] @@ -611,17 +623,17 @@ public async Task ExecuteReaderAsync() using (MySqlDataReader reader = await proc.ExecuteReaderAsync() as MySqlDataReader) { - Assert.NotNull(reader); - Assert.True(reader.Read(), "can read"); - Assert.True(reader.NextResult()); - Assert.True(reader.Read()); - Assert.AreEqual("done", reader.GetString(0)); + Assert.That(reader, Is.Not.Null); + Assert.That(reader.Read(), "can read"); + Assert.That(reader.NextResult()); + Assert.That(reader.Read()); + Assert.That(reader.GetString(0), Is.EqualTo("done")); reader.Close(); proc.CommandType = CommandType.Text; proc.CommandText = "SELECT COUNT(*) FROM CMDReaderAsyncTest"; object cnt = proc.ExecuteScalar(); - Assert.AreEqual(1, Convert.ToInt32(cnt)); + Assert.That(Convert.ToInt32(cnt), Is.EqualTo(1)); } } @@ -637,8 +649,8 @@ public async Task ExecuteScalarAsync() cmd.Parameters[1].Direction = ParameterDirection.Output; object result = await cmd.ExecuteScalarAsync(); - Assert.AreEqual("Test", result); - Assert.AreEqual("valuein", cmd.Parameters[1].Value); + Assert.That(result, Is.EqualTo("Test")); + Assert.That(cmd.Parameters[1].Value, Is.EqualTo("valuein")); } #if NET452 @@ -690,7 +702,7 @@ public void BatchUpdatesAndDeletes() da.Update(dt); } - Assert.AreEqual(1, listener.Find("Query Opened: UPDATE")); + Assert.That(listener.Find("Query Opened: UPDATE"), Is.EqualTo(1)); } [Test] @@ -707,10 +719,10 @@ public void ExecuteReaderReturnsReaderAfterCancel() command = new MySqlCommand("SELECT PrimaryKey FROM TableWithStringAsPrimaryKey", Connection); reader = command.ExecuteReader(CommandBehavior.KeyInfo); - Assert.NotNull(reader); + Assert.That(reader, Is.Not.Null); dataTableSchema = reader.GetSchemaTable(); - Assert.True("PrimaryKey" == (string)dataTableSchema.Rows[0][dataTableSchema.Columns[0]]); + Assert.That("PrimaryKey" == (string)dataTableSchema.Rows[0][dataTableSchema.Columns[0]]); reader.Close(); } @@ -723,10 +735,10 @@ public void CloneCommand() var cmd2 = (MySqlCommand)cmd.Clone(); - Assert.AreEqual(1, cmd2.Parameters.Count); - Assert.AreEqual(1, cmd2.Attributes.Count); - StringAssert.AreEqualIgnoringCase("attr_value", cmd2.Attributes[0].Value.ToString()); - StringAssert.AreEqualIgnoringCase("param_value", cmd2.Parameters[0].Value.ToString()); + Assert.That(cmd2.Parameters.Count, Is.EqualTo(1)); + Assert.That(cmd2.Attributes.Count, Is.EqualTo(1)); + Assert.That(cmd2.Attributes[0].Value.ToString(), Is.EqualTo("attr_value").IgnoreCase); + Assert.That(cmd2.Parameters[0].Value.ToString(), Is.EqualTo("param_value").IgnoreCase); } /// @@ -746,9 +758,9 @@ public void ExecuteReaderAfterClosingCommand() reader = cmd.ExecuteReader(); } - Assert.True(reader.Read()); - Assert.AreEqual("TEST", reader.GetString(0)); - Assert.False(reader.Read()); + Assert.That(reader.Read()); + Assert.That(reader.GetString(0), Is.EqualTo("TEST")); + Assert.That(reader.Read(), Is.False); } } @@ -760,14 +772,14 @@ public void CommandNegativeTimeout() { MySqlConnection conn = new MySqlConnection($"server={Host};default command timeout=10"); MySqlCommand cmd = new MySqlCommand("", conn); - Assert.AreEqual(10, cmd.CommandTimeout); + Assert.That(cmd.CommandTimeout, Is.EqualTo(10)); Assert.Throws(() => conn = new MySqlConnection($"server={Host};default command timeout=-1")); var ex = Assert.Throws(() => cmd.CommandTimeout = -1); - StringAssert.AreEqualIgnoringCase("Command timeout must not be negative", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Command timeout must not be negative").IgnoreCase); cmd.CommandTimeout = 15; - Assert.AreEqual(15, cmd.CommandTimeout); + Assert.That(cmd.CommandTimeout, Is.EqualTo(15)); } #region SQL Injection @@ -791,7 +803,7 @@ public void SqlInjection1() cmd.Parameters[0].Value = "\u2032 OR 1=1;-- --"; cmd.ExecuteNonQuery(); - Assert.AreEqual(count, (Int64)cnt.ExecuteScalar()); + Assert.That((Int64)cnt.ExecuteScalar(), Is.EqualTo(count)); } #endregion @@ -837,11 +849,11 @@ PRIMARY KEY (`inventory_id`) { while (reader.Read()) { - Assert.AreEqual(999999, cmd.CommandTimeout); - Assert.IsNotEmpty(reader.GetValue(0).ToString()); - Assert.IsNotEmpty(reader.GetValue(1).ToString()); - Assert.IsNotEmpty(reader.GetValue(2).ToString()); - Assert.IsNotEmpty(reader.GetValue(3).ToString()); + Assert.That(cmd.CommandTimeout, Is.EqualTo(999999)); + Assert.That(reader.GetValue(0).ToString(), Is.Not.Empty); + Assert.That(reader.GetValue(1).ToString(), Is.Not.Empty); + Assert.That(reader.GetValue(2).ToString(), Is.Not.Empty); + Assert.That(reader.GetValue(3).ToString(), Is.Not.Empty); } } } @@ -871,9 +883,9 @@ public void ReservedWordUse() { while (rdr.Read()) { - Assert.AreEqual("1", rdr[0]); - Assert.AreEqual("test", rdr[1]); - Assert.AreEqual("status", rdr[2]); + Assert.That(rdr[0], Is.EqualTo("1")); + Assert.That(rdr[1], Is.EqualTo("test")); + Assert.That(rdr[2], Is.EqualTo("status")); } } } @@ -923,10 +935,10 @@ public void ExecuteCmdWithTabsAndNewLines() using (var cmd = Connection.CreateCommand()) { cmd.CommandText = "SELECT\nCOUNT(*)\nFROM\nTest;"; - Assert.AreEqual(1, cmd.ExecuteScalar()); + Assert.That(cmd.ExecuteScalar(), Is.EqualTo(1)); cmd.CommandText = "SELECT\tCOUNT(*)\n\t\tFROM\tTest;"; - Assert.AreEqual(1, cmd.ExecuteScalar()); + Assert.That(cmd.ExecuteScalar(), Is.EqualTo(1)); } } @@ -944,10 +956,10 @@ public void LastInsertedIdInMultipleStatements() + "INSERT INTO TestForeignKey (foreign_id, column2) VALUES(LAST_INSERT_ID(), 'test');"; cmd.ExecuteNonQuery(); - Assert.AreEqual(1, cmd.LastInsertedId); + Assert.That(cmd.LastInsertedId, Is.EqualTo(1)); cmd.ExecuteNonQuery(); - Assert.AreEqual(2, cmd.LastInsertedId); + Assert.That(cmd.LastInsertedId, Is.EqualTo(2)); cmd.CommandText = "SELECT * FROM Test"; int id = 1; @@ -955,11 +967,11 @@ public void LastInsertedIdInMultipleStatements() using var reader = cmd.ExecuteReader(); while (reader.Read()) { - Assert.IsTrue(reader.GetInt32(0) == id); + Assert.That(reader.GetInt32(0) == id); id++; } - Assert.AreEqual(-1, cmd.LastInsertedId); + Assert.That(cmd.LastInsertedId, Is.EqualTo(-1)); } /// @@ -973,9 +985,9 @@ public void LastInserteIdRedux() using var cmd = Connection.CreateCommand(); cmd.CommandText = @"INSERT INTO Test (text) VALUES ('test1'); INSERT INTO Test (text) VALUES ('test2');"; - Assert.AreEqual(2, cmd.ExecuteNonQuery()); - Assert.AreEqual(2, cmd.LastInsertedId); + Assert.That(cmd.ExecuteNonQuery(), Is.EqualTo(2)); + Assert.That(cmd.LastInsertedId, Is.EqualTo(2)); } } -} \ No newline at end of file +} diff --git a/MySQL.Data/tests/MySql.Data.Tests/CmdTestsCompressed.cs b/MySQL.Data/tests/MySql.Data.Tests/CmdTestsCompressed.cs index 148e3db6f..7ce26eb36 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/CmdTestsCompressed.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/CmdTestsCompressed.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -27,6 +27,7 @@ // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA using NUnit.Framework; +using NUnit.Framework.Legacy; namespace MySql.Data.MySqlClient.Tests { @@ -43,4 +44,4 @@ public override void InsertingPreparedNulls() base.InsertingPreparedNulls(); } } -} \ No newline at end of file +} diff --git a/MySQL.Data/tests/MySql.Data.Tests/ConnectionStringBuilderTests.cs b/MySQL.Data/tests/MySql.Data.Tests/ConnectionStringBuilderTests.cs index baee233cd..e399e076e 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/ConnectionStringBuilderTests.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/ConnectionStringBuilderTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2022, Oracle and/or its affiliates. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -28,6 +28,7 @@ using MySql.Data.Common; using NUnit.Framework; +using NUnit.Framework.Legacy; using System; using System.Collections.Generic; using System.Data; @@ -53,48 +54,48 @@ public void Simple() sb.ConnectionString = "server=localhost;uid=reggie;pwd=pass;port=1111;" + "connection timeout=23; pooling=true; min pool size=33; " + "max pool size=66;keepalive=1"; - Assert.AreEqual("localhost", sb.Server); - Assert.AreEqual("reggie", sb.UserID); - Assert.AreEqual("pass", sb.Password); - Assert.AreEqual(1111, Convert.ToInt32(sb.Port)); - Assert.AreEqual(23, Convert.ToInt32(sb.ConnectionTimeout)); - Assert.True(sb.Pooling); - Assert.AreEqual(33, Convert.ToInt32(sb.MinimumPoolSize)); - Assert.AreEqual(66, Convert.ToInt32(sb.MaximumPoolSize)); - Assert.AreEqual(1, Convert.ToInt32(sb.Keepalive)); + Assert.That(sb.Server, Is.EqualTo("localhost")); + Assert.That(sb.UserID, Is.EqualTo("reggie")); + Assert.That(sb.Password, Is.EqualTo("pass")); + Assert.That(Convert.ToInt32(sb.Port), Is.EqualTo(1111)); + Assert.That(Convert.ToInt32(sb.ConnectionTimeout), Is.EqualTo(23)); + Assert.That(sb.Pooling); + Assert.That(Convert.ToInt32(sb.MinimumPoolSize), Is.EqualTo(33)); + Assert.That(Convert.ToInt32(sb.MaximumPoolSize), Is.EqualTo(66)); + Assert.That(Convert.ToInt32(sb.Keepalive), Is.EqualTo(1)); Exception ex = Assert.Throws(() => sb.ConnectionString = "server=localhost;badkey=badvalue"); #if NETFRAMEWORK - Assert.AreEqual($"Option not supported.{Environment.NewLine}Parameter name: badkey", ex.Message); + Assert.That(ex.Message, Is.EqualTo($"Option not supported{Environment.NewLine}Parameter name: badkey")); #else - Assert.AreEqual("Option not supported. (Parameter 'badkey')", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Option not supported (Parameter 'badkey')")); #endif sb.Clear(); - Assert.AreEqual(15, Convert.ToInt32(sb.ConnectionTimeout)); - Assert.True(sb.Pooling); - Assert.True(sb.Pooling); - Assert.AreEqual(3306, Convert.ToInt32(sb.Port)); - Assert.AreEqual(String.Empty, sb.Server); - Assert.False(sb.PersistSecurityInfo); - Assert.AreEqual(0, Convert.ToInt32(sb.ConnectionLifeTime)); - Assert.False(sb.ConnectionReset); - Assert.AreEqual(0, Convert.ToInt32(sb.MinimumPoolSize)); - Assert.AreEqual(100, Convert.ToInt32(sb.MaximumPoolSize)); - Assert.AreEqual(String.Empty, sb.UserID); - Assert.AreEqual(String.Empty, sb.Password); - Assert.False(sb.UseUsageAdvisor); - Assert.AreEqual(String.Empty, sb.CharacterSet); - Assert.False(sb.UseCompression); - Assert.AreEqual("MYSQL", sb.PipeName); - Assert.False(sb.Logging); - Assert.True(sb.AllowBatch); - Assert.False(sb.ConvertZeroDateTime); - Assert.AreEqual("MYSQL", sb.SharedMemoryName); - Assert.AreEqual(String.Empty, sb.Database); - Assert.AreEqual(MySqlConnectionProtocol.Sockets, sb.ConnectionProtocol); - Assert.False(sb.AllowZeroDateTime); - Assert.False(sb.UsePerformanceMonitor); - Assert.AreEqual(25, Convert.ToInt32(sb.ProcedureCacheSize)); - Assert.AreEqual(0, Convert.ToInt32(sb.Keepalive)); + Assert.That(Convert.ToInt32(sb.ConnectionTimeout), Is.EqualTo(15)); + Assert.That(sb.Pooling); + Assert.That(sb.Pooling); + Assert.That(Convert.ToInt32(sb.Port), Is.EqualTo(3306)); + Assert.That(sb.Server, Is.EqualTo(String.Empty)); + Assert.That(sb.PersistSecurityInfo, Is.False); + Assert.That(Convert.ToInt32(sb.ConnectionLifeTime), Is.EqualTo(0)); + Assert.That(sb.ConnectionReset, Is.False); + Assert.That(Convert.ToInt32(sb.MinimumPoolSize), Is.EqualTo(0)); + Assert.That(Convert.ToInt32(sb.MaximumPoolSize), Is.EqualTo(100)); + Assert.That(sb.UserID, Is.EqualTo(String.Empty)); + Assert.That(sb.Password, Is.EqualTo(String.Empty)); + Assert.That(sb.UseUsageAdvisor, Is.False); + Assert.That(sb.CharacterSet, Is.EqualTo(String.Empty)); + Assert.That(sb.UseCompression, Is.False); + Assert.That(sb.PipeName, Is.EqualTo("MYSQL")); + Assert.That(sb.Logging, Is.False); + Assert.That(sb.AllowBatch); + Assert.That(sb.ConvertZeroDateTime, Is.False); + Assert.That(sb.SharedMemoryName, Is.EqualTo("MYSQL")); + Assert.That(sb.Database, Is.EqualTo(String.Empty)); + Assert.That(sb.ConnectionProtocol, Is.EqualTo(MySqlConnectionProtocol.Sockets)); + Assert.That(sb.AllowZeroDateTime, Is.False); + Assert.That(sb.UsePerformanceMonitor, Is.False); + Assert.That(Convert.ToInt32(sb.ProcedureCacheSize), Is.EqualTo(25)); + Assert.That(Convert.ToInt32(sb.Keepalive), Is.EqualTo(0)); } /// @@ -106,7 +107,7 @@ public void SettingValueMultipeTimes() MySqlConnectionStringBuilder s = new MySqlConnectionStringBuilder(); s["database"] = "test"; s["database"] = "test2"; - Assert.AreEqual("database=test2", s.ConnectionString); + Assert.That(s.ConnectionString, Is.EqualTo("database=test2")); } /// @@ -117,8 +118,8 @@ public void NoValueGivenForConnectionStringOption() { MySqlConnectionStringBuilder s = new MySqlConnectionStringBuilder(); s.ConnectionString = "compress=;pooling="; - Assert.False(s.UseCompression); - Assert.True(s.Pooling); + Assert.That(s.UseCompression, Is.False); + Assert.That(s.Pooling); } /// @@ -129,18 +130,18 @@ public void ContainsKey() { MySqlConnectionStringBuilder s = new MySqlConnectionStringBuilder(); s["database"] = "test"; - Assert.True(s.ContainsKey("initial catalog")); + Assert.That(s.ContainsKey("initial catalog")); s["server"] = "myserver"; - Assert.True(s.ContainsKey("server")); - Assert.True(s.ContainsKey("host")); - Assert.False(s.ContainsKey("badkey")); + Assert.That(s.ContainsKey("server")); + Assert.That(s.ContainsKey("host")); + Assert.That(s.ContainsKey("badkey"), Is.False); } [Test] public void SettingCheckParameters() { MySqlConnectionStringBuilder s = new MySqlConnectionStringBuilder("server=localhost;check parameters=false"); - Assert.False(s.CheckParameters); + Assert.That(s.CheckParameters, Is.False); } [TestCase("foo keyword")] @@ -150,9 +151,9 @@ public void SettingInvalidKeyThrowsArgumentException(string invalidKey) MySqlConnectionStringBuilder s = new MySqlConnectionStringBuilder(); Exception ex = Assert.Throws(() => s[invalidKey] = "foo"); #if NETFRAMEWORK - Assert.AreEqual($"Option not supported.{Environment.NewLine}Parameter name: {invalidKey}", ex.Message); + Assert.That(ex.Message, Is.EqualTo($"Option not supported{Environment.NewLine}Parameter name: {invalidKey}")); #else - Assert.AreEqual($"Option not supported. (Parameter '{invalidKey}')", ex.Message); + Assert.That(ex.Message, Is.EqualTo($"Option not supported (Parameter '{invalidKey}')")); #endif } @@ -165,7 +166,7 @@ public void SafeTryGetValue() object obj; MySqlConnectionStringBuilder s = new MySqlConnectionStringBuilder("server=localhost;"); s.TryGetValue("unknownproperty", out obj); - Assert.Null(obj); + Assert.That(obj, Is.Null); } #if !NETFRAMEWORK @@ -195,7 +196,7 @@ public void DotnetCoreNotCurrentlySupported() [Test] public void NonWindowsOSNotCurrentlySupported() { - if (Platform.IsWindows()) Assert.Ignore("This test is for non Windows OS only."); + Assume.That(!Platform.IsWindows(), "This test is for non Windows OS only."); List options = new List(new string[] { @@ -230,7 +231,7 @@ public void SettingTableCachingRaisesException() { var builder = new MySqlConnectionStringBuilder(); builder.TableCaching = true; - Assert.True(builder.TableCaching); + Assert.That(builder.TableCaching); } /// @@ -245,11 +246,11 @@ public void SettingInvalidAuthenticationMethod(string method) var builder = new MySqlConnectionStringBuilder(); builder.DefaultAuthenticationPlugin = " "; var ex = Assert.Throws(() => builder.DefaultAuthenticationPlugin = method); - StringAssert.AreEqualIgnoringCase(string.Format(Resources.AuthenticationMethodNotSupported, method), ex.Message); + Assert.That(ex.Message, Is.EqualTo(string.Format(Resources.AuthenticationMethodNotSupported, method)).IgnoreCase); var connStr = $"server=localhost;userid=root;defaultauthenticationplugin={method}"; ex = Assert.Throws(() => new MySqlConnection(connStr)); - StringAssert.AreEqualIgnoringCase(string.Format(Resources.AuthenticationMethodNotSupported, method), ex.Message); + Assert.That(ex.Message, Is.EqualTo(string.Format(Resources.AuthenticationMethodNotSupported, method)).IgnoreCase); connStr = "server=localhost;userid=root;defaultauthenticationplugin="; var conn = new MySqlConnection(connStr); @@ -265,23 +266,23 @@ public void UsingPwdAliases(string alias) { string value = "test"; var conn = new MySqlConnection($"{alias}={value};pwd2={value};pwd3={value}"); - StringAssert.AreEqualIgnoringCase(value, conn.Settings.Password); - StringAssert.AreEqualIgnoringCase(value, conn.Settings.Password2); - StringAssert.AreEqualIgnoringCase(value, conn.Settings.Password3); + Assert.That(conn.Settings.Password, Is.EqualTo(value).IgnoreCase); + Assert.That(conn.Settings.Password2, Is.EqualTo(value).IgnoreCase); + Assert.That(conn.Settings.Password3, Is.EqualTo(value).IgnoreCase); var connBuilder = new MySqlConnectionStringBuilder(); connBuilder[alias] = value; connBuilder["pwd2"] = value; connBuilder["pwd3"] = value; - StringAssert.AreEqualIgnoringCase(value, connBuilder.Password); - StringAssert.AreEqualIgnoringCase(value, connBuilder.Password2); - StringAssert.AreEqualIgnoringCase(value, connBuilder.Password3); + Assert.That(connBuilder.Password, Is.EqualTo(value).IgnoreCase); + Assert.That(connBuilder.Password2, Is.EqualTo(value).IgnoreCase); + Assert.That(connBuilder.Password3, Is.EqualTo(value).IgnoreCase); } [Test, Description("Session BaseString/MySQLConnectionString Builder")] public void ConnectionStringBuilderClassicTests() { - if (!Platform.IsWindows()) Assert.Ignore("This test is for Windows OS only."); + Assume.That(Platform.IsWindows(), "This test is for Windows OS only."); MySqlConnectionStringBuilder mysql = new MySqlConnectionStringBuilder(Settings.ConnectionString); @@ -298,7 +299,7 @@ public void ConnectionStringBuilderClassicTests() using (var conn = new MySqlConnection(mysql.ConnectionString)) { conn.Open(); - Assert.AreEqual(ConnectionState.Open, conn.connectionState); + Assert.That(conn.connectionState, Is.EqualTo(ConnectionState.Open)); } mysql = new MySqlConnectionStringBuilder(Settings.ConnectionString); @@ -315,7 +316,7 @@ public void ConnectionStringBuilderClassicTests() using (var conn = new MySqlConnection(mysql.ConnectionString)) { conn.Open(); - Assert.AreEqual(ConnectionState.Open, conn.connectionState); + Assert.That(conn.connectionState, Is.EqualTo(ConnectionState.Open)); } mysql = new MySqlConnectionStringBuilder(Settings.ConnectionString); @@ -328,7 +329,7 @@ public void ConnectionStringBuilderClassicTests() using (var conn = new MySqlConnection(mysql.ConnectionString)) { conn.Open(); - Assert.AreEqual(ConnectionState.Open, conn.connectionState); + Assert.That(conn.connectionState, Is.EqualTo(ConnectionState.Open)); } ////Scenario-2 @@ -381,7 +382,7 @@ public void ConnectionStringBuilderClassicTests() using (var conn = new MySqlConnection(mysql.ConnectionString)) { conn.Open(); - Assert.AreEqual(ConnectionState.Open, conn.connectionState); + Assert.That(conn.connectionState, Is.EqualTo(ConnectionState.Open)); } mysql.SslCa = _sslCa; @@ -389,7 +390,7 @@ public void ConnectionStringBuilderClassicTests() using (var conn = new MySqlConnection(mysql.ConnectionString)) { conn.Open(); - Assert.AreEqual(ConnectionState.Open, conn.connectionState); + Assert.That(conn.connectionState, Is.EqualTo(ConnectionState.Open)); } ////Basic Scenarios @@ -400,7 +401,7 @@ public void ConnectionStringBuilderClassicTests() using (var conn = new MySqlConnection(mysql.ConnectionString)) { conn.Open(); - Assert.AreEqual(ConnectionState.Open, conn.connectionState); + Assert.That(conn.connectionState, Is.EqualTo(ConnectionState.Open)); } } @@ -417,21 +418,21 @@ public void TryGetValue() MinimumPoolSize = 10, }; - Assert.IsTrue(connStringBuilder.ContainsKey("data source")); - Assert.IsTrue(connStringBuilder.TryGetValue("host", out var server)); - StringAssert.AreEqualIgnoringCase(connStringBuilder.Server, (string)server); + Assert.That(connStringBuilder.ContainsKey("data source")); + Assert.That(connStringBuilder.TryGetValue("host", out var server)); + Assert.That((string)server, Is.EqualTo(connStringBuilder.Server).IgnoreCase); - Assert.IsTrue(connStringBuilder.ContainsKey("MinimumPoolSize")); - Assert.IsTrue(connStringBuilder.TryGetValue("Minimum Pool Size", out var minpoolsize)); - Assert.AreEqual(connStringBuilder.MinimumPoolSize, (uint)minpoolsize); + Assert.That(connStringBuilder.ContainsKey("MinimumPoolSize")); + Assert.That(connStringBuilder.TryGetValue("Minimum Pool Size", out var minpoolsize)); + Assert.That((uint)minpoolsize, Is.EqualTo(connStringBuilder.MinimumPoolSize)); // Default value - Assert.IsTrue(connStringBuilder.TryGetValue("allowpublickeyretrieval", out var allowpublickeyretrieval)); - Assert.AreEqual(connStringBuilder.GetOption("allowpublickeyretrieval").DefaultValue, allowpublickeyretrieval); + Assert.That(connStringBuilder.TryGetValue("allowpublickeyretrieval", out var allowpublickeyretrieval)); + Assert.That(allowpublickeyretrieval, Is.EqualTo(connStringBuilder.GetOption("allowpublickeyretrieval").DefaultValue)); // Non existing option - Assert.IsFalse(connStringBuilder.TryGetValue("bar", out var nonexistingoption)); - Assert.IsNull(nonexistingoption); + Assert.That(connStringBuilder.TryGetValue("bar", out var nonexistingoption), Is.False); + Assert.That(nonexistingoption, Is.Null); } /// @@ -441,27 +442,27 @@ public void TryGetValue() [Test] public void KerberosAuthModeTest() { - if (!Platform.IsWindows()) Assert.Ignore("This test is for Windows OS only."); + Assume.That(Platform.IsWindows(), "This test is for Windows OS only."); string connString; MySqlConnection conn; conn = new MySqlConnection(); - Assert.True(conn.Settings.KerberosAuthMode == KerberosAuthMode.AUTO); + Assert.That(conn.Settings.KerberosAuthMode == KerberosAuthMode.AUTO); foreach (KerberosAuthMode mode in Enum.GetValues(typeof(KerberosAuthMode))) { connString = $"kerberosauthmode={mode}"; conn = new MySqlConnection(connString); - Assert.True(conn.Settings.KerberosAuthMode == mode); + Assert.That(conn.Settings.KerberosAuthMode == mode); connString = $"kerberos auth mode={mode}"; conn = new MySqlConnection(connString); - Assert.True(conn.Settings.KerberosAuthMode == mode); + Assert.That(conn.Settings.KerberosAuthMode == mode); } connString = "kerberosauthmode=INVALID"; Assert.Throws(() => conn = new MySqlConnection(connString)); } } -} \ No newline at end of file +} diff --git a/MySQL.Data/tests/MySql.Data.Tests/ConnectionTests.cs b/MySQL.Data/tests/MySql.Data.Tests/ConnectionTests.cs index 5aaf85f4a..9b5858a5e 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/ConnectionTests.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/ConnectionTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2023, Oracle and/or its affiliates. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -27,10 +27,14 @@ // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA using MySql.Data.Common; +using MySql.Data.Tests; using NUnit.Framework; +using NUnit.Framework.Legacy; using System; using System.Collections.Generic; using System.Data; +using System.Diagnostics; +using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -47,38 +51,38 @@ public void TestConnectionStrings() MySqlConnection c = new MySqlConnection(); // public properties - Assert.True(15 == c.ConnectionTimeout, "ConnectionTimeout"); - Assert.True(String.Empty == c.Database, "Database"); - Assert.True(String.Empty == c.DataSource, "DataSource"); - Assert.True(false == c.UseCompression, "Use Compression"); - Assert.True(ConnectionState.Closed == c.State, "State"); + Assert.That(15 == c.ConnectionTimeout, "ConnectionTimeout"); + Assert.That(String.Empty == c.Database, "Database"); + Assert.That(String.Empty == c.DataSource, "DataSource"); + Assert.That(false == c.UseCompression, "Use Compression"); + Assert.That(ConnectionState.Closed == c.State, "State"); c = new MySqlConnection("connection timeout=25; user id=myuser; " + "password=mypass; database=Test;server=myserver; use compression=true; " + "pooling=false;min pool size=5; max pool size=101"); // public properties - Assert.True(25 == c.ConnectionTimeout, "ConnectionTimeout"); - Assert.True("Test" == c.Database, "Database"); - Assert.True("myserver" == c.DataSource, "DataSource"); - Assert.True(true == c.UseCompression, "Use Compression"); - Assert.True(ConnectionState.Closed == c.State, "State"); + Assert.That(25 == c.ConnectionTimeout, "ConnectionTimeout"); + Assert.That("Test" == c.Database, "Database"); + Assert.That("myserver" == c.DataSource, "DataSource"); + Assert.That(true == c.UseCompression, "Use Compression"); + Assert.That(ConnectionState.Closed == c.State, "State"); c.ConnectionString = "connection timeout=15; user id=newuser; " + "password=newpass; port=3308; database=mydb; data source=myserver2; " + "use compression=true; pooling=true; min pool size=3; max pool size=76"; // public properties - Assert.True(15 == c.ConnectionTimeout, "ConnectionTimeout"); - Assert.True("mydb" == c.Database, "Database"); - Assert.True("myserver2" == c.DataSource, "DataSource"); - Assert.True(true == c.UseCompression, "Use Compression"); - Assert.True(ConnectionState.Closed == c.State, "State"); + Assert.That(15 == c.ConnectionTimeout, "ConnectionTimeout"); + Assert.That("mydb" == c.Database, "Database"); + Assert.That("myserver2" == c.DataSource, "DataSource"); + Assert.That(true == c.UseCompression, "Use Compression"); + Assert.That(ConnectionState.Closed == c.State, "State"); // Bug #30791289 - MYSQLCONNECTION(NULL) NOW THROWS NULLREFERENCEEXCEPTION var conn = new MySqlConnection($"server={Host};"); conn.ConnectionString = null; - Assert.AreEqual(string.Empty, conn.ConnectionString); + Assert.That(conn.ConnectionString, Is.EqualTo(string.Empty)); } [Test] @@ -89,15 +93,98 @@ public void ChangeDatabase() using (c) { c.Open(); - Assert.True(c.State == ConnectionState.Open); - Assert.AreEqual(connStr.Database, c.Database); + Assert.That(c.State == ConnectionState.Open); + Assert.That(c.Database, Is.EqualTo(connStr.Database)); string dbName = CreateDatabase("db1"); c.ChangeDatabase(dbName); - Assert.AreEqual(dbName, c.Database); + Assert.That(c.Database, Is.EqualTo(dbName)); } } + /// + /// Bug#35731216 Pool exhaustion after timeouts in transactions. + /// + [Test] + public void ConnectionPoolExhaustion() + { + for (var i = 0; i <= 11; i++) + { + var ex = Assert.Catch(() => CreateCommandTimeoutException()); + //Prior to the fix the exception thrown was 'error connecting: Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached.' after the 10th execution. + Assert.That(ex.Message, Is.EqualTo("Fatal error encountered during command execution")); + } + } + + private void CreateCommandTimeoutException() + { + MySqlConnectionStringBuilder settings = new MySqlConnectionStringBuilder(Connection.ConnectionString); + settings.Pooling = true; + settings.MaximumPoolSize = 10; + using (var conn = new MySqlConnection(settings.GetConnectionString(true))) + { + conn.Open(); + using (var tran = conn.BeginTransaction()) + { + using (var cmd = conn.CreateCommand()) + { + cmd.CommandText = "DO SLEEP(5);"; + cmd.CommandTimeout = 1; + cmd.ExecuteNonQuery(); + } + } + } + } + + /// + /// Bug#36319784 Minpoolsize different than 0 causes connector to hang after first connection + /// + [Test] + public void PoolingMultipleConnections() + { + Connection.Settings.Pooling = true; + Connection.Settings.MaximumPoolSize = 100; + Connection.Settings.MinimumPoolSize = 1; + MySqlConnection conn =new MySqlConnection(Connection.ConnectionString); + Assert.DoesNotThrow(() => conn.Open()); + + Connection.Settings.PersistSecurityInfo = false; + conn = conn = new MySqlConnection(Connection.ConnectionString); + Assert.Throws(() => conn.Open()); + + Connection.Settings.PersistSecurityInfo = true; + conn = conn = new MySqlConnection(Connection.ConnectionString ); + Assert.DoesNotThrow(() => conn.Open()); + } + + /// + /// Bug#35827809 Connector/Net allows a connection that has been disposed to be reopened. + /// + [Test] + public void ReOpenDisposedConnection() + { + using (MySqlConnection c = new MySqlConnection(Connection.ConnectionString)) + { + c.Open(); + c.Close(); + c.Dispose(); + Assert.Throws(() => c.Open()); + } + } + + /// + /// Bug#35474099 OpenAsync throws unhandled exception from thread pool. + /// + [Test] + public async Task OpenAsyncCatchException() + { + MockServer mockServer = new MockServer(false); + mockServer.StartServer(); + using var connection = new MySqlConnection($"server={mockServer.Address};port={mockServer.Port};user={Settings.UserID};connectiontimeout = 1"); + Assert.ThrowsAsync(async () => await connection.OpenAsync()); + mockServer.StopServer(); + } + [Test] public void ConnectingAsUTF8() { @@ -125,8 +212,8 @@ public void ConnectingAsUTF8() MySqlCommand cmd2 = new MySqlCommand("SELECT id, active FROM test", d); using (MySqlDataReader reader = cmd2.ExecuteReader()) { - Assert.True(reader.Read()); - Assert.True(reader.GetBoolean(1)); + Assert.That(reader.Read()); + Assert.That(reader.GetBoolean(1)); } } } @@ -139,8 +226,8 @@ public void PingUpdatesState() { var conn2 = GetConnection(); KillConnection(conn2); - Assert.False(conn2.Ping()); - Assert.True(conn2.State == ConnectionState.Closed); + Assert.That(conn2.Ping(), Is.False); + Assert.That(conn2.State == ConnectionState.Closed); conn2.Open(); conn2.Close(); } @@ -173,7 +260,7 @@ public void TestConnectingSocketBadHostName() connStr.Server = "badHostName"; MySqlConnection c = new MySqlConnection(connStr.GetConnectionString(true)); var ex = Assert.Throws(() => c.Open()); - if (Platform.IsWindows()) Assert.IsTrue(ex.InnerException.GetType() == typeof(ArgumentException)); + if (Platform.IsWindows()) Assert.That(ex.InnerException.GetType() == typeof(ArgumentException)); } /// @@ -193,7 +280,7 @@ public void ConnectionStringNotAffectedByChangeDatabase() c.Open(); string str = c.ConnectionString; int index = str.IndexOf("Database="); - Assert.AreEqual(-1, index); + Assert.That(index, Is.EqualTo(-1)); } } } @@ -212,12 +299,12 @@ public void ConnectionCloseByGC() c.Open(); threadId = c.ServerThread; WeakReference wr = new WeakReference(c); - Assert.True(wr.IsAlive); + Assert.That(wr.IsAlive); c = null; GC.Collect(); GC.WaitForPendingFinalizers(); - Assert.False(wr.IsAlive); - Assert.True(check.closed); + Assert.That(wr.IsAlive, Is.False); + Assert.That(check.closed); MySqlCommand cmd = new MySqlCommand("KILL " + threadId, Connection); cmd.ExecuteNonQuery(); @@ -294,10 +381,10 @@ public async Task TransactionAsync() MySqlTransaction txn = await Connection.BeginTransactionAsync(); MySqlConnection c = txn.Connection; - Assert.AreEqual(Connection, c); + Assert.That(c, Is.EqualTo(Connection)); MySqlCommand cmd = new MySqlCommand("SELECT name, name2 FROM TranAsyncTest WHERE key2='P'", Connection, txn); MySqlTransaction t2 = cmd.Transaction; - Assert.AreEqual(txn, t2); + Assert.That(t2, Is.EqualTo(txn)); MySqlDataReader reader = null; try { @@ -307,7 +394,7 @@ public async Task TransactionAsync() } catch (Exception ex) { - Assert.False(ex.Message != string.Empty, ex.Message); + Assert.That(ex.Message != string.Empty, Is.False, ex.Message); txn.Rollback(); } finally @@ -335,9 +422,9 @@ public async Task OpenAndCloseConnectionAsync() { var conn = new MySqlConnection(Connection.ConnectionString); await conn.OpenAsync(); - Assert.True(conn.State == ConnectionState.Open); + Assert.That(conn.State == ConnectionState.Open); await conn.CloseAsync(); - Assert.True(conn.State == ConnectionState.Closed); + Assert.That(conn.State == ConnectionState.Closed); } [Test] @@ -370,7 +457,7 @@ public async Task ClearAllPoolsAsync() public async Task GetSchemaCollectionAsync() { var schemaColl = await Connection.GetSchemaCollectionAsync("MetaDataCollections", null); - Assert.NotNull(schemaColl); + Assert.That(schemaColl, Is.Not.Null); } #endregion @@ -409,7 +496,7 @@ public void TestPersistSecurityInfoCachingPasswords() c.Open(); c.Close(); MySqlConnectionStringBuilder afterOpenSettings = new MySqlConnectionStringBuilder(c.ConnectionString); - Assert.AreEqual(connStr.Password, afterOpenSettings.Password); + Assert.That(afterOpenSettings.Password, Is.EqualTo(connStr.Password)); // Persist Security Info = false means that it should not be returned connStr.PersistSecurityInfo = false; @@ -417,7 +504,7 @@ public void TestPersistSecurityInfoCachingPasswords() c.Open(); c.Close(); afterOpenSettings = new MySqlConnectionStringBuilder(c.ConnectionString); - Assert.True(String.IsNullOrEmpty(afterOpenSettings.Password)); + Assert.That(String.IsNullOrEmpty(afterOpenSettings.Password)); } /// @@ -433,65 +520,69 @@ public void CloneConnectionDisclosePassword() MySqlConnection c = new MySqlConnection(connStr.ConnectionString); // The password, is not returned as part of the connection if the connection is open or has ever been in an open state - StringAssert.Contains("password", c.ConnectionString); + Assert.That(c.ConnectionString, Does.Contain("password")); // After open password should not be displayed c.Open(); - StringAssert.DoesNotContain("password", c.ConnectionString); + Assert.That(c.ConnectionString, Does.Not.Contain("password")); // Verify clone from open connection should not show password var cloneConnection = (MySqlConnection)c.Clone(); - StringAssert.DoesNotContain("password", cloneConnection.ConnectionString); + Assert.That(cloneConnection.ConnectionString, Does.Not.Contain("password")); // After close connection the password should not be displayed c.Close(); - StringAssert.DoesNotContain("password", c.ConnectionString); + Assert.That(c.ConnectionString, Does.Not.Contain("password")); // Verify clone connection doesn't show password after open connection cloneConnection.Open(); - StringAssert.DoesNotContain("password", cloneConnection.ConnectionString); + Assert.That(cloneConnection.ConnectionString, Does.Not.Contain("password")); // Verify clone connection doesn't show password after close connection cloneConnection.Close(); - StringAssert.DoesNotContain("password", cloneConnection.ConnectionString); + Assert.That(cloneConnection.ConnectionString, Does.Not.Contain("password")); // Verify password for a clone of closed connection, password should appears var closedConnection = new MySqlConnection(connStr.ConnectionString); var cloneClosed = (MySqlConnection)closedConnection.Clone(); - StringAssert.Contains("password", cloneClosed.ConnectionString); + Assert.That(cloneClosed.ConnectionString, Does.Contain("password")); // Open connection of a closed connection clone, password should be empty - Assert.False(cloneClosed.hasBeenOpen); + Assert.That(cloneClosed.hasBeenOpen, Is.False); cloneClosed.Open(); - StringAssert.DoesNotContain("password", cloneClosed.ConnectionString); - Assert.True(cloneClosed.hasBeenOpen); + Assert.That(cloneClosed.ConnectionString, Does.Not.Contain("password")); + Assert.That(cloneClosed.hasBeenOpen); // Close connection of a closed connection clone, password should be empty cloneClosed.Close(); - StringAssert.DoesNotContain("password", cloneClosed.ConnectionString); + Assert.That(cloneClosed.ConnectionString, Does.Not.Contain("password")); // Clone Password shloud be present if PersistSecurityInfo is true connStr.PersistSecurityInfo = true; c = new MySqlConnection(connStr.ConnectionString); cloneConnection = (MySqlConnection)c.Clone(); - StringAssert.Contains("password", cloneConnection.ConnectionString); + Assert.That(cloneConnection.ConnectionString, Does.Contain("password")); } [Test] [Property("Category", "Security")] public void ConnectionTimeout() { + MockServer mServer=new MockServer(false); + mServer.StartServer(); + MySqlConnectionStringBuilder connStr = new MySqlConnectionStringBuilder(Connection.ConnectionString); - connStr.Server = "10.20.30.40"; - connStr.Port = 3000; + connStr.Server = mServer.Address.ToString(); + connStr.Port = (uint)mServer.Port; connStr.ConnectionTimeout = 5; MySqlConnection c = new MySqlConnection(connStr.GetConnectionString(true)); - DateTime start = DateTime.Now; var ex = Assert.Throws(() => c.Open()); - Assert.True(ex.InnerException.InnerException is TimeoutException); TimeSpan diff = DateTime.Now.Subtract(start); - Assert.True(diff.TotalSeconds < 6, $"Timeout exceeded: {diff.TotalSeconds}"); + Assert.That(diff.TotalSeconds < 8, $"Timeout exceeded: {diff.TotalSeconds}"); + + mServer.StopServer(); + mServer.DisposeListener(); } [Test] @@ -552,12 +643,12 @@ public void PersistSecurityInfo() MySqlConnectionStringBuilder connStr = new MySqlConnectionStringBuilder(Connection.ConnectionString); connStr.PersistSecurityInfo = false; - Assert.False(String.IsNullOrEmpty(connStr.Password)); + Assert.That(String.IsNullOrEmpty(connStr.Password), Is.False); MySqlConnection c = new MySqlConnection(connStr.GetConnectionString(true)); c.Open(); c.Close(); connStr = new MySqlConnectionStringBuilder(c.ConnectionString); - Assert.True(String.IsNullOrEmpty(connStr.Password)); + Assert.That(String.IsNullOrEmpty(connStr.Password)); } /// @@ -585,13 +676,13 @@ public void CanOpenConnectionAfterAborting() { MySqlConnection connection = new MySqlConnection(Connection.ConnectionString); connection.Open(); - Assert.AreEqual(ConnectionState.Open, connection.State); + Assert.That(connection.State, Is.EqualTo(ConnectionState.Open)); connection.AbortAsync(false).GetAwaiter().GetResult(); - Assert.AreEqual(ConnectionState.Closed, connection.State); + Assert.That(connection.State, Is.EqualTo(ConnectionState.Closed)); connection.Open(); - Assert.AreEqual(ConnectionState.Open, connection.State); + Assert.That(connection.State, Is.EqualTo(ConnectionState.Open)); connection.Close(); } @@ -609,7 +700,7 @@ public void ConnectAttributes() MySqlCommand cmd = new MySqlCommand("SELECT * FROM performance_schema.session_connect_attrs WHERE PROCESSLIST_ID = connection_id()", Connection); MySqlDataReader dr = cmd.ExecuteReader(); - Assert.True(dr.HasRows, "No session_connect_attrs found"); + Assert.That(dr.HasRows, "No session_connect_attrs found"); MySqlConnectAttrs connectAttrs = new MySqlConnectAttrs(); bool isValidated = false; using (dr) @@ -618,13 +709,13 @@ public void ConnectAttributes() { if (dr.GetString(1).ToLowerInvariant().Contains("_client_name")) { - Assert.AreEqual(connectAttrs.ClientName, dr.GetString(2)); + Assert.That(dr.GetString(2), Is.EqualTo(connectAttrs.ClientName)); isValidated = true; break; } } } - Assert.True(isValidated, "Missing _client_name attribute"); + Assert.That(isValidated, "Missing _client_name attribute"); } /// @@ -655,7 +746,7 @@ public void PasswordExpiration() cmd.CommandText = "SELECT 1"; MySqlException ex = Assert.Throws(() => cmd.ExecuteScalar()); - Assert.AreEqual(1820, ex.Number); + Assert.That(ex.Number, Is.EqualTo(1820)); if (Version >= new Version(5, 7, 6)) cmd.CommandText = string.Format("SET PASSWORD = '{0}1'", _EXPIRED_USER); @@ -682,7 +773,7 @@ public void TestNonSupportedOptions() using (MySqlConnection c = new MySqlConnection(connstr)) { c.Open(); - Assert.AreEqual(ConnectionState.Open, c.State); + Assert.That(c.State, Is.EqualTo(ConnectionState.Open)); } } @@ -691,17 +782,17 @@ public void TestNonSupportedOptions() [Test] public void IPv6Connection() { - if (Version < new Version(5, 6, 0)) return; + Assume.That(Version >= new Version(5, 6, 0)); MySqlConnectionStringBuilder sb = new MySqlConnectionStringBuilder(Connection.ConnectionString); sb.Server = GetMySqlServerIp(true); - if (sb.Server == string.Empty) Assert.Ignore("No IPv6 available."); + Assume.That(sb.Server != string.Empty, "No IPv6 available."); using (MySqlConnection conn = new MySqlConnection(sb.ToString())) { conn.Open(); - Assert.AreEqual(ConnectionState.Open, conn.State); + Assert.That(conn.State, Is.EqualTo(ConnectionState.Open)); } } @@ -721,10 +812,10 @@ public void ExpiredPassword(string sql) using (MySqlConnection conn = new MySqlConnection(sb.ConnectionString)) { conn.Open(); - Assert.AreEqual(ConnectionState.Open, conn.State); + Assert.That(conn.State, Is.EqualTo(ConnectionState.Open)); MySqlCommand cmd = new MySqlCommand(sql, conn); var ex = Assert.Throws(() => cmd.ExecuteNonQuery()); - Assert.AreEqual(1820, ex.Number); + Assert.That(ex.Number, Is.EqualTo(1820)); } } @@ -763,7 +854,7 @@ public void ExpiredPwdWithOldPassword() { conn.Open(); MySqlCommand cmd = new MySqlCommand("SELECT 8", conn); - StringAssert.StartsWith("8", cmd.ExecuteScalar().ToString()); + Assert.That(cmd.ExecuteScalar().ToString(), Does.StartWith("8")); } sb.Password = expiredPwd; @@ -783,6 +874,8 @@ public void ExpiredPwdWithOldPassword() [Ignore("To be able to connect using Named Pipes, it requires to start the server supporting the protocol")] public void ConnectUsingNamedPipes() { + Assume.That(Platform.IsWindows(), "Named Pipes is only supported on Windows."); + var sb = new MySqlConnectionStringBuilder() { Server = Host, @@ -795,7 +888,55 @@ public void ConnectUsingNamedPipes() // Named Pipes connection protocol is not allowed to use SSL connections. using var conn = new MySqlConnection(sb.ConnectionString); var ex = Assert.Throws(() => conn.Open()); - StringAssert.AreEqualIgnoringCase(string.Format(Resources.SslNotAllowedForConnectionProtocol, sb.ConnectionProtocol), ex.Message); + Assert.That(ex.Message, Is.EqualTo(string.Format(Resources.SslNotAllowedForConnectionProtocol, sb.ConnectionProtocol)).IgnoreCase); + } + + /// + /// Bug#36208929 - Named pipe connection doesn't work in multithread environment + /// To be able to connect using Named Pipes, it requires to start the server supporting the protocol + /// mysqld --standalone --console --named-pipe=on + /// + [Test] + [Ignore("To be able to connect using Named Pipes, it requires to start the server supporting the protocol")] + public void NamedPipesMultithreadConnection() + { + Assume.That(Platform.IsWindows(), "Named Pipes is only supported on Windows."); + + var sb = new MySqlConnectionStringBuilder() + { + Server = Host, + UserID = RootUser, + ConnectionProtocol = MySqlConnectionProtocol.NamedPipe, + }; + + List threads = new List(); + for (int i = 0; i < 2; i++) + { + threads.Add(new Thread(() => + { + MySqlConnection connection = new MySqlConnection(sb.ConnectionString); + + Assert.DoesNotThrow(() => connection.Open()); + + for (int i = 0; i < 200; i++) + { + MySqlCommand cmd = connection.CreateCommand(); + cmd.CommandText = "Select CURRENT_USER();"; + cmd.CommandType = CommandType.Text; + Assert.DoesNotThrow(() => cmd.ExecuteNonQuery()); + } + })); + } + + foreach (Thread thread in threads) + { + thread.Start(); + } + + foreach (Thread thread in threads) + { + thread.Join(); + } } /// @@ -803,9 +944,10 @@ public void ConnectUsingNamedPipes() /// [Test] [Property("Category", "Security")] + [Ignore("To be able to connect using Shared Memory, it requires to start the server supporting the protocol")] public void ConnectUsingSharedMemory() { - if (!Platform.IsWindows()) Assert.Ignore("Shared Memory is only supported on Windows."); + Assume.That(Platform.IsWindows(), "Shared Memory is only supported on Windows."); var sb = new MySqlConnectionStringBuilder() { @@ -819,7 +961,7 @@ public void ConnectUsingSharedMemory() using (var conn = new MySqlConnection(sb.ConnectionString)) { conn.Open(); - Assert.AreEqual(ConnectionState.Open, conn.State); + Assert.That(conn.State, Is.EqualTo(ConnectionState.Open)); } // Shared Memory connection protocol is not allowed to use SSL connections. @@ -827,7 +969,55 @@ public void ConnectUsingSharedMemory() using (var conn = new MySqlConnection(sb.ConnectionString)) { var ex = Assert.Throws(() => conn.Open()); - StringAssert.AreEqualIgnoringCase(string.Format(Resources.SslNotAllowedForConnectionProtocol, sb.ConnectionProtocol), ex.Message); + Assert.That(ex.Message, Is.EqualTo(string.Format(Resources.SslNotAllowedForConnectionProtocol, sb.ConnectionProtocol)).IgnoreCase); + } + } + + /// + /// Bug#36208932 - Shared memory connection doesn't work in multithread environment + /// To be able to connect using Shared Memory, it requires to start the server supporting the protocol + /// mysqld --standalone --console --shared-memory=on + /// + [Test] + [Ignore("To be able to connect using Shared Memory, it requires to start the server supporting the protocol")] + public void SharedMemoryMultithreadConnection() + { + Assume.That(Platform.IsWindows(), "Shared Memory is only supported on Windows."); + + var sb = new MySqlConnectionStringBuilder() + { + Server = Host, + UserID = RootUser, + ConnectionProtocol = MySqlConnectionProtocol.SharedMemory, + }; + + List threads = new List(); + for (int i = 0; i < 2; i++) + { + threads.Add(new Thread(() => + { + MySqlConnection connection = new MySqlConnection(sb.ConnectionString); + + Assert.DoesNotThrow(() => connection.Open()); + + for (int i = 0; i < 200; i++) + { + MySqlCommand cmd = connection.CreateCommand(); + cmd.CommandText = "Select CURRENT_USER();"; + cmd.CommandType = CommandType.Text; + Assert.DoesNotThrow(() => cmd.ExecuteNonQuery()); + } + })); + } + + foreach (Thread thread in threads) + { + thread.Start(); + } + + foreach (Thread thread in threads) + { + thread.Join(); } } @@ -1029,7 +1219,7 @@ public void MediumTextMalformedPkg() string fullQuery = string.Format(query, sb.ToString(0, sb.Length - 2)); var res = MySqlHelper.ExecuteNonQuery(Connection.ConnectionString + ";ssl-mode=none", fullQuery, mySqlParameters.ToArray()); - Assert.AreEqual(res, 40000); + Assert.That(40000, Is.EqualTo(res)); ExecuteSQL("SET GLOBAL max_allowed_packet=1024000"); ExecuteSQL($"DROP TABLE `{Settings.Database}`.`testmalformed`;"); @@ -1038,7 +1228,7 @@ public void MediumTextMalformedPkg() [Test, Description("Verify Compression in classic protocol where default connection string is used without any option")] public void CompressionUnit() { - if (Version < new Version(8, 0, 0)) Assert.Ignore("This test is for MySql 8.0 or higher."); + Assume.That(Version >= new Version(8, 0, 0), "This test is for MySql 8.0 or higher."); using (var dbConn = new MySqlConnection(Connection.ConnectionString + ";UseCompression=True")) { var cmd = new MySqlCommand(); @@ -1055,9 +1245,9 @@ public void CompressionUnit() { if (i == 0) { - Assert.AreEqual("ON", reader.GetString(1)); + Assert.That(reader.GetString(1), Is.EqualTo("ON")); } - Assert.IsNotNull(reader.GetString(1)); + Assert.That(reader.GetString(1), Is.Not.Null); i++; } } @@ -1072,7 +1262,7 @@ public void CompressionUnit() { while (reader.Read()) { - Assert.IsNotNull(reader.GetString(0)); + Assert.That(reader.GetString(0), Is.Not.Null); i++; } } @@ -1096,9 +1286,9 @@ public void CompressionUnit() { if (i == 0) { - Assert.AreEqual("OFF", reader.GetString(1)); + Assert.That(reader.GetString(1), Is.EqualTo("OFF")); } - Assert.IsNotNull(reader.GetString(1)); + Assert.That(reader.GetString(1), Is.Not.Null); i++; } } @@ -1114,7 +1304,7 @@ public void CompressionUnit() { while (reader.Read()) { - Assert.IsNotNull(reader.GetString(0)); + Assert.That(reader.GetString(0), Is.Not.Null); i++; } } @@ -1126,7 +1316,7 @@ public void CompressionUnit() [Test, Description("Verify Compression in classic protocol where default connection string is used without any option")] public void CompressionValidationInClassicProtocol() { - if (Version < new Version(8, 0, 0)) Assert.Ignore("This test is for MySql 8.0 or higher."); + Assume.That(Version >= new Version(8, 0, 0), "This test is for MySql 8.0 or higher."); string[] compressionAlgorithms = new string[] { "zlib", "zstd", "uncompressed", "uncompressed,zlib", "uncompressed,zstd", "zstd,zlib", "zstd,zlib,uncompressed" }; for (int k = 0; k < compressionAlgorithms.Length; k++) { @@ -1140,7 +1330,7 @@ public void CompressionValidationInClassicProtocol() } dbConn.Open(); - Assert.AreEqual(ConnectionState.Open, dbConn.State); + Assert.That(dbConn.State, Is.EqualTo(ConnectionState.Open)); MySqlCommand cmd = new MySqlCommand(); cmd.Connection = dbConn; cmd.CommandText = "select * from performance_schema.session_status where variable_name like 'COMPRESSION%' order by 1"; @@ -1157,14 +1347,14 @@ public void CompressionValidationInClassicProtocol() { // Compression should have been set to OFF as UseCompression is set to True in connection string but server is // started with uncompressed and uncompressed/zstd - Assert.AreEqual("OFF", reader.GetString(1)); + Assert.That(reader.GetString(1), Is.EqualTo("OFF")); } else { - Assert.AreEqual("ON", reader.GetString(1)); + Assert.That(reader.GetString(1), Is.EqualTo("ON")); } } - Assert.IsNotNull(reader.GetString(1)); + Assert.That(reader.GetString(1), Is.Not.Null); i++; } } @@ -1179,7 +1369,7 @@ public void CompressionValidationInClassicProtocol() { while (reader.Read()) { - Assert.AreEqual(compressionAlgorithms[k], reader.GetString(0)); + Assert.That(reader.GetString(0), Is.EqualTo(compressionAlgorithms[k])); i++; } } @@ -1210,7 +1400,7 @@ public void CompressionValidationInClassicProtocol() } dbConn.Open(); - Assert.AreEqual(ConnectionState.Open, dbConn.State); + Assert.That(dbConn.State, Is.EqualTo(ConnectionState.Open)); MySqlCommand cmd = new MySqlCommand(); cmd.Connection = dbConn; cmd.CommandText = "select * from performance_schema.session_status where variable_name like 'COMPRESSION%' order by 1"; @@ -1223,9 +1413,9 @@ public void CompressionValidationInClassicProtocol() { if (i == 0) { - Assert.AreEqual("OFF", reader.GetString(1)); + Assert.That(reader.GetString(1), Is.EqualTo("OFF")); } - Assert.IsNotNull(reader.GetString(1)); + Assert.That(reader.GetString(1), Is.Not.Null); i++; } } @@ -1240,7 +1430,7 @@ public void CompressionValidationInClassicProtocol() { while (reader.Read()) { - Assert.AreEqual(compressionAlgorithms[k], reader.GetString(0)); + Assert.That(reader.GetString(0), Is.EqualTo(compressionAlgorithms[k])); i++; } } @@ -1268,7 +1458,7 @@ public void CompressionValidationInClassicProtocol() [Test, Description("Test MySql Password Expiration with blank password")] public void ExpiredBlankPassword() { - if (Version < new Version(8, 0, 0)) Assert.Ignore("This test is for MySql 8.0 or higher."); + Assume.That(Version >= new Version(8, 0, 0), "This test is for MySql 8.0 or higher."); string host = Host == "localhost" ? Host : "%"; MySqlConnectionStringBuilder sb = new MySqlConnectionStringBuilder(Connection.ConnectionString); @@ -1303,7 +1493,7 @@ public void ExpiredBlankPassword() [Test, Description("Test MySql Password Expiration with query variables")] public void ExpiredPasswordBug2() { - if (Version < new Version(8, 0, 0)) Assert.Ignore("This test is for MySql 8.0 or higher."); + Assume.That(Version >= new Version(8, 0, 0), "This test is for MySql 8.0 or higher."); var _expiredPwd = "expiredPwd"; SetupExpiredPasswordUser(_expiredPwd); @@ -1328,7 +1518,7 @@ public void ExpiredPasswordBug2() [Test, Description("Test MySql Password Expiration with IsPasswordExpired validation")] public void ExpiredPasswordBug3() { - if (Version < new Version(8, 0, 0)) Assert.Ignore("This test is for MySql 8.0 or higher."); + Assume.That(Version >= new Version(8, 0, 0), "This test is for MySql 8.0 or higher."); string host = Host == "localhost" ? Host : "%"; var _expiredPwd = "expiredPwd"; @@ -1344,7 +1534,7 @@ public void ExpiredPasswordBug3() using (MySqlConnection conn = new MySqlConnection(sb.ConnectionString)) { conn.Open(); - Assert.True(conn.IsPasswordExpired); + Assert.That(conn.IsPasswordExpired); } ExecuteSQL($"ALTER USER '{_EXPIRED_USER}'@'{host}' Identified BY '{_newPwd}'"); @@ -1362,16 +1552,16 @@ public void ExpiredPasswordBug3() using (var rdr = cmd.ExecuteReader()) { while (rdr.Read()) - Assert.IsNotNull(rdr[0].ToString()); + Assert.That(rdr[0].ToString(), Is.Not.Null); } - Assert.False(conn.IsPasswordExpired); + Assert.That(conn.IsPasswordExpired, Is.False); } } [Test, Description("Test MySql Password Expiration and set password")] public void ExpiredPasswordBug4() { - if (Version < new Version(8, 0, 0)) Assert.Ignore("This test is for MySql 8.0 or higher."); + Assume.That(Version >= new Version(8, 0, 0), "This test is for MySql 8.0 or higher."); string host = Host == "localhost" ? Host : "%"; var _expiredPwd = "expiredPwd"; @@ -1386,7 +1576,7 @@ public void ExpiredPasswordBug4() using (MySqlConnection conn = new MySqlConnection(sb.ConnectionString)) { conn.Open(); - Assert.True(conn.IsPasswordExpired); + Assert.That(conn.IsPasswordExpired); } ExecuteSQL($"set password for {expiredFull}='{_newPwd}'"); @@ -1405,9 +1595,9 @@ public void ExpiredPasswordBug4() using (var rdr = cmd.ExecuteReader()) { while (rdr.Read()) - Assert.IsNotNull(rdr[0].ToString()); + Assert.That(rdr[0].ToString(), Is.Not.Null); } - Assert.False(conn.IsPasswordExpired); + Assert.That(conn.IsPasswordExpired, Is.False); } sb.UserID = _EXPIRED_USER; @@ -1428,7 +1618,7 @@ public void InvalidConnectTimeoutParameter() connStr = $"server={Settings.Server};user={Settings.UserID};port={Settings.Port};password={Settings.Password};connectiontimeout=10000"; using (var conn = new MySqlConnection(connStr)) { - Assert.IsInstanceOf(conn); + Assert.That(conn, Is.InstanceOf()); } } @@ -1437,9 +1627,9 @@ public void ConnectionDispose() { MySqlConnection conn = new MySqlConnection(Settings.ConnectionString); conn.Open(); - Assert.AreEqual(ConnectionState.Open, conn.connectionState); + Assert.That(conn.connectionState, Is.EqualTo(ConnectionState.Open)); conn.Dispose(); - Assert.AreEqual(ConnectionState.Closed, conn.connectionState); + Assert.That(conn.connectionState, Is.EqualTo(ConnectionState.Closed)); } [Test] @@ -1450,7 +1640,7 @@ public void ConnectionPasswordException() using (var conn = new MySqlConnection(myConnectionString)) { conn.Open(); - Assert.AreEqual(ConnectionState.Open, conn.State); + Assert.That(conn.State, Is.EqualTo(ConnectionState.Open)); } myConnectionString = $"server={Host};user={Settings.UserID};port={Port};password=wrong"; @@ -1458,7 +1648,7 @@ public void ConnectionPasswordException() { var ex = Assert.Throws(() => conn.Open()); code = ((MySqlException)ex.GetBaseException()).Number; - Assert.AreEqual(1045, code); + Assert.That(code, Is.EqualTo(1045)); } } @@ -1497,6 +1687,55 @@ public void OpenMultipleConnectionsOnMultipleThreads() Task.WaitAll(tasks.ToArray()); } + #if NET462 || NET48 + /// + /// Deadlock bug on application with Synchronization context (Net full framework Asp.NET app, Windows Forms App, WPF app. + /// Any App with - WindowsFormsSynchronizationContext, DispatcherSynchronizationContext and AspNetSynchronizationContext + /// will deadlock if missing ConfigureAwait(false) inside the MySql library. + /// + //[Test] + //public void OpenMultipleConnectionsOnMultipleThreadsInAppWithSynchronizationContext() + //{ + // var sb = new MySqlConnectionStringBuilder(Connection.ConnectionString); + // sb.Pooling = true; + + // var tasks = new List(); + // for (int i = 0; i < 5; i++) + // { + // tasks.Add(Task.Run(() => + // { + // SynchronizationContext.SetSynchronizationContext(new System.Windows.Forms.WindowsFormsSynchronizationContext()); + // using (var connection = new MySqlConnection(sb.ConnectionString)) + // { + // connection.Open(); + // } + // })); + // } + // Assert.IsTrue(Task.WaitAll(tasks.ToArray(),5000),"Deadlock when connecting - cancelled waiting after 5 seconds."); + //} + + //[Test] + //public void OpenAsyncMultipleConnectionsOnMultipleThreadsInAppWithSynchronizationContext() + //{ + // var sb = new MySqlConnectionStringBuilder(Connection.ConnectionString); + // sb.Pooling = true; + + // var tasks = new List(); + // for (int i = 0; i < 5; i++) + // { + // tasks.Add(Task.Run(() => + // { + // SynchronizationContext.SetSynchronizationContext(new System.Windows.Forms.WindowsFormsSynchronizationContext()); + // using (var connection = new MySqlConnection(sb.ConnectionString)) + // { + // connection.OpenAsync().ConfigureAwait(false).GetAwaiter().GetResult(); + // } + // })); + // } + // Assert.IsTrue(Task.WaitAll(tasks.ToArray(),5000),"Deadlock when connecting - cancelled waiting after 5 seconds."); + //} + #endif + #region Methods private void ExecuteQueriesSuccess(string sql, string password) @@ -1508,7 +1747,7 @@ private void ExecuteQueriesSuccess(string sql, string password) using (MySqlConnection conn = new MySqlConnection(sb.ConnectionString)) { conn.Open(); - Assert.AreEqual(ConnectionState.Open, conn.State); + Assert.That(conn.State, Is.EqualTo(ConnectionState.Open)); MySqlCommand cmd = new MySqlCommand(sql, conn); cmd.ExecuteNonQuery(); } @@ -1523,7 +1762,7 @@ private void ExecuteQueriesFail(string sql, string user, string password) using (MySqlConnection conn = new MySqlConnection(sb.ConnectionString)) { conn.Open(); - Assert.AreEqual(ConnectionState.Open, conn.State); + Assert.That(conn.State, Is.EqualTo(ConnectionState.Open)); MySqlCommand cmd = new MySqlCommand(sql, conn); Assert.Throws(() => cmd.ExecuteNonQuery()); } @@ -1539,7 +1778,7 @@ private void SetupExpirePasswordExecuteQueriesFail(string sql, string password) using (MySqlConnection conn = new MySqlConnection(sb.ConnectionString)) { conn.Open(); - Assert.AreEqual(ConnectionState.Open, conn.State); + Assert.That(conn.State, Is.EqualTo(ConnectionState.Open)); MySqlCommand cmd = new MySqlCommand(sql, conn); Assert.Throws(() => cmd.ExecuteNonQuery()); } diff --git a/MySQL.Data/tests/MySql.Data.Tests/DataTypeTests.cs b/MySQL.Data/tests/MySql.Data.Tests/DataTypeTests.cs index 3aefc8284..e3048f459 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/DataTypeTests.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/DataTypeTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2022, Oracle and/or its affiliates. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -28,6 +28,7 @@ using MySql.Data.Types; using NUnit.Framework; +using NUnit.Framework.Legacy; using System; using System.Data; using System.Text; @@ -64,19 +65,19 @@ private void InternalBytesAndBooleans(bool prepare) if (prepare) cmd.Prepare(); using (MySqlDataReader reader = cmd.ExecuteReader()) { - Assert.True(reader.Read()); + Assert.That(reader.Read()); Assert.Throws(() => reader.GetByte(0)); - Assert.AreEqual(140, reader.GetByte(1)); - Assert.True(reader.GetBoolean(1)); - Assert.AreEqual(20, Convert.ToInt32(reader.GetUInt32(2))); - Assert.AreEqual(20, reader.GetInt32(2)); + Assert.That(reader.GetByte(1), Is.EqualTo(140)); + Assert.That(reader.GetBoolean(1)); + Assert.That(Convert.ToInt32(reader.GetUInt32(2)), Is.EqualTo(20)); + Assert.That(reader.GetInt32(2), Is.EqualTo(20)); - Assert.True(reader.Read()); - Assert.AreEqual(0, reader.GetByte(0)); - Assert.AreEqual(0, reader.GetByte(1)); - Assert.False(reader.GetBoolean(1)); + Assert.That(reader.Read()); + Assert.That(reader.GetByte(0), Is.EqualTo(0)); + Assert.That(reader.GetByte(1), Is.EqualTo(0)); + Assert.That(reader.GetBoolean(1), Is.False); - Assert.False(reader.Read()); + Assert.That(reader.Read(), Is.False); } } @@ -97,21 +98,21 @@ public void TreatTinyAsBool() ExecuteSQL("INSERT INTO Test2 VALUES(0)"); ExecuteSQL("INSERT INTO Test2 VALUES(2)"); MySqlConnectionStringBuilder builder = new MySqlConnectionStringBuilder(Connection.ConnectionString); - Assert.True(builder.TreatTinyAsBoolean); + Assert.That(builder.TreatTinyAsBoolean); MySqlCommand cmd = new MySqlCommand("SELECT * from Test2", Connection); using (MySqlDataReader reader = cmd.ExecuteReader()) { bool b; - Assert.True(reader.Read()); + Assert.That(reader.Read()); b = (bool)reader.GetValue(0); - Assert.True(b); - Assert.True(reader.Read()); + Assert.That(b); + Assert.That(reader.Read()); b = (bool)reader.GetValue(0); - Assert.False(b); - Assert.True(reader.Read()); + Assert.That(b, Is.False); + Assert.That(reader.Read()); b = (bool)reader.GetValue(0); - Assert.True(b); + Assert.That(b); } } @@ -141,28 +142,28 @@ private void InternalTestFloats(bool prepared) if (prepared) cmd.Prepare(); int count = cmd.ExecuteNonQuery(); - Assert.AreEqual(1, count); + Assert.That(count, Is.EqualTo(1)); cmd.Parameters[0].Value = 1.5; cmd.Parameters[1].Value = 47.85; cmd.Parameters[2].Value = 123.85; count = cmd.ExecuteNonQuery(); - Assert.AreEqual(1, count); + Assert.That(count, Is.EqualTo(1)); cmd.CommandText = "SELECT * FROM Test"; if (prepared) cmd.Prepare(); using (MySqlDataReader reader = cmd.ExecuteReader()) { - Assert.True(reader.Read()); - Assert.True((decimal)2.3 == (decimal)reader.GetFloat(0)); - Assert.AreEqual(4.6, reader.GetDouble(1)); - Assert.True((decimal)23.82 == reader.GetDecimal(2)); - - Assert.True(reader.Read()); - Assert.True((decimal)1.5 == (decimal)reader.GetFloat(0)); - Assert.AreEqual(47.85, reader.GetDouble(1)); - Assert.True((decimal)123.85 == reader.GetDecimal(2)); + Assert.That(reader.Read()); + Assert.That((decimal)2.3 == (decimal)reader.GetFloat(0)); + Assert.That(reader.GetDouble(1), Is.EqualTo(4.6)); + Assert.That((decimal)23.82 == reader.GetDecimal(2)); + + Assert.That(reader.Read()); + Assert.That((decimal)1.5 == (decimal)reader.GetFloat(0)); + Assert.That(reader.GetDouble(1), Is.EqualTo(47.85)); + Assert.That((decimal)123.85 == reader.GetDecimal(2)); } } @@ -182,20 +183,20 @@ public void TestTime() reader.Read(); object value = reader["tm"]; - Assert.AreEqual(typeof(TimeSpan), value.GetType()); + Assert.That(value.GetType(), Is.EqualTo(typeof(TimeSpan))); TimeSpan ts = (TimeSpan)reader["tm"]; - Assert.AreEqual(0, ts.Hours); - Assert.AreEqual(0, ts.Minutes); - Assert.AreEqual(0, ts.Seconds); + Assert.That(ts.Hours, Is.EqualTo(0)); + Assert.That(ts.Minutes, Is.EqualTo(0)); + Assert.That(ts.Seconds, Is.EqualTo(0)); reader.Read(); value = reader["tm"]; - Assert.AreEqual(typeof(TimeSpan), value.GetType()); + Assert.That(value.GetType(), Is.EqualTo(typeof(TimeSpan))); ts = (TimeSpan)reader["tm"]; - Assert.AreEqual(21, ts.Days); - Assert.AreEqual(8, ts.Hours); - Assert.AreEqual(45, ts.Minutes); - Assert.AreEqual(17, ts.Seconds); + Assert.That(ts.Days, Is.EqualTo(21)); + Assert.That(ts.Hours, Is.EqualTo(8)); + Assert.That(ts.Minutes, Is.EqualTo(45)); + Assert.That(ts.Seconds, Is.EqualTo(17)); } } @@ -213,13 +214,13 @@ public void YearType() using (MySqlDataReader reader = cmd.ExecuteReader()) { reader.Read(); - Assert.True(1998 == reader.GetUInt32(0)); + Assert.That(1998 == reader.GetUInt32(0)); reader.Read(); - Assert.True(1990 == reader.GetUInt32(0)); + Assert.That(1990 == reader.GetUInt32(0)); reader.Read(); - Assert.True(2004 == reader.GetUInt32(0)); + Assert.That(2004 == reader.GetUInt32(0)); reader.Read(); - Assert.True(0 == reader.GetUInt32(0)); + Assert.That(0 == reader.GetUInt32(0)); } } @@ -227,16 +228,16 @@ public void YearType() public void TypeCoercion() { MySqlParameter p = new MySqlParameter("?test", 1); - Assert.AreEqual(DbType.Int32, p.DbType); - Assert.AreEqual(MySqlDbType.Int32, p.MySqlDbType); + Assert.That(p.DbType, Is.EqualTo(DbType.Int32)); + Assert.That(p.MySqlDbType, Is.EqualTo(MySqlDbType.Int32)); p.DbType = DbType.Int64; - Assert.AreEqual(DbType.Int64, p.DbType); - Assert.AreEqual(MySqlDbType.Int64, p.MySqlDbType); + Assert.That(p.DbType, Is.EqualTo(DbType.Int64)); + Assert.That(p.MySqlDbType, Is.EqualTo(MySqlDbType.Int64)); p.MySqlDbType = MySqlDbType.Int16; - Assert.AreEqual(DbType.Int16, p.DbType); - Assert.AreEqual(MySqlDbType.Int16, p.MySqlDbType); + Assert.That(p.DbType, Is.EqualTo(DbType.Int16)); + Assert.That(p.MySqlDbType, Is.EqualTo(MySqlDbType.Int16)); } [Test] @@ -287,18 +288,18 @@ public void BitAndDecimal() MySqlCommand cmd = new MySqlCommand("SELECT * FROM Test", c); using (MySqlDataReader reader = cmd.ExecuteReader()) { - Assert.True(reader.Read()); - Assert.AreEqual(2, reader.GetInt32(0)); - Assert.AreEqual(3, reader.GetInt32(1)); - Assert.AreEqual(120, reader.GetInt32(2)); - Assert.AreEqual(240, reader.GetInt32(3)); - Assert.AreEqual(1000, reader.GetInt32(4)); - Assert.True(reader.Read()); - Assert.True(reader.IsDBNull(0)); - Assert.True(reader.IsDBNull(1)); - Assert.AreEqual(100, reader.GetInt32(2)); - Assert.True(reader.IsDBNull(3)); - Assert.True(reader.IsDBNull(4)); + Assert.That(reader.Read()); + Assert.That(reader.GetInt32(0), Is.EqualTo(2)); + Assert.That(reader.GetInt32(1), Is.EqualTo(3)); + Assert.That(reader.GetInt32(2), Is.EqualTo(120)); + Assert.That(reader.GetInt32(3), Is.EqualTo(240)); + Assert.That(reader.GetInt32(4), Is.EqualTo(1000)); + Assert.That(reader.Read()); + Assert.That(reader.IsDBNull(0)); + Assert.That(reader.IsDBNull(1)); + Assert.That(reader.GetInt32(2), Is.EqualTo(100)); + Assert.That(reader.IsDBNull(3)); + Assert.That(reader.IsDBNull(4)); } } } @@ -310,24 +311,24 @@ public void DecimalTests() MySqlCommand cmd = new MySqlCommand("INSERT INTO Test VALUES(?dec)", Connection); cmd.Parameters.AddWithValue("?dec", (decimal)2.4); - Assert.AreEqual(1, cmd.ExecuteNonQuery()); + Assert.That(cmd.ExecuteNonQuery(), Is.EqualTo(1)); cmd.Prepare(); - Assert.AreEqual(1, cmd.ExecuteNonQuery()); + Assert.That(cmd.ExecuteNonQuery(), Is.EqualTo(1)); cmd.CommandText = "SELECT * FROM Test"; using (MySqlDataReader reader = cmd.ExecuteReader()) { - Assert.True(reader.Read()); - Assert.True(reader[0] is Decimal); - Assert.AreEqual((decimal)2.4, Convert.ToDecimal(reader[0])); + Assert.That(reader.Read()); + Assert.That(reader[0] is Decimal); + Assert.That(Convert.ToDecimal(reader[0]), Is.EqualTo((decimal)2.4)); - Assert.True(reader.Read()); - Assert.True(reader[0] is Decimal); - Assert.AreEqual((decimal)2.4, Convert.ToDecimal(reader[0])); + Assert.That(reader.Read()); + Assert.That(reader[0] is Decimal); + Assert.That(Convert.ToDecimal(reader[0]), Is.EqualTo((decimal)2.4)); - Assert.False(reader.Read()); - Assert.False(reader.NextResult()); + Assert.That(reader.Read(), Is.False); + Assert.That(reader.NextResult(), Is.False); } } @@ -338,24 +339,24 @@ public void DecimalTests2() MySqlCommand cmd = new MySqlCommand("INSERT INTO Test VALUES(?dec)", Connection); cmd.Parameters.AddWithValue("?dec", (decimal)2.4); - Assert.AreEqual(1, cmd.ExecuteNonQuery()); + Assert.That(cmd.ExecuteNonQuery(), Is.EqualTo(1)); cmd.Prepare(); - Assert.AreEqual(1, cmd.ExecuteNonQuery()); + Assert.That(cmd.ExecuteNonQuery(), Is.EqualTo(1)); cmd.CommandText = "SELECT * FROM Test"; using (MySqlDataReader reader = cmd.ExecuteReader()) { - Assert.True(reader.Read()); - Assert.True(reader[0] is Decimal); - Assert.AreEqual((decimal)2.4, Convert.ToDecimal(reader[0])); + Assert.That(reader.Read()); + Assert.That(reader[0] is Decimal); + Assert.That(Convert.ToDecimal(reader[0]), Is.EqualTo((decimal)2.4)); - Assert.True(reader.Read()); - Assert.True(reader[0] is Decimal); - Assert.AreEqual((decimal)2.4, Convert.ToDecimal(reader[0])); + Assert.That(reader.Read()); + Assert.That(reader[0] is Decimal); + Assert.That(Convert.ToDecimal(reader[0]), Is.EqualTo((decimal)2.4)); - Assert.False(reader.Read()); - Assert.False(reader.NextResult()); + Assert.That(reader.Read(), Is.False); + Assert.That(reader.NextResult(), Is.False); } } @@ -378,10 +379,10 @@ public void Bit() cmd.Prepare(); using (MySqlDataReader reader = cmd.ExecuteReader()) { - Assert.True(reader.Read()); - Assert.AreEqual(1, Convert.ToInt32(reader[0])); - Assert.AreEqual(2, Convert.ToInt32(reader[1])); - Assert.AreEqual(3, Convert.ToInt32(reader[2])); + Assert.That(reader.Read()); + Assert.That(Convert.ToInt32(reader[0]), Is.EqualTo(1)); + Assert.That(Convert.ToInt32(reader[1]), Is.EqualTo(2)); + Assert.That(Convert.ToInt32(reader[2]), Is.EqualTo(3)); } } @@ -399,10 +400,10 @@ public void UsingInt24InPreparedStatement(bool prepare, int value) command.Parameters.AddWithValue("@data", value).MySqlDbType = MySqlDbType.Int24; if (prepare) command.Prepare(); var rowsAffected = command.ExecuteNonQuery(); - Assert.AreEqual(1, rowsAffected); + Assert.That(rowsAffected, Is.EqualTo(1)); command.CommandText = "SELECT data FROM Test"; var data = command.ExecuteScalar(); - Assert.AreEqual(value, data); + Assert.That(data, Is.EqualTo(value)); } } @@ -437,9 +438,9 @@ public void TestNegativeTime() { reader.Read(); TimeSpan ts = reader.GetTimeSpan("t"); - Assert.AreEqual(-7, ts.Hours); - Assert.AreEqual(-24, ts.Minutes); - Assert.AreEqual(0, ts.Seconds); + Assert.That(ts.Hours, Is.EqualTo(-7)); + Assert.That(ts.Minutes, Is.EqualTo(-24)); + Assert.That(ts.Seconds, Is.EqualTo(0)); } } @@ -455,12 +456,10 @@ public void BinaryAndVarBinary() reader.Read(); byte[] buffer = new byte[2]; long read = reader.GetBytes(0, 0, buffer, 0, 2); - Assert.AreEqual('s', (char)buffer[0]); - Assert.AreEqual('o', (char)buffer[1]); - Assert.AreEqual(2, read); + Assert.That((char)buffer[0], Is.EqualTo('s')); + Assert.That((char)buffer[1], Is.EqualTo('o')); + Assert.That(read, Is.EqualTo(2)); - string s = reader.GetString(0); - Assert.AreEqual("something", s); } } @@ -471,10 +470,10 @@ public void NumericAsBinary() using (MySqlDataReader reader = cmd.ExecuteReader()) { reader.Read(); - Assert.AreEqual("BIGINT", reader.GetDataTypeName(0)); - Assert.AreEqual(typeof(Int64), reader.GetFieldType(0)); - Assert.AreEqual("System.Int64", reader.GetValue(0).GetType().FullName); - Assert.AreEqual(0, Convert.ToInt32(reader.GetValue(0))); + Assert.That(reader.GetDataTypeName(0), Is.EqualTo("BIGINT")); + Assert.That(reader.GetFieldType(0), Is.EqualTo(typeof(Int64))); + Assert.That(reader.GetValue(0).GetType().FullName, Is.EqualTo("System.Int64")); + Assert.That(Convert.ToInt32(reader.GetValue(0)), Is.EqualTo(0)); } } @@ -488,11 +487,11 @@ public void BinaryTypes() using (var reader = cmd.ExecuteReader()) { reader.Read(); - Assert.AreEqual(typeof(String), reader.GetFieldType("c1")); - Assert.AreEqual(typeof(byte[]), reader.GetFieldType("c2")); - Assert.AreEqual(typeof(String), reader.GetFieldType("c3")); - Assert.AreEqual(typeof(byte[]), reader.GetFieldType("c4")); - Assert.AreEqual(typeof(byte[]), reader.GetFieldType("c5")); + Assert.That(reader.GetFieldType("c1"), Is.EqualTo(typeof(String))); + Assert.That(reader.GetFieldType("c2"), Is.EqualTo(typeof(byte[]))); + Assert.That(reader.GetFieldType("c3"), Is.EqualTo(typeof(String))); + Assert.That(reader.GetFieldType("c4"), Is.EqualTo(typeof(byte[]))); + Assert.That(reader.GetFieldType("c5"), Is.EqualTo(typeof(byte[]))); } } @@ -509,8 +508,8 @@ AS TRUE_DEFAULT FROM INFORMATION_SCHEMA.COLUMNS using (var reader = cmd.ExecuteReader()) { reader.Read(); - Assert.AreEqual(typeof(string), reader.GetFieldType(0)); - Assert.AreEqual(typeof(Int64), reader.GetFieldType(1)); + Assert.That(reader.GetFieldType(0), Is.EqualTo(typeof(string))); + Assert.That(reader.GetFieldType(1), Is.EqualTo(typeof(Int64))); } } @@ -528,8 +527,8 @@ public void RespectBinaryFlag() using (var reader = cmd.ExecuteReader()) { reader.Read(); - Assert.AreEqual(typeof(string), reader.GetFieldType(0)); - Assert.AreEqual(typeof(System.Byte[]), reader.GetFieldType(1)); + Assert.That(reader.GetFieldType(0), Is.EqualTo(typeof(string))); + Assert.That(reader.GetFieldType(1), Is.EqualTo(typeof(System.Byte[]))); } } } @@ -547,14 +546,14 @@ public void Boolean() using (var reader = cmd.ExecuteReader()) { reader.Read(); - Assert.AreEqual(typeof(Boolean), reader.GetFieldType(1)); - Assert.AreEqual(typeof(SByte), reader.GetFieldType(2)); - Assert.True(reader.GetBoolean(1)); - Assert.AreEqual(1, Convert.ToInt32(reader.GetValue(2))); + Assert.That(reader.GetFieldType(1), Is.EqualTo(typeof(Boolean))); + Assert.That(reader.GetFieldType(2), Is.EqualTo(typeof(SByte))); + Assert.That(reader.GetBoolean(1)); + Assert.That(Convert.ToInt32(reader.GetValue(2)), Is.EqualTo(1)); reader.Read(); - Assert.False(reader.GetBoolean(1)); - Assert.AreEqual(0, Convert.ToInt32(reader.GetValue(2))); + Assert.That(reader.GetBoolean(1), Is.False); + Assert.That(Convert.ToInt32(reader.GetValue(2)), Is.EqualTo(0)); } } @@ -580,10 +579,10 @@ public void Binary16AsGuid() using (var reader = cmd2.ExecuteReader()) { reader.Read(); - Assert.AreEqual(typeof(Guid), reader.GetFieldType(1)); - Assert.AreEqual(typeof(byte[]), reader.GetFieldType(2)); - Assert.AreEqual(typeof(byte[]), reader.GetFieldType(3)); - Assert.AreEqual(g, reader.GetGuid(1)); + Assert.That(reader.GetFieldType(1), Is.EqualTo(typeof(Guid))); + Assert.That(reader.GetFieldType(2), Is.EqualTo(typeof(byte[]))); + Assert.That(reader.GetFieldType(3), Is.EqualTo(typeof(byte[]))); + Assert.That(reader.GetGuid(1), Is.EqualTo(g)); } string s = BitConverter.ToString(bytes); @@ -598,7 +597,7 @@ public void Binary16AsGuid() { reader.Read(); Guid g1 = reader.GetGuid(1); - Assert.AreEqual(g, g1); + Assert.That(g1, Is.EqualTo(g)); } } } @@ -642,22 +641,22 @@ Enabled bit(1) NOT NULL, PRIMARY KEY (`Id`)) LEFT OUTER JOIN Child c ON m.Id=c.MainId ORDER BY m.Descr", Connection); using (var reader = cmd.ExecuteReader()) { - Assert.True(reader.Read()); - Assert.AreEqual("AAA", reader.GetString(0)); - Assert.True(reader.IsDBNull(1)); - Assert.True(reader.IsDBNull(2)); - - Assert.True(reader.Read()); - Assert.AreEqual("BBB", reader.GetString(0)); - Assert.AreEqual(12345, Convert.ToInt32(reader.GetValue(1))); - Assert.AreEqual(1, Convert.ToInt32(reader.GetValue(2))); - - Assert.True(reader.Read()); - Assert.AreEqual("CCC", reader.GetString(0)); - Assert.True(reader.IsDBNull(1)); - Assert.True(reader.IsDBNull(2)); - - Assert.False(reader.Read()); + Assert.That(reader.Read()); + Assert.That(reader.GetString(0), Is.EqualTo("AAA")); + Assert.That(reader.IsDBNull(1)); + Assert.That(reader.IsDBNull(2)); + + Assert.That(reader.Read()); + Assert.That(reader.GetString(0), Is.EqualTo("BBB")); + Assert.That(Convert.ToInt32(reader.GetValue(1)), Is.EqualTo(12345)); + Assert.That(Convert.ToInt32(reader.GetValue(2)), Is.EqualTo(1)); + + Assert.That(reader.Read()); + Assert.That(reader.GetString(0), Is.EqualTo("CCC")); + Assert.That(reader.IsDBNull(1)); + Assert.That(reader.IsDBNull(2)); + + Assert.That(reader.Read(), Is.False); } } @@ -690,7 +689,7 @@ public void GeometryType() public void CanParseGeometryValueString() { var v = MySqlGeometry.Parse("POINT (47.37 -122.21)"); - Assert.AreEqual("POINT(47.37 -122.21)", v.ToString()); + Assert.That(v.ToString(), Is.EqualTo("POINT(47.37 -122.21)")); } [Test] @@ -698,7 +697,7 @@ public void CanTryParseGeometryValueString() { MySqlGeometry v = new MySqlGeometry(0, 0); MySqlGeometry.TryParse("POINT (47.37 -122.21)", out v); - Assert.AreEqual("POINT(47.37 -122.21)", v.ToString()); + Assert.That(v.ToString(), Is.EqualTo("POINT(47.37 -122.21)")); } [Test] @@ -706,7 +705,7 @@ public void CanTryParseGeometryValueStringWithSRIDValue() { var mysqlGeometryResult = new MySqlGeometry(0, 0); MySqlGeometry.TryParse("SRID=101;POINT (47.37 -122.21)", out mysqlGeometryResult); - Assert.AreEqual("SRID=101;POINT(47.37 -122.21)", mysqlGeometryResult.ToString()); + Assert.That(mysqlGeometryResult.ToString(), Is.EqualTo("SRID=101;POINT(47.37 -122.21)")); } [Test] @@ -756,7 +755,7 @@ public void CanFetchGeometryAsBinary() reader.Read(); var val = reader.GetValue(0) as Byte[]; var MyGeometry = new MySqlGeometry(MySqlDbType.Geometry, val); - Assert.AreEqual("POINT(47.37 -122.21)", MyGeometry.ToString()); + Assert.That(MyGeometry.ToString(), Is.EqualTo("POINT(47.37 -122.21)")); } } @@ -777,12 +776,10 @@ public void CanSaveSridValueOnGeometry() "SELECT ST_SRID(v) FROM Test" : "SELECT SRID(v) FROM Test"; - using (MySqlDataReader reader = cmd.ExecuteReader()) - { - reader.Read(); - var val = reader.GetString(0); - Assert.AreEqual("101", val); - } + using var reader = cmd.ExecuteReader(); + reader.Read(); + var val = reader.GetInt32(0); + Assert.That(val, Is.EqualTo(101)); } [Test] @@ -806,7 +803,7 @@ public void CanFetchGeometryAsText() { reader.Read(); var val = reader.GetString(0); - Assert.AreEqual("POINT(47.37 -122.21)", val); + Assert.That(val, Is.EqualTo("POINT(47.37 -122.21)")); } } @@ -833,8 +830,8 @@ public void CanUseReaderGetMySqlGeometry() reader.Read(); var val = reader.GetMySqlGeometry(0); var valWithName = reader.GetMySqlGeometry("v"); - Assert.AreEqual("POINT(47.37 -122.21)", val.ToString()); - Assert.AreEqual("POINT(47.37 -122.21)", valWithName.ToString()); + Assert.That(val.ToString(), Is.EqualTo("POINT(47.37 -122.21)")); + Assert.That(valWithName.ToString(), Is.EqualTo("POINT(47.37 -122.21)")); } // reading as geometry @@ -844,8 +841,8 @@ public void CanUseReaderGetMySqlGeometry() reader.Read(); var val = reader.GetMySqlGeometry(0); var valWithName = reader.GetMySqlGeometry("v"); - Assert.AreEqual("POINT(47.37 -122.21)", val.ToString()); - Assert.AreEqual("POINT(47.37 -122.21)", valWithName.ToString()); + Assert.That(val.ToString(), Is.EqualTo("POINT(47.37 -122.21)")); + Assert.That(valWithName.ToString(), Is.EqualTo("POINT(47.37 -122.21)")); } } @@ -855,7 +852,7 @@ public void CanGetToStringFromMySqlGeometry() { MySqlGeometry v = new MySqlGeometry(47.37, -122.21); var valToString = v.ToString(); - Assert.AreEqual("POINT(47.37 -122.21)", valToString); + Assert.That(valToString, Is.EqualTo("POINT(47.37 -122.21)")); } /// @@ -867,9 +864,9 @@ public void CanCreateMySqlGeometryFromEmptyGeometryCollection() var bytes = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; MySqlGeometry v = new MySqlGeometry(MySqlDbType.Geometry, bytes); #if !NETFRAMEWORK - Assert.AreEqual("POINT(3.5E-323 0)", v.ToString()); + Assert.That(v.ToString(), Is.EqualTo("POINT(3.5E-323 0)")); #else - Assert.AreEqual("POINT(3.45845952088873E-323 0)", v.ToString()); + Assert.That(v.ToString(), Is.EqualTo("POINT(3.45845952088873E-323 0)")); #endif } @@ -893,8 +890,8 @@ public void CanGetMySqlGeometryFromEmptyGeometryCollection() reader.Read(); var val = reader.GetMySqlGeometry(0); var valWithName = reader.GetMySqlGeometry("v"); - Assert.AreEqual("POINT(0 0)", val.ToString()); - Assert.AreEqual("POINT(0 0)", valWithName.ToString()); + Assert.That(val.ToString(), Is.EqualTo("POINT(0 0)")); + Assert.That(valWithName.ToString(), Is.EqualTo("POINT(0 0)")); } // reading as geometry @@ -905,11 +902,11 @@ public void CanGetMySqlGeometryFromEmptyGeometryCollection() var val = reader.GetMySqlGeometry(0); var valWithName = reader.GetMySqlGeometry("v"); #if !NETFRAMEWORK - Assert.AreEqual("POINT(3.5E-323 0)", val.ToString()); - Assert.AreEqual("POINT(3.5E-323 0)", valWithName.ToString()); + Assert.That(val.ToString(), Is.EqualTo("POINT(3.5E-323 0)")); + Assert.That(valWithName.ToString(), Is.EqualTo("POINT(3.5E-323 0)")); #else - Assert.AreEqual("POINT(3.45845952088873E-323 0)", val.ToString()); - Assert.AreEqual("POINT(3.45845952088873E-323 0)", valWithName.ToString()); + Assert.That(val.ToString(), Is.EqualTo("POINT(3.45845952088873E-323 0)")); + Assert.That(valWithName.ToString(), Is.EqualTo("POINT(3.45845952088873E-323 0)")); #endif } } @@ -931,7 +928,7 @@ public void Bug30169716() command.CommandText = "INSERT INTO geometries(data) VALUES(@data); "; command.Parameters.AddWithValue("@data", geometry); int result = command.ExecuteNonQuery(); - Assert.AreEqual(1, result); + Assert.That(result, Is.EqualTo(1)); } } @@ -955,7 +952,7 @@ public void StoringAndRetrievingDouble() { reader.Read(); double d = reader.GetDouble(0); - Assert.AreEqual(Math.PI, d); + Assert.That(d, Is.EqualTo(Math.PI)); } } @@ -973,9 +970,9 @@ public void SByteFromReader() using (MySqlDataReader reader = cmd.ExecuteReader()) { reader.Read(); - Assert.AreEqual(99, reader.GetSByte(0)); - Assert.AreEqual(217, reader.GetByte(1)); - Assert.AreEqual(99, reader.GetByte(0)); + Assert.That(reader.GetSByte(0), Is.EqualTo(99)); + Assert.That(reader.GetByte(1), Is.EqualTo(217)); + Assert.That(reader.GetByte(0), Is.EqualTo(99)); } } @@ -998,8 +995,8 @@ public void NewGuidDataType() using (var reader = cmd.ExecuteReader()) { reader.Read(); - Assert.AreEqual(1, reader.GetValue(0)); - Assert.AreEqual(guid, reader.GetGuid(1)); + Assert.That(reader.GetValue(0), Is.EqualTo(1)); + Assert.That(reader.GetGuid(1), Is.EqualTo(guid)); } } } @@ -1032,11 +1029,11 @@ public void ReadBinary16AsBinary() reader.Read(); object o = reader.GetValue(1); - Assert.True(o is Guid); + Assert.That(o is Guid); byte[] bytes = new byte[16]; long size = reader.GetBytes(1, 0, bytes, 0, 16); - Assert.AreEqual(16, size); + Assert.That(size, Is.EqualTo(16)); } } } @@ -1053,7 +1050,7 @@ public void ReadingUUIDAsGuid() cmd.CommandText = "SELECT guid FROM Test"; Guid g = (Guid)cmd.ExecuteScalar(); - Assert.AreEqual(serverGuid, g); + Assert.That(g, Is.EqualTo(serverGuid)); } [Test] @@ -1068,7 +1065,7 @@ public void NewGuidType() cmd.CommandText = "SELECT guid FROM Test"; Guid readG = (Guid)cmd.ExecuteScalar(); - Assert.AreEqual(g, readG); + Assert.That(readG, Is.EqualTo(g)); } /// @@ -1091,9 +1088,9 @@ public void NotGuidType() using (MySqlDataReader reader = cmd.ExecuteReader()) { reader.Read(); - Assert.True(reader["id"] is int); - Assert.True(reader["val"] is string); - Assert.True(reader["guid"] is Guid); + Assert.That(reader["id"] is int); + Assert.That(reader["val"] is string); + Assert.That(reader["guid"] is Guid); } } @@ -1152,7 +1149,7 @@ public void UTF8Char12AsGuid() { reader.Read(); string s = reader.GetString(1); - Assert.AreEqual("Name", s); + Assert.That(s, Is.EqualTo("Name")); } } } @@ -1172,13 +1169,13 @@ public void MySqlDecimal() reader.Read(); MySqlDecimal dec = reader.GetMySqlDecimal(1); string s = dec.ToString(); - Assert.AreEqual(9999999999999999999999999999999999.99, dec.ToDouble()); - Assert.AreEqual("9999999999999999999999999999999999.99", dec.ToString()); + Assert.That(dec.ToDouble(), Is.EqualTo(9999999999999999999999999999999999.99)); + Assert.That(dec.ToString(), Is.EqualTo("9999999999999999999999999999999999.99")); void Value() { _ = dec.Value; } Exception ex = Assert.Throws(() => Value()); - Assert.AreEqual("Value was either too large or too small for a Decimal.", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Value was either too large or too small for a Decimal.")); } } @@ -1202,10 +1199,10 @@ public void DoubleMinValue() { reader.Read(); double d = reader.GetDouble(0); - Assert.AreEqual(d, double.MinValue); + Assert.That(double.MinValue, Is.EqualTo(d)); reader.Read(); d = reader.GetDouble(0); - Assert.AreEqual(d, double.MaxValue); + Assert.That(double.MaxValue, Is.EqualTo(d)); } } @@ -1237,13 +1234,13 @@ public void Timediff() { MySqlCommand cmd = new MySqlCommand("select timediff('2 0:1:1.0', '4 1:2:3.123456')", Connection); var result = cmd.ExecuteScalar(); - Assert.AreEqual(new TimeSpan(new TimeSpan(-2, -1, -1, -2).Ticks - 1234560), result); + Assert.That(result, Is.EqualTo(new TimeSpan(new TimeSpan(-2, -1, -1, -2).Ticks - 1234560))); } [Test] public void CanReadJsonValue() { - if (Version < new Version(5, 7)) Assert.Ignore("This test is for MySql 5.7 or higher"); ; + Assume.That(Version >= new Version(5, 7, 0), "This test is for MySql 5.7 or higher."); ExecuteSQL("CREATE TABLE Test(Id int NOT NULL PRIMARY KEY, jsoncolumn JSON)"); MySqlCommand cmd = new MySqlCommand("INSERT INTO Test VALUES (@id, '[1]')", Connection); cmd.Parameters.AddWithValue("@id", 1); @@ -1255,8 +1252,8 @@ public void CanReadJsonValue() cmd = new MySqlCommand("SELECT jsoncolumn from Test where id = 2 ", Connection); using (MySqlDataReader reader = cmd.ExecuteReader()) { - Assert.True(reader.Read()); - Assert.AreEqual("[\"a\", {\"b\": [true, false]}, [10, 20]]", reader.GetString(0)); + Assert.That(reader.Read()); + Assert.That(reader.GetString(0), Is.EqualTo("[\"a\", {\"b\": [true, false]}, [10, 20]]")); } ExecuteSQL("delete from Test"); @@ -1283,13 +1280,13 @@ public void CanReadJsonValue() cmd = new MySqlCommand("SELECT jsoncolumn from Test where id = 2", Connection); using (var reader = cmd.ExecuteReader()) { - Assert.AreEqual(true, reader.Read(), "Matching the values"); + Assert.That(reader.Read(), Is.EqualTo(true), "Matching the values"); var checkValue = "{\"age\": 25, \"name\": \"Bob\"}"; - Assert.AreEqual(checkValue, reader.GetString(0), "Matching the values"); + Assert.That(reader.GetString(0), Is.EqualTo(checkValue), "Matching the values"); } cmd = new MySqlCommand("SELECT count(*) from Test", Connection); var count = cmd.ExecuteScalar(); - Assert.AreEqual(5, count); + Assert.That(count, Is.EqualTo(5)); cmd = new MySqlCommand(@"INSERT INTO Test VALUES(@id,' { ""name"" : ""harald"",""Date"": ""2013-08-07"",""Time"": ""11:18:29.000000"",""DateTimeOfRegistration"": ""2013-08-07 12:18:29.000000""} ')", Connection); @@ -1299,10 +1296,10 @@ public void CanReadJsonValue() cmd = new MySqlCommand("SELECT jsoncolumn from Test where id=1000", Connection); using (var reader = cmd.ExecuteReader()) { - Assert.AreEqual(true, reader.Read(), "Matching the values"); + Assert.That(reader.Read(), Is.EqualTo(true), "Matching the values"); var checkValue = "{\"Date\": \"2013-08-07\", \"Time\": \"11:18:29.000000\", \"name\": \"harald\", \"DateTimeOfRegistration\": \"2013-08-07 12:18:29.000000\"}"; - Assert.AreEqual(checkValue, reader.GetString(0), "Matching the values"); + Assert.That(reader.GetString(0), Is.EqualTo(checkValue), "Matching the values"); } //Multiple Columns @@ -1317,25 +1314,25 @@ public void CanReadJsonValue() cmd = new MySqlCommand("SELECT jsoncolumn1 from Test where id=100000", Connection); using (var reader = cmd.ExecuteReader()) { - Assert.AreEqual(true, reader.Read(), "Matching the values"); + Assert.That(reader.Read(), Is.EqualTo(true), "Matching the values"); var checkValue = "{\"name\": \"bob\"}"; - Assert.AreEqual(checkValue, reader.GetString(0), "Matching the values"); + Assert.That(reader.GetString(0), Is.EqualTo(checkValue), "Matching the values"); } cmd = new MySqlCommand("SELECT jsoncolumn2 from Test where id=100000", Connection); using (var reader = cmd.ExecuteReader()) { - Assert.AreEqual(true, reader.Read(), "Matching the values"); + Assert.That(reader.Read(), Is.EqualTo(true), "Matching the values"); var checkValue = "{\"marks\": 97}"; - Assert.AreEqual(checkValue, reader.GetString(0), "Matching the values"); + Assert.That(reader.GetString(0), Is.EqualTo(checkValue), "Matching the values"); } cmd = new MySqlCommand("SELECT jsoncolumn3 from Test where id=100000", Connection); using (var reader = cmd.ExecuteReader()) { - Assert.AreEqual(true, reader.Read(), "Matching the values"); + Assert.That(reader.Read(), Is.EqualTo(true), "Matching the values"); var checkValue = "{\"distinction\": true}"; - Assert.AreEqual(checkValue, reader.GetString(0), "Matching the values"); + Assert.That(reader.GetString(0), Is.EqualTo(checkValue), "Matching the values"); } } @@ -1358,8 +1355,8 @@ public void CanUpdateJsonValue() using (MySqlDataReader reader = cmd.ExecuteReader()) { - Assert.True(reader.Read()); - Assert.AreEqual("[\"a\", {\"b\": [true, false]}, [10, 20]]", reader.GetString(0)); + Assert.That(reader.Read()); + Assert.That(reader.GetString(0), Is.EqualTo("[\"a\", {\"b\": [true, false]}, [10, 20]]")); } cmd = new MySqlCommand(@"INSERT INTO Test VALUES(@id,' { ""name"" : ""bob"",""Date"": ""2015-10-09"",""Time"": ""12:18:29.000000"",""DateTimeOfRegistration"": ""2015-10-09 12:18:29.000000""} ')", @@ -1374,10 +1371,10 @@ public void CanUpdateJsonValue() cmd = new MySqlCommand("SELECT jsoncolumn from Test where id=100000", Connection); using (var reader = cmd.ExecuteReader()) { - Assert.AreEqual(true, reader.Read(), "Matching the values"); + Assert.That(reader.Read(), Is.EqualTo(true), "Matching the values"); var checkValue = "{\"Date\": \"2013-08-07\", \"Time\": \"11:18:29.000000\", \"name\": \"harald\", \"DateTimeOfRegistration\": \"2013-08-07 12:18:29.000000\"}"; - Assert.AreEqual(checkValue, reader.GetString(0), "Matching the values"); + Assert.That(reader.GetString(0), Is.EqualTo(checkValue), "Matching the values"); } } @@ -1415,8 +1412,8 @@ public void CanUseGeneratedColumns() using (MySqlDataReader reader = cmd.ExecuteReader()) { - Assert.True(reader.Read()); - Assert.True(reader.GetString(0).Equals("Berlin", StringComparison.CurrentCulture)); + Assert.That(reader.Read()); + Assert.That(reader.GetString(0).Equals("Berlin", StringComparison.CurrentCulture)); } } @@ -1437,7 +1434,7 @@ public void DateTimeTreatedAsVarChar() using (DataTable schema = reader.GetSchemaTable()) { MySqlDbType providerType = (MySqlDbType)(int)schema.Rows[0]["ProviderType"]; - Assert.AreEqual(MySqlDbType.DateTime, providerType); + Assert.That(providerType, Is.EqualTo(MySqlDbType.DateTime)); } } } @@ -1455,7 +1452,7 @@ public void NullGuid() using var reader = cmd.ExecuteReader(); while (reader.Read()) { - Assert.True(reader.IsDBNull(0)); + Assert.That(reader.IsDBNull(0)); } } @@ -1473,7 +1470,7 @@ public void ReadChar36ColumnPrepared() using var reader = cmd.ExecuteReader(); while (reader.Read()) { - StringAssert.AreEqualIgnoringCase(guid, reader.GetGuid(0).ToString()); + Assert.That(reader.GetGuid(0).ToString(), Is.EqualTo(guid).IgnoreCase); } } @@ -1495,10 +1492,10 @@ public void UnexpectedColumnSize() using (var reader = cmd.ExecuteReader()) { var schemaTable = reader.GetSchemaTable(); - Assert.AreEqual("36", schemaTable.Rows[0]["ColumnSize"].ToString(), "Matching the Column Size"); - Assert.AreEqual("37", schemaTable.Rows[1]["ColumnSize"].ToString(), "Matching the Column Size"); - Assert.AreEqual("255", schemaTable.Rows[2]["ColumnSize"].ToString(), "Matching the Column Size"); - Assert.AreEqual("65535", schemaTable.Rows[3]["ColumnSize"].ToString(), "Matching the Column Size"); + Assert.That(schemaTable.Rows[0]["ColumnSize"].ToString(), Is.EqualTo("36"), "Matching the Column Size"); + Assert.That(schemaTable.Rows[1]["ColumnSize"].ToString(), Is.EqualTo("37"), "Matching the Column Size"); + Assert.That(schemaTable.Rows[2]["ColumnSize"].ToString(), Is.EqualTo("255"), "Matching the Column Size"); + Assert.That(schemaTable.Rows[3]["ColumnSize"].ToString(), Is.EqualTo("65535"), "Matching the Column Size"); } } } @@ -1506,7 +1503,7 @@ public void UnexpectedColumnSize() [Test, Description("Test Can Read long JSON Values")] public void ReadJSONLongValues() { - if (Version < new Version(5, 7)) Assert.Ignore("This test is for MySql 5.7 or higher."); + Assume.That(Version >= new Version(5, 7, 0), "This test is for MySql 5.7 or higher."); var sb = new StringBuilder("0"); for (int x = 1; x <= 575; x++) { @@ -1525,9 +1522,9 @@ public void ReadJSONLongValues() cmd = new MySqlCommand("SELECT jsoncolumn from Test where id = " + i, Connection); using (var reader = cmd.ExecuteReader()) { - Assert.AreEqual(true, reader.Read(), "Matching the values"); + Assert.That(reader.Read(), Is.EqualTo(true), "Matching the values"); var checkValue = @"{""age"": " + i + "}"; - Assert.AreEqual(checkValue, reader.GetString(0), "Matching the values"); + Assert.That(reader.GetString(0), Is.EqualTo(checkValue), "Matching the values"); } // long string @@ -1540,17 +1537,17 @@ public void ReadJSONLongValues() cmd = new MySqlCommand("SELECT jsoncolumn from Test where id = 2", Connection); using (var reader = cmd.ExecuteReader()) { - Assert.AreEqual(true, reader.Read(), "Matching the values"); + Assert.That(reader.Read(), Is.EqualTo(true), "Matching the values"); var checkValue = @"{""name"": """ + sb.ToString() + @"""}"; - Assert.AreEqual(checkValue, reader.GetString(0), "Matching the values"); + Assert.That(reader.GetString(0), Is.EqualTo(checkValue), "Matching the values"); } } [Test, Description("Test Can Read JSON Value Stress")] public void ReadJSONValueStress() { - if (Version < new Version(5, 7)) Assert.Ignore("This test is for MySql 5.7 or higher."); + Assume.That(Version >= new Version(5, 7, 0), "This test is for MySql 5.7 or higher."); ExecuteSQL("CREATE TABLE Test (Id int NOT NULL PRIMARY KEY, jsoncolumn JSON)"); string jsonTest = null; for (var i = 0; i < 1000; i++) @@ -1565,9 +1562,9 @@ public void ReadJSONValueStress() using (var reader = cmd.ExecuteReader()) { - Assert.AreEqual(true, reader.Read(), "Matching the values"); + Assert.That(reader.Read(), Is.EqualTo(true), "Matching the values"); var checkValue = @"{""age"": " + i + "}"; - Assert.AreEqual(checkValue, reader.GetString(0), "Matching the values"); + Assert.That(reader.GetString(0), Is.EqualTo(checkValue), "Matching the values"); } } } @@ -1589,17 +1586,17 @@ public void ZeroTimeValues() command.Prepare(); using (var reader = command.ExecuteReader()) { - Assert.True(reader.Read()); - Assert.AreEqual("00:00:00", reader.GetValue(0).ToString()); - Assert.AreEqual("00:00:00", reader.GetTimeSpan(0).ToString()); + Assert.That(reader.Read()); + Assert.That(reader.GetValue(0).ToString(), Is.EqualTo("00:00:00")); + Assert.That(reader.GetTimeSpan(0).ToString(), Is.EqualTo("00:00:00")); - Assert.True(reader.Read()); - Assert.AreEqual("01:01:01", reader.GetValue(0).ToString()); - Assert.AreEqual("01:01:01", reader.GetTimeSpan(0).ToString()); + Assert.That(reader.Read()); + Assert.That(reader.GetValue(0).ToString(), Is.EqualTo("01:01:01")); + Assert.That(reader.GetTimeSpan(0).ToString(), Is.EqualTo("01:01:01")); - Assert.True(reader.Read()); - Assert.AreEqual("00:00:00", reader.GetValue(0).ToString()); - Assert.AreEqual("00:00:00", reader.GetTimeSpan(0).ToString()); + Assert.That(reader.Read()); + Assert.That(reader.GetValue(0).ToString(), Is.EqualTo("00:00:00")); + Assert.That(reader.GetTimeSpan(0).ToString(), Is.EqualTo("00:00:00")); } } } @@ -1621,14 +1618,14 @@ public void TimespanWithMicrosecondsPrepared() // Try the INSERT cmd.CommandText = "INSERT INTO Test VALUES(@value)"; cmd.Prepare(); - Assert.AreEqual(1, cmd.ExecuteNonQuery()); + Assert.That(cmd.ExecuteNonQuery(), Is.EqualTo(1)); // Try the SELECT cmd.CommandText = "SELECT tm FROM Test WHERE tm = @value;"; cmd.Prepare(); using var reader = cmd.ExecuteReader(); - Assert.IsTrue(reader.Read()); - Assert.AreEqual(value, reader.GetValue(0)); + Assert.That(reader.Read()); + Assert.That(reader.GetValue(0), Is.EqualTo(value)); } /// @@ -1651,17 +1648,110 @@ public void GetIntForTinyInt(bool treatAsBool, bool isPrepared) using var reader = cmd.ExecuteReader(); reader.Read(); - Assert.AreEqual(treatAsBool ? 1 : -2, reader.GetSByte(0)); + Assert.That(reader.GetSByte(0), Is.EqualTo(treatAsBool ? 1 : -2)); Assert.Throws(() => reader.GetByte(0)); - Assert.AreEqual(treatAsBool ? 1 : -2, reader.GetInt16(0)); - Assert.AreEqual(treatAsBool ? 1 : -2, reader.GetInt32(0)); - Assert.AreEqual(treatAsBool ? 1 : -2, reader.GetInt64(0)); + Assert.That(reader.GetInt16(0), Is.EqualTo(treatAsBool ? 1 : -2)); + Assert.That(reader.GetInt32(0), Is.EqualTo(treatAsBool ? 1 : -2)); + Assert.That(reader.GetInt64(0), Is.EqualTo(treatAsBool ? 1 : -2)); - Assert.AreEqual(treatAsBool ? 1 : -2, reader.GetFieldValue(0)); + Assert.That(reader.GetFieldValue(0), Is.EqualTo(treatAsBool ? 1 : -2)); Assert.Throws(() => reader.GetFieldValue(0)); - Assert.AreEqual(treatAsBool ? 1 : -2, reader.GetFieldValue(0)); - Assert.AreEqual(treatAsBool ? 1 : -2, reader.GetFieldValue(0)); - Assert.AreEqual(treatAsBool ? 1 : -2, reader.GetFieldValue(0)); + Assert.That(reader.GetFieldValue(0), Is.EqualTo(treatAsBool ? 1 : -2)); + Assert.That(reader.GetFieldValue(0), Is.EqualTo(treatAsBool ? 1 : -2)); + Assert.That(reader.GetFieldValue(0), Is.EqualTo(treatAsBool ? 1 : -2)); + } + + [Test] + public void BadVectorDataThrowsException() + { + Assume.That(Version >= new Version(9, 0, 0), "This test is for MySql 9.0 or higher."); + + ExecuteSQL(@"CREATE TABLE Test (vector1 VECTOR)"); + using var cmd = new MySqlCommand(); + cmd.Connection = Connection; + + // insert a value + cmd.CommandText = "INSERT INTO Test VALUES(@v1)"; + cmd.Parameters.Add("v1", MySqlDbType.Vector); + cmd.Parameters[0].Value = "not a vector value"; + Assert.Throws(() => cmd.ExecuteNonQuery()); + } + + [TestCase(false)] + [TestCase(true)] + public void InsertAndSelectVector(bool prepared) + { + Assume.That(Version >= new Version(9, 0, 0), "This test is for MySql 9.0 or higher."); + + ExecuteSQL(@"CREATE TABLE Test (vector1 VECTOR)"); + using var cmd = new MySqlCommand(); + cmd.Connection = Connection; + + // insert a value + cmd.CommandText = "INSERT INTO Test VALUES(@v1)"; + cmd.Parameters.Add("v1", MySqlDbType.Vector); + float[] floatArray = [1.2f, 2.3f, 3.4f]; + + // copy floats into byteArray + byte[] byteArray = new byte[floatArray.Length * 4]; + Buffer.BlockCopy(floatArray, 0, byteArray, 0, byteArray.Length); + + cmd.Parameters[0].Value = byteArray; + if (prepared) cmd.Prepare(); + cmd.ExecuteNonQuery(); + + // now select that value back out and compare + cmd.CommandText = "SELECT vector1 from Test"; + if (prepared) cmd.Prepare(); + using var reader = cmd.ExecuteReader(); + reader.Read(); + var value = reader.GetValue(0); + Assert.That(value, Is.InstanceOf(typeof(byte[]))); + byteArray = (byte[])value; + + float[] floatArray2 = new float[byteArray.Length / 4]; + Buffer.BlockCopy(byteArray, 0, floatArray2, 0, byteArray.Length); + + Assert.That(floatArray2.Length, Is.EqualTo(3)); + Assert.That(floatArray2[0], Is.EqualTo(1.2f)); + Assert.That(floatArray2[1], Is.EqualTo(2.3f)); + Assert.That(floatArray2[2], Is.EqualTo(3.4f)); + } + + [TestCase(false)] + [TestCase(true)] + public void VectorReturnedFromSproc(bool prepared) + { + Assume.That(Version >= new Version(9, 0, 0), "This test is for MySql 9.0 or higher."); + + ExecuteSQL("DROP PROCEDURE IF EXISTS spTest"); + ExecuteSQL(@"CREATE PROCEDURE spTest (OUT v1 VECTOR) BEGIN + SELECT STRING_TO_VECTOR('[1.2, 2.3, 3.4]') INTO v1; END"); + using var cmd = new MySqlCommand(); + cmd.Connection = Connection; + + // prepare and execute the command + cmd.CommandText = "spTest"; + cmd.Parameters.Add("v1", MySqlDbType.Vector); + cmd.Parameters[0].Direction = ParameterDirection.Output; + cmd.CommandType = CommandType.StoredProcedure; + if (prepared) cmd.Prepare(); + cmd.ExecuteNonQuery(); + + // now the parameter should contain the output value + Assert.That(cmd.Parameters[0].Value, Is.InstanceOf(typeof(byte[]))); + byte[] byteArray = (byte[])cmd.Parameters[0].Value; + + // now check to see if it has the correct values + float[] floatArray = new float[byteArray.Length / 4]; + Buffer.BlockCopy(byteArray, 0, floatArray, 0, byteArray.Length); + + Assert.That(floatArray.Length, Is.EqualTo(3)); + Assert.That(floatArray[0], Is.EqualTo(1.2f)); + Assert.That(floatArray[1], Is.EqualTo(2.3f)); + Assert.That(floatArray[2], Is.EqualTo(3.4f)); } } -} \ No newline at end of file + + +} diff --git a/MySQL.Data/tests/MySql.Data.Tests/DateTimeTests.cs b/MySQL.Data/tests/MySql.Data.Tests/DateTimeTests.cs index 97bb7dffb..a2ded784e 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/DateTimeTests.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/DateTimeTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2022, Oracle and/or its affiliates. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -28,6 +28,7 @@ using MySql.Data.Types; using NUnit.Framework; +using NUnit.Framework.Legacy; using System; using System.Globalization; using System.Text; @@ -59,9 +60,9 @@ public void ConvertZeroDateTime() MySqlCommand cmd = new MySqlCommand("SELECT * FROM Test", c); using (MySqlDataReader reader = cmd.ExecuteReader()) { - Assert.True(reader.Read()); - Assert.AreEqual(DateTime.MinValue.Date, reader.GetDateTime(1).Date); - Assert.AreEqual(DateTime.MinValue.Date, reader.GetDateTime(2).Date); + Assert.That(reader.Read()); + Assert.That(reader.GetDateTime(1).Date, Is.EqualTo(DateTime.MinValue.Date)); + Assert.That(reader.GetDateTime(2).Date, Is.EqualTo(DateTime.MinValue.Date)); } } } @@ -79,18 +80,18 @@ public void TestNotAllowZeroDateAndTime() MySqlCommand cmd = new MySqlCommand("SELECT * FROM Test", Connection); using (MySqlDataReader reader = cmd.ExecuteReader()) { - Assert.True(reader.Read()); + Assert.That(reader.Read()); MySqlDateTime testDate = reader.GetMySqlDateTime(2); - Assert.False(testDate.IsValidDateTime, "IsZero is false"); + Assert.That(testDate.IsValidDateTime, Is.False, "IsZero is false"); Exception ex = Assert.Throws(() => reader.GetValue(2)); - Assert.AreEqual("Unable to convert MySQL date/time value to System.DateTime", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Unable to convert MySQL date/time value to System.DateTime")); - Assert.True(reader.Read()); + Assert.That(reader.Read()); DateTime dt2 = (DateTime)reader.GetValue(2); - Assert.AreEqual(new DateTime(2004, 11, 11).Date, dt2.Date); + Assert.That(dt2.Date, Is.EqualTo(new DateTime(2004, 11, 11).Date)); } ExecuteSQL($"SET SQL_MODE = '{sql_mode}'"); @@ -107,12 +108,12 @@ public void DateAdd() cmd.Parameters.AddWithValue("?someday", now); using (MySqlDataReader reader = cmd.ExecuteReader()) { - Assert.True(reader.Read()); + Assert.That(reader.Read()); DateTime dt = reader.GetDateTime(0); - Assert.AreEqual(later.Date, dt.Date); - Assert.AreEqual(later.Hour, dt.Hour); - Assert.AreEqual(later.Minute, dt.Minute); - Assert.AreEqual(later.Second, dt.Second); + Assert.That(dt.Date, Is.EqualTo(later.Date)); + Assert.That(dt.Hour, Is.EqualTo(later.Hour)); + Assert.That(dt.Minute, Is.EqualTo(later.Minute)); + Assert.That(dt.Second, Is.EqualTo(later.Second)); } } @@ -129,7 +130,7 @@ public void TestZeroDateTimeException() { reader.Read(); Exception ex = Assert.Throws(() => reader.GetDateTime(2)); - Assert.AreEqual("Unable to convert MySQL date/time value to System.DateTime", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Unable to convert MySQL date/time value to System.DateTime")); } } @@ -156,12 +157,12 @@ public void LargeDateTime() cmd.CommandText = "SELECT id,dt FROM Test"; using (MySqlDataReader reader = cmd.ExecuteReader()) { - Assert.True(reader.Read()); - Assert.AreEqual(DateTime.Parse("9997-10-29").Date, reader.GetDateTime(1).Date); - Assert.True(reader.Read()); - Assert.AreEqual(DateTime.Parse("9997-10-30").Date, reader.GetDateTime(1).Date); - Assert.True(reader.Read()); - Assert.AreEqual(DateTime.Parse("9999-12-31").Date, reader.GetDateTime(1).Date); + Assert.That(reader.Read()); + Assert.That(reader.GetDateTime(1).Date, Is.EqualTo(DateTime.Parse("9997-10-29").Date)); + Assert.That(reader.Read()); + Assert.That(reader.GetDateTime(1).Date, Is.EqualTo(DateTime.Parse("9997-10-30").Date)); + Assert.That(reader.Read()); + Assert.That(reader.GetDateTime(1).Date, Is.EqualTo(DateTime.Parse("9999-12-31").Date)); } } @@ -179,12 +180,12 @@ public void UsingDatesAsStrings() MySqlCommand cmd2 = new MySqlCommand("SELECT * FROM Test", Connection); using (var reader = cmd2.ExecuteReader()) { - Assert.True(reader.Read()); + Assert.That(reader.Read()); DateTime dt = reader.GetDateTime("dt"); - Assert.AreEqual(2005, dt.Year); - Assert.AreEqual(3, dt.Month); - Assert.AreEqual(4, dt.Day); - Assert.False(reader.Read()); + Assert.That(dt.Year, Is.EqualTo(2005)); + Assert.That(dt.Month, Is.EqualTo(3)); + Assert.That(dt.Day, Is.EqualTo(4)); + Assert.That(reader.Read(), Is.False); } } @@ -257,7 +258,7 @@ public void MySqlDateTimeFormatting() { DateTime dt = DateTime.Now; MySqlDateTime mdt = new MySqlDateTime(dt); - Assert.AreEqual(dt.ToString(CultureInfo.InvariantCulture), mdt.ToString()); + Assert.That(mdt.ToString(), Is.EqualTo(dt.ToString(CultureInfo.InvariantCulture))); } /// @@ -279,7 +280,7 @@ public void DateFormat() cmd.Parameters.AddWithValue("?datefilter", dt.Date); using (MySqlDataReader reader = cmd.ExecuteReader()) { - Assert.True(reader.Read()); + Assert.That(reader.Read()); } } @@ -306,7 +307,7 @@ public void TimeColumnWithMicrosecondsOnPrepare() { command.Prepare(); var result = (TimeSpan)command.ExecuteScalar(); - Assert.True(result.ToString() == "1.02:03:04.5670000"); + Assert.That(result.ToString() == "1.02:03:04.5670000"); } ExecuteSQL(@"Delete from test_time;"); @@ -321,7 +322,7 @@ public void TimeColumnWithMicrosecondsOnPrepare() { command.Prepare(); var result = (TimeSpan)command.ExecuteScalar(); - Assert.True(result.ToString() == "1.02:03:04.0005600"); + Assert.That(result.ToString() == "1.02:03:04.0005600"); } } @@ -359,7 +360,7 @@ public void CanUpdateMicroseconds() while (rdr.Read()) { - Assert.AreEqual("12:34:56.123456", rdr.GetDateTime(0).ToString("hh:mm:ss.ffffff")); + Assert.That(rdr.GetDateTime(0).ToString("hh:mm:ss.ffffff"), Is.EqualTo("12:34:56.123456")); } rdr.Close(); } @@ -417,7 +418,7 @@ public void CanUpdateMicrosecondsWithPrepare() while (rdr.Read()) { - Assert.AreEqual("12:34:59.999999", rdr.GetDateTime(0).ToString("hh:mm:ss.ffffff")); + Assert.That(rdr.GetDateTime(0).ToString("hh:mm:ss.ffffff"), Is.EqualTo("12:34:59.999999")); } rdr.Close(); } @@ -456,9 +457,9 @@ public void CanUpdateMillisecondsUsingTimeType() while (rdr.Read()) { #if !NETFRAMEWORK - Assert.AreEqual(345, rdr.GetTimeSpan(0).Milliseconds); + Assert.That(rdr.GetTimeSpan(0).Milliseconds, Is.EqualTo(345)); #else - Assert.AreEqual(346, rdr.GetTimeSpan(0).Milliseconds); + Assert.That(rdr.GetTimeSpan(0).Milliseconds, Is.EqualTo(346)); #endif } } @@ -504,7 +505,7 @@ public void CanUpdateMillisecondsUsingTimeTypeOnPrepareStatements() { while (rdr.Read()) { - Assert.AreEqual(2, rdr.GetTimeSpan(0).Milliseconds); + Assert.That(rdr.GetTimeSpan(0).Milliseconds, Is.EqualTo(2)); } } } @@ -546,7 +547,7 @@ public void CanUpdateMillisecondsUsingTimeStampType() while (rdr.Read()) { - Assert.AreEqual(123456, rdr.GetMySqlDateTime(0).Microsecond); + Assert.That(rdr.GetMySqlDateTime(0).Microsecond, Is.EqualTo(123456)); } rdr.Close(); } @@ -589,7 +590,7 @@ public void CanUpdateMillisecondsUsingTimeStampTypeWithPrepare() { while (rdr.Read()) { - Assert.AreEqual(123456, rdr.GetMySqlDateTime(0).Microsecond); + Assert.That(rdr.GetMySqlDateTime(0).Microsecond, Is.EqualTo(123456)); } } } @@ -616,8 +617,8 @@ public void TimestampValuesAreLocal() reader.Read(); DateTime dt1 = reader.GetDateTime(0); DateTime ts = reader.GetDateTime(1); - Assert.AreEqual(DateTimeKind.Unspecified, dt1.Kind); - Assert.AreEqual(DateTimeKind.Local, ts.Kind); + Assert.That(dt1.Kind, Is.EqualTo(DateTimeKind.Unspecified)); + Assert.That(ts.Kind, Is.EqualTo(DateTimeKind.Local)); } } @@ -655,7 +656,7 @@ public void TimestampCorrectTimezone() { reader.Read(); DateTime ts = reader.GetDateTime(1); - Assert.AreEqual(DateTimeKind.Utc, ts.Kind); + Assert.That(ts.Kind, Is.EqualTo(DateTimeKind.Utc)); } // Now set it to non-UTC cmd.CommandText = "set @@global.time_zone = '+5:00'"; @@ -668,7 +669,7 @@ public void TimestampCorrectTimezone() { reader.Read(); DateTime ts = reader.GetDateTime(1); - Assert.AreEqual(DateTimeKind.Local, ts.Kind); + Assert.That(ts.Kind, Is.EqualTo(DateTimeKind.Local)); } } finally @@ -715,7 +716,7 @@ public void CanSaveMillisecondsPrecision3WithPrepare() while (rdr.Read()) { - Assert.AreEqual("11:09:07.0060", rdr.GetDateTime(0).ToString("hh:mm:ss.ffff")); + Assert.That(rdr.GetDateTime(0).ToString("hh:mm:ss.ffff"), Is.EqualTo("11:09:07.0060")); } rdr.Close(); } @@ -742,7 +743,7 @@ public void CanSaveMillisecondsPrecision3() while (rdr.Read()) { - Assert.AreEqual("11:09:07.0060", rdr.GetDateTime(0).ToString("hh:mm:ss.ffff")); + Assert.That(rdr.GetDateTime(0).ToString("hh:mm:ss.ffff"), Is.EqualTo("11:09:07.0060")); } rdr.Close(); } @@ -768,7 +769,7 @@ public void CanSaveMicrosecondsPrecision4() while (rdr.Read()) { - Assert.AreEqual(dt.ToString("hh:mm:ss.ffff"), rdr.GetDateTime(0).ToString("hh:mm:ss.ffff")); + Assert.That(rdr.GetDateTime(0).ToString("hh:mm:ss.ffff"), Is.EqualTo(dt.ToString("hh:mm:ss.ffff"))); } rdr.Close(); } @@ -782,7 +783,7 @@ public void ShowMicrosecondError() cmd.Connection = Connection; string date = cmd.ExecuteScalar().ToString(); DateTime temp; - Assert.True(DateTime.TryParse(date, out temp)); + Assert.That(DateTime.TryParse(date, out temp)); } /// @@ -810,7 +811,7 @@ public void CanDefineCurrentTimeStampAsDefaultOnDateTime() while (reader.Read()) { - Assert.True(DateTime.TryParse(reader.GetDateTime(0).ToString(), out tempDate)); + Assert.That(DateTime.TryParse(reader.GetDateTime(0).ToString(), out tempDate)); } reader.Close(); } @@ -836,13 +837,13 @@ public void ReadAndWriteMicroseconds() cmd.CommandText = " SELECT * from ReadAndWriteMicroseconds"; using (MySqlDataReader reader = cmd.ExecuteReader()) { - Assert.True(reader.Read()); - Assert.AreEqual(milliseconds.Ticks, reader.GetTimeSpan(1).Ticks); - Assert.AreEqual(microseconds.Ticks, reader.GetTimeSpan(2).Ticks); - Assert.AreEqual(microseconds.Ticks, reader.GetDateTime(3).Ticks); - Assert.AreEqual(microseconds.Millisecond, reader.GetDateTime(3).Millisecond); - Assert.AreEqual(microseconds.Millisecond, reader.GetMySqlDateTime(3).Millisecond); - Assert.AreEqual((microseconds.Ticks % 10000000) / 10, reader.GetMySqlDateTime(3).Microsecond); + Assert.That(reader.Read()); + Assert.That(reader.GetTimeSpan(1).Ticks, Is.EqualTo(milliseconds.Ticks)); + Assert.That(reader.GetTimeSpan(2).Ticks, Is.EqualTo(microseconds.Ticks)); + Assert.That(reader.GetDateTime(3).Ticks, Is.EqualTo(microseconds.Ticks)); + Assert.That(reader.GetDateTime(3).Millisecond, Is.EqualTo(microseconds.Millisecond)); + Assert.That(reader.GetMySqlDateTime(3).Millisecond, Is.EqualTo(microseconds.Millisecond)); + Assert.That(reader.GetMySqlDateTime(3).Microsecond, Is.EqualTo((microseconds.Ticks % 10000000) / 10)); } } @@ -863,7 +864,7 @@ public void TimeZoneOffset() { using (MySqlConnection conn2 = GetConnection()) { - Assert.AreEqual(timeZoneHours, conn2.driver.timeZoneOffset); + Assert.That(conn2.driver.timeZoneOffset, Is.EqualTo(timeZoneHours)); } } finally @@ -893,9 +894,9 @@ public void TimeZoneOffsetUsingReader() var myTimestampSb = (DateTime)reader["mytimestampcolumn"]; var myTimestampGdt = reader.GetDateTime("mytimestampcolumn"); - Assert.True(myTimestampSb.Kind == myTimestampGdt.Kind); - Assert.True(conn.driver.timeZoneOffset == ((DateTimeOffset)myTimestampSb).Offset.Hours, $"Driver: {conn.driver.timeZoneOffset}; Sb: {((DateTimeOffset)myTimestampSb).Offset.Hours}"); - Assert.True(conn.driver.timeZoneOffset == ((DateTimeOffset)myTimestampGdt).Offset.Hours); + Assert.That(myTimestampSb.Kind == myTimestampGdt.Kind); + Assert.That(conn.driver.timeZoneOffset == ((DateTimeOffset)myTimestampSb).Offset.Hours, $"Driver: {conn.driver.timeZoneOffset}; Sb: {((DateTimeOffset)myTimestampSb).Offset.Hours}"); + Assert.That(conn.driver.timeZoneOffset == ((DateTimeOffset)myTimestampGdt).Offset.Hours); reader.Close(); } @@ -931,7 +932,7 @@ public void MilisecondsWithTimeColumn() { reader.Read(); var val = reader.GetValue(0); - StringAssert.StartsWith(timeValue.Substring(0, 14), val.ToString()); + Assert.That(val.ToString(), Does.StartWith(timeValue.Substring(0, 14))); } cmd.CommandText = "DROP TABLE IF EXISTS T"; @@ -950,7 +951,7 @@ public void MilisecondsWithTimeColumn() { reader.Read(); var val = reader.GetTimeSpan(0); - StringAssert.StartsWith(timeValue.Substring(0, 12), val.ToString()); + Assert.That(val.ToString(), Does.StartWith(timeValue.Substring(0, 12))); } } } @@ -985,9 +986,9 @@ public void IConvertibleImplementation() { var mySqlDateTime = new MySqlDateTime(DateTime.Now); - Assert.AreEqual(TypeCode.DateTime, ((IConvertible)mySqlDateTime).GetTypeCode()); - Assert.NotNull(((IConvertible)mySqlDateTime).ToString()); - Assert.NotNull(Convert.ToString(mySqlDateTime)); + Assert.That(((IConvertible)mySqlDateTime).GetTypeCode(), Is.EqualTo(TypeCode.DateTime)); + Assert.That(((IConvertible)mySqlDateTime).ToString(), Is.Not.Null); + Assert.That(Convert.ToString(mySqlDateTime), Is.Not.Null); } } } diff --git a/MySQL.Data/tests/MySql.Data.Tests/DnsSrvTests.cs b/MySQL.Data/tests/MySql.Data.Tests/DnsSrvTests.cs index 9f2ebfbc9..e17739ae7 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/DnsSrvTests.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/DnsSrvTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2019, 2022, Oracle and/or its affiliates. +// Copyright © 2019, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -29,6 +29,7 @@ using MySql.Data.Common; using MySql.Data.Common.DnsClient; using NUnit.Framework; +using NUnit.Framework.Legacy; using System; using System.Collections.Generic; using System.Linq; @@ -50,17 +51,17 @@ public void DnsSrvConnectionStringInvalidOptions(string connString) var exception = Assert.Throws(() => new MySqlConnection(connString)); } - [TestCase("server=localhost;port=33060;dns-srv=true;", "Specifying a port number with DNS SRV lookup is not permitted.")] - [TestCase("server=localhost,10.10.10.10;dns-srv=true;", "Specifying multiple host names with DNS SRV lookup is not permitted.")] - [TestCase("host=localhost,10.10.10.10;dns-srv=TRUE;", "Specifying multiple host names with DNS SRV lookup is not permitted.")] - [TestCase("server=(address=localhost,priority=100), (address=10.10.10.10,priority=90);dns-srv=true;", "Specifying multiple host names with DNS SRV lookup is not permitted.")] - [TestCase("server=localhost;protocol=unix;Dns-Srv=true;", "Using Unix domain sockets with DNS SRV lookup is not permitted.")] - [TestCase("server=localhost;protocol=unixSocket;dns-srv=true;", "Using Unix domain sockets with DNS SRV lookup is not permitted.")] - [TestCase("server=localhost;connectionprotocol=unix;DnsSrv=true;", "Using Unix domain sockets with DNS SRV lookup is not permitted.")] + [TestCase("server=localhost;port=33060;dns-srv=true;", "Specifying a port number with DNS SRV lookup is not permitted")] + [TestCase("server=localhost,10.10.10.10;dns-srv=true;", "Specifying multiple host names with DNS SRV lookup is not permitted")] + [TestCase("host=localhost,10.10.10.10;dns-srv=TRUE;", "Specifying multiple host names with DNS SRV lookup is not permitted")] + [TestCase("server=(address=localhost,priority=100), (address=10.10.10.10,priority=90);dns-srv=true;", "Specifying multiple host names with DNS SRV lookup is not permitted")] + [TestCase("server=localhost;protocol=unix;Dns-Srv=true;", "Using Unix domain sockets with DNS SRV lookup is not permitted")] + [TestCase("server=localhost;protocol=unixSocket;dns-srv=true;", "Using Unix domain sockets with DNS SRV lookup is not permitted")] + [TestCase("server=localhost;connectionprotocol=unix;DnsSrv=true;", "Using Unix domain sockets with DNS SRV lookup is not permitted")] public void DnsSrvConnectionStringInvalidConfiguration(string connString, string exceptionMessage) { var exception = Assert.Throws(() => new MySqlConnection(connString)); - Assert.AreEqual(exceptionMessage, exception.Message); + Assert.That(exception.Message, Is.EqualTo(exceptionMessage)); } [TestCase("server=localhost;port=33060;dns-srv=false;")] @@ -74,7 +75,7 @@ public void DnsSrvConnectionStringInvalidConfiguration(string connString, string public void DnsSrvConnectionStringValidConfiguration(string connString) { var conn = new MySqlConnection(connString); - Assert.NotNull(conn); + Assert.That(conn, Is.Not.Null); } [Test] @@ -85,21 +86,21 @@ public void DnsSrvConnectionAnonymousTypeInvalidConfiguration() sb.Port = 3306; sb.Server = "localhost"; var exception = Assert.Throws(() => new MySqlConnection(sb.ConnectionString)); - Assert.AreEqual(Resources.DnsSrvInvalidConnOptionPort, exception.Message); + Assert.That(exception.Message, Is.EqualTo(Resources.DnsSrvInvalidConnOptionPort)); sb = new MySqlConnectionStringBuilder(); sb.DnsSrv = true; sb.Server = "_mysqlx._tcp.foo.abc.com"; sb.ConnectionProtocol = MySqlConnectionProtocol.Unix; exception = Assert.Throws(() => new MySqlConnection(sb.ConnectionString)); - Assert.AreEqual(Resources.DnsSrvInvalidConnOptionUnixSocket, exception.Message); + Assert.That(exception.Message, Is.EqualTo(Resources.DnsSrvInvalidConnOptionUnixSocket)); sb = new MySqlConnectionStringBuilder(); sb.DnsSrv = true; sb.Server = "localhost, 10.10.10.10"; sb.ConnectionProtocol = MySqlConnectionProtocol.Unix; exception = Assert.Throws(() => new MySqlConnection(sb.ConnectionString)); - Assert.AreEqual(Resources.DnsSrvInvalidConnOptionMultihost, exception.Message); + Assert.That(exception.Message, Is.EqualTo(Resources.DnsSrvInvalidConnOptionMultihost)); } [Test] @@ -125,7 +126,7 @@ public void DnsSrvRecordsTest() var sortedRecords = DnsSrv.SortSrvRecords(dnsRecords.ToList()); - Assert.True(sortedRecords.Select(r => r.Target).SequenceEqual(expectedOrder.Select(r => r.Target))); + Assert.That(sortedRecords.Select(r => r.Target).SequenceEqual(expectedOrder.Select(r => r.Target))); } } -} \ No newline at end of file +} diff --git a/MySQL.Data/tests/MySql.Data.Tests/EventTests.cs b/MySQL.Data/tests/MySql.Data.Tests/EventTests.cs index 9d31609f6..81e95eb60 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/EventTests.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/EventTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -28,6 +28,7 @@ using System.Data; using NUnit.Framework; +using NUnit.Framework.Legacy; namespace MySql.Data.MySqlClient.Tests { @@ -73,4 +74,4 @@ private void StateChangeHandler(object sender, StateChangeEventArgs e) { } } -} \ No newline at end of file +} diff --git a/MySQL.Data/tests/MySql.Data.Tests/ExceptionTests.cs b/MySQL.Data/tests/MySql.Data.Tests/ExceptionTests.cs index c138474f8..cd3059b6d 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/ExceptionTests.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/ExceptionTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2022, Oracle and/or its affiliates. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -27,6 +27,7 @@ // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA using NUnit.Framework; +using NUnit.Framework.Legacy; using System; using System.Data; using System.Reflection; @@ -57,8 +58,8 @@ public void Timeout() MySqlCommand cmd = new MySqlCommand("SELECT * FROM Test", connection); Exception ex = Assert.Throws(() => cmd.ExecuteReader()); - Assert.AreEqual("Connection must be valid and open.", ex.Message); - Assert.AreEqual(ConnectionState.Closed, connection.State); + Assert.That(ex.Message, Is.EqualTo("Connection must be valid and open.")); + Assert.That(connection.State, Is.EqualTo(ConnectionState.Closed)); connection.Close(); } @@ -75,7 +76,7 @@ public void ErrorData() } catch (Exception ex) { - Assert.AreEqual(1064, ex.Data["Server Error Code"]); + Assert.That(ex.Data["Server Error Code"], Is.EqualTo(1064)); } } @@ -99,7 +100,7 @@ public void TimeoutErrorMessages() Thread.Sleep(6000); command = new MySqlCommand("SELECT CONNECTION_ID();", connection); var ex = Assert.Throws(() => command.ExecuteScalar()); - Assert.AreEqual((int)MySqlErrorCode.ErrorClientInteractionTimeout, ex.Number); + Assert.That(ex.Number, Is.EqualTo((int)MySqlErrorCode.ErrorClientInteractionTimeout)); } } @@ -138,7 +139,7 @@ public void UngrantedAccessException() /// [TestCase("Port", 1455, 1042)] [TestCase("Database", "nonExistingDB", 1049)] - [TestCase("UserID", "nonExistingUser", 1045)] + [TestCase("UserID", "nonExistingUser", 1045)] // Check server bug Bug#36527984 in case of failure [TestCase("Server", "nonExistingServer", 1042)] [TestCase("MaxConnections", "", 1040)] public void AuthenticationExceptionNumber(string propertyName, object propertyValue, int exNumber) @@ -157,7 +158,7 @@ public void AuthenticationExceptionNumber(string propertyName, object propertyVa ExecuteSQL("SET GLOBAL max_connections = 1;"); } MySqlException exDefault = Assert.Throws(() => conn.Open()); - Assert.AreEqual(exNumber, exDefault.Number); + Assert.That(exDefault.Number, Is.EqualTo(exNumber)); } } } diff --git a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/BlobTestsPipe.cs b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/BlobTestsPipe.cs index 4b406bdd7..56fd2cee3 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/BlobTestsPipe.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/BlobTestsPipe.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -26,14 +26,12 @@ // along with this program; if not, write to the Free Software Foundation, Inc., // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +using NUnit.Framework.Internal; + namespace MySql.Data.MySqlClient.Tests { public class BlobTestsPipe : BlobTests { - public BlobTestsPipe(TestFixture fixture) : base(fixture) - { - } - internal override void AdjustConnectionSettings(MySqlConnectionStringBuilder settings) { settings.ConnectionProtocol = MySqlConnectionProtocol.NamedPipe; diff --git a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/BlobTestsPipeCompressed.cs b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/BlobTestsPipeCompressed.cs index 557f72f4c..0f9d7fd81 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/BlobTestsPipeCompressed.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/BlobTestsPipeCompressed.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -27,6 +27,7 @@ // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +using NUnit.Framework.Internal; using System.ComponentModel; namespace MySql.Data.MySqlClient.Tests @@ -34,11 +35,6 @@ namespace MySql.Data.MySqlClient.Tests [Category("Compressed")] public class BlobTestsPipeCompressed : BlobTests { - public BlobTestsPipeCompressed(TestFixture fixture) : base(fixture) - { - - } - internal override void AdjustConnectionSettings(MySqlConnectionStringBuilder settings) { settings.ConnectionProtocol = MySqlConnectionProtocol.NamedPipe; @@ -46,4 +42,4 @@ internal override void AdjustConnectionSettings(MySqlConnectionStringBuilder set settings.SslMode = MySqlSslMode.None; } } -} \ No newline at end of file +} diff --git a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/BlobTestsSharedMem.cs b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/BlobTestsSharedMem.cs index 5da5fb5af..f2f3af134 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/BlobTestsSharedMem.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/BlobTestsSharedMem.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -27,19 +27,16 @@ // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +using NUnit.Framework.Internal; + namespace MySql.Data.MySqlClient.Tests { public class BlobTestsSharedMem : BlobTests { - - public BlobTestsSharedMem(TestFixture fixture) : base(fixture) - { - } - internal override void AdjustConnectionSettings(MySqlConnectionStringBuilder settings) { settings.ConnectionProtocol = MySqlConnectionProtocol.SharedMemory; settings.SslMode = MySqlSslMode.None; } } -} \ No newline at end of file +} diff --git a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/BlobTestsSharedMemCompressed.cs b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/BlobTestsSharedMemCompressed.cs index 19f1eccc6..af916620c 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/BlobTestsSharedMemCompressed.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/BlobTestsSharedMemCompressed.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -27,6 +27,7 @@ // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +using NUnit.Framework.Internal; using System.ComponentModel; namespace MySql.Data.MySqlClient.Tests @@ -34,11 +35,6 @@ namespace MySql.Data.MySqlClient.Tests [Category("Compressed")] public class BlobTestsSharedMemCompressed : BlobTests { - public BlobTestsSharedMemCompressed(TestFixture fixture) : base(fixture) - { - - } - internal override void AdjustConnectionSettings(MySqlConnectionStringBuilder settings) { settings.ConnectionProtocol = MySqlConnectionProtocol.SharedMemory; @@ -47,4 +43,4 @@ internal override void AdjustConnectionSettings(MySqlConnectionStringBuilder set } } -} \ No newline at end of file +} diff --git a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/CmdTestsPipe.cs b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/CmdTestsPipe.cs index 298499417..d805b0efd 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/CmdTestsPipe.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/CmdTestsPipe.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -31,15 +31,10 @@ namespace MySql.Data.MySqlClient.Tests { public class CmdTestsPipe : CmdTests { - - public CmdTestsPipe(TestFixture fixture) : base(fixture) - { - } - internal override void AdjustConnectionSettings(MySqlConnectionStringBuilder settings) { settings.ConnectionProtocol = MySqlConnectionProtocol.NamedPipe; settings.SslMode = MySqlSslMode.None; } } -} \ No newline at end of file +} diff --git a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/CmdTestsPipeCompressed.cs b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/CmdTestsPipeCompressed.cs index ca170eec2..98e341eac 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/CmdTestsPipeCompressed.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/CmdTestsPipeCompressed.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -26,16 +26,13 @@ // along with this program; if not, write to the Free Software Foundation, Inc., // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +using NUnit.Framework.Internal; using System; namespace MySql.Data.MySqlClient.Tests { public class CmdTestsPipeCompressed : CmdTests { - public CmdTestsPipeCompressed(TestFixture fixture) : base(fixture) - { - } - internal override void AdjustConnectionSettings(MySqlConnectionStringBuilder settings) { settings.ConnectionProtocol = MySqlConnectionProtocol.NamedPipe; @@ -43,4 +40,4 @@ internal override void AdjustConnectionSettings(MySqlConnectionStringBuilder set settings.UseCompression = true; } } -} \ No newline at end of file +} diff --git a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/CmdTestsSharedMem.cs b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/CmdTestsSharedMem.cs index a7a28c3c6..99144722e 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/CmdTestsSharedMem.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/CmdTestsSharedMem.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -26,18 +26,16 @@ // along with this program; if not, write to the Free Software Foundation, Inc., // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +using NUnit.Framework.Internal; + namespace MySql.Data.MySqlClient.Tests { public class CmdTestsSharedMem : CmdTests { - public CmdTestsSharedMem(TestFixture fixture) : base(fixture) - { - } - internal override void AdjustConnectionSettings(MySqlConnectionStringBuilder settings) { settings.ConnectionProtocol = MySqlConnectionProtocol.SharedMemory; settings.SslMode = MySqlSslMode.None; } } -} \ No newline at end of file +} diff --git a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/CmdTestsSharedmemCompressed.cs b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/CmdTestsSharedmemCompressed.cs index 55d721794..94954727c 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/CmdTestsSharedmemCompressed.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/CmdTestsSharedmemCompressed.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -31,11 +31,6 @@ namespace MySql.Data.MySqlClient.Tests { public class CmdTestsSharedMemCompressed : CmdTests { - - public CmdTestsSharedMemCompressed(TestFixture fixture) : base(fixture) - { - } - internal override void AdjustConnectionSettings(MySqlConnectionStringBuilder settings) { settings.ConnectionProtocol = MySqlConnectionProtocol.SharedMemory; @@ -43,4 +38,4 @@ internal override void AdjustConnectionSettings(MySqlConnectionStringBuilder set settings.UseCompression = true; } } -} \ No newline at end of file +} diff --git a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/CultureTests.cs b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/CultureTests.cs index ccd55ae5b..4fde4772e 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/CultureTests.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/CultureTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -28,6 +28,7 @@ using System; using NUnit.Framework; +using NUnit.Framework.Legacy; using System.Threading; using System.Globalization; using System.Data; @@ -74,7 +75,7 @@ private void InternalTestFloats(bool prepared) if (prepared) cmd.Prepare(); int count = cmd.ExecuteNonQuery(); - Assert.AreEqual(1, count); + Assert.That(count, Is.EqualTo(1)); try { @@ -83,9 +84,9 @@ private void InternalTestFloats(bool prepared) using (MySqlDataReader reader = cmd.ExecuteReader()) { reader.Read(); - Assert.AreEqual((decimal)2.3, (decimal)reader.GetFloat(0)); - Assert.AreEqual(4.6, reader.GetDouble(1)); - Assert.AreEqual((decimal)23.82, reader.GetDecimal(2)); + Assert.That((decimal)reader.GetFloat(0), Is.EqualTo((decimal)2.3)); + Assert.That(reader.GetDouble(1), Is.EqualTo(4.6)); + Assert.That(reader.GetDecimal(2), Is.EqualTo((decimal)23.82)); } } finally @@ -133,12 +134,12 @@ public void ArabicCalendars() MySqlCommand cmd = new MySqlCommand("SELECT dt FROM test", Connection); DateTime dt = (DateTime)cmd.ExecuteScalar(); - Assert.AreEqual(2007, dt.Year); - Assert.AreEqual(1, dt.Month); - Assert.AreEqual(1, dt.Day); - Assert.AreEqual(12, dt.Hour); - Assert.AreEqual(30, dt.Minute); - Assert.AreEqual(45, dt.Second); + Assert.That(dt.Year, Is.EqualTo(2007)); + Assert.That(dt.Month, Is.EqualTo(1)); + Assert.That(dt.Day, Is.EqualTo(1)); + Assert.That(dt.Hour, Is.EqualTo(12)); + Assert.That(dt.Minute, Is.EqualTo(30)); + Assert.That(dt.Second, Is.EqualTo(45)); Thread.CurrentThread.CurrentCulture = curCulture; Thread.CurrentThread.CurrentUICulture = curUICulture; @@ -171,9 +172,9 @@ public void FunctionsReturnStringAndDecimal() "select *,(select b from bug52187b) as field_b from bug52187a", con); DataTable dt = new DataTable(); da.Fill(dt); - Assert.AreEqual(1, dt.Rows.Count); - Assert.AreEqual((decimal)1.25, (decimal)dt.Rows[0][0]); - Assert.AreEqual((decimal)5.99, (decimal)dt.Rows[0][1]); + Assert.That(dt.Rows.Count, Is.EqualTo(1)); + Assert.That((decimal)dt.Rows[0][0], Is.EqualTo((decimal)1.25)); + Assert.That((decimal)dt.Rows[0][1], Is.EqualTo((decimal)5.99)); } } finally diff --git a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/DataTypeTests.cs b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/DataTypeTests.cs index ef4c8a20a..cf9c4a195 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/DataTypeTests.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/DataTypeTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -28,6 +28,7 @@ using System; using NUnit.Framework; +using NUnit.Framework.Legacy; using System.Data; using System.Data.Common; @@ -56,9 +57,9 @@ public void UpdateDecimalColumns() dt.Clear(); da.Fill(dt); - Assert.AreEqual(1, dt.Rows.Count); - Assert.AreEqual(1, dt.Rows[0]["id"]); - Assert.AreEqual((decimal)23.4, Convert.ToDecimal(dt.Rows[0]["dec1"])); + Assert.That(dt.Rows.Count, Is.EqualTo(1)); + Assert.That(dt.Rows[0]["id"], Is.EqualTo(1)); + Assert.That(Convert.ToDecimal(dt.Rows[0]["dec1"]), Is.EqualTo((decimal)23.4)); cb.Dispose(); } @@ -99,7 +100,7 @@ public void UnsignedTypes() using (MySqlDataReader dr = cmd.ExecuteReader()) { dr.Read(); - Assert.AreEqual(20, dr.GetUInt16(0)); + Assert.That(dr.GetUInt16(0), Is.EqualTo(20)); } } @@ -117,11 +118,11 @@ public void DecimalPrecision() { DataTable dt = reader.GetSchemaTable(); DataRow columnDefinition = dt.Rows[0]; - Assert.AreEqual(35, columnDefinition[SchemaTableColumn.NumericPrecision]); + Assert.That(columnDefinition[SchemaTableColumn.NumericPrecision], Is.EqualTo(35)); columnDefinition = dt.Rows[1]; - Assert.AreEqual(36, columnDefinition[SchemaTableColumn.NumericPrecision]); + Assert.That(columnDefinition[SchemaTableColumn.NumericPrecision], Is.EqualTo(36)); columnDefinition = dt.Rows[2]; - Assert.AreEqual(36, columnDefinition[SchemaTableColumn.NumericPrecision]); + Assert.That(columnDefinition[SchemaTableColumn.NumericPrecision], Is.EqualTo(36)); } } } diff --git a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/DateTimeTests.cs b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/DateTimeTests.cs index 20b8fc326..de1d3a3a2 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/DateTimeTests.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/DateTimeTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -28,6 +28,7 @@ using System; using NUnit.Framework; +using NUnit.Framework.Legacy; using MySql.Data.Types; using System.Data; using System.Globalization; @@ -57,14 +58,14 @@ public void TestAllowZeroDateTime() { reader.Read(); - Assert.True(reader.GetValue(1) is MySqlDateTime); - Assert.True(reader.GetValue(2) is MySqlDateTime); + Assert.That(reader.GetValue(1) is MySqlDateTime); + Assert.That(reader.GetValue(2) is MySqlDateTime); - Assert.False(reader.GetMySqlDateTime(1).IsValidDateTime); - Assert.False(reader.GetMySqlDateTime(2).IsValidDateTime); + Assert.That(!reader.GetMySqlDateTime(1).IsValidDateTime); + Assert.That(!reader.GetMySqlDateTime(2).IsValidDateTime); Exception ex = Assert.Throws(() =>reader.GetDateTime(1)); - Assert.AreEqual("Unable to convert MySQL date/time value to System.DateTime", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Unable to convert MySQL date/time value to System.DateTime")); } DataTable dt = new DataTable(); @@ -82,11 +83,11 @@ public void TestAllowZeroDateTime() dt.Clear(); da.Fill(dt); - Assert.AreEqual(2, dt.Rows.Count); + Assert.That(dt.Rows.Count, Is.EqualTo(2)); MySqlDateTime date = (MySqlDateTime)dt.Rows[1]["d"]; - Assert.AreEqual(2003, date.Year); - Assert.AreEqual(9, date.Month); - Assert.AreEqual(24, date.Day); + Assert.That(date.Year, Is.EqualTo(2003)); + Assert.That(date.Month, Is.EqualTo(9)); + Assert.That(date.Day, Is.EqualTo(24)); cb.Dispose(); } } @@ -117,10 +118,10 @@ public void SortingMySqlDateTimes() DataView dv = dt.DefaultView; dv.Sort = "dt ASC"; - Assert.AreEqual(new DateTime(2004, 10, 1).Date, Convert.ToDateTime(dv[0]["dt"]).Date); - Assert.AreEqual(new DateTime(2004, 10, 2).Date, Convert.ToDateTime(dv[1]["dt"]).Date); - Assert.AreEqual(new DateTime(2004, 11, 1).Date, Convert.ToDateTime(dv[2]["dt"]).Date); - Assert.AreEqual(new DateTime(2004, 11, 2).Date, Convert.ToDateTime(dv[3]["dt"]).Date); + Assert.That(Convert.ToDateTime(dv[0]["dt"]).Date, Is.EqualTo(new DateTime(2004, 10, 1).Date)); + Assert.That(Convert.ToDateTime(dv[1]["dt"]).Date, Is.EqualTo(new DateTime(2004, 10, 2).Date)); + Assert.That(Convert.ToDateTime(dv[2]["dt"]).Date, Is.EqualTo(new DateTime(2004, 11, 1).Date)); + Assert.That(Convert.ToDateTime(dv[3]["dt"]).Date, Is.EqualTo(new DateTime(2004, 11, 2).Date)); Thread.CurrentThread.CurrentCulture = curCulture; Thread.CurrentThread.CurrentUICulture = curUICulture; @@ -157,8 +158,8 @@ public void InsertDateTimeValue() da.Fill(dt); cb.Dispose(); - Assert.AreEqual(1, dt.Rows.Count); - Assert.AreEqual(now.Date, ((DateTime)dt.Rows[0]["dt"]).Date); + Assert.That(dt.Rows.Count, Is.EqualTo(1)); + Assert.That(((DateTime)dt.Rows[0]["dt"]).Date, Is.EqualTo(now.Date)); } } @@ -191,9 +192,9 @@ public void DateTimeInDataTable() dt.Rows.Clear(); da.Fill(dt); - Assert.AreEqual(2, dt.Rows.Count); + Assert.That(dt.Rows.Count, Is.EqualTo(2)); cb.Dispose(); } } } -} \ No newline at end of file +} diff --git a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/GetSchemaTests.cs b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/GetSchemaTests.cs index 79501e17a..d0928792e 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/GetSchemaTests.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/GetSchemaTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2022, Oracle and/or its affiliates. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -28,6 +28,7 @@ using MySql.Data.Common; using NUnit.Framework; +using NUnit.Framework.Legacy; using System; using System.Data; using System.Linq; @@ -47,25 +48,25 @@ public void Collections() DataTable dt = Connection.GetSchema(); int row = 0; - Assert.AreEqual("MetaDataCollections", dt.Rows[row++][0]); - Assert.AreEqual("DataSourceInformation", dt.Rows[row++][0]); - Assert.AreEqual("DataTypes", dt.Rows[row++][0]); - Assert.AreEqual("Restrictions", dt.Rows[row++][0]); - Assert.AreEqual("ReservedWords", dt.Rows[row++][0]); - Assert.AreEqual("Databases", dt.Rows[row++][0]); - Assert.AreEqual("Tables", dt.Rows[row++][0]); - Assert.AreEqual("Columns", dt.Rows[row++][0]); - Assert.AreEqual("Users", dt.Rows[row++][0]); - Assert.AreEqual("Foreign Keys", dt.Rows[row++][0]); - Assert.AreEqual("IndexColumns", dt.Rows[row++][0]); - Assert.AreEqual("Indexes", dt.Rows[row++][0]); - Assert.AreEqual("Foreign Key Columns", dt.Rows[row++][0]); - Assert.AreEqual("UDF", dt.Rows[row++][0]); - Assert.AreEqual("Views", dt.Rows[row++][0]); - Assert.AreEqual("ViewColumns", dt.Rows[row++][0]); - Assert.AreEqual("Procedure Parameters", dt.Rows[row++][0]); - Assert.AreEqual("Procedures", dt.Rows[row++][0]); - Assert.AreEqual("Triggers", dt.Rows[row++][0]); + Assert.That(dt.Rows[row++][0], Is.EqualTo("MetaDataCollections")); + Assert.That(dt.Rows[row++][0], Is.EqualTo("DataSourceInformation")); + Assert.That(dt.Rows[row++][0], Is.EqualTo("DataTypes")); + Assert.That(dt.Rows[row++][0], Is.EqualTo("Restrictions")); + Assert.That(dt.Rows[row++][0], Is.EqualTo("ReservedWords")); + Assert.That(dt.Rows[row++][0], Is.EqualTo("Databases")); + Assert.That(dt.Rows[row++][0], Is.EqualTo("Tables")); + Assert.That(dt.Rows[row++][0], Is.EqualTo("Columns")); + Assert.That(dt.Rows[row++][0], Is.EqualTo("Users")); + Assert.That(dt.Rows[row++][0], Is.EqualTo("Foreign Keys")); + Assert.That(dt.Rows[row++][0], Is.EqualTo("IndexColumns")); + Assert.That(dt.Rows[row++][0], Is.EqualTo("Indexes")); + Assert.That(dt.Rows[row++][0], Is.EqualTo("Foreign Key Columns")); + Assert.That(dt.Rows[row++][0], Is.EqualTo("UDF")); + Assert.That(dt.Rows[row++][0], Is.EqualTo("Views")); + Assert.That(dt.Rows[row++][0], Is.EqualTo("ViewColumns")); + Assert.That(dt.Rows[row++][0], Is.EqualTo("Procedure Parameters")); + Assert.That(dt.Rows[row++][0], Is.EqualTo("Procedures")); + Assert.That(dt.Rows[row++][0], Is.EqualTo("Triggers")); } /// @@ -75,6 +76,8 @@ public void Collections() [Test] public void DataTypes() { + Assume.That(Version >= new Version(9, 0, 0), "This test is for MySql 9.0 or higher."); + DataTable dt = Connection.GetSchema("DataTypes", new string[] { }); foreach (DataRow row in dt.Rows) @@ -82,63 +85,63 @@ public void DataTypes() string type = row["TypeName"].ToString(); Type systemType = Type.GetType(row["DataType"].ToString()); if (type == "BIT") - Assert.AreEqual(typeof(System.UInt64), systemType); + Assert.That(systemType, Is.EqualTo(typeof(System.UInt64))); else if (type == "DATE" || type == "DATETIME" || type == "TIMESTAMP") - Assert.AreEqual(typeof(System.DateTime), systemType); + Assert.That(systemType, Is.EqualTo(typeof(System.DateTime))); else if (type == "BLOB" || type == "TINYBLOB" || type == "MEDIUMBLOB" || type == "LONGBLOB") - Assert.AreEqual(typeof(System.Byte[]), systemType); + Assert.That(systemType, Is.EqualTo(typeof(System.Byte[]))); else if (type == "TIME") - Assert.AreEqual(typeof(System.TimeSpan), systemType); + Assert.That(systemType, Is.EqualTo(typeof(System.TimeSpan))); else if (type == "CHAR" || type == "VARCHAR") { - Assert.AreEqual(typeof(System.String), systemType); - Assert.False(Convert.ToBoolean(row["IsFixedLength"])); + Assert.That(systemType, Is.EqualTo(typeof(System.String))); + Assert.That(!Convert.ToBoolean(row["IsFixedLength"])); string format = type + "({0})"; - Assert.AreEqual(format, row["CreateFormat"].ToString()); + Assert.That(row["CreateFormat"].ToString(), Is.EqualTo(format)); } else if (type == "SET" || type == "ENUM") - Assert.AreEqual(typeof(System.String), systemType); + Assert.That(systemType, Is.EqualTo(typeof(System.String))); else if (type == "DOUBLE") - Assert.AreEqual(typeof(System.Double), systemType); + Assert.That(systemType, Is.EqualTo(typeof(System.Double))); else if (type == "SINGLE") - Assert.AreEqual(typeof(System.Single), systemType); + Assert.That(systemType, Is.EqualTo(typeof(System.Single))); else if (type == "TINYINT") { if (row["CreateFormat"].ToString().EndsWith("UNSIGNED", StringComparison.OrdinalIgnoreCase)) - Assert.AreEqual(typeof(System.Byte), systemType); + Assert.That(systemType, Is.EqualTo(typeof(System.Byte))); else - Assert.AreEqual(typeof(System.SByte), systemType); + Assert.That(systemType, Is.EqualTo(typeof(System.SByte))); } else if (type == "SMALLINT") { if (row["CreateFormat"].ToString().EndsWith("UNSIGNED", StringComparison.OrdinalIgnoreCase)) - Assert.AreEqual(typeof(System.UInt16), systemType); + Assert.That(systemType, Is.EqualTo(typeof(System.UInt16))); else - Assert.AreEqual(typeof(System.Int16), systemType); + Assert.That(systemType, Is.EqualTo(typeof(System.Int16))); } else if (type == "MEDIUMINT" || type == "INT") { if (row["CreateFormat"].ToString().EndsWith("UNSIGNED", StringComparison.OrdinalIgnoreCase)) - Assert.AreEqual(typeof(System.UInt32), systemType); + Assert.That(systemType, Is.EqualTo(typeof(System.UInt32))); else - Assert.AreEqual(typeof(System.Int32), systemType); + Assert.That(systemType, Is.EqualTo(typeof(System.Int32))); } else if (type == "BIGINT") { if (row["CreateFormat"].ToString().EndsWith("UNSIGNED", StringComparison.OrdinalIgnoreCase)) - Assert.AreEqual(typeof(System.UInt64), systemType); + Assert.That(systemType, Is.EqualTo(typeof(System.UInt64))); else - Assert.AreEqual(typeof(System.Int64), systemType); + Assert.That(systemType, Is.EqualTo(typeof(System.Int64))); } else if (type == "DECIMAL") { - Assert.AreEqual(typeof(System.Decimal), systemType); - Assert.AreEqual("DECIMAL({0},{1})", row["CreateFormat"].ToString()); + Assert.That(systemType, Is.EqualTo(typeof(System.Decimal))); + Assert.That(row["CreateFormat"].ToString(), Is.EqualTo("DECIMAL({0},{1})")); } else if (type == "TINYINT") - Assert.AreEqual(typeof(System.Byte), systemType); + Assert.That(systemType, Is.EqualTo(typeof(System.Byte))); } } @@ -152,20 +155,20 @@ public void Tables() restrictions[1] = Connection.Database; restrictions[2] = "test1"; DataTable dt = Connection.GetSchema("Tables", restrictions); - Assert.True(dt.Columns["VERSION"].DataType == typeof(UInt64) + Assert.That(dt.Columns["VERSION"].DataType == typeof(UInt64) || dt.Columns["VERSION"].DataType == typeof(Int64)); - Assert.True(dt.Columns["TABLE_ROWS"].DataType == typeof(UInt64)); - Assert.True(dt.Columns["AVG_ROW_LENGTH"].DataType == typeof(UInt64)); - Assert.True(dt.Columns["DATA_LENGTH"].DataType == typeof(UInt64)); - Assert.True(dt.Columns["MAX_DATA_LENGTH"].DataType == typeof(UInt64)); - Assert.True(dt.Columns["INDEX_LENGTH"].DataType == typeof(UInt64)); - Assert.True(dt.Columns["DATA_FREE"].DataType == typeof(UInt64)); - Assert.True(dt.Columns["AUTO_INCREMENT"].DataType == typeof(UInt64)); - Assert.True(dt.Columns["CHECKSUM"].DataType == typeof(UInt64) + Assert.That(dt.Columns["TABLE_ROWS"].DataType == typeof(UInt64)); + Assert.That(dt.Columns["AVG_ROW_LENGTH"].DataType == typeof(UInt64)); + Assert.That(dt.Columns["DATA_LENGTH"].DataType == typeof(UInt64)); + Assert.That(dt.Columns["MAX_DATA_LENGTH"].DataType == typeof(UInt64)); + Assert.That(dt.Columns["INDEX_LENGTH"].DataType == typeof(UInt64)); + Assert.That(dt.Columns["DATA_FREE"].DataType == typeof(UInt64)); + Assert.That(dt.Columns["AUTO_INCREMENT"].DataType == typeof(UInt64)); + Assert.That(dt.Columns["CHECKSUM"].DataType == typeof(UInt64) || dt.Columns["CHECKSUM"].DataType == typeof(Int64)); - Assert.True(dt.Rows.Count == 1); - Assert.AreEqual("Tables", dt.TableName); - Assert.AreEqual("test1", dt.Rows[0][2]); + Assert.That(dt.Rows.Count == 1); + Assert.That(dt.TableName, Is.EqualTo("Tables")); + Assert.That(dt.Rows[0][2], Is.EqualTo("test1")); } [Test] @@ -179,63 +182,63 @@ col3 varchar(50) character set utf8, col4 tinyint unsigned, restrictions[1] = Connection.Database; restrictions[2] = "Test"; DataTable dt = Connection.GetSchema("Columns", restrictions); - Assert.AreEqual(5, dt.Rows.Count); - Assert.AreEqual("Columns", dt.TableName); + Assert.That(dt.Rows.Count, Is.EqualTo(5)); + Assert.That(dt.TableName, Is.EqualTo("Columns")); if (Connection.driver.Version.isAtLeast(8, 0, 1)) { - Assert.True(dt.Columns["ORDINAL_POSITION"].DataType == typeof(UInt32)); - Assert.True(dt.Columns["CHARACTER_MAXIMUM_LENGTH"].DataType == typeof(Int64)); - Assert.True(dt.Columns["NUMERIC_PRECISION"].DataType == typeof(UInt64)); - Assert.True(dt.Columns["NUMERIC_SCALE"].DataType == typeof(UInt64)); + Assert.That(dt.Columns["ORDINAL_POSITION"].DataType == typeof(UInt32)); + Assert.That(dt.Columns["CHARACTER_MAXIMUM_LENGTH"].DataType == typeof(Int64)); + Assert.That(dt.Columns["NUMERIC_PRECISION"].DataType == typeof(UInt64)); + Assert.That(dt.Columns["NUMERIC_SCALE"].DataType == typeof(UInt64)); } else { - Assert.True(dt.Columns["ORDINAL_POSITION"].DataType == typeof(UInt64)); - Assert.True(dt.Columns["CHARACTER_MAXIMUM_LENGTH"].DataType == typeof(UInt64)); - Assert.True(dt.Columns["NUMERIC_PRECISION"].DataType == typeof(UInt64)); - Assert.True(dt.Columns["NUMERIC_SCALE"].DataType == typeof(UInt64)); + Assert.That(dt.Columns["ORDINAL_POSITION"].DataType == typeof(UInt64)); + Assert.That(dt.Columns["CHARACTER_MAXIMUM_LENGTH"].DataType == typeof(UInt64)); + Assert.That(dt.Columns["NUMERIC_PRECISION"].DataType == typeof(UInt64)); + Assert.That(dt.Columns["NUMERIC_SCALE"].DataType == typeof(UInt64)); } // first column - Assert.AreEqual((Connection.Database).ToUpper(), dt.Rows[0]["TABLE_SCHEMA"].ToString().ToUpper()); - Assert.AreEqual("COL1", dt.Rows[0]["COLUMN_NAME"].ToString().ToUpper()); - Assert.AreEqual(1, Convert.ToInt32(dt.Rows[0]["ORDINAL_POSITION"])); - Assert.AreEqual("YES", dt.Rows[0]["IS_NULLABLE"]); - Assert.AreEqual("INT", dt.Rows[0]["DATA_TYPE"].ToString().ToUpper()); + Assert.That(dt.Rows[0]["TABLE_SCHEMA"].ToString().ToUpper(), Is.EqualTo((Connection.Database).ToUpper())); + Assert.That(dt.Rows[0]["COLUMN_NAME"].ToString().ToUpper(), Is.EqualTo("COL1")); + Assert.That(Convert.ToInt32(dt.Rows[0]["ORDINAL_POSITION"]), Is.EqualTo(1)); + Assert.That(dt.Rows[0]["IS_NULLABLE"], Is.EqualTo("YES")); + Assert.That(dt.Rows[0]["DATA_TYPE"].ToString().ToUpper(), Is.EqualTo("INT")); // second column - Assert.AreEqual((Connection.Database).ToUpper(), dt.Rows[1]["TABLE_SCHEMA"].ToString().ToUpper()); - Assert.AreEqual("COL2", dt.Rows[1]["COLUMN_NAME"].ToString().ToUpper()); - Assert.AreEqual(2, Convert.ToInt32(dt.Rows[1]["ORDINAL_POSITION"])); - Assert.AreEqual("YES", dt.Rows[1]["IS_NULLABLE"]); - Assert.AreEqual("DECIMAL", dt.Rows[1]["DATA_TYPE"].ToString().ToUpper()); - Assert.AreEqual("DECIMAL(20,5)", dt.Rows[1]["COLUMN_TYPE"].ToString().ToUpper()); - Assert.AreEqual(20, Convert.ToInt32(dt.Rows[1]["NUMERIC_PRECISION"])); - Assert.AreEqual(5, Convert.ToInt32(dt.Rows[1]["NUMERIC_SCALE"])); + Assert.That(dt.Rows[1]["TABLE_SCHEMA"].ToString().ToUpper(), Is.EqualTo((Connection.Database).ToUpper())); + Assert.That(dt.Rows[1]["COLUMN_NAME"].ToString().ToUpper(), Is.EqualTo("COL2")); + Assert.That(Convert.ToInt32(dt.Rows[1]["ORDINAL_POSITION"]), Is.EqualTo(2)); + Assert.That(dt.Rows[1]["IS_NULLABLE"], Is.EqualTo("YES")); + Assert.That(dt.Rows[1]["DATA_TYPE"].ToString().ToUpper(), Is.EqualTo("DECIMAL")); + Assert.That(dt.Rows[1]["COLUMN_TYPE"].ToString().ToUpper(), Is.EqualTo("DECIMAL(20,5)")); + Assert.That(Convert.ToInt32(dt.Rows[1]["NUMERIC_PRECISION"]), Is.EqualTo(20)); + Assert.That(Convert.ToInt32(dt.Rows[1]["NUMERIC_SCALE"]), Is.EqualTo(5)); // third column - Assert.AreEqual((Connection.Database).ToUpper(), dt.Rows[2]["TABLE_SCHEMA"].ToString().ToUpper()); - Assert.AreEqual("COL3", dt.Rows[2]["COLUMN_NAME"].ToString().ToUpper()); - Assert.AreEqual(3, Convert.ToInt32(dt.Rows[2]["ORDINAL_POSITION"])); - Assert.AreEqual("YES", dt.Rows[2]["IS_NULLABLE"]); - Assert.AreEqual("VARCHAR", dt.Rows[2]["DATA_TYPE"].ToString().ToUpper()); - Assert.AreEqual("VARCHAR(50)", dt.Rows[2]["COLUMN_TYPE"].ToString().ToUpper()); + Assert.That(dt.Rows[2]["TABLE_SCHEMA"].ToString().ToUpper(), Is.EqualTo((Connection.Database).ToUpper())); + Assert.That(dt.Rows[2]["COLUMN_NAME"].ToString().ToUpper(), Is.EqualTo("COL3")); + Assert.That(Convert.ToInt32(dt.Rows[2]["ORDINAL_POSITION"]), Is.EqualTo(3)); + Assert.That(dt.Rows[2]["IS_NULLABLE"], Is.EqualTo("YES")); + Assert.That(dt.Rows[2]["DATA_TYPE"].ToString().ToUpper(), Is.EqualTo("VARCHAR")); + Assert.That(dt.Rows[2]["COLUMN_TYPE"].ToString().ToUpper(), Is.EqualTo("VARCHAR(50)")); // fourth column - Assert.AreEqual((Connection.Database).ToUpper(), dt.Rows[3]["TABLE_SCHEMA"].ToString().ToUpper()); - Assert.AreEqual("COL4", dt.Rows[3]["COLUMN_NAME"].ToString().ToUpper()); - Assert.AreEqual(4, Convert.ToInt32(dt.Rows[3]["ORDINAL_POSITION"])); - Assert.AreEqual("YES", dt.Rows[3]["IS_NULLABLE"]); - Assert.AreEqual("TINYINT", dt.Rows[3]["DATA_TYPE"].ToString().ToUpper()); + Assert.That(dt.Rows[3]["TABLE_SCHEMA"].ToString().ToUpper(), Is.EqualTo((Connection.Database).ToUpper())); + Assert.That(dt.Rows[3]["COLUMN_NAME"].ToString().ToUpper(), Is.EqualTo("COL4")); + Assert.That(Convert.ToInt32(dt.Rows[3]["ORDINAL_POSITION"]), Is.EqualTo(4)); + Assert.That(dt.Rows[3]["IS_NULLABLE"], Is.EqualTo("YES")); + Assert.That(dt.Rows[3]["DATA_TYPE"].ToString().ToUpper(), Is.EqualTo("TINYINT")); // fifth column - Assert.AreEqual((Connection.Database).ToUpper(), dt.Rows[4]["TABLE_SCHEMA"].ToString().ToUpper()); - Assert.AreEqual("COL5", dt.Rows[4]["COLUMN_NAME"].ToString().ToUpper()); - Assert.AreEqual(5, Convert.ToInt32(dt.Rows[4]["ORDINAL_POSITION"])); - Assert.AreEqual("YES", dt.Rows[4]["IS_NULLABLE"]); - Assert.AreEqual("VARCHAR", dt.Rows[4]["DATA_TYPE"].ToString().ToUpper()); - Assert.AreEqual("VARCHAR(20)", dt.Rows[4]["COLUMN_TYPE"].ToString().ToUpper()); - Assert.AreEqual("BOO", dt.Rows[4]["COLUMN_DEFAULT"].ToString().ToUpper()); + Assert.That(dt.Rows[4]["TABLE_SCHEMA"].ToString().ToUpper(), Is.EqualTo((Connection.Database).ToUpper())); + Assert.That(dt.Rows[4]["COLUMN_NAME"].ToString().ToUpper(), Is.EqualTo("COL5")); + Assert.That(Convert.ToInt32(dt.Rows[4]["ORDINAL_POSITION"]), Is.EqualTo(5)); + Assert.That(dt.Rows[4]["IS_NULLABLE"], Is.EqualTo("YES")); + Assert.That(dt.Rows[4]["DATA_TYPE"].ToString().ToUpper(), Is.EqualTo("VARCHAR")); + Assert.That(dt.Rows[4]["COLUMN_TYPE"].ToString().ToUpper(), Is.EqualTo("VARCHAR(20)")); + Assert.That(dt.Rows[4]["COLUMN_DEFAULT"].ToString().ToUpper(), Is.EqualTo("BOO")); } @@ -246,8 +249,8 @@ col3 varchar(50) character set utf8, col4 tinyint unsigned, [Test] public void CanGetSchemaInformationGeneratedColumns() { - if (!System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows)) Assert.Ignore(); - if (Version < new Version(5, 7, 6)) Assert.Ignore(); + Assume.That(System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows)); + Assume.That(Version >= new Version(5, 7, 6)); ExecuteSQL("CREATE TABLE `Test` (`ID` int NOT NULL AUTO_INCREMENT PRIMARY KEY, `Name` char(35) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL)"); @@ -255,13 +258,13 @@ public void CanGetSchemaInformationGeneratedColumns() cmd.ExecuteNonQuery(); DataTable dt = Connection.GetSchema("Columns", new string[] { null, null, "Test", null }); - Assert.AreEqual(3, dt.Rows.Count); - Assert.AreEqual("Columns", dt.TableName); + Assert.That(dt.Rows.Count, Is.EqualTo(3)); + Assert.That(dt.TableName, Is.EqualTo("Columns")); if (Version.Major >= 5 && Version.Minor >= 7 && Version.Build >= 6) { - Assert.AreEqual("char", dt.Rows[2]["DATA_TYPE"]); - Assert.AreEqual("Name", dt.Rows[2]["GENERATION_EXPRESSION"].ToString().Trim('`')); - Assert.AreEqual("STORED GENERATED", dt.Rows[2]["EXTRA"]); + Assert.That(dt.Rows[2]["DATA_TYPE"], Is.EqualTo("char")); + Assert.That(dt.Rows[2]["GENERATION_EXPRESSION"].ToString().Trim('`'), Is.EqualTo("Name")); + Assert.That(dt.Rows[2]["EXTRA"], Is.EqualTo("STORED GENERATED")); } } @@ -275,11 +278,11 @@ public void EnumAndSetColumns() ExecuteSQL("CREATE TABLE Test (col1 set('A','B','C'), col2 enum('A','B','C'))"); DataTable dt = Connection.GetSchema("Columns", new string[] { null, null, "Test", null }); - Assert.AreEqual(2, dt.Rows.Count); - Assert.AreEqual("set", dt.Rows[0]["DATA_TYPE"]); - Assert.AreEqual("enum", dt.Rows[1]["DATA_TYPE"]); - Assert.AreEqual("set('A','B','C')", dt.Rows[0]["COLUMN_TYPE"]); - Assert.AreEqual("enum('A','B','C')", dt.Rows[1]["COLUMN_TYPE"]); + Assert.That(dt.Rows.Count, Is.EqualTo(2)); + Assert.That(dt.Rows[0]["DATA_TYPE"], Is.EqualTo("set")); + Assert.That(dt.Rows[1]["DATA_TYPE"], Is.EqualTo("enum")); + Assert.That(dt.Rows[0]["COLUMN_TYPE"], Is.EqualTo("set('A','B','C')")); + Assert.That(dt.Rows[1]["COLUMN_TYPE"], Is.EqualTo("enum('A','B','C')")); } [Test] @@ -292,9 +295,9 @@ public void Procedures() restrictions[1] = Connection.Database; restrictions[2] = "spTest"; DataTable dt = Connection.GetSchema("Procedures", restrictions); - Assert.True(dt.Rows.Count == 1); - Assert.AreEqual("Procedures", dt.TableName); - Assert.AreEqual("spTest", dt.Rows[0][3]); + Assert.That(dt.Rows.Count == 1); + Assert.That(dt.TableName, Is.EqualTo("Procedures")); + Assert.That(dt.Rows[0][3], Is.EqualTo("spTest")); } /// @@ -306,8 +309,8 @@ public void ProcedureParameters() { var dt = Connection.GetSchema("PROCEDURE PARAMETERS"); - Assert.AreEqual("Procedure Parameters", dt.TableName); - Assert.True(dt.Rows.Count > 0); + Assert.That(dt.TableName, Is.EqualTo("Procedure Parameters")); + Assert.That(dt.Rows.Count > 0); } [Test] @@ -320,9 +323,9 @@ public void Functions() restrictions[1] = Connection.Database; restrictions[2] = "spFunc"; DataTable dt = Connection.GetSchema("Procedures", restrictions); - Assert.True(dt.Rows.Count == 1); - Assert.AreEqual("Procedures", dt.TableName); - Assert.AreEqual("spFunc", dt.Rows[0][3]); + Assert.That(dt.Rows.Count == 1); + Assert.That(dt.TableName, Is.EqualTo("Procedures")); + Assert.That(dt.Rows[0][3], Is.EqualTo("spFunc")); } [Test] @@ -333,29 +336,29 @@ public void Indexes() restrictions[2] = "Test"; restrictions[1] = Connection.Database; DataTable dt = Connection.GetSchema("Indexes", restrictions); - Assert.AreEqual(1, dt.Rows.Count); - StringAssert.AreEqualIgnoringCase("test", dt.Rows[0]["TABLE_NAME"].ToString()); - Assert.True((bool)dt.Rows[0]["PRIMARY"]); - Assert.True((bool)dt.Rows[0]["UNIQUE"]); + Assert.That(dt.Rows.Count, Is.EqualTo(1)); + Assert.That(dt.Rows[0]["TABLE_NAME"].ToString(), Is.EqualTo("test").IgnoreCase); + Assert.That((bool)dt.Rows[0]["PRIMARY"]); + Assert.That((bool)dt.Rows[0]["UNIQUE"]); ExecuteSQL("DROP TABLE IF EXISTS Test"); ExecuteSQL("CREATE TABLE Test (id int, name varchar(50), " + "UNIQUE KEY key2 (name))"); dt = Connection.GetSchema("Indexes", restrictions); - Assert.AreEqual(1, dt.Rows.Count); - StringAssert.AreEqualIgnoringCase("test", dt.Rows[0]["TABLE_NAME"].ToString()); - Assert.AreEqual("key2", dt.Rows[0]["INDEX_NAME"]); - Assert.False((bool)dt.Rows[0]["PRIMARY"]); - Assert.True((bool)dt.Rows[0]["UNIQUE"]); + Assert.That(dt.Rows.Count, Is.EqualTo(1)); + Assert.That(dt.Rows[0]["TABLE_NAME"].ToString(), Is.EqualTo("test").IgnoreCase); + Assert.That(dt.Rows[0]["INDEX_NAME"], Is.EqualTo("key2")); + Assert.That(!(bool)dt.Rows[0]["PRIMARY"]); + Assert.That((bool)dt.Rows[0]["UNIQUE"]); restrictions[3] = "key2"; dt = Connection.GetSchema("Indexes", restrictions); - Assert.AreEqual(1, dt.Rows.Count); - StringAssert.AreEqualIgnoringCase("test", dt.Rows[0]["TABLE_NAME"].ToString()); - Assert.AreEqual("key2", dt.Rows[0]["INDEX_NAME"]); - Assert.False((bool)dt.Rows[0]["PRIMARY"]); - Assert.True((bool)dt.Rows[0]["UNIQUE"]); + Assert.That(dt.Rows.Count, Is.EqualTo(1)); + Assert.That(dt.Rows[0]["TABLE_NAME"].ToString(), Is.EqualTo("test").IgnoreCase); + Assert.That(dt.Rows[0]["INDEX_NAME"], Is.EqualTo("key2")); + Assert.That(!(bool)dt.Rows[0]["PRIMARY"]); + Assert.That((bool)dt.Rows[0]["UNIQUE"]); /// /// Bug #48101 MySqlConnection.GetSchema on "Indexes" throws when there's a table named "b`a`d" @@ -366,11 +369,11 @@ public void Indexes() restrictions[2] = "Te`s`t"; dt = Connection.GetSchema("Indexes", restrictions); - Assert.AreEqual(1, dt.Rows.Count); - StringAssert.AreEqualIgnoringCase("te`s`t", dt.Rows[0]["TABLE_NAME"].ToString()); - Assert.AreEqual("key2", dt.Rows[0]["INDEX_NAME"]); - Assert.False((bool)dt.Rows[0]["PRIMARY"]); - Assert.False((bool)dt.Rows[0]["UNIQUE"]); + Assert.That(dt.Rows.Count, Is.EqualTo(1)); + Assert.That(dt.Rows[0]["TABLE_NAME"].ToString(), Is.EqualTo("te`s`t").IgnoreCase); + Assert.That(dt.Rows[0]["INDEX_NAME"], Is.EqualTo("key2")); + Assert.That(!(bool)dt.Rows[0]["PRIMARY"]); + Assert.That(!(bool)dt.Rows[0]["UNIQUE"]); } [Test] @@ -381,9 +384,9 @@ public void IndexColumns() restrictions[2] = "Test"; restrictions[1] = Connection.Database; DataTable dt = Connection.GetSchema("IndexColumns", restrictions); - Assert.AreEqual(1, dt.Rows.Count); - StringAssert.AreEqualIgnoringCase("test", dt.Rows[0]["TABLE_NAME"].ToString()); - Assert.AreEqual("id", dt.Rows[0]["COLUMN_NAME"]); + Assert.That(dt.Rows.Count, Is.EqualTo(1)); + Assert.That(dt.Rows[0]["TABLE_NAME"].ToString(), Is.EqualTo("test").IgnoreCase); + Assert.That(dt.Rows[0]["COLUMN_NAME"], Is.EqualTo("id")); ExecuteSQL("DROP TABLE IF EXISTS Test"); ExecuteSQL("CREATE TABLE Test (id int, id1 int, id2 int, " + @@ -392,29 +395,29 @@ public void IndexColumns() restrictions[1] = Connection.Database; restrictions[4] = "id2"; dt = Connection.GetSchema("IndexColumns", restrictions); - Assert.AreEqual(1, dt.Rows.Count); - StringAssert.AreEqualIgnoringCase("test", dt.Rows[0]["TABLE_NAME"].ToString()); - Assert.AreEqual("id2", dt.Rows[0]["COLUMN_NAME"]); - Assert.AreEqual(2, dt.Rows[0]["ORDINAL_POSITION"]); + Assert.That(dt.Rows.Count, Is.EqualTo(1)); + Assert.That(dt.Rows[0]["TABLE_NAME"].ToString(), Is.EqualTo("test").IgnoreCase); + Assert.That(dt.Rows[0]["COLUMN_NAME"], Is.EqualTo("id2")); + Assert.That(dt.Rows[0]["ORDINAL_POSITION"], Is.EqualTo(2)); restrictions[3] = "key1"; dt = Connection.GetSchema("IndexColumns", restrictions); - Assert.AreEqual(1, dt.Rows.Count); - StringAssert.AreEqualIgnoringCase("test", dt.Rows[0]["TABLE_NAME"].ToString()); - Assert.AreEqual("id2", dt.Rows[0]["COLUMN_NAME"]); - Assert.AreEqual(2, dt.Rows[0]["ORDINAL_POSITION"]); + Assert.That(dt.Rows.Count, Is.EqualTo(1)); + Assert.That(dt.Rows[0]["TABLE_NAME"].ToString(), Is.EqualTo("test").IgnoreCase); + Assert.That(dt.Rows[0]["COLUMN_NAME"], Is.EqualTo("id2")); + Assert.That(dt.Rows[0]["ORDINAL_POSITION"], Is.EqualTo(2)); restrictions = new string[3]; restrictions[1] = Connection.Database; restrictions[2] = "Test"; dt = Connection.GetSchema("IndexColumns", restrictions); - Assert.AreEqual(2, dt.Rows.Count); - StringAssert.AreEqualIgnoringCase("test", dt.Rows[0]["TABLE_NAME"].ToString()); - Assert.AreEqual("id1", dt.Rows[0]["COLUMN_NAME"]); - Assert.AreEqual(1, dt.Rows[0]["ORDINAL_POSITION"]); - StringAssert.AreEqualIgnoringCase("test", dt.Rows[0]["TABLE_NAME"].ToString()); - Assert.AreEqual("id2", dt.Rows[1]["COLUMN_NAME"]); - Assert.AreEqual(2, dt.Rows[1]["ORDINAL_POSITION"]); + Assert.That(dt.Rows.Count, Is.EqualTo(2)); + Assert.That(dt.Rows[0]["TABLE_NAME"].ToString(), Is.EqualTo("test").IgnoreCase); + Assert.That(dt.Rows[0]["COLUMN_NAME"], Is.EqualTo("id1")); + Assert.That(dt.Rows[0]["ORDINAL_POSITION"], Is.EqualTo(1)); + Assert.That(dt.Rows[0]["TABLE_NAME"].ToString(), Is.EqualTo("test").IgnoreCase); + Assert.That(dt.Rows[1]["COLUMN_NAME"], Is.EqualTo("id2")); + Assert.That(dt.Rows[1]["ORDINAL_POSITION"], Is.EqualTo(2)); restrictions = new string[4]; ExecuteSQL("DROP TABLE IF EXISTS Test"); @@ -435,9 +438,9 @@ public void Views() restrictions[1] = Connection.Database; restrictions[2] = "vw"; DataTable dt = Connection.GetSchema("Views", restrictions); - Assert.True(dt.Rows.Count == 1); - Assert.AreEqual("Views", dt.TableName); - Assert.AreEqual("vw", dt.Rows[0]["TABLE_NAME"]); + Assert.That(dt.Rows.Count == 1); + Assert.That(dt.TableName, Is.EqualTo("Views")); + Assert.That(dt.Rows[0]["TABLE_NAME"], Is.EqualTo("vw")); } [Test] @@ -450,11 +453,11 @@ public void ViewColumns() restrictions[1] = Connection.Database; restrictions[2] = "vw"; DataTable dt = Connection.GetSchema("ViewColumns", restrictions); - Assert.True(dt.Rows.Count == 1); - Assert.AreEqual("ViewColumns", dt.TableName); - Assert.AreEqual(Connection.Database.ToLower(), dt.Rows[0]["VIEW_SCHEMA"].ToString().ToLower()); - Assert.AreEqual("vw", dt.Rows[0]["VIEW_NAME"]); - Assert.AreEqual("theTime", dt.Rows[0]["COLUMN_NAME"]); + Assert.That(dt.Rows.Count == 1); + Assert.That(dt.TableName, Is.EqualTo("ViewColumns")); + Assert.That(dt.Rows[0]["VIEW_SCHEMA"].ToString().ToLower(), Is.EqualTo(Connection.Database.ToLower())); + Assert.That(dt.Rows[0]["VIEW_NAME"], Is.EqualTo("vw")); + Assert.That(dt.Rows[0]["COLUMN_NAME"], Is.EqualTo("theTime")); } [Test] @@ -470,14 +473,14 @@ public void SingleForeignKey() restrictions[1] = Connection.Database; restrictions[2] = "child"; DataTable dt = Connection.GetSchema("Foreign Keys", restrictions); - Assert.AreEqual(1, dt.Rows.Count); + Assert.That(dt.Rows.Count, Is.EqualTo(1)); DataRow row = dt.Rows[0]; - Assert.AreEqual(Connection.Database.ToLower(), row[1].ToString().ToLower()); - Assert.AreEqual("c1", row[2]); - Assert.AreEqual(Connection.Database.ToLower(), row[4].ToString().ToLower()); - Assert.AreEqual("child", row[5]); - Assert.AreEqual(Connection.Database.ToLower(), row[10].ToString().ToLower()); - Assert.AreEqual("parent", row[11]); + Assert.That(row[1].ToString().ToLower(), Is.EqualTo(Connection.Database.ToLower())); + Assert.That(row[2], Is.EqualTo("c1")); + Assert.That(row[4].ToString().ToLower(), Is.EqualTo(Connection.Database.ToLower())); + Assert.That(row[5], Is.EqualTo("child")); + Assert.That(row[10].ToString().ToLower(), Is.EqualTo(Connection.Database.ToLower())); + Assert.That(row[11], Is.EqualTo("parent")); } /// @@ -486,7 +489,7 @@ public void SingleForeignKey() [Test] public void ForeignKeys() { - if (!System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows)) Assert.Ignore(); + Assume.That(System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows)); ExecuteSQL("DROP TABLE IF EXISTS product_order"); ExecuteSQL("DROP TABLE IF EXISTS customer"); @@ -503,7 +506,7 @@ public void ForeignKeys() "FOREIGN KEY (customer_id) REFERENCES customer(id)) ENGINE=INNODB"); DataTable dt = Connection.GetSchema("Foreign Keys"); - Assert.True(dt.Columns.Contains("REFERENCED_TABLE_CATALOG")); + Assert.That(dt.Columns.Contains("REFERENCED_TABLE_CATALOG")); } [Test] @@ -528,22 +531,22 @@ public void MultiSingleForeignKey() restrictions[1] = Connection.Database; restrictions[2] = "product_order"; DataTable dt = Connection.GetSchema("Foreign Keys", restrictions); - Assert.AreEqual(2, dt.Rows.Count); + Assert.That(dt.Rows.Count, Is.EqualTo(2)); DataRow row = dt.Rows[0]; - Assert.AreEqual(Connection.Database.ToLower(), row[1].ToString().ToLower()); - Assert.AreEqual("product_order_ibfk_1", row[2]); - Assert.AreEqual(Connection.Database.ToLower(), row[4].ToString().ToLower()); - Assert.AreEqual("product_order", row[5]); - Assert.AreEqual(Connection.Database.ToLower(), row[10].ToString().ToLower()); - Assert.AreEqual("product", row[11]); + Assert.That(row[1].ToString().ToLower(), Is.EqualTo(Connection.Database.ToLower())); + Assert.That(row[2], Is.EqualTo("product_order_ibfk_1")); + Assert.That(row[4].ToString().ToLower(), Is.EqualTo(Connection.Database.ToLower())); + Assert.That(row[5], Is.EqualTo("product_order")); + Assert.That(row[10].ToString().ToLower(), Is.EqualTo(Connection.Database.ToLower())); + Assert.That(row[11], Is.EqualTo("product")); row = dt.Rows[1]; - Assert.AreEqual(Connection.Database.ToLower(), row[1].ToString().ToLower()); - Assert.AreEqual("product_order_ibfk_2", row[2]); - Assert.AreEqual(Connection.Database.ToLower(), row[4].ToString().ToLower()); - Assert.AreEqual("product_order", row[5]); - Assert.AreEqual(Connection.Database.ToLower(), row[10].ToString().ToLower()); - Assert.AreEqual("customer", row[11]); + Assert.That(row[1].ToString().ToLower(), Is.EqualTo(Connection.Database.ToLower())); + Assert.That(row[2], Is.EqualTo("product_order_ibfk_2")); + Assert.That(row[4].ToString().ToLower(), Is.EqualTo(Connection.Database.ToLower())); + Assert.That(row[5], Is.EqualTo("product_order")); + Assert.That(row[10].ToString().ToLower(), Is.EqualTo(Connection.Database.ToLower())); + Assert.That(row[11], Is.EqualTo("customer")); } [Test] @@ -561,13 +564,13 @@ public void Triggers() restrictions[1] = Connection.Database; restrictions[2] = "test1"; DataTable dt = Connection.GetSchema("Triggers", restrictions); - Assert.True(dt.Rows.Count == 1); - Assert.AreEqual("Triggers", dt.TableName); - Assert.AreEqual("trigger1", dt.Rows[0]["TRIGGER_NAME"]); - Assert.AreEqual("INSERT", dt.Rows[0]["EVENT_MANIPULATION"]); - Assert.AreEqual("test1", dt.Rows[0]["EVENT_OBJECT_TABLE"]); - Assert.AreEqual("ROW", dt.Rows[0]["ACTION_ORIENTATION"]); - Assert.AreEqual("AFTER", dt.Rows[0]["ACTION_TIMING"]); + Assert.That(dt.Rows.Count == 1); + Assert.That(dt.TableName, Is.EqualTo("Triggers")); + Assert.That(dt.Rows[0]["TRIGGER_NAME"], Is.EqualTo("trigger1")); + Assert.That(dt.Rows[0]["EVENT_MANIPULATION"], Is.EqualTo("INSERT")); + Assert.That(dt.Rows[0]["EVENT_OBJECT_TABLE"], Is.EqualTo("test1")); + Assert.That(dt.Rows[0]["ACTION_ORIENTATION"], Is.EqualTo("ROW")); + Assert.That(dt.Rows[0]["ACTION_TIMING"], Is.EqualTo("AFTER")); } [Test] @@ -580,10 +583,10 @@ public void UsingQuotedRestrictions() restrictions[1] = Connection.Database; restrictions[2] = "`test1`"; DataTable dt = Connection.GetSchema("Tables", restrictions); - Assert.True(dt.Rows.Count == 1); - Assert.AreEqual("Tables", dt.TableName); - Assert.AreEqual("test1", dt.Rows[0][2]); - Assert.AreEqual("`test1`", restrictions[2]); + Assert.That(dt.Rows.Count == 1); + Assert.That(dt.TableName, Is.EqualTo("Tables")); + Assert.That(dt.Rows[0][2], Is.EqualTo("test1")); + Assert.That(restrictions[2], Is.EqualTo("`test1`")); } [Test] @@ -591,8 +594,8 @@ public void ReservedWords() { DataTable dt = Connection.GetSchema("ReservedWords"); foreach (DataRow row in dt.Rows) - Assert.False(String.IsNullOrEmpty(row[0] as string)); - Assert.AreEqual(235, dt.Rows.Count); // number of keywords: 235 + Assert.That(!String.IsNullOrEmpty(row[0] as string)); + Assert.That(dt.Rows.Count, Is.EqualTo(235)); // number of keywords: 235 } [Test] @@ -611,22 +614,22 @@ public void GetSchemaCollections() MySqlSchemaCollection schemaCollection = schema.GetSchema("columns", restrictions); - Assert.True(schemaCollection.Columns.Count == 20); - Assert.True(schemaCollection.Rows.Count == 2); - Assert.AreEqual("parent", schemaCollection.Rows[0]["TABLE_NAME"]); - Assert.AreEqual("id", schemaCollection.Rows[0]["COLUMN_NAME"]); + Assert.That(schemaCollection.Columns.Count == 20); + Assert.That(schemaCollection.Rows.Count == 2); + Assert.That(schemaCollection.Rows[0]["TABLE_NAME"], Is.EqualTo("parent")); + Assert.That(schemaCollection.Rows[0]["COLUMN_NAME"], Is.EqualTo("id")); schemaCollection = schema.GetForeignKeysAsync(restrictions, false).GetAwaiter().GetResult(); - Assert.True(schemaCollection.AsDataTable().Columns.Contains("REFERENCED_TABLE_NAME")); + Assert.That(schemaCollection.AsDataTable().Columns.Contains("REFERENCED_TABLE_NAME")); schemaCollection = schema.GetForeignKeyColumnsAsync(restrictions, false).GetAwaiter().GetResult(); - Assert.True(schemaCollection.AsDataTable().Columns.Contains("REFERENCED_COLUMN_NAME")); + Assert.That(schemaCollection.AsDataTable().Columns.Contains("REFERENCED_COLUMN_NAME")); schemaCollection = schema.GetUDFAsync(restrictions, false).GetAwaiter().GetResult(); - Assert.True(schemaCollection.AsDataTable().Columns.Contains("RETURN_TYPE")); + Assert.That(schemaCollection.AsDataTable().Columns.Contains("RETURN_TYPE")); schemaCollection = schema.GetUsersAsync(restrictions, false).GetAwaiter().GetResult(); - Assert.True(schemaCollection.AsDataTable().Columns.Contains("USERNAME")); + Assert.That(schemaCollection.AsDataTable().Columns.Contains("USERNAME")); using (var conn = new MySqlConnection(Connection.ConnectionString)) { @@ -635,8 +638,8 @@ public void GetSchemaCollections() foreach (DataRow row in table.Rows) foreach (DataColumn col in table.Columns) { - Assert.IsNotNull(col.ColumnName); - Assert.IsNotNull(row[col]); + Assert.That(col.ColumnName, Is.Not.Null); + Assert.That(row[col], Is.Not.Null); } } @@ -661,11 +664,11 @@ public void ColumnSizeWithOldGuids() { DataTable schemaTable = reader.GetSchemaTable(); - Assert.AreEqual(36, schemaTable.Rows[0]["ColumnSize"]); - Assert.AreEqual(16, schemaTable.Rows[1]["ColumnSize"]); - Assert.AreEqual(37, schemaTable.Rows[2]["ColumnSize"]); - Assert.AreEqual(255, schemaTable.Rows[3]["ColumnSize"]); - Assert.AreEqual(65535, schemaTable.Rows[4]["ColumnSize"]); + Assert.That(schemaTable.Rows[0]["ColumnSize"], Is.EqualTo(36)); + Assert.That(schemaTable.Rows[1]["ColumnSize"], Is.EqualTo(16)); + Assert.That(schemaTable.Rows[2]["ColumnSize"], Is.EqualTo(37)); + Assert.That(schemaTable.Rows[3]["ColumnSize"], Is.EqualTo(255)); + Assert.That(schemaTable.Rows[4]["ColumnSize"], Is.EqualTo(65535)); } } } @@ -677,8 +680,8 @@ public void ColumnSizeWithOldGuids() [Test] public void IsLongProperty() { - if (!Platform.IsWindows()) Assert.Ignore("This test is for Windows OS only."); - if (Version < new Version(5, 7, 6)) Assert.Ignore("This test is for MySql 5.7.6 or higher"); + Assume.That(Platform.IsWindows(), "This test is for Windows OS only."); + Assume.That(Version >= new Version(5, 7, 6), "This test is for MySql 5.7.6 or higher"); ExecuteSQL("Drop table if exists datatypes1"); ExecuteSQL("create table datatypes1(`longtext` longtext,`longblob` longblob)"); ExecuteSQL("insert into datatypes1 values('test', _binary'test')"); @@ -688,10 +691,10 @@ public void IsLongProperty() using (var reader = cmd.ExecuteReader()) { var schemaTable = reader.GetSchemaTable(); - Assert.AreEqual("-1", schemaTable.Rows[0]["ColumnSize"].ToString(), "Matching the Column Size"); - Assert.AreEqual("True", schemaTable.Rows[0]["IsLong"].ToString(), "Matching the Column Size"); - Assert.AreEqual("-1", schemaTable.Rows[1]["ColumnSize"].ToString(), "Matching the Column Size"); - Assert.AreEqual("True", schemaTable.Rows[1]["IsLong"].ToString(), "Matching the Column Size"); + Assert.That(schemaTable.Rows[0]["ColumnSize"].ToString(), Is.EqualTo("-1"), "Matching the Column Size"); + Assert.That(schemaTable.Rows[0]["IsLong"].ToString(), Is.EqualTo("True"), "Matching the Column Size"); + Assert.That(schemaTable.Rows[1]["ColumnSize"].ToString(), Is.EqualTo("-1"), "Matching the Column Size"); + Assert.That(schemaTable.Rows[1]["IsLong"].ToString(), Is.EqualTo("True"), "Matching the Column Size"); } } } @@ -702,8 +705,8 @@ public void IsLongProperty() [Test] public void NumericPrecisionProperty() { - if (!Platform.IsWindows()) Assert.Ignore("This test is for Windows OS only."); - if (Version < new Version(5, 7, 6)) Assert.Ignore(); + Assume.That(Platform.IsWindows(), "This test is for Windows OS only."); + Assume.That(Version >= new Version(5, 7, 6), "This test is for MySql 5.7.6 or higher"); ExecuteSQL("Drop table if exists datatypes2"); ExecuteSQL("create table datatypes2(decimal0 decimal(8, 0))"); using (var cmd = Connection.CreateCommand()) @@ -712,8 +715,8 @@ public void NumericPrecisionProperty() using (var reader = cmd.ExecuteReader()) { var schemaTable = reader.GetSchemaTable(); - Assert.AreEqual(8, schemaTable.Rows[0]["NumericPrecision"]); - Assert.AreEqual(0, schemaTable.Rows[0]["NumericScale"]); + Assert.That(schemaTable.Rows[0]["NumericPrecision"], Is.EqualTo(8)); + Assert.That(schemaTable.Rows[0]["NumericScale"], Is.EqualTo(0)); } } } @@ -734,18 +737,21 @@ public void GetSchemaReturnColumnsByOrdinalPosition() string[] expected = new string[] { "x", "a", "z", "c" }; for (int i = 0; i < rows.Count; i++) - Assert.AreEqual(rows[i]["COLUMN_NAME"], expected[i]); + Assert.That(expected[i], Is.EqualTo(rows[i]["COLUMN_NAME"])); } [Test, Description("Test to verify different variations in Generated Coloumns")] public void GeneratedColumnsVariations() { - if (Version < new Version(5, 7)) Assert.Ignore("This test is for MySql 5.7 or higher"); + Assume.That(Version >= new Version(5, 7, 0), "This test is for MySql 5.7 or higher"); using (var conn = new MySqlConnection(Settings.ConnectionString)) { conn.Open(); - var cmd = new MySqlCommand("create table Test(c1 int, c2 double GENERATED ALWAYS AS(c1 * 101 / 102) Stored COMMENT 'First Gen Col', c3 Json GENERATED ALWAYS AS(concat('{\"F1\":', c1, '}')) VIRTUAL COMMENT 'Second Gen /**/Col', c4 bigint GENERATED ALWAYS as (c1*10000) VIRTUAL UNIQUE KEY Comment '3rd Col' NOT NULL)", conn); + var cmd = new MySqlCommand( + @"create table Test(c1 int, + c2 double GENERATED ALWAYS AS(c1 * 101 / 102) Stored COMMENT 'First Gen Col', + c3 bigint GENERATED ALWAYS as (c1*10000) VIRTUAL UNIQUE KEY Comment '3rd Col' NOT NULL)", conn); cmd.ExecuteNonQuery(); cmd = new MySqlCommand("insert into Test(c1) values(1000)", conn); @@ -756,25 +762,25 @@ public void GeneratedColumnsVariations() using (var reader = cmd.ExecuteReader()) { - Assert.True(reader.Read(), "Matching the values"); - Assert.True(reader.GetString(0).Equals("1000", StringComparison.CurrentCulture), "Matching the values"); - Assert.True(reader.GetString(1).Equals("990.196078431", StringComparison.CurrentCulture), "Matching the values"); - Assert.True(reader.GetString(2).Equals("{\"F1\": 1000}", StringComparison.CurrentCulture), "Matching the values"); - Assert.True(reader.GetString(3).Equals("10000000", StringComparison.CurrentCulture), "Matching the values"); + Assert.That(reader.Read(), "Matching the values"); + Assert.That(reader.GetInt32(0).Equals(1000), "Matching the values"); + if (Version >= new Version(9, 3, 0)) + Assert.That(reader.GetDouble(1).Equals(990.1961), "Matching the values"); + else + Assert.That(reader.GetDouble(1).Equals(990.196078431), "Matching the values"); + Assert.That(reader.GetInt64(2).Equals(10000000), "Matching the values"); } var dt = conn.GetSchema("Columns", new[] { null, null, "Test", null }); - Assert.AreEqual(4, dt.Rows.Count, "Matching the values"); - Assert.AreEqual("Columns", dt.TableName, "Matching the values"); - Assert.AreEqual("int", dt.Rows[0]["DATA_TYPE"].ToString(), "Matching the values"); - Assert.AreEqual("double", dt.Rows[1]["DATA_TYPE"].ToString(), "Matching the values"); - Assert.AreEqual("json", dt.Rows[2]["DATA_TYPE"].ToString(), "Matching the values"); - Assert.AreEqual("bigint", dt.Rows[3]["DATA_TYPE"].ToString(), "Matching the values"); - Assert.AreEqual("", dt.Rows[0]["GENERATION_EXPRESSION"].ToString(), "Matching the values"); - Assert.AreEqual("", dt.Rows[0]["EXTRA"].ToString(), "Matching the values"); - Assert.AreEqual("STORED GENERATED", dt.Rows[1]["EXTRA"].ToString(), "Matching the values"); - Assert.AreEqual("VIRTUAL GENERATED", dt.Rows[2]["EXTRA"].ToString(), "Matching the values"); - Assert.AreEqual("VIRTUAL GENERATED", dt.Rows[3]["EXTRA"].ToString(), "Matching the values"); + Assert.That(dt.Rows.Count, Is.EqualTo(3), "Matching the values"); + Assert.That(dt.TableName, Is.EqualTo("Columns"), "Matching the values"); + Assert.That(dt.Rows[0]["DATA_TYPE"].ToString(), Is.EqualTo("int"), "Matching the values"); + Assert.That(dt.Rows[1]["DATA_TYPE"].ToString(), Is.EqualTo("double"), "Matching the values"); + Assert.That(dt.Rows[2]["DATA_TYPE"].ToString(), Is.EqualTo("bigint"), "Matching the values"); + Assert.That(dt.Rows[0]["GENERATION_EXPRESSION"].ToString(), Is.EqualTo(""), "Matching the values"); + Assert.That(dt.Rows[0]["EXTRA"].ToString(), Is.EqualTo(""), "Matching the values"); + Assert.That(dt.Rows[1]["EXTRA"].ToString(), Is.EqualTo("STORED GENERATED"), "Matching the values"); + Assert.That(dt.Rows[2]["EXTRA"].ToString(), Is.EqualTo("VIRTUAL GENERATED"), "Matching the values"); } } @@ -792,12 +798,12 @@ public void GetIndexColumnsWithFullTextIndex() { string cmdText = $"SELECT name, index_id, table_id, space from INFORMATION_SCHEMA.INNODB_INDEXES WHERE name = '{indexName}'"; MySqlCommand cmd = new MySqlCommand(cmdText, Connection); - StringAssert.AreEqualIgnoringCase(indexName, cmd.ExecuteScalar().ToString()); + Assert.That(cmd.ExecuteScalar().ToString(), Is.EqualTo(indexName).IgnoreCase); } var indexColumns = Connection.GetSchema("IndexColumns"); var row = indexColumns.Select("TABLE_NAME = 'Test'"); - StringAssert.AreEqualIgnoringCase(indexName, row[0]["INDEX_NAME"].ToString()); + Assert.That(row[0]["INDEX_NAME"].ToString(), Is.EqualTo(indexName).IgnoreCase); } } -} \ No newline at end of file +} diff --git a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/InstallerTests.cs b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/InstallerTests.cs index 6bd16bd4f..06223a189 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/InstallerTests.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/InstallerTests.cs @@ -1,16 +1,16 @@ -// Copyright © 2013, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -112,7 +112,7 @@ public void CanRemoveAssemblyBinding() && nodesDependantAssembly[0].ChildNodes[0].Attributes[0].Value.Contains("MySql")) { - Assert.True(true, "Error when removing assembly binding redirection"); + Assert.That(true, "Error when removing assembly binding redirection"); } } } diff --git a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/MediumTrust/MediumTrustDomain.cs b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/MediumTrust/MediumTrustDomain.cs index 2ad5addf6..7fe63735e 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/MediumTrust/MediumTrustDomain.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/MediumTrust/MediumTrustDomain.cs @@ -1,16 +1,16 @@ -// Copyright © 2013, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/MediumTrust/MediumTrustFixtureAttribute.cs b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/MediumTrust/MediumTrustFixtureAttribute.cs index c68e25c60..d2c7c873f 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/MediumTrust/MediumTrustFixtureAttribute.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/MediumTrust/MediumTrustFixtureAttribute.cs @@ -1,16 +1,16 @@ -// Copyright © 2013, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/MediumTrust/MediumTrustTestClassCommand.cs b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/MediumTrust/MediumTrustTestClassCommand.cs index 949e95475..da37668da 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/MediumTrust/MediumTrustTestClassCommand.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/MediumTrust/MediumTrustTestClassCommand.cs @@ -1,16 +1,16 @@ -// Copyright © 2013, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/MediumTrust/MediumTrustTestCommand.cs b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/MediumTrust/MediumTrustTestCommand.cs index 708ae40c2..79ce8fc83 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/MediumTrust/MediumTrustTestCommand.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/MediumTrust/MediumTrustTestCommand.cs @@ -1,16 +1,16 @@ -// Copyright © 2013, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/MediumTrust/MySql.MediumTrustsTests.cs b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/MediumTrust/MySql.MediumTrustsTests.cs index 235f4eb09..a75c63762 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/MediumTrust/MySql.MediumTrustsTests.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/MediumTrust/MySql.MediumTrustsTests.cs @@ -1,16 +1,16 @@ -// Copyright © 2013, 2014, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/MediumTrust/MySqlClientPermissionTests.cs b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/MediumTrust/MySqlClientPermissionTests.cs index 954e3e6ca..e25a0f97d 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/MediumTrust/MySqlClientPermissionTests.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/MediumTrust/MySqlClientPermissionTests.cs @@ -1,16 +1,16 @@ -// Copyright © 2004, 2011, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2004, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/MySQLHelperTests.cs b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/MySQLHelperTests.cs index f75706edd..2dba3548a 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/MySQLHelperTests.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/MySQLHelperTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -28,6 +28,7 @@ using System; using NUnit.Framework; +using NUnit.Framework.Legacy; using System.Data; using System.Threading.Tasks; using System.Threading; @@ -47,7 +48,7 @@ protected override void Cleanup() [Test] public void EscapeStringMethodCanEscapeQuotationMark() { - if (!System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows)) Assert.Ignore(); + Assume.That(System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows)); ExecuteSQL("CREATE TABLE Test (id int NOT NULL, name VARCHAR(100))"); @@ -60,7 +61,7 @@ public void EscapeStringMethodCanEscapeQuotationMark() cmd.CommandText = "SELECT name FROM Test WHERE id=1"; string name = (string)cmd.ExecuteScalar(); - Assert.True("test\"name\"" == name, "Update result with quotation mark"); + Assert.That("test\"name\"" == name, "Update result with quotation mark"); } #region Async @@ -73,12 +74,12 @@ public async Task ExecuteNonQueryAsync() try { int result = await MySqlHelper.ExecuteNonQueryAsync(Connection, "call MSHNonQueryAsyncSpTest", null); - Assert.AreNotEqual(-1, result); + Assert.That(result, Is.Not.EqualTo(-1)); MySqlCommand cmd = new MySqlCommand("SELECT COUNT(*) FROM MSHNonQueryAsyncTest;", Connection); cmd.CommandType = System.Data.CommandType.Text; object cnt = cmd.ExecuteScalar(); - Assert.AreEqual(100, Convert.ToInt32(cnt)); + Assert.That(Convert.ToInt32(cnt), Is.EqualTo(100)); } finally { @@ -100,34 +101,34 @@ public async Task ExecuteDataSetAsync() string sql = "SELECT MSHDataSetAsyncTable1.key FROM MSHDataSetAsyncTable1 WHERE MSHDataSetAsyncTable1.key=1; " + "SELECT MSHDataSetAsyncTable2.key FROM MSHDataSetAsyncTable2 WHERE MSHDataSetAsyncTable2.key=1"; DataSet ds = await MySqlHelper.ExecuteDatasetAsync(Connection, sql, null); - Assert.AreEqual(2, ds.Tables.Count); - Assert.AreEqual(1, ds.Tables[0].Rows.Count); - Assert.AreEqual(1, ds.Tables[1].Rows.Count); - Assert.AreEqual(1, ds.Tables[0].Rows[0]["key"]); - Assert.AreEqual(1, ds.Tables[1].Rows[0]["key"]); + Assert.That(ds.Tables.Count, Is.EqualTo(2)); + Assert.That(ds.Tables[0].Rows.Count, Is.EqualTo(1)); + Assert.That(ds.Tables[1].Rows.Count, Is.EqualTo(1)); + Assert.That(ds.Tables[0].Rows[0]["key"], Is.EqualTo(1)); + Assert.That(ds.Tables[1].Rows[0]["key"], Is.EqualTo(1)); ds = await MySqlHelper.ExecuteDatasetAsync(Connection, sql); - Assert.AreEqual(2, ds.Tables.Count); - Assert.AreEqual(1, ds.Tables[0].Rows.Count); - Assert.AreEqual(1, ds.Tables[1].Rows[0]["key"]); + Assert.That(ds.Tables.Count, Is.EqualTo(2)); + Assert.That(ds.Tables[0].Rows.Count, Is.EqualTo(1)); + Assert.That(ds.Tables[1].Rows[0]["key"], Is.EqualTo(1)); ds = await MySqlHelper.ExecuteDatasetAsync(Connection.ConnectionString, sql, null); - Assert.AreEqual(1, ds.Tables[0].Rows.Count); - Assert.AreEqual(1, ds.Tables[1].Rows.Count); - Assert.AreEqual(1, ds.Tables[0].Rows[0]["key"]); + Assert.That(ds.Tables[0].Rows.Count, Is.EqualTo(1)); + Assert.That(ds.Tables[1].Rows.Count, Is.EqualTo(1)); + Assert.That(ds.Tables[0].Rows[0]["key"], Is.EqualTo(1)); ds = await MySqlHelper.ExecuteDatasetAsync(Connection.ConnectionString, sql); - Assert.AreEqual(2, ds.Tables.Count); - Assert.AreEqual(1, ds.Tables[0].Rows.Count); - Assert.AreEqual(1, ds.Tables[1].Rows[0]["key"]); + Assert.That(ds.Tables.Count, Is.EqualTo(2)); + Assert.That(ds.Tables[0].Rows.Count, Is.EqualTo(1)); + Assert.That(ds.Tables[1].Rows[0]["key"], Is.EqualTo(1)); ds = await MySqlHelper.ExecuteDatasetAsync(Connection.ConnectionString, sql, CancellationToken.None, null); - Assert.AreEqual(2, ds.Tables.Count); - Assert.AreEqual(1, ds.Tables[0].Rows.Count); + Assert.That(ds.Tables.Count, Is.EqualTo(2)); + Assert.That(ds.Tables[0].Rows.Count, Is.EqualTo(1)); ds = await MySqlHelper.ExecuteDatasetAsync(Connection, sql, CancellationToken.None); - Assert.AreEqual(2, ds.Tables.Count); - Assert.AreEqual(1, ds.Tables[0].Rows[0]["key"]); + Assert.That(ds.Tables.Count, Is.EqualTo(2)); + Assert.That(ds.Tables[0].Rows[0]["key"], Is.EqualTo(1)); } finally { @@ -146,17 +147,17 @@ public async Task ExecuteReaderAsync() { using (MySqlDataReader reader = await MySqlHelper.ExecuteReaderAsync(Connection, "call MSHReaderAsyncSpTest")) { - Assert.NotNull(reader); - Assert.True(reader.Read(), "can read"); - Assert.True(reader.NextResult()); - Assert.True(reader.Read()); - Assert.AreEqual("done", reader.GetString(0)); + Assert.That(reader, Is.Not.Null); + Assert.That(reader.Read(), "can read"); + Assert.That(reader.NextResult()); + Assert.That(reader.Read()); + Assert.That(reader.GetString(0), Is.EqualTo("done")); reader.Close(); MySqlCommand cmd = new MySqlCommand("SELECT COUNT(*) FROM MSHReaderAsyncTest", Connection); cmd.CommandType = CommandType.Text; object cnt = cmd.ExecuteScalar(); - Assert.AreEqual(1, Convert.ToInt32(cnt)); + Assert.That(Convert.ToInt32(cnt), Is.EqualTo(1)); } } finally @@ -166,6 +167,26 @@ public async Task ExecuteReaderAsync() } } + /// + /// Bug #36303124 MySqlHelper.ExecuteReaderAsync causes stack overflow + /// + [Test] + public async Task MySqlHelper_ExecuteReader() + { + try + { + ExecuteSQL("CREATE TABLE Test (`id` int NOT NULL); INSERT INTO Test (id) VALUES (1);"); + + var reader = await MySqlHelper.ExecuteReaderAsync(Connection.ConnectionString, "SELECT * FROM Test WHERE id = @id", new MySqlParameter("@id", 1)); + + Assert.DoesNotThrowAsync(async () => await MySqlHelper.ExecuteReaderAsync(Connection.ConnectionString, "SELECT * FROM Test WHERE id = @id", new MySqlParameter("@id", 1))); + } + finally + { + ExecuteSQL("DROP TABLE Test;"); + } + } + [Test] public async Task ExecuteScalarAsync() { @@ -175,7 +196,7 @@ public async Task ExecuteScalarAsync() try { object result = await MySqlHelper.ExecuteScalarAsync(Connection, "SELECT MSHScalarAsyncTable1.key FROM MSHScalarAsyncTable1 WHERE MSHScalarAsyncTable1.key=1;"); - Assert.AreEqual(1, int.Parse(result.ToString())); + Assert.That(int.Parse(result.ToString()), Is.EqualTo(1)); } finally { @@ -192,7 +213,7 @@ public async Task ExecuteDataRowAsync() try { DataRow result = await MySqlHelper.ExecuteDataRowAsync(Connection.ConnectionString, "SELECT name FROM Test WHERE id=1", null); - Assert.AreEqual("name", result[0]); + Assert.That(result[0], Is.EqualTo("name")); } finally @@ -215,7 +236,7 @@ public void UpdateDataSet() MySqlHelper.UpdateDataSet(Connection.ConnectionString, "SELECT * FROM Test", ds, "Test"); DataRow result = ds.Tables["Test"].Rows[0]; - Assert.AreEqual("updatedName", result["name"]); + Assert.That(result["name"], Is.EqualTo("updatedName")); } [Test] @@ -234,7 +255,7 @@ public async Task UpdateDataSetAsync() { await MySqlHelper.UpdateDataSetAsync(Connection.ConnectionString, "SELECT * FROM Test", ds, "Test"); DataRow result = ds.Tables["Test"].Rows[0]; - Assert.AreEqual("updatedName", result["name"]); + Assert.That(result["name"], Is.EqualTo("updatedName")); } finally { @@ -251,20 +272,20 @@ public void ExecuteDataset() DataSet ds = MySqlHelper.ExecuteDataset(Connection, "SELECT * FROM Test"); Assert.That(ds.Tables, Has.One.Items); - Assert.AreEqual(2, ds.Tables[0].Rows.Count); - Assert.AreEqual("name", ds.Tables[0].Rows[0][1]); + Assert.That(ds.Tables[0].Rows.Count, Is.EqualTo(2)); + Assert.That(ds.Tables[0].Rows[0][1], Is.EqualTo("name")); MySqlParameter mySqlParameter = new MySqlParameter("@id", 2); ds = MySqlHelper.ExecuteDataset(Connection, "SELECT * FROM Test WHERE id = @id", mySqlParameter); Assert.That(ds.Tables, Has.One.Items); - Assert.AreEqual(1, ds.Tables[0].Rows.Count); - Assert.AreEqual("name2", ds.Tables[0].Rows[0][1]); + Assert.That(ds.Tables[0].Rows.Count, Is.EqualTo(1)); + Assert.That(ds.Tables[0].Rows[0][1], Is.EqualTo("name2")); ds = MySqlHelper.ExecuteDataset(Connection.ConnectionString, "SELECT * FROM Test", null); Assert.That(ds.Tables, Has.One.Items); - Assert.AreEqual(2, ds.Tables[0].Rows.Count); - Assert.AreEqual("name", ds.Tables[0].Rows[0][1]); - Assert.AreEqual("name2", ds.Tables[0].Rows[1][1]); + Assert.That(ds.Tables[0].Rows.Count, Is.EqualTo(2)); + Assert.That(ds.Tables[0].Rows[0][1], Is.EqualTo("name")); + Assert.That(ds.Tables[0].Rows[1][1], Is.EqualTo("name2")); } #endregion } diff --git a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/MySqlCommandBuilderTests.cs b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/MySqlCommandBuilderTests.cs index c4d9127f1..0901d9b69 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/MySqlCommandBuilderTests.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/MySqlCommandBuilderTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2022, Oracle and/or its affiliates. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -27,6 +27,7 @@ // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA using NUnit.Framework; +using NUnit.Framework.Legacy; using System; using System.Data; @@ -57,14 +58,14 @@ public void MultiWord() row["multi word"] = 2; dt.Rows.Add(row); da.Update(dt); - Assert.AreEqual(1, dt.Rows.Count); - Assert.AreEqual(2, dt.Rows[0]["multi word"]); + Assert.That(dt.Rows.Count, Is.EqualTo(1)); + Assert.That(dt.Rows[0]["multi word"], Is.EqualTo(2)); dt.Rows[0]["multi word"] = 3; da.Update(dt); cb.Dispose(); - Assert.AreEqual(1, dt.Rows.Count); - Assert.AreEqual(3, dt.Rows[0]["multi word"]); + Assert.That(dt.Rows.Count, Is.EqualTo(1)); + Assert.That(dt.Rows[0]["multi word"], Is.EqualTo(3)); } [Test] @@ -79,17 +80,17 @@ public void LastOneWins() cb.ConflictOption = ConflictOption.OverwriteChanges; DataTable dt = new DataTable(); da.Fill(dt); - Assert.AreEqual(1, dt.Rows.Count); + Assert.That(dt.Rows.Count, Is.EqualTo(1)); ExecuteSQL("UPDATE Test SET name='Test2' WHERE id=1"); dt.Rows[0]["name"] = "Test3"; - Assert.AreEqual(1, da.Update(dt)); + Assert.That(da.Update(dt), Is.EqualTo(1)); dt.Rows.Clear(); da.Fill(dt); - Assert.AreEqual(1, dt.Rows.Count); - Assert.AreEqual("Test3", dt.Rows[0]["name"]); + Assert.That(dt.Rows.Count, Is.EqualTo(1)); + Assert.That(dt.Rows[0]["name"], Is.EqualTo("Test3")); } [Test] @@ -103,18 +104,18 @@ public void NotLastOneWins() cb.ConflictOption = ConflictOption.CompareAllSearchableValues; DataTable dt = new DataTable(); da.Fill(dt); - Assert.AreEqual(1, dt.Rows.Count); + Assert.That(dt.Rows.Count, Is.EqualTo(1)); ExecuteSQL("UPDATE Test SET name='Test2' WHERE id=1"); dt.Rows[0]["name"] = "Test3"; void Update() { da.Update(dt); } Exception ex = Assert.Throws(() => Update()); - Assert.AreEqual("Concurrency violation: the UpdateCommand affected 0 of the expected 1 records.", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Concurrency violation: the UpdateCommand affected 0 of the expected 1 records.")); dt.Rows.Clear(); da.Fill(dt); - Assert.AreEqual(1, dt.Rows.Count); - Assert.AreEqual("Test2", dt.Rows[0]["name"]); + Assert.That(dt.Rows.Count, Is.EqualTo(1)); + Assert.That(dt.Rows[0]["name"], Is.EqualTo("Test2")); } /// @@ -140,9 +141,9 @@ public void UsingFunctions() da.SelectCommand.CommandText = "SELECT id, name, CONCAT(name, ' boo') as newname from Test where id=4"; dt.Clear(); da.Fill(dt); - Assert.AreEqual(1, dt.Rows.Count); - Assert.AreEqual("test1", dt.Rows[0]["name"]); - Assert.AreEqual("test1 boo", dt.Rows[0]["newname"]); + Assert.That(dt.Rows.Count, Is.EqualTo(1)); + Assert.That(dt.Rows[0]["name"], Is.EqualTo("test1")); + Assert.That(dt.Rows[0]["newname"], Is.EqualTo("test1 boo")); dt.Rows[0]["id"] = 5; da.Update(dt); @@ -150,8 +151,8 @@ public void UsingFunctions() dt.Clear(); da.SelectCommand.CommandText = "SELECT * FROM Test WHERE id=5"; da.Fill(dt); - Assert.AreEqual(1, dt.Rows.Count); - Assert.AreEqual("test1", dt.Rows[0]["name"]); + Assert.That(dt.Rows.Count, Is.EqualTo(1)); + Assert.That(dt.Rows[0]["name"], Is.EqualTo("test1")); da.SelectCommand.CommandText = "SELECT *, now() as stime FROM Test WHERE id<4"; cb = new MySqlCommandBuilder(da); @@ -234,8 +235,8 @@ public void SemicolonAtEndOfSQL() dt.Clear(); da.Fill(dt); cb.Dispose(); - Assert.AreEqual(1, dt.Rows.Count); - Assert.AreEqual(2, dt.Rows[0]["id"]); + Assert.That(dt.Rows.Count, Is.EqualTo(1)); + Assert.That(dt.Rows[0]["id"], Is.EqualTo(2)); } /// @@ -256,7 +257,7 @@ public void AutoIncrementColumnsOnInsert() DataTable dt = new DataTable(); da.Fill(dt); dt.Columns[0].AutoIncrement = true; - Assert.True(dt.Columns[0].AutoIncrement); + Assert.That(dt.Columns[0].AutoIncrement); dt.Columns[0].AutoIncrementSeed = -1; dt.Columns[0].AutoIncrementStep = -1; DataRow row = dt.NewRow(); @@ -267,9 +268,9 @@ public void AutoIncrementColumnsOnInsert() dt.Clear(); da.Fill(dt); - Assert.AreEqual(1, dt.Rows.Count); - Assert.AreEqual(1, dt.Rows[0]["id"]); - Assert.AreEqual("Test", dt.Rows[0]["name"]); + Assert.That(dt.Rows.Count, Is.EqualTo(1)); + Assert.That(dt.Rows[0]["id"], Is.EqualTo(1)); + Assert.That(dt.Rows[0]["name"], Is.EqualTo("Test")); cb.Dispose(); } @@ -297,17 +298,17 @@ public void AutoIncrementColumnsOnInsert2() row["name"] = "Test"; dt.Rows.Add(row); da.Update(dt); - Assert.AreEqual(1, Convert.ToInt32(dt.Rows[0]["id"])); - Assert.AreEqual("Test", dt.Rows[0]["name"]); + Assert.That(Convert.ToInt32(dt.Rows[0]["id"]), Is.EqualTo(1)); + Assert.That(dt.Rows[0]["name"], Is.EqualTo("Test")); row = dt.NewRow(); row["name"] = "Test2"; dt.Rows.Add(row); da.Update(dt); - Assert.AreEqual(2, Convert.ToInt32(dt.Rows[1]["id"])); - Assert.AreEqual("Test2", dt.Rows[1]["name"]); + Assert.That(Convert.ToInt32(dt.Rows[1]["id"]), Is.EqualTo(2)); + Assert.That(dt.Rows[1]["name"], Is.EqualTo("Test2")); - Assert.AreEqual(1, Convert.ToInt32(dt.Rows[0]["id"])); + Assert.That(Convert.ToInt32(dt.Rows[0]["id"]), Is.EqualTo(1)); } [Test] @@ -368,7 +369,7 @@ public void UpdatingWithDateInKey() dt.Clear(); da.SelectCommand.CommandText = "SELECT * FROM Test WHERE cod=6"; da.Fill(dt); - Assert.AreEqual(6, dt.Rows[0]["cod"]); + Assert.That(dt.Rows[0]["cod"], Is.EqualTo(6)); } /// @@ -378,14 +379,14 @@ public void UpdatingWithDateInKey() public void QuoteAndUnquoteIdentifiers() { MySqlCommandBuilder cb = new MySqlCommandBuilder(); - Assert.AreEqual("`boo`", cb.QuoteIdentifier("boo")); - Assert.AreEqual("`bo``o`", cb.QuoteIdentifier("bo`o")); - Assert.AreEqual("`boo`", cb.QuoteIdentifier("`boo`")); + Assert.That(cb.QuoteIdentifier("boo"), Is.EqualTo("`boo`")); + Assert.That(cb.QuoteIdentifier("bo`o"), Is.EqualTo("`bo``o`")); + Assert.That(cb.QuoteIdentifier("`boo`"), Is.EqualTo("`boo`")); // now do the unquoting - Assert.AreEqual("boo", cb.UnquoteIdentifier("`boo`")); - Assert.AreEqual("`boo", cb.UnquoteIdentifier("`boo")); - Assert.AreEqual("bo`o", cb.UnquoteIdentifier("`bo``o`")); + Assert.That(cb.UnquoteIdentifier("`boo`"), Is.EqualTo("boo")); + Assert.That(cb.UnquoteIdentifier("`boo"), Is.EqualTo("`boo")); + Assert.That(cb.UnquoteIdentifier("`bo``o`"), Is.EqualTo("bo`o")); } /// @@ -402,8 +403,7 @@ public void BigintUnsignedAsPK() var commandBuilder = new MySqlCommandBuilder(adapter); var myCommand = commandBuilder.GetUpdateCommand(); - StringAssert.AreEqualIgnoringCase($"UPDATE `test` SET `field1` = @p1 WHERE ((`id` = @p2) AND (`field1` = @p3))", - myCommand.CommandText); + Assert.That(myCommand.CommandText, Is.EqualTo($"UPDATE `test` SET `field1` = @p1 WHERE ((`id` = @p2) AND (`field1` = @p3))").IgnoreCase); } } } diff --git a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/MySqlDataAdapterTests.cs b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/MySqlDataAdapterTests.cs index d683e71de..df80661ab 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/MySqlDataAdapterTests.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/MySqlDataAdapterTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2022, Oracle and/or its affiliates. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -27,9 +27,11 @@ // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA using NUnit.Framework; +using NUnit.Framework.Legacy; using System; using System.Data; using System.Data.Common; +using System.Net; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -75,15 +77,15 @@ private void FillImpl(bool prepare) da.Fill(ds, "Test"); Assert.That(ds.Tables, Has.One.Items); - Assert.AreEqual(3, ds.Tables[0].Rows.Count); + Assert.That(ds.Tables[0].Rows.Count, Is.EqualTo(3)); - Assert.AreEqual(1, ds.Tables[0].Rows[0]["id2"]); - Assert.AreEqual(2, ds.Tables[0].Rows[1]["id2"]); - Assert.AreEqual(3, ds.Tables[0].Rows[2]["id2"]); + Assert.That(ds.Tables[0].Rows[0]["id2"], Is.EqualTo(1)); + Assert.That(ds.Tables[0].Rows[1]["id2"], Is.EqualTo(2)); + Assert.That(ds.Tables[0].Rows[2]["id2"], Is.EqualTo(3)); - Assert.AreEqual("Name 1", ds.Tables[0].Rows[0]["name"]); - Assert.AreEqual(DBNull.Value, ds.Tables[0].Rows[1]["name"]); - Assert.AreEqual(String.Empty, ds.Tables[0].Rows[2]["name"]); + Assert.That(ds.Tables[0].Rows[0]["name"], Is.EqualTo("Name 1")); + Assert.That(ds.Tables[0].Rows[1]["name"], Is.EqualTo(DBNull.Value)); + Assert.That(ds.Tables[0].Rows[2]["name"], Is.EqualTo(String.Empty)); } [Test] @@ -102,8 +104,8 @@ public void TestUpdate() int count = da.Update(dt); // make sure our refresh of auto increment values worked - Assert.True(count == 1, "checking insert count"); - Assert.True(dt.Rows[dt.Rows.Count - 1]["id"] != null, "Checking auto increment column"); + Assert.That(count == 1, "checking insert count"); + Assert.That(dt.Rows[dt.Rows.Count - 1]["id"] != null, "Checking auto increment column"); dt.Rows.Clear(); da.Fill(dt); @@ -115,25 +117,25 @@ public void TestUpdate() dt.Rows[0]["tm"] = day1.TimeOfDay; count = da.Update(dt); - Assert.True(dt.Rows[0]["ts"] != null, "checking refresh of record"); - Assert.True(dt.Rows[0]["id2"] != null, "checking refresh of primary column"); + Assert.That(dt.Rows[0]["ts"] != null, "checking refresh of record"); + Assert.That(dt.Rows[0]["id2"] != null, "checking refresh of primary column"); dt.Rows.Clear(); da.Fill(dt); - Assert.True(count == 1, "checking update count"); + Assert.That(count == 1, "checking update count"); DateTime dateTime = (DateTime)dt.Rows[0]["dt"]; - Assert.True(day1.Date == dateTime.Date, "checking date"); - Assert.True(day1.TimeOfDay == (TimeSpan)dt.Rows[0]["tm"], "checking time"); + Assert.That(day1.Date == dateTime.Date, "checking date"); + Assert.That(day1.TimeOfDay == (TimeSpan)dt.Rows[0]["tm"], "checking time"); dt.Rows[0].Delete(); count = da.Update(dt); - Assert.True(count == 1, "checking insert count"); + Assert.That(count == 1, "checking insert count"); dt.Rows.Clear(); da.Fill(dt); - Assert.True(dt.Rows.Count == 0, "checking row count"); + Assert.That(dt.Rows.Count == 0, "checking row count"); cb.Dispose(); } @@ -158,8 +160,8 @@ public void OriginalInName() dt.Rows.Add(row); da.Update(dt); - Assert.AreEqual(1, dt.Rows.Count); - Assert.AreEqual(2, dt.Rows[0]["OriginalId"]); + Assert.That(dt.Rows.Count, Is.EqualTo(1)); + Assert.That(dt.Rows[0]["OriginalId"], Is.EqualTo(2)); } [Test] @@ -178,13 +180,13 @@ public void UseAdapterPropertyOfCommandBuilder() dt.Rows[0]["name"] = "Test Update"; int updateCnt = da.Update(dt); - Assert.AreEqual(1, updateCnt); + Assert.That(updateCnt, Is.EqualTo(1)); dt.Rows.Clear(); da.Fill(dt); - Assert.AreEqual(1, dt.Rows.Count); - Assert.AreEqual("Test Update", dt.Rows[0]["name"]); + Assert.That(dt.Rows.Count, Is.EqualTo(1)); + Assert.That(dt.Rows[0]["name"], Is.EqualTo("Test Update")); } [Test] @@ -203,13 +205,13 @@ public void UpdateNullTextFieldToEmptyString() dt.Rows[0]["name"] = ""; int updateCnt = da.Update(dt); - Assert.AreEqual(1, updateCnt); + Assert.That(updateCnt, Is.EqualTo(1)); dt.Rows.Clear(); da.Fill(dt); - Assert.AreEqual(1, dt.Rows.Count); - Assert.AreEqual("", dt.Rows[0]["name"]); + Assert.That(dt.Rows.Count, Is.EqualTo(1)); + Assert.That(dt.Rows[0]["name"], Is.EqualTo("")); } [Test] @@ -229,7 +231,7 @@ public void UpdateExtendedTextFields() dt.Clear(); da.Fill(dt); - Assert.AreEqual("This is my new note", dt.Rows[0]["notes"]); + Assert.That(dt.Rows[0]["notes"], Is.EqualTo("This is my new note")); } [Test] @@ -243,7 +245,7 @@ public void SelectMoreThan252Rows() DataTable dt = new DataTable(); da.Fill(dt); - Assert.AreEqual(500, dt.Rows.Count); + Assert.That(dt.Rows.Count, Is.EqualTo(500)); } [Test] @@ -257,14 +259,14 @@ public void DiscreteValues() DataTable dt = new DataTable(); da.Fill(dt); - Assert.AreEqual("Test", dt.Rows[0]["name"]); - Assert.AreEqual("Test 1", dt.Rows[1]["name"]); + Assert.That(dt.Rows[0]["name"], Is.EqualTo("Test")); + Assert.That(dt.Rows[1]["name"], Is.EqualTo("Test 1")); - Assert.AreEqual("Text 1", dt.Rows[0]["b1"]); - Assert.AreEqual("Text 2", dt.Rows[1]["b1"]); + Assert.That(dt.Rows[0]["b1"], Is.EqualTo("Text 1")); + Assert.That(dt.Rows[1]["b1"], Is.EqualTo("Text 2")); - Assert.AreEqual(new DateTime(2004, 8, 1, 0, 0, 0).ToString(), dt.Rows[0]["dt"].ToString()); - Assert.AreEqual(new DateTime(2004, 7, 2, 0, 0, 0).ToString(), dt.Rows[1]["dt"].ToString()); + Assert.That(dt.Rows[0]["dt"].ToString(), Is.EqualTo(new DateTime(2004, 8, 1, 0, 0, 0).ToString())); + Assert.That(dt.Rows[1]["dt"].ToString(), Is.EqualTo(new DateTime(2004, 7, 2, 0, 0, 0).ToString())); } [Test] @@ -279,14 +281,14 @@ public void Bug5798() DataTable dt = new DataTable(); da.Fill(dt); - Assert.AreEqual(String.Empty, dt.Rows[0]["name"]); + Assert.That(dt.Rows[0]["name"], Is.EqualTo(String.Empty)); dt.Rows[0]["name"] = "Test"; da.Update(dt); dt.Clear(); da.Fill(dt); - Assert.AreEqual("Test", dt.Rows[0]["name"]); + Assert.That(dt.Rows[0]["name"], Is.EqualTo("Test")); } [Test] @@ -311,11 +313,11 @@ public void TestFillWithHelper() string sql = "SELECT table1.key FROM table1 WHERE table1.key=1; " + "SELECT table2.key FROM table2 WHERE table2.key=1"; DataSet ds = MySqlHelper.ExecuteDataset(Connection, sql, null); - Assert.AreEqual(2, ds.Tables.Count); - Assert.AreEqual(1, ds.Tables[0].Rows.Count); - Assert.AreEqual(1, ds.Tables[1].Rows.Count); - Assert.AreEqual(1, ds.Tables[0].Rows[0]["key"]); - Assert.AreEqual(1, ds.Tables[1].Rows[0]["key"]); + Assert.That(ds.Tables.Count, Is.EqualTo(2)); + Assert.That(ds.Tables[0].Rows.Count, Is.EqualTo(1)); + Assert.That(ds.Tables[1].Rows.Count, Is.EqualTo(1)); + Assert.That(ds.Tables[0].Rows[0]["key"], Is.EqualTo(1)); + Assert.That(ds.Tables[1].Rows[0]["key"], Is.EqualTo(1)); } /// @@ -331,7 +333,7 @@ public void AutoIncrementColumns() MySqlCommandBuilder cb = new MySqlCommandBuilder(da); DataSet ds = new DataSet(); da.Fill(ds); - Assert.AreEqual(1, Convert.ToInt32(ds.Tables[0].Rows[0]["id"])); + Assert.That(Convert.ToInt32(ds.Tables[0].Rows[0]["id"]), Is.EqualTo(1)); DataRow row = ds.Tables[0].NewRow(); ds.Tables[0].Rows.Add(row); @@ -339,8 +341,8 @@ public void AutoIncrementColumns() ds.Clear(); da.Fill(ds); - Assert.AreEqual(1, Convert.ToInt32(ds.Tables[0].Rows[0]["id"])); - Assert.AreEqual(2, Convert.ToInt32(ds.Tables[0].Rows[1]["id"])); + Assert.That(Convert.ToInt32(ds.Tables[0].Rows[0]["id"]), Is.EqualTo(1)); + Assert.That(Convert.ToInt32(ds.Tables[0].Rows[1]["id"]), Is.EqualTo(2)); cb.Dispose(); } @@ -359,9 +361,9 @@ public void Rollup() da.Fill(ds); Assert.That(ds.Tables, Has.One.Items); - Assert.AreEqual(3, ds.Tables[0].Rows.Count); - Assert.AreEqual(88, ds.Tables[0].Rows[2]["amount"]); - Assert.AreEqual(DBNull.Value, ds.Tables[0].Rows[2]["id"]); + Assert.That(ds.Tables[0].Rows.Count, Is.EqualTo(3)); + Assert.That(ds.Tables[0].Rows[2]["amount"], Is.EqualTo(88)); + Assert.That(ds.Tables[0].Rows[2]["id"], Is.EqualTo(DBNull.Value)); } /// @@ -406,7 +408,7 @@ public void Bug16307() { reader.Read(); int intCallNum = Int32.Parse(reader.GetValue(0).ToString()); - Assert.AreEqual(1, intCallNum); + Assert.That(intCallNum, Is.EqualTo(1)); } } @@ -423,24 +425,24 @@ public void QuietOpenAndClose() { MySqlDataAdapter da = new MySqlDataAdapter("SELECT * FROM Test", c); MySqlCommandBuilder cb = new MySqlCommandBuilder(da); - Assert.True(c.State == ConnectionState.Closed); + Assert.That(c.State == ConnectionState.Closed); DataTable dt = new DataTable(); da.Fill(dt); - Assert.True(c.State == ConnectionState.Closed); - Assert.AreEqual(1, dt.Rows.Count); + Assert.That(c.State == ConnectionState.Closed); + Assert.That(dt.Rows.Count, Is.EqualTo(1)); dt.Rows[0][0] = 2; DataRow[] rows = new DataRow[1]; rows[0] = dt.Rows[0]; da.Update(dt); - Assert.True(c.State == ConnectionState.Closed); + Assert.That(c.State == ConnectionState.Closed); dt.Clear(); c.Open(); - Assert.True(c.State == ConnectionState.Open); + Assert.That(c.State == ConnectionState.Open); da.Fill(dt); - Assert.True(c.State == ConnectionState.Open); - Assert.AreEqual(1, dt.Rows.Count); + Assert.That(c.State == ConnectionState.Open); + Assert.That(dt.Rows.Count, Is.EqualTo(1)); cb.Dispose(); } } @@ -480,9 +482,9 @@ public void FillWithNulls() dt.Clear(); da.Fill(dt); - Assert.AreEqual(1, dt.Rows.Count); - Assert.AreEqual(1, dt.Rows[0]["id"]); - Assert.AreEqual("Test1", dt.Rows[0]["name"]); + Assert.That(dt.Rows.Count, Is.EqualTo(1)); + Assert.That(dt.Rows[0]["id"], Is.EqualTo(1)); + Assert.That(dt.Rows[0]["name"], Is.EqualTo("Test1")); row = dt.NewRow(); row["name"] = System.DBNull.Value; @@ -492,9 +494,9 @@ public void FillWithNulls() dt.Clear(); da.Fill(dt); - Assert.AreEqual(2, dt.Rows.Count); - Assert.AreEqual(2, dt.Rows[1]["id"]); - Assert.AreEqual(DBNull.Value, dt.Rows[1]["name"]); + Assert.That(dt.Rows.Count, Is.EqualTo(2)); + Assert.That(dt.Rows[1]["id"], Is.EqualTo(2)); + Assert.That(dt.Rows[1]["name"], Is.EqualTo(DBNull.Value)); row = dt.NewRow(); row["name"] = "Test3"; @@ -504,9 +506,9 @@ public void FillWithNulls() dt.Clear(); da.Fill(dt); - Assert.AreEqual(3, dt.Rows.Count); - Assert.AreEqual(3, dt.Rows[2]["id"]); - Assert.AreEqual("Test3", dt.Rows[2]["name"]); + Assert.That(dt.Rows.Count, Is.EqualTo(3)); + Assert.That(dt.Rows[2]["id"], Is.EqualTo(3)); + Assert.That(dt.Rows[2]["name"], Is.EqualTo("Test3")); cb.Dispose(); } @@ -529,7 +531,7 @@ public void PagingFill() MySqlDataAdapter da = new MySqlDataAdapter("SELECT * FROM Test", Connection); DataTable dt = new DataTable(); da.Fill(0, 10, new DataTable[] { dt }); - Assert.AreEqual(10, dt.Rows.Count); + Assert.That(dt.Rows.Count, Is.EqualTo(10)); } private string MakeLargeString(int len) @@ -563,7 +565,7 @@ public void SkippingRowsLargerThan1024() [Test] public void TestBatchingInserts() { - if (!System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows)) Assert.Ignore(); + Assume.That(System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows)); ExecuteSQL("CREATE TABLE Test (id INT, name VARCHAR(20), PRIMARY KEY(id))"); @@ -590,11 +592,11 @@ public void TestBatchingInserts() dt.Rows.Clear(); da.Fill(dt); - Assert.AreEqual(100, dt.Rows.Count); + Assert.That(dt.Rows.Count, Is.EqualTo(100)); for (int i = 0; i < 100; i++) { - Assert.AreEqual(i + 1, dt.Rows[i]["id"]); - Assert.AreEqual("name " + (i + 1), dt.Rows[i]["name"]); + Assert.That(dt.Rows[i]["id"], Is.EqualTo(i + 1)); + Assert.That(dt.Rows[i]["name"], Is.EqualTo("name " + (i + 1))); } } @@ -626,13 +628,13 @@ public void TestBatchingUpdates() dt.Rows.Clear(); da.Fill(dt); - Assert.AreEqual(3, dt.Rows.Count); - Assert.AreEqual(2, dt.Rows[0]["id"]); - Assert.AreEqual(4, dt.Rows[1]["id"]); - Assert.AreEqual(6, dt.Rows[2]["id"]); - Assert.AreEqual("new test value", dt.Rows[0]["name"]); - Assert.AreEqual("Test 1", dt.Rows[1]["name"]); - Assert.AreEqual("new test value #2", dt.Rows[2]["name"]); + Assert.That(dt.Rows.Count, Is.EqualTo(3)); + Assert.That(dt.Rows[0]["id"], Is.EqualTo(2)); + Assert.That(dt.Rows[1]["id"], Is.EqualTo(4)); + Assert.That(dt.Rows[2]["id"], Is.EqualTo(6)); + Assert.That(dt.Rows[0]["name"], Is.EqualTo("new test value")); + Assert.That(dt.Rows[1]["name"], Is.EqualTo("Test 1")); + Assert.That(dt.Rows[2]["name"], Is.EqualTo("new test value #2")); } [Test] @@ -674,13 +676,13 @@ public void TestBatchingMixed() dt.Rows.Clear(); da.Fill(dt); - Assert.AreEqual(3, dt.Rows.Count); - Assert.AreEqual(4, dt.Rows[0]["id"]); - Assert.AreEqual(6, dt.Rows[1]["id"]); - Assert.AreEqual(7, dt.Rows[2]["id"]); - Assert.AreEqual("Test 1", dt.Rows[0]["name"]); - Assert.AreEqual("new test value #2", dt.Rows[1]["name"]); - Assert.AreEqual("foobar", dt.Rows[2]["name"]); + Assert.That(dt.Rows.Count, Is.EqualTo(3)); + Assert.That(dt.Rows[0]["id"], Is.EqualTo(4)); + Assert.That(dt.Rows[1]["id"], Is.EqualTo(6)); + Assert.That(dt.Rows[2]["id"], Is.EqualTo(7)); + Assert.That(dt.Rows[0]["name"], Is.EqualTo("Test 1")); + Assert.That(dt.Rows[1]["name"], Is.EqualTo("new test value #2")); + Assert.That(dt.Rows[2]["name"], Is.EqualTo("foobar")); } [Test] @@ -716,9 +718,60 @@ public void TestBatchingInsertsMoreThanMaxPacket() dt.Rows.Clear(); da.Fill(dt); - Assert.AreEqual(numRows, dt.Rows.Count); + Assert.That(dt.Rows.Count, Is.EqualTo(numRows)); for (int i = 0; i < numRows; i++) - Assert.AreEqual(i, dt.Rows[i]["id"]); + Assert.That(dt.Rows[i]["id"], Is.EqualTo(i)); + } + + /// + /// Bug#35240186 Contribution: Run inserts in batch command as one block + /// + [Test] + [TestCase(true)] + [TestCase(false)] + public void TestBatchingInsertsAllRowsInOneGo(bool rewriteStatements) + { + ExecuteSQL("CREATE TABLE Test (id INT AUTO_INCREMENT, name VARCHAR(20), PRIMARY KEY(id))"); + ExecuteSQL("INSERT INTO Test VALUES (1, 'Test 1')"); + using MySqlConnection conn = new MySqlConnection(Connection.ConnectionString + ";rewritebatchedstatements=" + rewriteStatements.ToString() + ";"); + { + conn.Open(); + bool testing = true; + Console.WriteLine(testing.ToString()); + MySqlDataAdapter da = new MySqlDataAdapter("SELECT * FROM Test", conn); + MySqlCommand ins = new MySqlCommand("INSERT INTO Test (id, name) VALUES (?p1, ?p2)", conn); + da.InsertCommand = ins; + ins.UpdatedRowSource = UpdateRowSource.None; + ins.Parameters.Add("?p1", MySqlDbType.Int32).SourceColumn = "id"; + ins.Parameters.Add("?p2", MySqlDbType.VarChar, 20).SourceColumn = "name"; + + DataTable dt = new DataTable(); + da.Fill(dt); + + for (int i = 1; i <= 3; i++) + { + DataRow row = dt.NewRow(); + row["id"] = DBNull.Value; + row["name"] = "name " + i; + dt.Rows.Add(row); + } + + da.UpdateBatchSize = 0; + da.Update(dt); + MySqlCommand lsid = new MySqlCommand("SELECT LAST_INSERT_ID();", conn); + var lastInsertedId = (ulong)lsid.ExecuteScalar(); + + if (rewriteStatements) + { + //The batched statements are rewritten to be processed all together, that is why the last inserted ID is 2 + Assert.That(lastInsertedId, Is.EqualTo(2)); + } + else + { + //The batched statements are not rewritten, and are processed one by one, in this case the last inserted ID is 4 + Assert.That(lastInsertedId, Is.EqualTo(4)); + } + } } [Test] @@ -732,9 +785,9 @@ public void FunctionsReturnString() MySqlDataAdapter da = new MySqlDataAdapter("SELECT CONCAT(1,2)", c); DataTable dt = new DataTable(); da.Fill(dt); - Assert.AreEqual(1, dt.Rows.Count); - Assert.AreEqual("12", dt.Rows[0][0]); - Assert.True(dt.Rows[0][0] is string); + Assert.That(dt.Rows.Count, Is.EqualTo(1)); + Assert.That(dt.Rows[0][0], Is.EqualTo("12")); + Assert.That(dt.Rows[0][0] is string); } } @@ -803,7 +856,7 @@ public void AdapterConcurrentException() table.Rows.Add(r); da.Update(table); - Assert.AreEqual(DataRowState.Unchanged, r.RowState); + Assert.That(r.RowState, Is.EqualTo(DataRowState.Unchanged)); table.Rows[0].Delete(); @@ -813,8 +866,8 @@ public void AdapterConcurrentException() da.Update(table); // here was concurrencyviolation da.Fill(ds); - Assert.AreEqual(1, ds.Tables["T"].Rows.Count); - Assert.AreEqual("row2", ds.Tables["T"].Rows[0]["field"]); + Assert.That(ds.Tables["T"].Rows.Count, Is.EqualTo(1)); + Assert.That(ds.Tables["T"].Rows[0]["field"], Is.EqualTo("row2")); } /// @@ -865,11 +918,11 @@ public void BatchingConnectionClosed() dt.Rows.Clear(); da.Fill(dt); - Assert.AreEqual(100, dt.Rows.Count); + Assert.That(dt.Rows.Count, Is.EqualTo(100)); for (int i = 0; i < 100; i++) { - Assert.AreEqual(i + 1, dt.Rows[i]["id"]); - Assert.AreEqual("name " + (i + 1), dt.Rows[i]["name"]); + Assert.That(dt.Rows[i]["id"], Is.EqualTo(i + 1)); + Assert.That(dt.Rows[i]["name"], Is.EqualTo("name " + (i + 1))); } foreach (DataRow row in dt.Rows) @@ -884,7 +937,7 @@ public void BatchingConnectionClosed() da.Update(dt); dt.Rows.Clear(); da.Fill(dt); - Assert.AreEqual(0, dt.Rows.Count); + Assert.That(dt.Rows.Count, Is.EqualTo(0)); } @@ -949,13 +1002,13 @@ public void UpdateReturnFirstRecord() DataTable table = ds.Tables["bugtable"]; DataRow row = table.Rows[0]; row["field"] = "newvalue"; - Assert.AreEqual(DataRowState.Modified, row.RowState); - Assert.AreEqual(0, (int)row["counter"]); + Assert.That(row.RowState, Is.EqualTo(DataRowState.Modified)); + Assert.That((int)row["counter"], Is.EqualTo(0)); da.Update(table); // Verify that "counter" field was changed by updating stored procedure. - Assert.AreEqual(1, (int)row["counter"]); + Assert.That((int)row["counter"], Is.EqualTo(1)); } [Test] @@ -972,13 +1025,13 @@ public void FillFromStoredProcedureMultipleTimesCreatesExpectedRows() adapter.SelectCommand.CommandType = CommandType.StoredProcedure; DataTable table = new DataTable(); adapter.Fill(table); - Assert.AreEqual(1, table.Rows.Count); + Assert.That(table.Rows.Count, Is.EqualTo(1)); adapter = new MySqlDataAdapter("SimpleSelect", connection); adapter.SelectCommand.CommandType = CommandType.StoredProcedure; table = new DataTable(); adapter.Fill(table); - Assert.AreEqual(1, table.Rows.Count); + Assert.That(table.Rows.Count, Is.EqualTo(1)); MySqlConnection.ClearPool(connection); } @@ -999,7 +1052,7 @@ public void ChangeStoredProcedureBasedSelectCommandDoesNotThrow() adapter.SelectCommand.CommandType = CommandType.StoredProcedure; DataTable table = new DataTable(); adapter.Fill(table); - Assert.AreEqual(1, table.Rows.Count); + Assert.That(table.Rows.Count, Is.EqualTo(1)); adapter.SelectCommand = new MySqlCommand("SimpleSelect2", connection); adapter.SelectCommand.CommandType = CommandType.StoredProcedure; @@ -1008,7 +1061,7 @@ public void ChangeStoredProcedureBasedSelectCommandDoesNotThrow() try { adapter.Fill(table); - Assert.AreEqual(1, table.Rows.Count); + Assert.That(table.Rows.Count, Is.EqualTo(1)); } finally { @@ -1036,7 +1089,7 @@ public async Task CommandBuilderAsync() var changes = dt.GetChanges(); var count = da.Update(changes); dt.AcceptChanges(); - Assert.True(count == 1, "checking update count"); + Assert.That(count == 1, "checking update count"); await conn.CloseAsync(); } @@ -1053,7 +1106,7 @@ public async Task CommandBuilderAsync() var changes = dt.GetChanges(); var count = da.Update(changes); dt.AcceptChanges(); - Assert.True(count == 1, "checking update count"); + Assert.That(count == 1, "checking update count"); await conn.CloseAsync(); } } @@ -1104,7 +1157,7 @@ public void BatchOverMaxPacketAllowed() dataAdapter.UpdateBatchSize = 2; var ex = Assert.Throws(() => dataAdapter.Update(dataRows)); - StringAssert.AreEqualIgnoringCase(Resources.QueryTooLarge, ex.Message); + Assert.That(ex.Message, Is.EqualTo(Resources.QueryTooLarge).IgnoreCase); } // setting back to the initial value @@ -1125,31 +1178,31 @@ public async Task FillAsyncDataSet() await da.FillAsync(ds, "DAFillAsyncTest"); Assert.That(ds.Tables, Has.One.Items); - Assert.AreEqual(3, ds.Tables[0].Rows.Count); + Assert.That(ds.Tables[0].Rows.Count, Is.EqualTo(3)); - Assert.AreEqual(1, ds.Tables[0].Rows[0]["id2"]); - Assert.AreEqual(2, ds.Tables[0].Rows[1]["id2"]); - Assert.AreEqual(3, ds.Tables[0].Rows[2]["id2"]); + Assert.That(ds.Tables[0].Rows[0]["id2"], Is.EqualTo(1)); + Assert.That(ds.Tables[0].Rows[1]["id2"], Is.EqualTo(2)); + Assert.That(ds.Tables[0].Rows[2]["id2"], Is.EqualTo(3)); - Assert.AreEqual("Name 1", ds.Tables[0].Rows[0]["name"]); - Assert.AreEqual(DBNull.Value, ds.Tables[0].Rows[1]["name"]); - Assert.AreEqual(String.Empty, ds.Tables[0].Rows[2]["name"]); + Assert.That(ds.Tables[0].Rows[0]["name"], Is.EqualTo("Name 1")); + Assert.That(ds.Tables[0].Rows[1]["name"], Is.EqualTo(DBNull.Value)); + Assert.That(ds.Tables[0].Rows[2]["name"], Is.EqualTo(String.Empty)); ds.Reset(); await da.FillAsync(ds); Assert.That(ds.Tables, Has.One.Items); - Assert.AreEqual(3, ds.Tables[0].Rows.Count); - Assert.AreEqual("Name 1", ds.Tables[0].Rows[0]["name"]); + Assert.That(ds.Tables[0].Rows.Count, Is.EqualTo(3)); + Assert.That(ds.Tables[0].Rows[0]["name"], Is.EqualTo("Name 1")); ds.Reset(); await da.FillAsync(ds, 1, 2, "DAFillAsyncTest"); Assert.That(ds.Tables, Has.One.Items); - Assert.AreEqual(2, ds.Tables[0].Rows.Count); - Assert.AreEqual(2, ds.Tables[0].Rows[0]["id2"]); - Assert.AreEqual(DBNull.Value, ds.Tables[0].Rows[0]["name"]); - Assert.AreEqual(String.Empty, ds.Tables[0].Rows[1]["name"]); + Assert.That(ds.Tables[0].Rows.Count, Is.EqualTo(2)); + Assert.That(ds.Tables[0].Rows[0]["id2"], Is.EqualTo(2)); + Assert.That(ds.Tables[0].Rows[0]["name"], Is.EqualTo(DBNull.Value)); + Assert.That(ds.Tables[0].Rows[1]["name"], Is.EqualTo(String.Empty)); ds.Reset(); using (MySqlCommand cmd = new MySqlCommand("select * from DAFillAsyncTest", Connection)) @@ -1157,18 +1210,18 @@ public async Task FillAsyncDataSet() await da.FillAsync(ds, "DAFillAsyncTest", reader, 0, 1); Assert.That(ds.Tables, Has.One.Items); - Assert.AreEqual(1, ds.Tables[0].Rows.Count); - Assert.AreEqual(1, ds.Tables[0].Rows[0]["id2"]); - Assert.AreEqual("Name 1", ds.Tables[0].Rows[0]["name"]); + Assert.That(ds.Tables[0].Rows.Count, Is.EqualTo(1)); + Assert.That(ds.Tables[0].Rows[0]["id2"], Is.EqualTo(1)); + Assert.That(ds.Tables[0].Rows[0]["name"], Is.EqualTo("Name 1")); ds.Reset(); using (MySqlCommand cmd = new MySqlCommand("select * from DAFillAsyncTest", Connection)) await da.FillAsync(ds, 0, 2, "DAFillAsyncTest", cmd, CommandBehavior.Default); Assert.That(ds.Tables, Has.One.Items); - Assert.AreEqual(2, ds.Tables[0].Rows.Count); - Assert.AreEqual(1, ds.Tables[0].Rows[0]["id2"]); - Assert.AreEqual(DBNull.Value, ds.Tables[0].Rows[1]["name"]); + Assert.That(ds.Tables[0].Rows.Count, Is.EqualTo(2)); + Assert.That(ds.Tables[0].Rows[0]["id2"], Is.EqualTo(1)); + Assert.That(ds.Tables[0].Rows[1]["name"], Is.EqualTo(DBNull.Value)); } [Test] @@ -1184,51 +1237,51 @@ public async Task FillAsyncDataTable() DataTable dt = new DataTable(); await da.FillAsync(dt); - Assert.AreEqual(3, dt.Rows.Count); - Assert.AreEqual(7, dt.Columns.Count); - Assert.AreEqual("Name 1", dt.Rows[0]["name"]); - Assert.AreEqual(DBNull.Value, dt.Rows[1]["name"]); - Assert.AreEqual(String.Empty, dt.Rows[2]["name"]); + Assert.That(dt.Rows.Count, Is.EqualTo(3)); + Assert.That(dt.Columns.Count, Is.EqualTo(7)); + Assert.That(dt.Rows[0]["name"], Is.EqualTo("Name 1")); + Assert.That(dt.Rows[1]["name"], Is.EqualTo(DBNull.Value)); + Assert.That(dt.Rows[2]["name"], Is.EqualTo(String.Empty)); dt.Reset(); using (MySqlCommand cmd = new MySqlCommand("select * from DAFillAsyncDtTest", Connection)) using (MySqlDataReader reader = cmd.ExecuteReader()) await da.FillAsync(dt, reader); - Assert.AreEqual(3, dt.Rows.Count); - Assert.AreEqual(7, dt.Columns.Count); - Assert.AreEqual(1, dt.Rows[0]["id2"]); - Assert.AreEqual(2, dt.Rows[1]["id2"]); - Assert.AreEqual(3, dt.Rows[2]["id2"]); + Assert.That(dt.Rows.Count, Is.EqualTo(3)); + Assert.That(dt.Columns.Count, Is.EqualTo(7)); + Assert.That(dt.Rows[0]["id2"], Is.EqualTo(1)); + Assert.That(dt.Rows[1]["id2"], Is.EqualTo(2)); + Assert.That(dt.Rows[2]["id2"], Is.EqualTo(3)); dt.Reset(); using (MySqlCommand cmd = new MySqlCommand("select * from DAFillAsyncDtTest", Connection)) await da.FillAsync(dt, cmd, CommandBehavior.Default); - Assert.AreEqual(3, dt.Rows.Count); - Assert.AreEqual(7, dt.Columns.Count); - Assert.AreEqual(DBNull.Value, dt.Rows[1]["name"]); - Assert.AreEqual(2, dt.Rows[1]["id2"]); - Assert.AreEqual(3, dt.Rows[2]["id2"]); + Assert.That(dt.Rows.Count, Is.EqualTo(3)); + Assert.That(dt.Columns.Count, Is.EqualTo(7)); + Assert.That(dt.Rows[1]["name"], Is.EqualTo(DBNull.Value)); + Assert.That(dt.Rows[1]["id2"], Is.EqualTo(2)); + Assert.That(dt.Rows[2]["id2"], Is.EqualTo(3)); dt.Reset(); DataTable[] dataTables = { dt }; await da.FillAsync(0, 1, dataTables); Assert.That(dataTables, Has.One.Items); - Assert.AreEqual(1, dataTables[0].Rows.Count); - Assert.AreEqual(1, dataTables[0].Rows[0]["id2"]); - Assert.AreEqual("Name 1", dataTables[0].Rows[0]["name"]); + Assert.That(dataTables[0].Rows.Count, Is.EqualTo(1)); + Assert.That(dataTables[0].Rows[0]["id2"], Is.EqualTo(1)); + Assert.That(dataTables[0].Rows[0]["name"], Is.EqualTo("Name 1")); dt.Reset(); using (MySqlCommand cmd = new MySqlCommand("select * from DAFillAsyncDtTest", Connection)) await da.FillAsync(dataTables, 1, 2, cmd, CommandBehavior.Default); Assert.That(dataTables, Has.One.Items); - Assert.AreEqual(2, dataTables[0].Rows.Count); - Assert.AreEqual(2, dataTables[0].Rows[0]["id2"]); - Assert.AreEqual(DBNull.Value, dataTables[0].Rows[0]["name"]); - Assert.AreEqual(String.Empty, dataTables[0].Rows[1]["name"]); + Assert.That(dataTables[0].Rows.Count, Is.EqualTo(2)); + Assert.That(dataTables[0].Rows[0]["id2"], Is.EqualTo(2)); + Assert.That(dataTables[0].Rows[0]["name"], Is.EqualTo(DBNull.Value)); + Assert.That(dataTables[0].Rows[1]["name"], Is.EqualTo(String.Empty)); } [Test] @@ -1247,48 +1300,48 @@ public async Task FillSchemaAsync() MySqlDataAdapter da = new MySqlDataAdapter(cmd); DataTable schema = new DataTable(); await da.FillSchemaAsync(schema, SchemaType.Source); - Assert.AreEqual(2, schema.Columns.Count); + Assert.That(schema.Columns.Count, Is.EqualTo(2)); DataSet ds = new DataSet(); await da.FillSchemaAsync(ds, SchemaType.Source); - Assert.True(ds.Tables.Count == 1); - Assert.AreEqual(2, ds.Tables[0].Columns.Count); + Assert.That(ds.Tables.Count == 1); + Assert.That(ds.Tables[0].Columns.Count, Is.EqualTo(2)); ds.Reset(); using (cmd) using (reader = cmd.ExecuteReader(CommandBehavior.SchemaOnly)) await da.FillSchemaAsync(ds, SchemaType.Source, "DAFillSchemaAsyncTest", reader); - Assert.True(ds.Tables.Count == 1); - Assert.AreEqual(2, ds.Tables[0].Columns.Count); + Assert.That(ds.Tables.Count == 1); + Assert.That(ds.Tables[0].Columns.Count, Is.EqualTo(2)); ds.Reset(); using (cmd) await da.FillSchemaAsync(ds, SchemaType.Source, cmd, "DAFillSchemaAsyncTest", CommandBehavior.SchemaOnly); - Assert.True(ds.Tables.Count == 1); - Assert.AreEqual(2, ds.Tables[0].Columns.Count); + Assert.That(ds.Tables.Count == 1); + Assert.That(ds.Tables[0].Columns.Count, Is.EqualTo(2)); ds.Reset(); using (cmd) await da.FillSchemaAsync(ds, SchemaType.Source, "DAFillSchemaAsyncTest", CancellationToken.None); - Assert.True(ds.Tables.Count == 1); - Assert.AreEqual(2, ds.Tables[0].Columns.Count); + Assert.That(ds.Tables.Count == 1); + Assert.That(ds.Tables[0].Columns.Count, Is.EqualTo(2)); DataTable dataTable = new DataTable(); using (cmd) using (reader = cmd.ExecuteReader(CommandBehavior.SchemaOnly)) await da.FillSchemaAsync(dataTable, SchemaType.Source, reader); - Assert.AreEqual(2, dataTable.Columns.Count); + Assert.That(dataTable.Columns.Count, Is.EqualTo(2)); dataTable.Reset(); using (cmd) await da.FillSchemaAsync(dataTable, SchemaType.Source, cmd, CommandBehavior.SchemaOnly); - Assert.AreEqual(2, dataTable.Columns.Count); - Assert.AreEqual("id", dataTable.Columns[0].ColumnName); + Assert.That(dataTable.Columns.Count, Is.EqualTo(2)); + Assert.That(dataTable.Columns[0].ColumnName, Is.EqualTo("id")); } [Test] @@ -1306,8 +1359,8 @@ public async Task UpdateAsync() dt.Rows.Add(dr); int count = await da.UpdateAsync(dt); - Assert.True(count == 1, "checking insert count"); - Assert.True(dt.Rows[dt.Rows.Count - 1]["id"] != null, "Checking auto increment column"); + Assert.That(count == 1, "checking insert count"); + Assert.That(dt.Rows[dt.Rows.Count - 1]["id"] != null, "Checking auto increment column"); dt.Rows.Clear(); da.Fill(dt); @@ -1319,25 +1372,25 @@ public async Task UpdateAsync() dt.Rows[0]["tm"] = day1.TimeOfDay; count = await da.UpdateAsync(dt); - Assert.True(dt.Rows[0]["ts"] != null, "checking refresh of record"); - Assert.True(dt.Rows[0]["id2"] != null, "checking refresh of primary column"); + Assert.That(dt.Rows[0]["ts"] != null, "checking refresh of record"); + Assert.That(dt.Rows[0]["id2"] != null, "checking refresh of primary column"); dt.Rows.Clear(); da.Fill(dt); - Assert.True(count == 1, "checking update count"); + Assert.That(count == 1, "checking update count"); DateTime dateTime = (DateTime)dt.Rows[0]["dt"]; - Assert.True(day1.Date == dateTime.Date, "checking date"); - Assert.True(day1.TimeOfDay == (TimeSpan)dt.Rows[0]["tm"], "checking time"); + Assert.That(day1.Date == dateTime.Date, "checking date"); + Assert.That(day1.TimeOfDay == (TimeSpan)dt.Rows[0]["tm"], "checking time"); dt.Rows[0].Delete(); count = await da.UpdateAsync(dt); - Assert.True(count == 1, "checking insert count"); + Assert.That(count == 1, "checking insert count"); dt.Rows.Clear(); da.Fill(dt); - Assert.True(dt.Rows.Count == 0, "checking row count"); + Assert.That(dt.Rows.Count == 0, "checking row count"); dr = dt.NewRow(); dr["id2"] = 3; @@ -1346,7 +1399,7 @@ public async Task UpdateAsync() DataRow[] dataRows = dt.Select(null, null, DataViewRowState.Added); count = await da.UpdateAsync(dataRows); - Assert.True(count == 1, "checking update count"); + Assert.That(count == 1, "checking update count"); DataSet ds = new DataSet(); da.Fill(ds); @@ -1356,7 +1409,7 @@ public async Task UpdateAsync() ds.Tables[0].Rows.Add(dr); count = await da.UpdateAsync(ds); - Assert.True(count == 1, "checking update count"); + Assert.That(count == 1, "checking update count"); dr = dt.NewRow(); dr["id2"] = 4; @@ -1369,7 +1422,7 @@ public async Task UpdateAsync() dataRows = dt.Select(null, null, DataViewRowState.Added); count = await da.UpdateAsync(dataRows, mapping); - Assert.True(count == 1, "checking update count"); + Assert.That(count == 1, "checking update count"); ds.Reset(); da.FillSchema(ds, SchemaType.Mapped); @@ -1380,7 +1433,7 @@ public async Task UpdateAsync() ds.Tables[0].Rows.Add(dr); count = await da.UpdateAsync(ds, "Table"); - Assert.True(count == 1, "checking update count"); + Assert.That(count == 1, "checking update count"); cb.Dispose(); } diff --git a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/MySqlDataReaderTests.cs b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/MySqlDataReaderTests.cs index da290e298..4d738a60c 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/MySqlDataReaderTests.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/MySqlDataReaderTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -27,6 +27,7 @@ // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA using NUnit.Framework; +using NUnit.Framework.Legacy; using System.Data; namespace MySql.Data.MySqlClient.Tests @@ -49,9 +50,9 @@ public void SchemaOnly() using (MySqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SchemaOnly)) { DataTable table = reader.GetSchemaTable(); - Assert.AreEqual(5, table.Rows.Count); - Assert.AreEqual(22, table.Columns.Count); - Assert.False(reader.Read()); + Assert.That(table.Rows.Count, Is.EqualTo(5)); + Assert.That(table.Columns.Count, Is.EqualTo(22)); + Assert.That(!reader.Read()); } } diff --git a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/NETCore20Tests.cs b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/NETCore20Tests.cs index de0ab53d1..43ef07643 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/NETCore20Tests.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/NETCore20Tests.cs @@ -1,28 +1,35 @@ -// Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2018, 2025, Oracle and/or its affiliates. // -// MySQL Connector/NET is licensed under the terms of the GPLv2 -// , like most -// MySQL Connectors. There are special exceptions to the terms and -// conditions of the GPLv2 as it is applied to this software, see the -// FLOSS License Exception -// . +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. // -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published -// by the Free Software Foundation; version 2 of the License. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -// for more details. +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. // -// You should have received a copy of the GNU General Public License along -// with this program; if not, write to the Free Software Foundation, Inc., +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA using System; using System.Data; using NUnit.Framework; +using NUnit.Framework.Legacy; namespace MySql.Data.MySqlClient.Tests { @@ -67,11 +74,11 @@ public void ConstraintsTest() ds.Relations.Add(dataRelation); Assert.That(ds.Tables[0].Constraints, Has.One.Items); - Assert.IsInstanceOf(ds.Tables[0].Constraints[0]); + Assert.That(ds.Tables[0].Constraints[0], Is.InstanceOf()); - Assert.AreEqual(2, ds.Tables[1].Constraints.Count); - Assert.IsInstanceOf(ds.Tables[0].Constraints[0]); - Assert.IsInstanceOf(ds.Tables[1].Constraints[1]); + Assert.That(ds.Tables[1].Constraints.Count, Is.EqualTo(2)); + Assert.That(ds.Tables[0].Constraints[0], Is.InstanceOf()); + Assert.That(ds.Tables[1].Constraints[1], Is.InstanceOf()); } [Test] @@ -89,16 +96,16 @@ public void DataTableReaderTest() using (DataTableReader dataTableReader = new DataTableReader(childDt)) { - Assert.True(dataTableReader.HasRows); - Assert.AreEqual(3, dataTableReader.FieldCount); + Assert.That(dataTableReader.HasRows); + Assert.That(dataTableReader.FieldCount, Is.EqualTo(3)); } PropertyCollection propertyCollection = childDt.ExtendedProperties; propertyCollection.Add("TimeStamp", DateTime.Now); propertyCollection.Add("Version", 1); - CollectionAssert.IsNotEmpty(childDt.ExtendedProperties); - Assert.AreEqual(2, childDt.ExtendedProperties.Count); + Assert.That(childDt.ExtendedProperties, Is.Not.Empty); + Assert.That(childDt.ExtendedProperties.Count, Is.EqualTo(2)); } [Test] @@ -132,9 +139,9 @@ public void DataViewSettingsTest() dataViewManager.DataViewSettings[parentDt].Sort = "name"; - Assert.True(dataViewManager.DataViewSettings[childDt].Sort == ""); - Assert.AreEqual("name", dataViewManager.DataViewSettings[parentDt].Sort); - CollectionAssert.IsNotEmpty(dataViewManager.DataViewSettings); + Assert.That(dataViewManager.DataViewSettings[childDt].Sort == ""); + Assert.That(dataViewManager.DataViewSettings[parentDt].Sort, Is.EqualTo("name")); + Assert.That(dataViewManager.DataViewSettings, Is.Not.Empty); } [Test] @@ -150,13 +157,13 @@ public void SchemaColumnTest() parentDa.Fill(parentDt); parentDt.Columns["id"].Unique = true; - Assert.True(parentDt.Columns[0].Unique); - Assert.False(parentDt.Columns[0].AllowDBNull); - Assert.AreEqual("name", parentDt.Columns[1].ColumnName); + Assert.That(parentDt.Columns[0].Unique); + Assert.That(!parentDt.Columns[0].AllowDBNull); + Assert.That(parentDt.Columns[1].ColumnName, Is.EqualTo("name")); - Assert.AreEqual(0, parentDt.Columns[0].AutoIncrementSeed); - Assert.False(parentDt.Columns[0].ReadOnly); - Assert.False(parentDt.Columns[1].AutoIncrement); + Assert.That(parentDt.Columns[0].AutoIncrementSeed, Is.EqualTo(0)); + Assert.That(!parentDt.Columns[0].ReadOnly); + Assert.That(!parentDt.Columns[1].AutoIncrement); } } -} \ No newline at end of file +} diff --git a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/OutputParametersBatchPrepared.cs b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/OutputParametersBatchPrepared.cs index e0d9b5fa4..144987844 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/OutputParametersBatchPrepared.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/OutputParametersBatchPrepared.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/OutputParametersNoBatch.cs b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/OutputParametersNoBatch.cs index eaa605bd2..facd8f010 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/OutputParametersNoBatch.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/OutputParametersNoBatch.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -35,4 +35,4 @@ internal override void AdjustConnectionSettings(MySqlConnectionStringBuilder set settings.AllowBatch = false; } } -} \ No newline at end of file +} diff --git a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/OutputParametersNoBatchPrepared.cs b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/OutputParametersNoBatchPrepared.cs index a8dd1bbcd..664faf15a 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/OutputParametersNoBatchPrepared.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/OutputParametersNoBatchPrepared.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -41,4 +41,4 @@ internal override void AdjustConnectionSettings(MySqlConnectionStringBuilder set settings.AllowBatch = false; } } -} \ No newline at end of file +} diff --git a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/PSPipe.cs b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/PSPipe.cs index 113e51b6c..fa8d58015 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/PSPipe.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/PSPipe.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -30,11 +30,6 @@ namespace MySql.Data.MySqlClient.Tests { public class PSPipe : PreparedStatements { - - public PSPipe(TestFixture fixture) : base(fixture) - { - } - internal override void AdjustConnectionSettings(MySqlConnectionStringBuilder settings) { settings.ConnectionProtocol = MySqlConnectionProtocol.NamedPipe; diff --git a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/PSPipeCompressed.cs b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/PSPipeCompressed.cs index 12b17730b..a673f8a88 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/PSPipeCompressed.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/PSPipeCompressed.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -26,15 +26,12 @@ // along with this program; if not, write to the Free Software Foundation, Inc., // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +using NUnit.Framework.Internal; + namespace MySql.Data.MySqlClient.Tests { public class PSPipeCompressed : PreparedStatements { - - public PSPipeCompressed(TestFixture fixture) : base(fixture) - { - } - internal override void AdjustConnectionSettings(MySqlConnectionStringBuilder settings) { settings.ConnectionProtocol = MySqlConnectionProtocol.NamedPipe; diff --git a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/PSSharedMemory.cs b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/PSSharedMemory.cs index 17b93e689..a0c85b501 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/PSSharedMemory.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/PSSharedMemory.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -26,14 +26,12 @@ // along with this program; if not, write to the Free Software Foundation, Inc., // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +using NUnit.Framework.Internal; + namespace MySql.Data.MySqlClient.Tests { public class PSSharedMemory : PreparedStatements { - public PSSharedMemory(TestFixture fixture) : base (fixture) - { - } - internal override void AdjustConnectionSettings(MySqlConnectionStringBuilder settings) { settings.ConnectionProtocol = MySqlConnectionProtocol.SharedMemory; diff --git a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/PSSharedMemoryCompressed.cs b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/PSSharedMemoryCompressed.cs index e93683ccc..adff43f9f 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/PSSharedMemoryCompressed.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/PSSharedMemoryCompressed.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -26,14 +26,12 @@ // along with this program; if not, write to the Free Software Foundation, Inc., // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +using NUnit.Framework.Internal; + namespace MySql.Data.MySqlClient.Tests { public class PSSharedMemoryCompressed : PreparedStatements { - public PSSharedMemoryCompressed(TestFixture fixture) : base(fixture) - { - } - internal override void AdjustConnectionSettings(MySqlConnectionStringBuilder settings) { settings.ConnectionProtocol = MySqlConnectionProtocol.SharedMemory; diff --git a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/PartialTrustSandbox.cs b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/PartialTrustSandbox.cs index e1e6b4e83..b62cbd27d 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/PartialTrustSandbox.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/PartialTrustSandbox.cs @@ -1,16 +1,16 @@ -// Copyright © 2013, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/PerfMonTests.cs b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/PerfMonTests.cs index 14c8f6869..248ca2ad3 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/PerfMonTests.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/PerfMonTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -27,6 +27,7 @@ // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA using NUnit.Framework; +using NUnit.Framework.Legacy; namespace MySql.Data.MySqlClient.Tests { diff --git a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/ProcedureParameterTests.cs b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/ProcedureParameterTests.cs index 62d90c882..d9d74515c 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/ProcedureParameterTests.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/ProcedureParameterTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2022, Oracle and/or its affiliates. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -27,6 +27,7 @@ // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA using NUnit.Framework; +using NUnit.Framework.Legacy; using System; using System.Data; @@ -43,23 +44,23 @@ public void ProcedureParameters() restrictions[1] = Connection.Database; restrictions[2] = "ProcedureParameters"; DataTable dt = Connection.GetSchema("Procedure Parameters", restrictions); - Assert.True(dt.Rows.Count == 2, "Actual result " + dt.Rows.Count); - Assert.AreEqual("Procedure Parameters", dt.TableName); - Assert.AreEqual(Connection.Database, dt.Rows[0]["SPECIFIC_SCHEMA"].ToString()); - Assert.AreEqual("ProcedureParameters", dt.Rows[0]["SPECIFIC_NAME"].ToString()); - Assert.AreEqual("id", dt.Rows[0]["PARAMETER_NAME"].ToString().ToLower()); - Assert.AreEqual(1, dt.Rows[0]["ORDINAL_POSITION"]); - Assert.AreEqual("IN", dt.Rows[0]["PARAMETER_MODE"]); + Assert.That(dt.Rows.Count == 2, "Actual result " + dt.Rows.Count); + Assert.That(dt.TableName, Is.EqualTo("Procedure Parameters")); + Assert.That(dt.Rows[0]["SPECIFIC_SCHEMA"].ToString(), Is.EqualTo(Connection.Database)); + Assert.That(dt.Rows[0]["SPECIFIC_NAME"].ToString(), Is.EqualTo("ProcedureParameters")); + Assert.That(dt.Rows[0]["PARAMETER_NAME"].ToString().ToLower(), Is.EqualTo("id")); + Assert.That(dt.Rows[0]["ORDINAL_POSITION"], Is.EqualTo(1)); + Assert.That(dt.Rows[0]["PARAMETER_MODE"], Is.EqualTo("IN")); restrictions[4] = "name"; dt.Clear(); dt = Connection.GetSchema("Procedure Parameters", restrictions); - Assert.AreEqual(1, dt.Rows.Count); - Assert.AreEqual(Connection.Database, dt.Rows[0]["SPECIFIC_SCHEMA"].ToString()); - Assert.AreEqual("ProcedureParameters", dt.Rows[0]["SPECIFIC_NAME"].ToString()); - Assert.AreEqual("name", dt.Rows[0]["PARAMETER_NAME"].ToString().ToLower()); - Assert.AreEqual(2, dt.Rows[0]["ORDINAL_POSITION"]); - Assert.AreEqual("IN", dt.Rows[0]["PARAMETER_MODE"]); + Assert.That(dt.Rows.Count, Is.EqualTo(1)); + Assert.That(dt.Rows[0]["SPECIFIC_SCHEMA"].ToString(), Is.EqualTo(Connection.Database)); + Assert.That(dt.Rows[0]["SPECIFIC_NAME"].ToString(), Is.EqualTo("ProcedureParameters")); + Assert.That(dt.Rows[0]["PARAMETER_NAME"].ToString().ToLower(), Is.EqualTo("name")); + Assert.That(dt.Rows[0]["ORDINAL_POSITION"], Is.EqualTo(2)); + Assert.That(dt.Rows[0]["PARAMETER_MODE"], Is.EqualTo("IN")); ExecuteSQL("DROP FUNCTION IF EXISTS spFunc"); ExecuteSQL("CREATE FUNCTION spFunc (id int) RETURNS INT BEGIN RETURN 1; END"); @@ -68,17 +69,17 @@ public void ProcedureParameters() restrictions[1] = Connection.Database; restrictions[2] = "spFunc"; dt = Connection.GetSchema("Procedure Parameters", restrictions); - Assert.True(dt.Rows.Count == 2); - Assert.AreEqual("Procedure Parameters", dt.TableName); - Assert.AreEqual(Connection.Database.ToLower(), dt.Rows[0]["SPECIFIC_SCHEMA"].ToString().ToLower()); - Assert.AreEqual("spfunc", dt.Rows[0]["SPECIFIC_NAME"].ToString().ToLower()); - Assert.AreEqual(0, dt.Rows[0]["ORDINAL_POSITION"]); - - Assert.AreEqual(Connection.Database.ToLower(), dt.Rows[1]["SPECIFIC_SCHEMA"].ToString().ToLower()); - Assert.AreEqual("spfunc", dt.Rows[1]["SPECIFIC_NAME"].ToString().ToLower()); - Assert.AreEqual("id", dt.Rows[1]["PARAMETER_NAME"].ToString().ToLower()); - Assert.AreEqual(1, dt.Rows[1]["ORDINAL_POSITION"]); - Assert.AreEqual("IN", dt.Rows[1]["PARAMETER_MODE"]); + Assert.That(dt.Rows.Count == 2); + Assert.That(dt.TableName, Is.EqualTo("Procedure Parameters")); + Assert.That(dt.Rows[0]["SPECIFIC_SCHEMA"].ToString().ToLower(), Is.EqualTo(Connection.Database.ToLower())); + Assert.That(dt.Rows[0]["SPECIFIC_NAME"].ToString().ToLower(), Is.EqualTo("spfunc")); + Assert.That(dt.Rows[0]["ORDINAL_POSITION"], Is.EqualTo(0)); + + Assert.That(dt.Rows[1]["SPECIFIC_SCHEMA"].ToString().ToLower(), Is.EqualTo(Connection.Database.ToLower())); + Assert.That(dt.Rows[1]["SPECIFIC_NAME"].ToString().ToLower(), Is.EqualTo("spfunc")); + Assert.That(dt.Rows[1]["PARAMETER_NAME"].ToString().ToLower(), Is.EqualTo("id")); + Assert.That(dt.Rows[1]["ORDINAL_POSITION"], Is.EqualTo(1)); + Assert.That(dt.Rows[1]["PARAMETER_MODE"], Is.EqualTo("IN")); } /// @@ -97,24 +98,24 @@ public void ProcedureParameters2() restrictions[2] = "spTest"; DataTable dt = Connection.GetSchema("Procedure Parameters", restrictions); - Assert.True(dt.Rows.Count == 2, "Actual result " + dt.Rows.Count); - Assert.AreEqual(Connection.Database.ToLower(), dt.Rows[0]["SPECIFIC_SCHEMA"].ToString().ToLower()); - Assert.AreEqual("sptest", dt.Rows[0]["SPECIFIC_NAME"].ToString().ToLower()); - Assert.AreEqual("/*id*/", dt.Rows[0]["PARAMETER_NAME"].ToString().ToLower()); - Assert.AreEqual(1, dt.Rows[0]["ORDINAL_POSITION"]); - Assert.AreEqual("IN", dt.Rows[0]["PARAMETER_MODE"]); - Assert.AreEqual("VARCHAR", dt.Rows[0]["DATA_TYPE"].ToString().ToUpper()); - Assert.AreEqual(20, dt.Rows[0]["CHARACTER_MAXIMUM_LENGTH"]); - Assert.AreEqual(20, dt.Rows[0]["CHARACTER_OCTET_LENGTH"]); - - Assert.AreEqual(Connection.Database.ToLower(), dt.Rows[1]["SPECIFIC_SCHEMA"].ToString().ToLower()); - Assert.AreEqual("sptest", dt.Rows[1]["SPECIFIC_NAME"].ToString().ToLower()); - Assert.AreEqual("result2", dt.Rows[1]["PARAMETER_NAME"].ToString().ToLower()); - Assert.AreEqual(2, dt.Rows[1]["ORDINAL_POSITION"]); - Assert.AreEqual("OUT", dt.Rows[1]["PARAMETER_MODE"]); - Assert.AreEqual("DECIMAL", dt.Rows[1]["DATA_TYPE"].ToString().ToUpper()); - Assert.AreEqual(10, Convert.ToInt32(dt.Rows[1]["NUMERIC_PRECISION"])); - Assert.AreEqual(2, dt.Rows[1]["NUMERIC_SCALE"]); + Assert.That(dt.Rows.Count == 2, "Actual result " + dt.Rows.Count); + Assert.That(dt.Rows[0]["SPECIFIC_SCHEMA"].ToString().ToLower(), Is.EqualTo(Connection.Database.ToLower())); + Assert.That(dt.Rows[0]["SPECIFIC_NAME"].ToString().ToLower(), Is.EqualTo("sptest")); + Assert.That(dt.Rows[0]["PARAMETER_NAME"].ToString().ToLower(), Is.EqualTo("/*id*/")); + Assert.That(dt.Rows[0]["ORDINAL_POSITION"], Is.EqualTo(1)); + Assert.That(dt.Rows[0]["PARAMETER_MODE"], Is.EqualTo("IN")); + Assert.That(dt.Rows[0]["DATA_TYPE"].ToString().ToUpper(), Is.EqualTo("VARCHAR")); + Assert.That(dt.Rows[0]["CHARACTER_MAXIMUM_LENGTH"], Is.EqualTo(20)); + Assert.That(dt.Rows[0]["CHARACTER_OCTET_LENGTH"], Is.EqualTo(20)); + + Assert.That(dt.Rows[1]["SPECIFIC_SCHEMA"].ToString().ToLower(), Is.EqualTo(Connection.Database.ToLower())); + Assert.That(dt.Rows[1]["SPECIFIC_NAME"].ToString().ToLower(), Is.EqualTo("sptest")); + Assert.That(dt.Rows[1]["PARAMETER_NAME"].ToString().ToLower(), Is.EqualTo("result2")); + Assert.That(dt.Rows[1]["ORDINAL_POSITION"], Is.EqualTo(2)); + Assert.That(dt.Rows[1]["PARAMETER_MODE"], Is.EqualTo("OUT")); + Assert.That(dt.Rows[1]["DATA_TYPE"].ToString().ToUpper(), Is.EqualTo("DECIMAL")); + Assert.That(Convert.ToInt32(dt.Rows[1]["NUMERIC_PRECISION"]), Is.EqualTo(10)); + Assert.That(dt.Rows[1]["NUMERIC_SCALE"], Is.EqualTo(2)); } [Test] @@ -146,96 +147,96 @@ _SONGS_LIST varchar(8000) character set latin1, restrictions[2] = "spTest"; DataTable dt = Connection.GetSchema("Procedure Parameters", restrictions); - Assert.True(dt.Rows.Count == 12, "Rows count failed"); - Assert.AreEqual(Connection.Database.ToLower(), dt.Rows[0]["SPECIFIC_SCHEMA"].ToString().ToLower()); - Assert.AreEqual("sptest", dt.Rows[0]["SPECIFIC_NAME"].ToString().ToLower()); - Assert.AreEqual("_action", dt.Rows[0]["PARAMETER_NAME"].ToString().ToLower()); - Assert.AreEqual(1, dt.Rows[0]["ORDINAL_POSITION"]); - Assert.AreEqual("IN", dt.Rows[0]["PARAMETER_MODE"]); - Assert.AreEqual("VARCHAR", dt.Rows[0]["DATA_TYPE"].ToString().ToUpper()); - Assert.AreEqual(20, dt.Rows[0]["CHARACTER_OCTET_LENGTH"]); - - Assert.AreEqual(Connection.Database.ToLower(), dt.Rows[1]["SPECIFIC_SCHEMA"].ToString().ToLower()); - Assert.AreEqual("sptest", dt.Rows[1]["SPECIFIC_NAME"].ToString().ToLower()); - Assert.AreEqual("/*dumb-identifier-1*/", dt.Rows[1]["PARAMETER_NAME"].ToString().ToLower()); - Assert.AreEqual(2, dt.Rows[1]["ORDINAL_POSITION"]); - Assert.AreEqual("IN", dt.Rows[1]["PARAMETER_MODE"]); - Assert.AreEqual("INT", dt.Rows[1]["DATA_TYPE"].ToString().ToUpper()); - - Assert.AreEqual(Connection.Database.ToLower(), dt.Rows[2]["SPECIFIC_SCHEMA"].ToString().ToLower()); - Assert.AreEqual("sptest", dt.Rows[2]["SPECIFIC_NAME"].ToString().ToLower()); - Assert.AreEqual("#dumb-identifier-2", dt.Rows[2]["PARAMETER_NAME"].ToString().ToLower()); - Assert.AreEqual(3, dt.Rows[2]["ORDINAL_POSITION"]); - Assert.AreEqual("IN", dt.Rows[2]["PARAMETER_MODE"]); - Assert.AreEqual("INT", dt.Rows[2]["DATA_TYPE"].ToString().ToUpper()); - - Assert.AreEqual(Connection.Database.ToLower(), dt.Rows[3]["SPECIFIC_SCHEMA"].ToString().ToLower()); - Assert.AreEqual("sptest", dt.Rows[3]["SPECIFIC_NAME"].ToString().ToLower()); - Assert.AreEqual("--dumb-identifier-3", dt.Rows[3]["PARAMETER_NAME"].ToString().ToLower()); - Assert.AreEqual(4, dt.Rows[3]["ORDINAL_POSITION"]); - Assert.AreEqual("IN", dt.Rows[3]["PARAMETER_MODE"]); - Assert.AreEqual("INT", dt.Rows[3]["DATA_TYPE"].ToString().ToUpper()); - - Assert.AreEqual(Connection.Database.ToLower(), dt.Rows[4]["SPECIFIC_SCHEMA"].ToString().ToLower()); - Assert.AreEqual("sptest", dt.Rows[4]["SPECIFIC_NAME"].ToString().ToLower()); - Assert.AreEqual("_client_id", dt.Rows[4]["PARAMETER_NAME"].ToString().ToLower()); - Assert.AreEqual(5, dt.Rows[4]["ORDINAL_POSITION"]); - Assert.AreEqual("IN", dt.Rows[4]["PARAMETER_MODE"]); - Assert.AreEqual("INT", dt.Rows[4]["DATA_TYPE"].ToString().ToUpper()); - - Assert.AreEqual(Connection.Database.ToLower(), dt.Rows[5]["SPECIFIC_SCHEMA"].ToString().ToLower()); - Assert.AreEqual("sptest", dt.Rows[5]["SPECIFIC_NAME"].ToString().ToLower()); - Assert.AreEqual("_login_id", dt.Rows[5]["PARAMETER_NAME"].ToString().ToLower()); - Assert.AreEqual(6, dt.Rows[5]["ORDINAL_POSITION"]); - Assert.AreEqual("IN", dt.Rows[5]["PARAMETER_MODE"]); - Assert.AreEqual("INT", dt.Rows[5]["DATA_TYPE"].ToString().ToUpper()); - - Assert.AreEqual(Connection.Database.ToLower(), dt.Rows[6]["SPECIFIC_SCHEMA"].ToString().ToLower()); - Assert.AreEqual("sptest", dt.Rows[6]["SPECIFIC_NAME"].ToString().ToLower()); - Assert.AreEqual("_where", dt.Rows[6]["PARAMETER_NAME"].ToString().ToLower()); - Assert.AreEqual(7, dt.Rows[6]["ORDINAL_POSITION"]); - Assert.AreEqual("IN", dt.Rows[6]["PARAMETER_MODE"]); - Assert.AreEqual("VARCHAR", dt.Rows[6]["DATA_TYPE"].ToString().ToUpper()); - Assert.AreEqual(2000, dt.Rows[6]["CHARACTER_OCTET_LENGTH"]); - - Assert.AreEqual(Connection.Database.ToLower(), dt.Rows[7]["SPECIFIC_SCHEMA"].ToString().ToLower()); - Assert.AreEqual("sptest", dt.Rows[7]["SPECIFIC_NAME"].ToString().ToLower()); - Assert.AreEqual("_sort", dt.Rows[7]["PARAMETER_NAME"].ToString().ToLower()); - Assert.AreEqual(8, dt.Rows[7]["ORDINAL_POSITION"]); - Assert.AreEqual("IN", dt.Rows[7]["PARAMETER_MODE"]); - Assert.AreEqual("VARCHAR", dt.Rows[7]["DATA_TYPE"].ToString().ToUpper()); - Assert.AreEqual(8000, dt.Rows[7]["CHARACTER_OCTET_LENGTH"]); - - Assert.AreEqual(Connection.Database.ToLower(), dt.Rows[8]["SPECIFIC_SCHEMA"].ToString().ToLower()); - Assert.AreEqual("sptest", dt.Rows[8]["SPECIFIC_NAME"].ToString().ToLower()); - Assert.AreEqual("_sql", dt.Rows[8]["PARAMETER_NAME"].ToString().ToLower()); - Assert.AreEqual(9, dt.Rows[8]["ORDINAL_POSITION"]); - Assert.AreEqual("OUT", dt.Rows[8]["PARAMETER_MODE"]); - Assert.AreEqual("VARCHAR", dt.Rows[8]["DATA_TYPE"].ToString().ToUpper()); - Assert.AreEqual(8000, dt.Rows[8]["CHARACTER_OCTET_LENGTH"]); - - Assert.AreEqual(Connection.Database.ToLower(), dt.Rows[9]["SPECIFIC_SCHEMA"].ToString().ToLower()); - Assert.AreEqual("sptest", dt.Rows[9]["SPECIFIC_NAME"].ToString().ToLower()); - Assert.AreEqual("_song_id", dt.Rows[9]["PARAMETER_NAME"].ToString().ToLower()); - Assert.AreEqual(10, dt.Rows[9]["ORDINAL_POSITION"]); - Assert.AreEqual("IN", dt.Rows[9]["PARAMETER_MODE"]); - Assert.AreEqual("INT", dt.Rows[9]["DATA_TYPE"].ToString().ToUpper()); - - Assert.AreEqual(Connection.Database.ToLower(), dt.Rows[10]["SPECIFIC_SCHEMA"].ToString().ToLower()); - Assert.AreEqual("sptest", dt.Rows[10]["SPECIFIC_NAME"].ToString().ToLower()); - Assert.AreEqual("_notes", dt.Rows[10]["PARAMETER_NAME"].ToString().ToLower()); - Assert.AreEqual(11, dt.Rows[10]["ORDINAL_POSITION"]); - Assert.AreEqual("IN", dt.Rows[10]["PARAMETER_MODE"]); - Assert.AreEqual("VARCHAR", dt.Rows[10]["DATA_TYPE"].ToString().ToUpper()); - Assert.AreEqual(2000, dt.Rows[10]["CHARACTER_OCTET_LENGTH"]); - - Assert.AreEqual(Connection.Database.ToLower(), dt.Rows[11]["SPECIFIC_SCHEMA"].ToString().ToLower()); - Assert.AreEqual("sptest", dt.Rows[11]["SPECIFIC_NAME"].ToString().ToLower()); - Assert.AreEqual("_result", dt.Rows[11]["PARAMETER_NAME"].ToString().ToLower()); - Assert.AreEqual(12, dt.Rows[11]["ORDINAL_POSITION"]); - Assert.AreEqual("OUT", dt.Rows[11]["PARAMETER_MODE"]); - Assert.AreEqual("VARCHAR", dt.Rows[11]["DATA_TYPE"].ToString().ToUpper()); - Assert.AreEqual(10, dt.Rows[11]["CHARACTER_OCTET_LENGTH"]); + Assert.That(dt.Rows.Count == 12, Is.True, "Rows count failed"); + Assert.That(dt.Rows[0]["SPECIFIC_SCHEMA"].ToString().ToLower(), Is.EqualTo(Connection.Database.ToLower())); + Assert.That(dt.Rows[0]["SPECIFIC_NAME"].ToString().ToLower(), Is.EqualTo("sptest")); + Assert.That(dt.Rows[0]["PARAMETER_NAME"].ToString().ToLower(), Is.EqualTo("_action")); + Assert.That(dt.Rows[0]["ORDINAL_POSITION"], Is.EqualTo(1)); + Assert.That(dt.Rows[0]["PARAMETER_MODE"], Is.EqualTo("IN")); + Assert.That(dt.Rows[0]["DATA_TYPE"].ToString().ToUpper(), Is.EqualTo("VARCHAR")); + Assert.That(dt.Rows[0]["CHARACTER_OCTET_LENGTH"], Is.EqualTo(20)); + + Assert.That(dt.Rows[1]["SPECIFIC_SCHEMA"].ToString().ToLower(), Is.EqualTo(Connection.Database.ToLower())); + Assert.That(dt.Rows[1]["SPECIFIC_NAME"].ToString().ToLower(), Is.EqualTo("sptest")); + Assert.That(dt.Rows[1]["PARAMETER_NAME"].ToString().ToLower(), Is.EqualTo("/*dumb-identifier-1*/")); + Assert.That(dt.Rows[1]["ORDINAL_POSITION"], Is.EqualTo(2)); + Assert.That(dt.Rows[1]["PARAMETER_MODE"], Is.EqualTo("IN")); + Assert.That(dt.Rows[1]["DATA_TYPE"].ToString().ToUpper(), Is.EqualTo("INT")); + + Assert.That(dt.Rows[2]["SPECIFIC_SCHEMA"].ToString().ToLower(), Is.EqualTo(Connection.Database.ToLower())); + Assert.That(dt.Rows[2]["SPECIFIC_NAME"].ToString().ToLower(), Is.EqualTo("sptest")); + Assert.That(dt.Rows[2]["PARAMETER_NAME"].ToString().ToLower(), Is.EqualTo("#dumb-identifier-2")); + Assert.That(dt.Rows[2]["ORDINAL_POSITION"], Is.EqualTo(3)); + Assert.That(dt.Rows[2]["PARAMETER_MODE"], Is.EqualTo("IN")); + Assert.That(dt.Rows[2]["DATA_TYPE"].ToString().ToUpper(), Is.EqualTo("INT")); + + Assert.That(dt.Rows[3]["SPECIFIC_SCHEMA"].ToString().ToLower(), Is.EqualTo(Connection.Database.ToLower())); + Assert.That(dt.Rows[3]["SPECIFIC_NAME"].ToString().ToLower(), Is.EqualTo("sptest")); + Assert.That(dt.Rows[3]["PARAMETER_NAME"].ToString().ToLower(), Is.EqualTo("--dumb-identifier-3")); + Assert.That(dt.Rows[3]["ORDINAL_POSITION"], Is.EqualTo(4)); + Assert.That(dt.Rows[3]["PARAMETER_MODE"], Is.EqualTo("IN")); + Assert.That(dt.Rows[3]["DATA_TYPE"].ToString().ToUpper(), Is.EqualTo("INT")); + + Assert.That(dt.Rows[4]["SPECIFIC_SCHEMA"].ToString().ToLower(), Is.EqualTo(Connection.Database.ToLower())); + Assert.That(dt.Rows[4]["SPECIFIC_NAME"].ToString().ToLower(), Is.EqualTo("sptest")); + Assert.That(dt.Rows[4]["PARAMETER_NAME"].ToString().ToLower(), Is.EqualTo("_client_id")); + Assert.That(dt.Rows[4]["ORDINAL_POSITION"], Is.EqualTo(5)); + Assert.That(dt.Rows[4]["PARAMETER_MODE"], Is.EqualTo("IN")); + Assert.That(dt.Rows[4]["DATA_TYPE"].ToString().ToUpper(), Is.EqualTo("INT")); + + Assert.That(dt.Rows[5]["SPECIFIC_SCHEMA"].ToString().ToLower(), Is.EqualTo(Connection.Database.ToLower())); + Assert.That(dt.Rows[5]["SPECIFIC_NAME"].ToString().ToLower(), Is.EqualTo("sptest")); + Assert.That(dt.Rows[5]["PARAMETER_NAME"].ToString().ToLower(), Is.EqualTo("_login_id")); + Assert.That(dt.Rows[5]["ORDINAL_POSITION"], Is.EqualTo(6)); + Assert.That(dt.Rows[5]["PARAMETER_MODE"], Is.EqualTo("IN")); + Assert.That(dt.Rows[5]["DATA_TYPE"].ToString().ToUpper(), Is.EqualTo("INT")); + + Assert.That(dt.Rows[6]["SPECIFIC_SCHEMA"].ToString().ToLower(), Is.EqualTo(Connection.Database.ToLower())); + Assert.That(dt.Rows[6]["SPECIFIC_NAME"].ToString().ToLower(), Is.EqualTo("sptest")); + Assert.That(dt.Rows[6]["PARAMETER_NAME"].ToString().ToLower(), Is.EqualTo("_where")); + Assert.That(dt.Rows[6]["ORDINAL_POSITION"], Is.EqualTo(7)); + Assert.That(dt.Rows[6]["PARAMETER_MODE"], Is.EqualTo("IN")); + Assert.That(dt.Rows[6]["DATA_TYPE"].ToString().ToUpper(), Is.EqualTo("VARCHAR")); + Assert.That(dt.Rows[6]["CHARACTER_OCTET_LENGTH"], Is.EqualTo(2000)); + + Assert.That(dt.Rows[7]["SPECIFIC_SCHEMA"].ToString().ToLower(), Is.EqualTo(Connection.Database.ToLower())); + Assert.That(dt.Rows[7]["SPECIFIC_NAME"].ToString().ToLower(), Is.EqualTo("sptest")); + Assert.That(dt.Rows[7]["PARAMETER_NAME"].ToString().ToLower(), Is.EqualTo("_sort")); + Assert.That(dt.Rows[7]["ORDINAL_POSITION"], Is.EqualTo(8)); + Assert.That(dt.Rows[7]["PARAMETER_MODE"], Is.EqualTo("IN")); + Assert.That(dt.Rows[7]["DATA_TYPE"].ToString().ToUpper(), Is.EqualTo("VARCHAR")); + Assert.That(dt.Rows[7]["CHARACTER_OCTET_LENGTH"], Is.EqualTo(8000)); + + Assert.That(dt.Rows[8]["SPECIFIC_SCHEMA"].ToString().ToLower(), Is.EqualTo(Connection.Database.ToLower())); + Assert.That(dt.Rows[8]["SPECIFIC_NAME"].ToString().ToLower(), Is.EqualTo("sptest")); + Assert.That(dt.Rows[8]["PARAMETER_NAME"].ToString().ToLower(), Is.EqualTo("_sql")); + Assert.That(dt.Rows[8]["ORDINAL_POSITION"], Is.EqualTo(9)); + Assert.That(dt.Rows[8]["PARAMETER_MODE"], Is.EqualTo("OUT")); + Assert.That(dt.Rows[8]["DATA_TYPE"].ToString().ToUpper(), Is.EqualTo("VARCHAR")); + Assert.That(dt.Rows[8]["CHARACTER_OCTET_LENGTH"], Is.EqualTo(8000)); + + Assert.That(dt.Rows[9]["SPECIFIC_SCHEMA"].ToString().ToLower(), Is.EqualTo(Connection.Database.ToLower())); + Assert.That(dt.Rows[9]["SPECIFIC_NAME"].ToString().ToLower(), Is.EqualTo("sptest")); + Assert.That(dt.Rows[9]["PARAMETER_NAME"].ToString().ToLower(), Is.EqualTo("_song_id")); + Assert.That(dt.Rows[9]["ORDINAL_POSITION"], Is.EqualTo(10)); + Assert.That(dt.Rows[9]["PARAMETER_MODE"], Is.EqualTo("IN")); + Assert.That(dt.Rows[9]["DATA_TYPE"].ToString().ToUpper(), Is.EqualTo("INT")); + + Assert.That(dt.Rows[10]["SPECIFIC_SCHEMA"].ToString().ToLower(), Is.EqualTo(Connection.Database.ToLower())); + Assert.That(dt.Rows[10]["SPECIFIC_NAME"].ToString().ToLower(), Is.EqualTo("sptest")); + Assert.That(dt.Rows[10]["PARAMETER_NAME"].ToString().ToLower(), Is.EqualTo("_notes")); + Assert.That(dt.Rows[10]["ORDINAL_POSITION"], Is.EqualTo(11)); + Assert.That(dt.Rows[10]["PARAMETER_MODE"], Is.EqualTo("IN")); + Assert.That(dt.Rows[10]["DATA_TYPE"].ToString().ToUpper(), Is.EqualTo("VARCHAR")); + Assert.That(dt.Rows[10]["CHARACTER_OCTET_LENGTH"], Is.EqualTo(2000)); + + Assert.That(dt.Rows[11]["SPECIFIC_SCHEMA"].ToString().ToLower(), Is.EqualTo(Connection.Database.ToLower())); + Assert.That(dt.Rows[11]["SPECIFIC_NAME"].ToString().ToLower(), Is.EqualTo("sptest")); + Assert.That(dt.Rows[11]["PARAMETER_NAME"].ToString().ToLower(), Is.EqualTo("_result")); + Assert.That(dt.Rows[11]["ORDINAL_POSITION"], Is.EqualTo(12)); + Assert.That(dt.Rows[11]["PARAMETER_MODE"], Is.EqualTo("OUT")); + Assert.That(dt.Rows[11]["DATA_TYPE"].ToString().ToUpper(), Is.EqualTo("VARCHAR")); + Assert.That(dt.Rows[11]["CHARACTER_OCTET_LENGTH"], Is.EqualTo(10)); } [Test] @@ -251,17 +252,17 @@ public void ProcedureParameters4() restrictions[2] = "ProcedureParameters4"; DataTable dt = Connection.GetSchema("Procedure Parameters", restrictions); - Assert.True(dt.Rows.Count == 1, "Actual Result " + dt.Rows.Count); - Assert.AreEqual(Connection.Database, dt.Rows[0]["SPECIFIC_SCHEMA"].ToString()); - Assert.AreEqual("ProcedureParameters4", dt.Rows[0]["SPECIFIC_NAME"].ToString()); - Assert.AreEqual("name", dt.Rows[0]["PARAMETER_NAME"].ToString().ToLower()); - Assert.AreEqual(1, dt.Rows[0]["ORDINAL_POSITION"]); - Assert.AreEqual("IN", dt.Rows[0]["PARAMETER_MODE"]); - Assert.AreEqual("VARCHAR", dt.Rows[0]["DATA_TYPE"].ToString().ToUpper()); - Assert.AreEqual(1200, dt.Rows[0]["CHARACTER_MAXIMUM_LENGTH"]); - Assert.AreEqual(3600, dt.Rows[0]["CHARACTER_OCTET_LENGTH"]); - Assert.AreEqual(charset, dt.Rows[0]["CHARACTER_SET_NAME"]); - Assert.AreEqual($"{charset}_general_ci", dt.Rows[0]["COLLATION_NAME"]); + Assert.That(dt.Rows.Count == 1, Is.True, "Actual Result " + dt.Rows.Count); + Assert.That(dt.Rows[0]["SPECIFIC_SCHEMA"].ToString(), Is.EqualTo(Connection.Database)); + Assert.That(dt.Rows[0]["SPECIFIC_NAME"].ToString(), Is.EqualTo("ProcedureParameters4")); + Assert.That(dt.Rows[0]["PARAMETER_NAME"].ToString().ToLower(), Is.EqualTo("name")); + Assert.That(dt.Rows[0]["ORDINAL_POSITION"], Is.EqualTo(1)); + Assert.That(dt.Rows[0]["PARAMETER_MODE"], Is.EqualTo("IN")); + Assert.That(dt.Rows[0]["DATA_TYPE"].ToString().ToUpper(), Is.EqualTo("VARCHAR")); + Assert.That(dt.Rows[0]["CHARACTER_MAXIMUM_LENGTH"], Is.EqualTo(1200)); + Assert.That(dt.Rows[0]["CHARACTER_OCTET_LENGTH"], Is.EqualTo(3600)); + Assert.That(dt.Rows[0]["CHARACTER_SET_NAME"], Is.EqualTo(charset)); + Assert.That(dt.Rows[0]["COLLATION_NAME"], Is.EqualTo($"{charset}_general_ci")); } [Test] @@ -275,23 +276,23 @@ public void ProcedureParameters5() restrictions[2] = "ProcedureParameters5"; DataTable dt = Connection.GetSchema("Procedure Parameters", restrictions); - Assert.True(dt.Rows.Count == 2); - Assert.AreEqual(Connection.Database, dt.Rows[0]["SPECIFIC_SCHEMA"].ToString()); - Assert.AreEqual("ProcedureParameters5", dt.Rows[0]["SPECIFIC_NAME"].ToString()); - Assert.AreEqual("name", dt.Rows[0]["PARAMETER_NAME"].ToString().ToLower()); - Assert.AreEqual(1, dt.Rows[0]["ORDINAL_POSITION"]); - Assert.AreEqual("IN", dt.Rows[0]["PARAMETER_MODE"]); - Assert.AreEqual("VARCHAR", dt.Rows[0]["DATA_TYPE"].ToString().ToUpper()); - Assert.AreEqual("latin1", dt.Rows[0]["CHARACTER_SET_NAME"]); - Assert.AreEqual(1200, dt.Rows[0]["CHARACTER_OCTET_LENGTH"]); - - Assert.AreEqual(Connection.Database, dt.Rows[1]["SPECIFIC_SCHEMA"].ToString()); - Assert.AreEqual("ProcedureParameters5", dt.Rows[1]["SPECIFIC_NAME"].ToString()); - Assert.AreEqual("name2", dt.Rows[1]["PARAMETER_NAME"].ToString().ToLower()); - Assert.AreEqual(2, dt.Rows[1]["ORDINAL_POSITION"]); - Assert.AreEqual("IN", dt.Rows[1]["PARAMETER_MODE"]); - Assert.AreEqual("TEXT", dt.Rows[1]["DATA_TYPE"].ToString().ToUpper()); - Assert.AreEqual("ucs2", dt.Rows[1]["CHARACTER_SET_NAME"]); + Assert.That(dt.Rows.Count == 2, Is.True); + Assert.That(dt.Rows[0]["SPECIFIC_SCHEMA"].ToString(), Is.EqualTo(Connection.Database)); + Assert.That(dt.Rows[0]["SPECIFIC_NAME"].ToString(), Is.EqualTo("ProcedureParameters5")); + Assert.That(dt.Rows[0]["PARAMETER_NAME"].ToString().ToLower(), Is.EqualTo("name")); + Assert.That(dt.Rows[0]["ORDINAL_POSITION"], Is.EqualTo(1)); + Assert.That(dt.Rows[0]["PARAMETER_MODE"], Is.EqualTo("IN")); + Assert.That(dt.Rows[0]["DATA_TYPE"].ToString().ToUpper(), Is.EqualTo("VARCHAR")); + Assert.That(dt.Rows[0]["CHARACTER_SET_NAME"], Is.EqualTo("latin1")); + Assert.That(dt.Rows[0]["CHARACTER_OCTET_LENGTH"], Is.EqualTo(1200)); + + Assert.That(dt.Rows[1]["SPECIFIC_SCHEMA"].ToString(), Is.EqualTo(Connection.Database)); + Assert.That(dt.Rows[1]["SPECIFIC_NAME"].ToString(), Is.EqualTo("ProcedureParameters5")); + Assert.That(dt.Rows[1]["PARAMETER_NAME"].ToString().ToLower(), Is.EqualTo("name2")); + Assert.That(dt.Rows[1]["ORDINAL_POSITION"], Is.EqualTo(2)); + Assert.That(dt.Rows[1]["PARAMETER_MODE"], Is.EqualTo("IN")); + Assert.That(dt.Rows[1]["DATA_TYPE"].ToString().ToUpper(), Is.EqualTo("TEXT")); + Assert.That(dt.Rows[1]["CHARACTER_SET_NAME"], Is.EqualTo("ucs2")); } [Test] @@ -313,19 +314,13 @@ name VARCHAR(20) /* this is a comment */ CHARACTER SET ascii, restrictions[2] = "DTD_Identifier"; DataTable dt = Connection.GetSchema("Procedure Parameters", restrictions); - Assert.True(dt.Rows.Count == 6, "Actual Result " + dt.Rows.Count); - Assert.AreEqual("INT(10) UNSIGNED ZEROFILL", - dt.Rows[0]["DTD_IDENTIFIER"].ToString().ToUpper()); - Assert.AreEqual("DECIMAL(10,2)", - dt.Rows[1]["DTD_IDENTIFIER"].ToString().ToUpper()); - Assert.AreEqual("VARCHAR(20)", - dt.Rows[2]["DTD_IDENTIFIER"].ToString().ToUpper()); - Assert.AreEqual("TINYTEXT", - dt.Rows[3]["DTD_IDENTIFIER"].ToString().ToUpper()); - Assert.AreEqual("ENUM('A','B','C')", - dt.Rows[4]["DTD_IDENTIFIER"].ToString().ToUpper()); - Assert.AreEqual("SET('1','2','3')", - dt.Rows[5]["DTD_IDENTIFIER"].ToString().ToUpper()); + Assert.That(dt.Rows.Count == 6, Is.True, "Actual Result " + dt.Rows.Count); + Assert.That(dt.Rows[0]["DTD_IDENTIFIER"].ToString().ToUpper(), Is.EqualTo("INT(10) UNSIGNED ZEROFILL")); + Assert.That(dt.Rows[1]["DTD_IDENTIFIER"].ToString().ToUpper(), Is.EqualTo("DECIMAL(10,2)")); + Assert.That(dt.Rows[2]["DTD_IDENTIFIER"].ToString().ToUpper(), Is.EqualTo("VARCHAR(20)")); + Assert.That(dt.Rows[3]["DTD_IDENTIFIER"].ToString().ToUpper(), Is.EqualTo("TINYTEXT")); + Assert.That(dt.Rows[4]["DTD_IDENTIFIER"].ToString().ToUpper(), Is.EqualTo("ENUM('A','B','C')")); + Assert.That(dt.Rows[5]["DTD_IDENTIFIER"].ToString().ToUpper(), Is.EqualTo("SET('1','2','3')")); conn.Close(); } } @@ -350,20 +345,20 @@ name VARCHAR(20) /* this is a comment */ CHARACTER SET ascii, cmd.CommandText = "PossibleValues"; cmd.CommandType = CommandType.StoredProcedure; MySqlCommandBuilder.DeriveParameters(cmd); - Assert.Null(cmd.Parameters["@id"].PossibleValues); - Assert.Null(cmd.Parameters["@dec1"].PossibleValues); - Assert.Null(cmd.Parameters["@name"].PossibleValues); - Assert.Null(cmd.Parameters["@t1"].PossibleValues); + Assert.That(cmd.Parameters["@id"].PossibleValues, Is.Null); + Assert.That(cmd.Parameters["@dec1"].PossibleValues, Is.Null); + Assert.That(cmd.Parameters["@name"].PossibleValues, Is.Null); + Assert.That(cmd.Parameters["@t1"].PossibleValues, Is.Null); MySqlParameter t2 = cmd.Parameters["@t2"]; - Assert.NotNull(t2.PossibleValues); - Assert.AreEqual("a", t2.PossibleValues[0]); - Assert.AreEqual("b", t2.PossibleValues[1]); - Assert.AreEqual("c", t2.PossibleValues[2]); + Assert.That(t2.PossibleValues, Is.Not.Null); + Assert.That(t2.PossibleValues[0], Is.EqualTo("a")); + Assert.That(t2.PossibleValues[1], Is.EqualTo("b")); + Assert.That(t2.PossibleValues[2], Is.EqualTo("c")); MySqlParameter t3 = cmd.Parameters["@t3"]; - Assert.NotNull(t3.PossibleValues); - Assert.AreEqual("1", t3.PossibleValues[0]); - Assert.AreEqual("2", t3.PossibleValues[1]); - Assert.AreEqual("3", t3.PossibleValues[2]); + Assert.That(t3.PossibleValues, Is.Not.Null); + Assert.That(t3.PossibleValues[0], Is.EqualTo("1")); + Assert.That(t3.PossibleValues[1], Is.EqualTo("2")); + Assert.That(t3.PossibleValues[2], Is.EqualTo("3")); conn.Close(); } @@ -378,20 +373,20 @@ name VARCHAR(20) /* this is a comment */ CHARACTER SET ascii, cmd.CommandText = "PossibleValues"; cmd.CommandType = CommandType.StoredProcedure; MySqlCommandBuilder.DeriveParameters(cmd); - Assert.Null(cmd.Parameters["@id"].PossibleValues); - Assert.Null(cmd.Parameters["@dec1"].PossibleValues); - Assert.Null(cmd.Parameters["@name"].PossibleValues); - Assert.Null(cmd.Parameters["@t1"].PossibleValues); + Assert.That(cmd.Parameters["@id"].PossibleValues, Is.Null); + Assert.That(cmd.Parameters["@dec1"].PossibleValues, Is.Null); + Assert.That(cmd.Parameters["@name"].PossibleValues, Is.Null); + Assert.That(cmd.Parameters["@t1"].PossibleValues, Is.Null); MySqlParameter t2 = cmd.Parameters["@t2"]; - Assert.NotNull(t2.PossibleValues); - Assert.AreEqual("a", t2.PossibleValues[0]); - Assert.AreEqual("b", t2.PossibleValues[1]); - Assert.AreEqual("c", t2.PossibleValues[2]); + Assert.That(t2.PossibleValues, Is.Not.Null); + Assert.That(t2.PossibleValues[0], Is.EqualTo("a")); + Assert.That(t2.PossibleValues[1], Is.EqualTo("b")); + Assert.That(t2.PossibleValues[2], Is.EqualTo("c")); MySqlParameter t3 = cmd.Parameters["@t3"]; - Assert.NotNull(t3.PossibleValues); - Assert.AreEqual("1", t3.PossibleValues[0]); - Assert.AreEqual("2", t3.PossibleValues[1]); - Assert.AreEqual("3", t3.PossibleValues[2]); + Assert.That(t3.PossibleValues, Is.Not.Null); + Assert.That(t3.PossibleValues[0], Is.EqualTo("1")); + Assert.That(t3.PossibleValues[1], Is.EqualTo("2")); + Assert.That(t3.PossibleValues[2], Is.EqualTo("3")); conn.Close(); } } @@ -467,7 +462,7 @@ SQL SECURITY INVOKER da.SelectCommand = cmd; DataSet ds = new DataSet(); da.Fill(ds); - Assert.True(ds.Tables.Count > 0); + Assert.That(ds.Tables.Count > 0, Is.True); //Test with not existing procedure cmd.CommandText = "get_hello3"; @@ -480,7 +475,7 @@ SQL SECURITY INVOKER if (hasPrivileges) { da.Fill(ds); - Assert.True(ds.Tables.Count > 0); + Assert.That(ds.Tables.Count > 0, Is.True); } else { @@ -527,15 +522,15 @@ OUT value INT while (reader.Read()) { var stdout1 = reader.GetInt32(0); - Assert.AreEqual(2, stdout1); + Assert.That(stdout1, Is.EqualTo(2)); var schema = reader.GetSchemaTable(); - Assert.NotNull(schema); - Assert.True(reader.HasRows); - Assert.AreEqual(1, reader.FieldCount); + Assert.That(schema, Is.Not.Null); + Assert.That(reader.HasRows, Is.True); + Assert.That(reader.FieldCount, Is.EqualTo(1)); } } var outparam1 = _outputParam.Value; - Assert.AreEqual(1, outparam1); + Assert.That(outparam1, Is.EqualTo(1)); } @@ -561,12 +556,12 @@ OUT value INT { reader.Read(); var schema = reader.GetSchemaTable(); - Assert.Null(schema); - Assert.False(reader.HasRows); - Assert.AreEqual(0, reader.FieldCount); + Assert.That(schema, Is.Null); + Assert.That(reader.HasRows, Is.False); + Assert.That(reader.FieldCount, Is.EqualTo(0)); } var outparam1 = _outputParam2.Value; - Assert.AreEqual(1, outparam1); + Assert.That(outparam1, Is.EqualTo(1)); } } } diff --git a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/ReplicationTests.cs b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/ReplicationTests.cs index 37445ed5c..c599595f0 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/ReplicationTests.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/ReplicationTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -27,6 +27,7 @@ // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA using NUnit.Framework; +using NUnit.Framework.Legacy; namespace MySql.Data.MySqlClient.Tests { @@ -45,7 +46,7 @@ public void Simple() } catch (MySqlException ex) { - StringAssert.Contains("Replicated", ex.Message); + Assert.That(ex.Message, Does.Contain("Replicated")); } } } diff --git a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/StressTestsPipe.cs b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/StressTestsPipe.cs index f5874e185..b5f0e5fc0 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/StressTestsPipe.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/StressTestsPipe.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -30,10 +30,6 @@ namespace MySql.Data.MySqlClient.Tests { public class StressTestsPipe : StressTests { - public StressTestsPipe(TestFixture fixture) : base(fixture) - { - } - internal override void AdjustConnectionSettings(MySqlConnectionStringBuilder settings) { settings.ConnectionProtocol = MySqlConnectionProtocol.NamedPipe; diff --git a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/StressTestsPipeCompressed.cs b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/StressTestsPipeCompressed.cs index dd0d9a548..2642e165b 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/StressTestsPipeCompressed.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/StressTestsPipeCompressed.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -26,14 +26,12 @@ // along with this program; if not, write to the Free Software Foundation, Inc., // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +using NUnit.Framework.Internal; + namespace MySql.Data.MySqlClient.Tests { public class StressTestsPipeCompressed : StressTests { - public StressTestsPipeCompressed(TestFixture fixture) : base(fixture) - { - } - internal override void AdjustConnectionSettings(MySqlConnectionStringBuilder settings) { settings.ConnectionProtocol = MySqlConnectionProtocol.NamedPipe; diff --git a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/StressTestsSharedMemory.cs b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/StressTestsSharedMemory.cs index 7dcb6e9a4..533a47399 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/StressTestsSharedMemory.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/StressTestsSharedMemory.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -26,14 +26,12 @@ // along with this program; if not, write to the Free Software Foundation, Inc., // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +using NUnit.Framework.Internal; + namespace MySql.Data.MySqlClient.Tests { public class StressTestsSharedMemory : StressTests { - public StressTestsSharedMemory(TestFixture fixture) : base(fixture) - { - } - internal override void AdjustConnectionSettings(MySqlConnectionStringBuilder settings) { settings.ConnectionProtocol = MySqlConnectionProtocol.SharedMemory; diff --git a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/StressTestsSharedMemoryCompressed.cs b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/StressTestsSharedMemoryCompressed.cs index 15379a454..853ee4daa 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/StressTestsSharedMemoryCompressed.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/StressTestsSharedMemoryCompressed.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -26,11 +26,13 @@ // along with this program; if not, write to the Free Software Foundation, Inc., // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +using NUnit.Framework.Internal; + namespace MySql.Data.MySqlClient.Tests { public class StressTestsSharedMemoryCompressed : StressTests { - public StressTestsSharedMemoryCompressed(TestFixture fixture) : base(fixture) + public StressTestsSharedMemoryCompressed() : base() { } diff --git a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/ThreadingTests.cs b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/ThreadingTests.cs index b3c80ad4c..36fe37067 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/ThreadingTests.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/ThreadingTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -28,6 +28,7 @@ using System; using NUnit.Framework; +using NUnit.Framework.Legacy; using System.Threading; using System.Collections; @@ -124,7 +125,7 @@ public void HardenedThreadAbortException() t.Abort(); t.Join(); - Assert.NotNull(lastException); + Assert.That(lastException, Is.Not.Null); if (lastException is MySqlException) { @@ -133,7 +134,7 @@ public void HardenedThreadAbortException() } //Assert.InstanceOf(typeof(ThreadAbortException), lastException); - Assert.IsInstanceOf(lastException); + Assert.That(lastException, Is.InstanceOf()); } } } diff --git a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/TimeoutAndCancel.cs b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/TimeoutAndCancel.cs index b4fbe2462..96cc83ac2 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/TimeoutAndCancel.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/TimeoutAndCancel.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2022, Oracle and/or its affiliates. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -28,10 +28,12 @@ using System; using NUnit.Framework; +using NUnit.Framework.Legacy; using System.Threading; using System.Data; using System.Globalization; using System.IO; +using NUnit.Framework.Internal; namespace MySql.Data.MySqlClient.Tests { @@ -49,7 +51,7 @@ private void CommandRunner(MySqlCommand cmdToRun) { object o = cmdToRun.ExecuteScalar(); resetEvent.Set(); - Assert.Null(o); + Assert.That(o, Is.Null); } #if NETFRAMEWORK @@ -76,7 +78,7 @@ public void CancelSingleQuery() // now cancel the command cmd.Cancel(); - Assert.True(resetEvent.WaitOne(30 * 1000), "timeout"); + Assert.That(resetEvent.WaitOne(30 * 1000), "timeout"); } #endif @@ -114,13 +116,13 @@ public void WaitTimeoutExpiring() catch (MySqlException ex) { if (Version < new Version("8.0.24")) - StringAssert.StartsWith("Fatal", ex.Message); + Assert.That(ex.Message, Does.StartWith("Fatal")); else - StringAssert.StartsWith("The client was disconnected", ex.Message); + Assert.That(ex.Message, Does.StartWith("The client was disconnected")); } - Assert.AreEqual(1, stateChangeCount); - Assert.AreEqual(ConnectionState.Closed, c.State); + Assert.That(stateChangeCount, Is.EqualTo(1)); + Assert.That(c.State, Is.EqualTo(ConnectionState.Closed)); } using (MySqlConnection c = new MySqlConnection(connStr)) @@ -129,7 +131,7 @@ public void WaitTimeoutExpiring() MySqlCommand cmd = new MySqlCommand("SELECT now() as thetime, database() as db", c); using (MySqlDataReader r = cmd.ExecuteReader()) { - Assert.True(r.Read()); + Assert.That(r.Read(), Is.True); } } } @@ -217,17 +219,17 @@ public void CancelSelect() } catch (MySqlException ex) { - Assert.True(ex.Number == (int)MySqlErrorCode.QueryInterrupted); + Assert.That(ex.Number, Is.EqualTo((int)MySqlErrorCode.QueryInterrupted)); if (rows < 1000) { bool readOK = reader.Read(); - Assert.False(readOK); + Assert.That(readOK, Is.False); } } } } - Assert.True(rows < 1000); + Assert.That(rows < 1000); } /// @@ -261,11 +263,11 @@ public void ConnectionStringModifiedAfterCancel() } catch (MySqlException ex) { - Assert.True(ex.InnerException is TimeoutException); - Assert.True(c.State == ConnectionState.Open); + Assert.That(ex.InnerException is TimeoutException, Is.True); + Assert.That(c.State, Is.EqualTo(ConnectionState.Open)); } string connStr2 = c.ConnectionString.ToLower(CultureInfo.InvariantCulture); - Assert.AreEqual(connStr1.ToLower(CultureInfo.InvariantCulture), connStr2); + Assert.That(connStr2, Is.EqualTo(connStr1.ToLower(CultureInfo.InvariantCulture))); c.Close(); } @@ -310,7 +312,7 @@ public void NetWriteTimeoutExpiring() // normally and then the problem, described above, occurs for (; i < rows; i++) { - Assert.False(!reader.Read(),"unexpected 'false' from reader.Read"); + Assert.That(!reader.Read(), Is.False, "unexpected 'false' from reader.Read"); if (i % 10 == 0) Thread.Sleep(1); object v = reader.GetValue(1); @@ -336,7 +338,7 @@ public void NetWriteTimeoutExpiring() // IT is relatively hard to predict where Console.WriteLine("Warning: all reads completed!"); - Assert.True(i == rows); + Assert.That(i, Is.EqualTo(rows)); } } } diff --git a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/TimeoutAndCancelCompressed.cs b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/TimeoutAndCancelCompressed.cs index d4a54048c..3c02ba9af 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/TimeoutAndCancelCompressed.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/TimeoutAndCancelCompressed.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/TimeoutAndCancelPipe.cs b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/TimeoutAndCancelPipe.cs index 79c4200c4..00e010872 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/TimeoutAndCancelPipe.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/TimeoutAndCancelPipe.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -30,10 +30,6 @@ namespace MySql.Data.MySqlClient.Tests { public class TimeoutAndCancelPipe : TimeoutAndCancel { - public TimeoutAndCancelPipe(TestFixture fixture) : base(fixture) - { - } - internal override void AdjustConnectionSettings(MySqlConnectionStringBuilder settings) { settings.ConnectionProtocol = MySqlConnectionProtocol.NamedPipe; diff --git a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/TimeoutAndCancelSharedMemory.cs b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/TimeoutAndCancelSharedMemory.cs index 21821e844..622a9bf1a 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/TimeoutAndCancelSharedMemory.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/TimeoutAndCancelSharedMemory.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -28,11 +28,13 @@ +using NUnit.Framework.Internal; + namespace MySql.Data.MySqlClient.Tests { public class TimeoutAndCancelSharedMemory : TimeoutAndCancel { - public TimeoutAndCancelSharedMemory(TestFixture fixture) : base(fixture) + public TimeoutAndCancelSharedMemory() : base() { } diff --git a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/TypeTests.cs b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/TypeTests.cs index 00a2ded7f..71c861b44 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/TypeTests.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/TypeTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2022, Oracle and/or its affiliates. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -27,6 +27,7 @@ // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA using NUnit.Framework; +using NUnit.Framework.Legacy; using MySql.Data.Types; using System.IO; @@ -34,7 +35,7 @@ namespace MySql.Data.MySqlClient.Tests { public class TypeTests : TestBase { -#if !NET7_0_OR_GREATER +#if !NET8_0_OR_GREATER /// /// Test fix for http://bugs.mysql.com/bug.php?id=40555 /// Make MySql.Data.Types.MySqlDateTime serializable. @@ -43,12 +44,12 @@ public class TypeTests : TestBase public void TestSerializationMySqlDataTime() { MySqlDateTime dt = new MySqlDateTime(2011, 10, 6, 11, 38, 01, 0); - Assert.AreEqual(2011, dt.Year); - Assert.AreEqual(10, dt.Month); - Assert.AreEqual(6, dt.Day); - Assert.AreEqual(11, dt.Hour); - Assert.AreEqual(38, dt.Minute); - Assert.AreEqual(1, dt.Second); + Assert.That(dt.Year, Is.EqualTo(2011)); + Assert.That(dt.Month, Is.EqualTo(10)); + Assert.That(dt.Day, Is.EqualTo(6)); + Assert.That(dt.Hour, Is.EqualTo(11)); + Assert.That(dt.Minute, Is.EqualTo(38)); + Assert.That(dt.Second, Is.EqualTo(1)); System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bf = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter(); MemoryStream ms = new MemoryStream(1024); @@ -56,13 +57,13 @@ public void TestSerializationMySqlDataTime() ms.Position = 0; object o = bf.Deserialize(ms); dt = (MySqlDateTime)o; - Assert.AreEqual(2011, dt.Year); - Assert.AreEqual(10, dt.Month); - Assert.AreEqual(6, dt.Day); - Assert.AreEqual(11, dt.Hour); - Assert.AreEqual(38, dt.Minute); - Assert.AreEqual(1, dt.Second); + Assert.That(dt.Year, Is.EqualTo(2011)); + Assert.That(dt.Month, Is.EqualTo(10)); + Assert.That(dt.Day, Is.EqualTo(6)); + Assert.That(dt.Hour, Is.EqualTo(11)); + Assert.That(dt.Minute, Is.EqualTo(38)); + Assert.That(dt.Second, Is.EqualTo(1)); } #endif } -} \ No newline at end of file +} diff --git a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/UsageAdvisorTests.cs b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/UsageAdvisorTests.cs index c4146d171..b8d746a6e 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/UsageAdvisorTests.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/Framework/netstandard2_0/UsageAdvisorTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -27,6 +27,7 @@ // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA using NUnit.Framework; +using NUnit.Framework.Legacy; using System.Diagnostics; using System; @@ -64,25 +65,25 @@ public void NotReadingEveryField() reader.Read(); reader.GetInt32(0); // access the first field reader.Read(); - Assert.True(reader.NextResult()); + Assert.That(reader.NextResult(), Is.True); reader.Read(); - Assert.AreEqual("Test3", reader.GetString(1)); - Assert.False(reader.NextResult()); + Assert.That(reader.GetString(1), Is.EqualTo("Test3")); + Assert.That(reader.NextResult(), Is.False); } - Assert.AreEqual(12, listener.Strings.Count); - StringAssert.Contains("Query Opened: SELECT * FROM Test; SELECT * FROM Test WHERE id > 2", listener.Strings[0]); - StringAssert.Contains("Resultset Opened: field(s) = 2, affected rows = -1, inserted id = -1", listener.Strings[1]); - StringAssert.Contains("Usage Advisor Warning: Query does not use an index", listener.Strings[2]); - StringAssert.Contains("Usage Advisor Warning: Skipped 2 rows. Consider a more focused query.", listener.Strings[3]); - StringAssert.Contains("Usage Advisor Warning: The following columns were not accessed: name", listener.Strings[4]); - StringAssert.Contains("Resultset Closed. Total rows=4, skipped rows=2, size (bytes)=32", listener.Strings[5]); - StringAssert.Contains("Resultset Opened: field(s) = 2, affected rows = -1, inserted id = -1", listener.Strings[6]); - StringAssert.Contains("Usage Advisor Warning: Query does not use an index", listener.Strings[7]); - StringAssert.Contains("Usage Advisor Warning: Skipped 1 rows. Consider a more focused query.", listener.Strings[8]); - StringAssert.Contains("Usage Advisor Warning: The following columns were not accessed: id", listener.Strings[9]); - StringAssert.Contains("Resultset Closed. Total rows=2, skipped rows=1, size (bytes)=16", listener.Strings[10]); - StringAssert.Contains("Query Closed", listener.Strings[11]); + Assert.That(listener.Strings.Count, Is.EqualTo(12)); + Assert.That(listener.Strings[0], Does.Contain("Query Opened: SELECT * FROM Test; SELECT * FROM Test WHERE id > 2")); + Assert.That(listener.Strings[1], Does.Contain("Resultset Opened: field(s) = 2, affected rows = -1, inserted id = -1")); + Assert.That(listener.Strings[2], Does.Contain("Usage Advisor Warning: Query does not use an index")); + Assert.That(listener.Strings[3], Does.Contain("Usage Advisor Warning: Skipped 2 rows. Consider a more focused query")); + Assert.That(listener.Strings[4], Does.Contain("Usage Advisor Warning: The following columns were not accessed: name")); + Assert.That(listener.Strings[5], Does.Contain("Resultset Closed. Total rows=4, skipped rows=2, size (bytes)=32")); + Assert.That(listener.Strings[6], Does.Contain("Resultset Opened: field(s) = 2, affected rows = -1, inserted id = -1")); + Assert.That(listener.Strings[7], Does.Contain("Usage Advisor Warning: Query does not use an index")); + Assert.That(listener.Strings[8], Does.Contain("Usage Advisor Warning: Skipped 1 rows. Consider a more focused query")); + Assert.That(listener.Strings[9], Does.Contain("Usage Advisor Warning: The following columns were not accessed: id")); + Assert.That(listener.Strings[10], Does.Contain("Resultset Closed. Total rows=2, skipped rows=1, size (bytes)=16")); + Assert.That(listener.Strings[11], Does.Contain("Query Closed")); } [Test] @@ -104,24 +105,24 @@ public void NotReadingEveryRow() { reader.Read(); reader.Read(); - Assert.True(reader.NextResult()); + Assert.That(reader.NextResult(), Is.True); reader.Read(); reader.Read(); - Assert.False(reader.NextResult()); + Assert.That(reader.NextResult(), Is.False); } - Assert.AreEqual(11, listener.Strings.Count); - StringAssert.Contains("Query Opened: SELECT * FROM Test; SELECT * FROM Test WHERE id > 2", listener.Strings[0]); - StringAssert.Contains("Resultset Opened: field(s) = 2, affected rows = -1, inserted id = -1", listener.Strings[1]); - StringAssert.Contains("Usage Advisor Warning: Query does not use an index", listener.Strings[2]); - StringAssert.Contains("Usage Advisor Warning: Skipped 2 rows. Consider a more focused query.", listener.Strings[3]); - StringAssert.Contains("Usage Advisor Warning: The following columns were not accessed: id,name", listener.Strings[4]); - StringAssert.Contains("Resultset Closed. Total rows=4, skipped rows=2, size (bytes)=32", listener.Strings[5]); - StringAssert.Contains("Resultset Opened: field(s) = 2, affected rows = -1, inserted id = -1", listener.Strings[6]); - StringAssert.Contains("Usage Advisor Warning: Query does not use an index", listener.Strings[7]); - StringAssert.Contains("Usage Advisor Warning: The following columns were not accessed: id,name", listener.Strings[8]); - StringAssert.Contains("Resultset Closed. Total rows=2, skipped rows=0, size (bytes)=16", listener.Strings[9]); - StringAssert.Contains("Query Closed", listener.Strings[10]); + Assert.That(listener.Strings, Has.Count.EqualTo(11)); + Assert.That(listener.Strings[0], Does.Contain("Query Opened: SELECT * FROM Test; SELECT * FROM Test WHERE id > 2")); + Assert.That(listener.Strings[1], Does.Contain("Resultset Opened: field(s) = 2, affected rows = -1, inserted id = -1")); + Assert.That(listener.Strings[2], Does.Contain("Usage Advisor Warning: Query does not use an index")); + Assert.That(listener.Strings[3], Does.Contain("Usage Advisor Warning: Skipped 2 rows. Consider a more focused query")); + Assert.That(listener.Strings[4], Does.Contain("Usage Advisor Warning: The following columns were not accessed: id,name")); + Assert.That(listener.Strings[5], Does.Contain("Resultset Closed. Total rows=4, skipped rows=2, size (bytes)=32")); + Assert.That(listener.Strings[6], Does.Contain("Resultset Opened: field(s) = 2, affected rows = -1, inserted id = -1")); + Assert.That(listener.Strings[7], Does.Contain("Usage Advisor Warning: Query does not use an index")); + Assert.That(listener.Strings[8], Does.Contain("Usage Advisor Warning: The following columns were not accessed: id,name")); + Assert.That(listener.Strings[9], Does.Contain("Resultset Closed. Total rows=2, skipped rows=0, size (bytes)=16")); + Assert.That(listener.Strings[10], Does.Contain("Query Closed")); } [Test] @@ -144,13 +145,13 @@ public void FieldConversion() string str = reader.GetString(1); } - Assert.AreEqual(6, listener.Strings.Count); - StringAssert.Contains("Query Opened: SELECT * FROM Test", listener.Strings[0]); - StringAssert.Contains("Resultset Opened: field(s) = 2, affected rows = -1, inserted id = -1", listener.Strings[1]); - StringAssert.Contains("Usage Advisor Warning: Query does not use an index", listener.Strings[2]); - StringAssert.Contains("Usage Advisor Warning: The field 'id' was converted to the following types: Int16,Int64", listener.Strings[3]); - StringAssert.Contains("Resultset Closed. Total rows=1, skipped rows=0, size (bytes)=8", listener.Strings[4]); - StringAssert.Contains("Query Closed", listener.Strings[5]); + Assert.That(listener.Strings.Count, Is.EqualTo(6)); + Assert.That(listener.Strings[0], Does.Contain("Query Opened: SELECT * FROM Test")); + Assert.That(listener.Strings[1], Does.Contain("Resultset Opened: field(s) = 2, affected rows = -1, inserted id = -1")); + Assert.That(listener.Strings[2], Does.Contain("Usage Advisor Warning: Query does not use an index")); + Assert.That(listener.Strings[3], Does.Contain("Usage Advisor Warning: The field 'id' was converted to the following types: Int16,Int64")); + Assert.That(listener.Strings[4], Does.Contain("Resultset Closed. Total rows=1, skipped rows=0, size (bytes)=8")); + Assert.That(listener.Strings[5], Does.Contain("Query Closed")); } [Test] @@ -173,13 +174,13 @@ public void NoIndexUsed() reader.Read(); } - Assert.AreEqual(6, listener.Strings.Count); - StringAssert.Contains("Query Opened: SELECT name FROM Test WHERE id=3", listener.Strings[0]); - StringAssert.Contains("Resultset Opened: field(s) = 1, affected rows = -1, inserted id = -1", listener.Strings[1]); - StringAssert.Contains("Usage Advisor Warning: Query does not use an index", listener.Strings[2]); - StringAssert.Contains("Usage Advisor Warning: The following columns were not accessed: name", listener.Strings[3]); - StringAssert.Contains("Resultset Closed. Total rows=1, skipped rows=0, size (bytes)=6", listener.Strings[4]); - StringAssert.Contains("Query Closed", listener.Strings[5]); + Assert.That(listener.Strings.Count, Is.EqualTo(6)); + Assert.That(listener.Strings[0], Does.Contain("Query Opened: SELECT name FROM Test WHERE id=3")); + Assert.That(listener.Strings[1], Does.Contain("Resultset Opened: field(s) = 1, affected rows = -1, inserted id = -1")); + Assert.That(listener.Strings[2], Does.Contain("Usage Advisor Warning: Query does not use an index")); + Assert.That(listener.Strings[3], Does.Contain("Usage Advisor Warning: The following columns were not accessed: name")); + Assert.That(listener.Strings[4], Does.Contain("Resultset Closed. Total rows=1, skipped rows=0, size (bytes)=6")); + Assert.That(listener.Strings[5], Does.Contain("Query Closed")); } [Test] @@ -202,13 +203,13 @@ public void BadIndexUsed() reader.Read(); } - Assert.AreEqual(6, listener.Strings.Count); - StringAssert.Contains("Query Opened: SELECT name FROM Test WHERE id=3", listener.Strings[0]); - StringAssert.Contains("Resultset Opened: field(s) = 1, affected rows = -1, inserted id = -1", listener.Strings[1]); - StringAssert.Contains("Usage Advisor Warning: Query does not use an index", listener.Strings[2]); - StringAssert.Contains("Usage Advisor Warning: The following columns were not accessed: name", listener.Strings[3]); - StringAssert.Contains("Resultset Closed. Total rows=1, skipped rows=0, size (bytes)=6", listener.Strings[4]); - StringAssert.Contains("Query Closed", listener.Strings[5]); + Assert.That(listener.Strings.Count, Is.EqualTo(6)); + Assert.That(listener.Strings[0], Does.Contain("Query Opened: SELECT name FROM Test WHERE id=3")); + Assert.That(listener.Strings[1], Does.Contain("Resultset Opened: field(s) = 1, affected rows = -1, inserted id = -1")); + Assert.That(listener.Strings[2], Does.Contain("Usage Advisor Warning: Query does not use an index")); + Assert.That(listener.Strings[3], Does.Contain("Usage Advisor Warning: The following columns were not accessed: name")); + Assert.That(listener.Strings[4], Does.Contain("Resultset Closed. Total rows=1, skipped rows=0, size (bytes)=6")); + Assert.That(listener.Strings[5], Does.Contain("Query Closed")); } } -} \ No newline at end of file +} diff --git a/MySQL.Data/tests/MySql.Data.Tests/GenericListener.cs b/MySQL.Data/tests/MySql.Data.Tests/GenericListener.cs index 52ac0bbbd..46fb9a42d 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/GenericListener.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/GenericListener.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/tests/MySql.Data.Tests/LoggingTests.cs b/MySQL.Data/tests/MySql.Data.Tests/LoggingTests.cs index 47c826a02..691199865 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/LoggingTests.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/LoggingTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -29,6 +29,7 @@ using System; using System.Text; using NUnit.Framework; +using NUnit.Framework.Legacy; using System.Diagnostics; namespace MySql.Data.MySqlClient.Tests @@ -66,11 +67,11 @@ public void SimpleLogging() } } //Assert.AreEqual(4, listener.Strings.Count); - Assert.AreEqual(27, listener.Strings.Count); - StringAssert.Contains("Query Opened: SELECT * FROM Test", listener.Strings[listener.Strings.Count - 5]); - StringAssert.Contains("Resultset Opened: field(s) = 2, affected rows = -1, inserted id = -1", listener.Strings[listener.Strings.Count - 4]); - StringAssert.Contains("Resultset Closed. Total rows=4, skipped rows=4, size (bytes)=32", listener.Strings[listener.Strings.Count - 3]); - StringAssert.Contains("Query Closed", listener.Strings[listener.Strings.Count - 2]); + Assert.That(listener.Strings.Count, Is.EqualTo(27)); + Assert.That(listener.Strings[listener.Strings.Count - 5], Does.Contain("Query Opened: SELECT * FROM Test")); + Assert.That(listener.Strings[listener.Strings.Count - 4], Does.Contain("Resultset Opened: field(s) = 2, affected rows = -1, inserted id = -1")); + Assert.That(listener.Strings[listener.Strings.Count - 3], Does.Contain("Resultset Closed. Total rows=4, skipped rows=4, size (bytes)=32")); + Assert.That(listener.Strings[listener.Strings.Count - 2], Does.Contain("Query Closed")); } [Test] @@ -90,16 +91,16 @@ public void Warnings() cmd.ExecuteNonQuery(); } - Assert.AreEqual(32, listener.Strings.Count); - StringAssert.Contains("Query Opened: INSERT IGNORE INTO Test VALUES (1, 'abcdef')", listener.Strings[listener.Strings.Count - 10]); - StringAssert.Contains("Resultset Opened: field(s) = 0, affected rows = 1, inserted id = 0", listener.Strings[listener.Strings.Count - 9]); - StringAssert.Contains("Resultset Closed. Total rows=0, skipped rows=0, size (bytes)=0", listener.Strings[listener.Strings.Count - 8]); - StringAssert.Contains("Query Opened: SHOW WARNINGS", listener.Strings[listener.Strings.Count - 7]); - StringAssert.Contains("Resultset Opened: field(s) = 3, affected rows = -1, inserted id = -1", listener.Strings[listener.Strings.Count - 6]); - StringAssert.Contains("Resultset Closed. Total rows=1, skipped rows=0, size (bytes)=55", listener.Strings[listener.Strings.Count - 5]); - StringAssert.Contains("Query Closed", listener.Strings[listener.Strings.Count - 4]); - StringAssert.Contains("MySql Warning: Level=Warning, Code=1265, Message=Data truncated for column 'name' at row 1", listener.Strings[listener.Strings.Count - 3]); - StringAssert.Contains("Query Closed", listener.Strings[listener.Strings.Count - 2]); + Assert.That(listener.Strings.Count, Is.EqualTo(32)); + Assert.That(listener.Strings[listener.Strings.Count - 10], Does.Contain("Query Opened: INSERT IGNORE INTO Test VALUES (1, 'abcdef')")); + Assert.That(listener.Strings[listener.Strings.Count - 9], Does.Contain("Resultset Opened: field(s) = 0, affected rows = 1, inserted id = 0")); + Assert.That(listener.Strings[listener.Strings.Count - 8], Does.Contain("Resultset Closed. Total rows=0, skipped rows=0, size (bytes)=0")); + Assert.That(listener.Strings[listener.Strings.Count - 7], Does.Contain("Query Opened: SHOW WARNINGS")); + Assert.That(listener.Strings[listener.Strings.Count - 6], Does.Contain("Resultset Opened: field(s) = 3, affected rows = -1, inserted id = -1")); + Assert.That(listener.Strings[listener.Strings.Count - 5], Does.Contain("Resultset Closed. Total rows=1, skipped rows=0, size (bytes)=55")); + Assert.That(listener.Strings[listener.Strings.Count - 4], Does.Contain("Query Closed")); + Assert.That(listener.Strings[listener.Strings.Count - 3], Does.Contain("MySql Warning: Level=Warning, Code=1265, Message=Data truncated for column 'name' at row 1")); + Assert.That(listener.Strings[listener.Strings.Count - 2], Does.Contain("Query Closed")); } [Test] @@ -120,10 +121,10 @@ public void ProviderNormalizingQuery() logConn.Open(); MySqlCommand cmd = new MySqlCommand(sql.ToString(), logConn); cmd.ExecuteNonQuery(); - } + } - Assert.AreEqual(28, listener.Strings.Count); - StringAssert.EndsWith("SELECT ?", listener.Strings[listener.Strings.Count - 5]); + Assert.That(listener.Strings.Count, Is.EqualTo(28)); + Assert.That(listener.Strings[listener.Strings.Count - 5], Does.EndWith("SELECT ?")); } /// @@ -151,4 +152,4 @@ public void QuotedTokenAt300() } } } -} \ No newline at end of file +} diff --git a/MySQL.Data/tests/MySql.Data.Tests/MockServer.cs b/MySQL.Data/tests/MySql.Data.Tests/MockServer.cs new file mode 100644 index 000000000..991052127 --- /dev/null +++ b/MySQL.Data/tests/MySql.Data.Tests/MockServer.cs @@ -0,0 +1,138 @@ +// Copyright © 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using System; +using System.Net; +using System.Net.Sockets; +using System.Threading; +using System.Threading.Tasks; + +namespace MySql.Data.Tests +{ + public class MockServer + { + private TcpListener listener; + + private int _port; + + private IPAddress _address; + + private ManualResetEvent _stopserver = new ManualResetEvent(false); + + private CancellationTokenSource cts; + + private bool _usetimeout; + + public int Port + { + get => _port; + set => _port = value; + } + + public IPAddress Address + { + get => _address; + set => _address = value; + } + + public MockServer(bool usetimeout) + { + GetMockServerInfo(); + _stopserver.Reset(); + _usetimeout = usetimeout; + cts = new CancellationTokenSource(TimeSpan.FromSeconds(12)); + } + + public void GetMockServerInfo() + { + TcpListener loopback = new TcpListener(IPAddress.Loopback, 0); + loopback.Start(); + _port = ((IPEndPoint)loopback.LocalEndpoint).Port; + loopback.Stop(); + _address = Dns.GetHostEntry("localhost").AddressList[0]; + } + + public void StopServer() + { + _stopserver.Set(); + } + public void DisposeListener() + { + if (listener != null) + { + listener.Stop(); + } + } + + public async Task ServerWorker(CancellationToken ct) + { + await Task.Run(() => + { + IPEndPoint endpoint = new IPEndPoint(IPAddress.Loopback, Port); + listener = new(endpoint); + + try + { + listener.Start(); + while (!_stopserver.WaitOne(1)) + { + listener.BeginAcceptSocket(new AsyncCallback(beginConnection), null); + } + } + catch (Exception) + { + } + finally + { + listener.Stop(); + } + }, ct).ConfigureAwait(false); + } + + public void StartServer() + { + ServerWorker(cts.Token).ConfigureAwait(false); + } + + private void beginConnection(IAsyncResult iar) + { + try + { + Socket client = listener.EndAcceptSocket(iar); + if (_usetimeout) + { + Task.Delay(500).Wait(); + client.Close(); + } + } + catch (Exception) + { + } + } + } +} \ No newline at end of file diff --git a/MySQL.Data/tests/MySql.Data.Tests/MySql.Data.Tests.csproj b/MySQL.Data/tests/MySql.Data.Tests/MySql.Data.Tests.csproj index 2b21049c2..4ec3a5c15 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/MySql.Data.Tests.csproj +++ b/MySQL.Data/tests/MySql.Data.Tests/MySql.Data.Tests.csproj @@ -3,17 +3,17 @@ MySql.Data.Tests MySql.Data.Tests Class Library - Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. - 8.2.0 + Copyright © 2016, 2025, Oracle and/or its affiliates. + 9.4.0 Oracle Oracle MySql.Data.Tests - net8.0;net7.0;net6.0;net462;net48; + net9.0;net8.0; MySql.Data.Tests MySql;.NET Connector;MySql Connector/NET;netcore;.Net Core;MySql Conector/Net Core;coreclr;C/NET;C/Net Core http://www.mysql.com/common/logos/logo-mysql-170x115.png http://dev.mysql.com/downloads/ - GPL-2.0-only + GPL-2.0-only WITH Universal-FOSS-exception-1.0 true false false @@ -28,7 +28,15 @@ CS1591,CS1587,CS1701,CS1702,CS1570,CA2100 - + + $(TargetFrameworks);net10.0 + + + + net462;net48;$(TargetFrameworks) + + + @@ -60,10 +68,9 @@ - - - - + + + diff --git a/MySQL.Data/tests/MySql.Data.Tests/MySqlBulkLoaderTests.cs b/MySQL.Data/tests/MySql.Data.Tests/MySqlBulkLoaderTests.cs index db2a09040..4eace9b66 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/MySqlBulkLoaderTests.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/MySqlBulkLoaderTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2022, Oracle and/or its affiliates. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -27,6 +27,7 @@ // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA using NUnit.Framework; +using NUnit.Framework.Legacy; using System; using System.Data; using System.IO; @@ -71,11 +72,11 @@ public void BulkLoadSimple() loader.Timeout = 0; loader.Local = true; int count = loader.Load(); - Assert.AreEqual(200, count); + Assert.That(count, Is.EqualTo(200)); DataTable dt = Utils.FillTable("SELECT * FROM Test", Connection); - Assert.AreEqual(200, dt.Rows.Count); - Assert.AreEqual("'Test'", dt.Rows[0][1].ToString().Trim()); + Assert.That(dt.Rows.Count, Is.EqualTo(200)); + Assert.That(dt.Rows[0][1].ToString().Trim(), Is.EqualTo("'Test'")); } [Test] @@ -102,11 +103,11 @@ public void BulkLoadReadOnlyFile() loader.Timeout = 0; loader.Local = true; int count = loader.Load(); - Assert.AreEqual(200, count); + Assert.That(count, Is.EqualTo(200)); DataTable dt = Utils.FillTable("SELECT * FROM Test", Connection); - Assert.AreEqual(200, dt.Rows.Count); - Assert.AreEqual("'Test'", dt.Rows[0][1].ToString().Trim()); + Assert.That(dt.Rows.Count, Is.EqualTo(200)); + Assert.That(dt.Rows[0][1].ToString().Trim(), Is.EqualTo("'Test'")); } finally { @@ -136,10 +137,10 @@ public void BulkLoadSimple2() loader.LineTerminator = "xxx"; loader.Local = true; int count = loader.Load(); - Assert.AreEqual(200, count); + Assert.That(count, Is.EqualTo(200)); MySqlCommand cmd = new MySqlCommand("SELECT COUNT(*) FROM Test", Connection); - Assert.AreEqual(200, Convert.ToInt32(cmd.ExecuteScalar())); + Assert.That(Convert.ToInt32(cmd.ExecuteScalar()), Is.EqualTo(200)); } [Test] @@ -164,10 +165,10 @@ public void BulkLoadSimple3() loader.NumberOfLinesToSkip = 50; loader.Local = true; int count = loader.Load(); - Assert.AreEqual(150, count); + Assert.That(count, Is.EqualTo(150)); MySqlCommand cmd = new MySqlCommand("SELECT COUNT(*) FROM Test", Connection); - Assert.AreEqual(150, Convert.ToInt32(cmd.ExecuteScalar())); + Assert.That(Convert.ToInt32(cmd.ExecuteScalar()), Is.EqualTo(150)); } [Test] @@ -198,10 +199,10 @@ public void BulkLoadSimple4() loader.LinePrefix = "bbb"; loader.Local = true; int count = loader.Load(); - Assert.AreEqual(200, count); + Assert.That(count, Is.EqualTo(200)); MySqlCommand cmd = new MySqlCommand("SELECT COUNT(*) FROM Test", Connection); - Assert.AreEqual(200, Convert.ToInt32(cmd.ExecuteScalar())); + Assert.That(Convert.ToInt32(cmd.ExecuteScalar()), Is.EqualTo(200)); } [Test] @@ -225,12 +226,12 @@ public void BulkLoadFieldQuoting() loader.FieldQuotationOptional = true; loader.Local = true; int count = loader.Load(); - Assert.AreEqual(200, count); + Assert.That(count, Is.EqualTo(200)); DataTable dt = Utils.FillTable("SELECT * FROM Test", Connection); - Assert.AreEqual(200, dt.Rows.Count); - Assert.AreEqual("col1", dt.Rows[0][1]); - Assert.AreEqual("col2", dt.Rows[0][2].ToString().Trim()); + Assert.That(dt.Rows.Count, Is.EqualTo(200)); + Assert.That(dt.Rows[0][1], Is.EqualTo("col1")); + Assert.That(dt.Rows[0][2].ToString().Trim(), Is.EqualTo("col2")); } [Test] @@ -254,12 +255,12 @@ public void BulkLoadEscaping() loader.FieldTerminator = ","; loader.Local = true; int count = loader.Load(); - Assert.AreEqual(200, count); + Assert.That(count, Is.EqualTo(200)); DataTable dt = Utils.FillTable("SELECT * FROM Test", Connection); - Assert.AreEqual(200, dt.Rows.Count); - Assert.AreEqual("col1still col1", dt.Rows[0][1]); - Assert.AreEqual("col2", dt.Rows[0][2].ToString().Trim()); + Assert.That(dt.Rows.Count, Is.EqualTo(200)); + Assert.That(dt.Rows[0][1], Is.EqualTo("col1still col1")); + Assert.That(dt.Rows[0][2].ToString().Trim(), Is.EqualTo("col2")); } [Test] @@ -282,7 +283,7 @@ public void BulkLoadConflictOptionReplace() loader.FieldTerminator = ","; loader.Local = true; int count = loader.Load(); - Assert.AreEqual(20, count); + Assert.That(count, Is.EqualTo(20)); path = Path.GetTempFileName(); sw = new StreamWriter(new FileStream(path, FileMode.Create)); @@ -301,8 +302,8 @@ public void BulkLoadConflictOptionReplace() loader.Load(); DataTable dt = Utils.FillTable("SELECT * FROM Test", Connection); - Assert.AreEqual(20, dt.Rows.Count); - Assert.AreEqual("col2", dt.Rows[0][1].ToString().Trim()); + Assert.That(dt.Rows.Count, Is.EqualTo(20)); + Assert.That(dt.Rows[0][1].ToString().Trim(), Is.EqualTo("col2")); } [Test] @@ -325,7 +326,7 @@ public void BulkLoadConflictOptionIgnore() loader.FieldTerminator = ","; loader.Local = true; int count = loader.Load(); - Assert.AreEqual(20, count); + Assert.That(count, Is.EqualTo(20)); path = Path.GetTempFileName(); sw = new StreamWriter(new FileStream(path, FileMode.Create)); @@ -344,8 +345,8 @@ public void BulkLoadConflictOptionIgnore() loader.Load(); DataTable dt = Utils.FillTable("SELECT * FROM Test", Connection); - Assert.AreEqual(20, dt.Rows.Count); - Assert.AreEqual("col1", dt.Rows[0][1].ToString().Trim()); + Assert.That(dt.Rows.Count, Is.EqualTo(20)); + Assert.That(dt.Rows[0][1].ToString().Trim(), Is.EqualTo("col1")); } #region AsyncTests @@ -372,8 +373,8 @@ public void BulkLoadSimpleAsync() int dataLoaded = loadResult.Result; DataTable dt = Utils.FillTable("SELECT * FROM BulkLoadSimpleAsyncTest", Connection); - Assert.AreEqual(dataLoaded, dt.Rows.Count); - Assert.AreEqual("'Test'", dt.Rows[0][1].ToString().Trim()); + Assert.That(dt.Rows.Count, Is.EqualTo(dataLoaded)); + Assert.That(dt.Rows[0][1].ToString().Trim(), Is.EqualTo("'Test'")); }).Wait(); } @@ -405,8 +406,8 @@ public void BulkLoadReadOnlyFileAsync() int dataLoaded = loadResult.Result; DataTable dt = Utils.FillTable("SELECT * FROM BulkLoadReadOnlyFileAsyncTest", Connection); - Assert.AreEqual(dataLoaded, dt.Rows.Count); - Assert.AreEqual("'Test'", dt.Rows[0][1].ToString().Trim()); + Assert.That(dt.Rows.Count, Is.EqualTo(dataLoaded)); + Assert.That(dt.Rows[0][1].ToString().Trim(), Is.EqualTo("'Test'")); }).Wait(); } finally @@ -441,9 +442,9 @@ public void BulkLoadFieldQuotingAsync() int dataLoaded = loadResult.Result; DataTable dt = Utils.FillTable("SELECT * FROM BulkLoadFieldQuotingAsyncTest", Connection); - Assert.AreEqual(dataLoaded, dt.Rows.Count); - Assert.AreEqual("col1", dt.Rows[0][1]); - Assert.AreEqual("col2", dt.Rows[0][2].ToString().Trim()); + Assert.That(dt.Rows.Count, Is.EqualTo(dataLoaded)); + Assert.That(dt.Rows[0][1], Is.EqualTo("col1")); + Assert.That(dt.Rows[0][2].ToString().Trim(), Is.EqualTo("col2")); }).Wait(); } @@ -472,9 +473,9 @@ public void BulkLoadEscapingAsync() int dataLoaded = loadResult.Result; DataTable dt = Utils.FillTable("SELECT * FROM BulkLoadEscapingAsyncTest", Connection); - Assert.AreEqual(dataLoaded, dt.Rows.Count); - Assert.AreEqual("col1still col1", dt.Rows[0][1]); - Assert.AreEqual("col2", dt.Rows[0][2].ToString().Trim()); + Assert.That(dt.Rows.Count, Is.EqualTo(dataLoaded)); + Assert.That(dt.Rows[0][1], Is.EqualTo("col1still col1")); + Assert.That(dt.Rows[0][2].ToString().Trim(), Is.EqualTo("col2")); }).Wait(); } @@ -516,8 +517,8 @@ public void BulkLoadConflictOptionReplaceAsync() loader.LoadAsync().Wait(); DataTable dt = Utils.FillTable("SELECT * FROM BulkLoadConflictOptionReplaceAsyncTest", Connection); - Assert.AreEqual(20, dt.Rows.Count); - Assert.AreEqual("col2", dt.Rows[0][1].ToString().Trim()); + Assert.That(dt.Rows.Count, Is.EqualTo(20)); + Assert.That(dt.Rows[0][1].ToString().Trim(), Is.EqualTo("col2")); } [Test] @@ -562,8 +563,8 @@ public void BulkLoadConflictOptionIgnoreAsync() { int dataLoaded = loadResult.Result; DataTable dt = Utils.FillTable("SELECT * FROM BulkLoadConflictOptionIgnoreAsyncTest", Connection); - Assert.AreEqual(20, dt.Rows.Count); - Assert.AreEqual("col1", dt.Rows[0][1].ToString().Trim()); + Assert.That(dt.Rows.Count, Is.EqualTo(20)); + Assert.That(dt.Rows[0][1].ToString().Trim(), Is.EqualTo("col1")); }).Wait(); } @@ -595,10 +596,10 @@ public void BulkLoadColumnOrderAsync() { int dataLoaded = loadResult.Result; DataTable dt = Utils.FillTable("SELECT * FROM BulkLoadColumnOrderAsyncTest", Connection); - Assert.AreEqual(20, dt.Rows.Count); - Assert.AreEqual("col1", dt.Rows[0][1]); - Assert.AreEqual("col2", dt.Rows[0][2]); - Assert.AreEqual("col3", dt.Rows[0][3].ToString().Trim()); + Assert.That(dt.Rows.Count, Is.EqualTo(20)); + Assert.That(dt.Rows[0][1], Is.EqualTo("col1")); + Assert.That(dt.Rows[0][2], Is.EqualTo("col2")); + Assert.That(dt.Rows[0][3].ToString().Trim(), Is.EqualTo("col3")); }).Wait(); } #endregion @@ -635,13 +636,13 @@ public void BulkLoadColumnOrder() loader.Columns.Add("n1"); loader.Local = true; int count = loader.Load(); - Assert.AreEqual(20, count); + Assert.That(count, Is.EqualTo(20)); DataTable dt = Utils.FillTable("SELECT * FROM Test", Connection); - Assert.AreEqual(20, dt.Rows.Count); - Assert.AreEqual("col1", dt.Rows[0][1]); - Assert.AreEqual("col2", dt.Rows[0][2]); - Assert.AreEqual("col3", dt.Rows[0][3].ToString().Trim()); + Assert.That(dt.Rows.Count, Is.EqualTo(20)); + Assert.That(dt.Rows[0][1], Is.EqualTo("col1")); + Assert.That(dt.Rows[0][2], Is.EqualTo("col2")); + Assert.That(dt.Rows[0][3].ToString().Trim(), Is.EqualTo("col3")); } /// @@ -702,11 +703,11 @@ public void BulkLoadUsingSafePath(bool allowLoadLocalInfile, string allowLoadLoc if (shouldPass) { int count = loader.Load(); - Assert.AreEqual(200, count); + Assert.That(count, Is.EqualTo(200)); DataTable dt = Utils.FillTable("SELECT * FROM Test", Connection); - Assert.AreEqual(200, dt.Rows.Count); - Assert.AreEqual("'Test'", dt.Rows[0][1].ToString().Trim()); + Assert.That(dt.Rows.Count, Is.EqualTo(200)); + Assert.That(dt.Rows[0][1].ToString().Trim(), Is.EqualTo("'Test'")); } else if (isSymLink && !Directory.Exists(allowLoadLocalInfileInPath)) Assert.Ignore("For the symbolic link test to run, it should be manually created before executing it."); @@ -715,11 +716,11 @@ public void BulkLoadUsingSafePath(bool allowLoadLocalInfile, string allowLoadLoc var ex = Assert.Throws(() => loader.Load()); if (allowLoadLocalInfileInPath == " " || allowLoadLocalInfileInPath is null) if (Version > new Version(8, 0)) - Assert.AreEqual("Loading local data is disabled; this must be enabled on both the client and server sides", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Loading local data is disabled; this must be enabled on both the client and server sides")); else - Assert.AreEqual("The used command is not allowed with this MySQL version", ex.Message); + Assert.That(ex.Message, Is.EqualTo("The used command is not allowed with this MySQL version")); else - StringAssert.Contains("allowloadlocalinfileinpath", ex.Message); + Assert.That(ex.Message, Does.Contain("allowloadlocalinfileinpath")); } File.Delete(path); @@ -754,10 +755,10 @@ public void InsertFilesInDatabase() cmd.Parameters.AddWithValue("@FileSize", fileSize); cmd.Parameters.AddWithValue("@File", rawData); var result = cmd.ExecuteNonQuery(); - Assert.IsNotNull(result); + Assert.That(result, Is.Not.Null); cmd.CommandText = "select count(*) from file;"; var count = cmd.ExecuteScalar(); - Assert.AreEqual(1, count); + Assert.That(count, Is.EqualTo(1)); } } @@ -782,11 +783,11 @@ public void BulkLoadStream() loader.Timeout = 0; loader.Local = true; int count = loader.Load(stream); - Assert.AreEqual(200, count); + Assert.That(count, Is.EqualTo(200)); DataTable dt = Utils.FillTable("SELECT * FROM Test", Connection); - Assert.AreEqual(200, dt.Rows.Count); - Assert.AreEqual("'Test'", dt.Rows[0][1].ToString().Trim()); + Assert.That(dt.Rows.Count, Is.EqualTo(200)); + Assert.That(dt.Rows[0][1].ToString().Trim(), Is.EqualTo("'Test'")); } [Test] @@ -816,10 +817,10 @@ public void BulkLoadStream2() loader.LinePrefix = "bbb"; loader.Local = true; int count = loader.Load(stream); - Assert.AreEqual(200, count); + Assert.That(count, Is.EqualTo(200)); using MySqlCommand cmd = new MySqlCommand("SELECT COUNT(*) FROM Test", Connection); - Assert.AreEqual(200, Convert.ToInt32(cmd.ExecuteScalar())); + Assert.That(Convert.ToInt32(cmd.ExecuteScalar()), Is.EqualTo(200)); } [Test] @@ -846,13 +847,13 @@ public void BulkLoadStreamColumnOrder() loader.Columns.Add("n1"); loader.Local = true; int count = loader.Load(stream); - Assert.AreEqual(20, count); + Assert.That(count, Is.EqualTo(20)); DataTable dt = Utils.FillTable("SELECT * FROM Test", Connection); - Assert.AreEqual(20, dt.Rows.Count); - Assert.AreEqual("col1", dt.Rows[0][1]); - Assert.AreEqual("col2", dt.Rows[0][2]); - Assert.AreEqual("col3", dt.Rows[0][3].ToString().Trim()); + Assert.That(dt.Rows.Count, Is.EqualTo(20)); + Assert.That(dt.Rows[0][1], Is.EqualTo("col1")); + Assert.That(dt.Rows[0][2], Is.EqualTo("col2")); + Assert.That(dt.Rows[0][3].ToString().Trim(), Is.EqualTo("col3")); } } -} \ No newline at end of file +} diff --git a/MySQL.Data/tests/MySql.Data.Tests/MySqlDataReaderTests.cs b/MySQL.Data/tests/MySql.Data.Tests/MySqlDataReaderTests.cs index 96a7fb9df..ec1ca03ed 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/MySqlDataReaderTests.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/MySqlDataReaderTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -28,6 +28,7 @@ using MySql.Data.Common; using NUnit.Framework; +using NUnit.Framework.Legacy; using System; using System.Data; using System.Data.SqlTypes; @@ -67,25 +68,25 @@ public void TestMultipleResultsets() cmd = new MySqlCommand("SELECT id FROM Test WHERE id<50; SELECT * FROM Test WHERE id >= 50;", Connection); using (MySqlDataReader reader = cmd.ExecuteReader()) { - Assert.NotNull(reader); - Assert.True(reader.HasRows); - Assert.True(reader.Read()); - Assert.AreEqual(1, reader.FieldCount); - Assert.True(reader.NextResult()); - Assert.True(reader.HasRows); - Assert.AreEqual(5, reader.FieldCount); + Assert.That(reader, Is.Not.Null); + Assert.That(reader.HasRows); + Assert.That(reader.Read()); + Assert.That(reader.FieldCount, Is.EqualTo(1)); + Assert.That(reader.NextResult()); + Assert.That(reader.HasRows); + Assert.That(reader.FieldCount, Is.EqualTo(5)); } // now do it again using (MySqlDataReader reader = cmd.ExecuteReader()) { - Assert.NotNull(reader); - Assert.True(reader.HasRows); - Assert.True(reader.Read()); - Assert.AreEqual(1, reader.FieldCount); - Assert.True(reader.NextResult()); - Assert.True(reader.HasRows); - Assert.AreEqual(5, reader.FieldCount); + Assert.That(reader, Is.Not.Null); + Assert.That(reader.HasRows); + Assert.That(reader.Read()); + Assert.That(reader.FieldCount, Is.EqualTo(1)); + Assert.That(reader.NextResult()); + Assert.That(reader.HasRows); + Assert.That(reader.FieldCount, Is.EqualTo(5)); } } @@ -106,26 +107,26 @@ public void GetBytes() reader.Read(); long sizeBytes = reader.GetBytes(4, 0, null, 0, 0); - Assert.AreEqual(len, sizeBytes); + Assert.That(sizeBytes, Is.EqualTo(len)); byte[] buff1 = new byte[len / 2]; byte[] buff2 = new byte[len - (len / 2)]; long buff1cnt = reader.GetBytes(4, 0, buff1, 0, len / 2); long buff2cnt = reader.GetBytes(4, buff1cnt, buff2, 0, buff2.Length); - Assert.AreEqual(buff1.Length, buff1cnt); - Assert.AreEqual(buff2.Length, buff2cnt); + Assert.That(buff1cnt, Is.EqualTo(buff1.Length)); + Assert.That(buff2cnt, Is.EqualTo(buff2.Length)); for (int i = 0; i < buff1.Length; i++) - Assert.AreEqual(bytes[i], buff1[i]); + Assert.That(buff1[i], Is.EqualTo(bytes[i])); for (int i = 0; i < buff2.Length; i++) - Assert.AreEqual(bytes[buff1.Length + i], buff2[i]); + Assert.That(buff2[i], Is.EqualTo(bytes[buff1.Length + i])); } // now check with sequential access using (MySqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess)) { - Assert.True(reader.Read()); + Assert.That(reader.Read()); int mylen = len; byte[] buff = new byte[8192]; int startIndex = 0; @@ -133,9 +134,9 @@ public void GetBytes() { int readLen = Math.Min(mylen, buff.Length); int retVal = (int)reader.GetBytes(4, startIndex, buff, 0, readLen); - Assert.AreEqual(readLen, retVal); + Assert.That(retVal, Is.EqualTo(readLen)); for (int i = 0; i < readLen; i++) - Assert.AreEqual(bytes[startIndex + i], buff[i]); + Assert.That(buff[i], Is.EqualTo(bytes[startIndex + i])); startIndex += readLen; mylen -= readLen; } @@ -154,10 +155,10 @@ public void TestSingleResultSetBehavior() using (MySqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SingleResult)) { bool result = reader.Read(); - Assert.True(result); + Assert.That(result); result = reader.NextResult(); - Assert.False(result); + Assert.That(result, Is.False); } } @@ -179,23 +180,23 @@ public void GetSchema() using (MySqlDataReader reader = cmd.ExecuteReader()) { DataTable dt = reader.GetSchemaTable(); - Assert.True(true == (Boolean)dt.Rows[0]["IsAutoIncrement"], "Checking auto increment"); - Assert.False((bool)dt.Rows[0]["IsUnique"], "Checking IsUnique"); - Assert.True((bool)dt.Rows[0]["IsKey"]); - Assert.True(false == (Boolean)dt.Rows[0]["AllowDBNull"], "Checking AllowDBNull"); - Assert.True(false == (Boolean)dt.Rows[1]["AllowDBNull"], "Checking AllowDBNull"); - Assert.AreEqual(255, dt.Rows[1]["ColumnSize"]); - Assert.AreEqual(40, dt.Rows[2]["ColumnSize"]); + Assert.That(true == (Boolean)dt.Rows[0]["IsAutoIncrement"], "Checking auto increment"); + Assert.That((bool)dt.Rows[0]["IsUnique"], Is.False, "Checking IsUnique"); + Assert.That((bool)dt.Rows[0]["IsKey"]); + Assert.That(false == (Boolean)dt.Rows[0]["AllowDBNull"], "Checking AllowDBNull"); + Assert.That(false == (Boolean)dt.Rows[1]["AllowDBNull"], "Checking AllowDBNull"); + Assert.That(dt.Rows[1]["ColumnSize"], Is.EqualTo(255)); + Assert.That(dt.Rows[2]["ColumnSize"], Is.EqualTo(40)); // udec column - Assert.AreEqual(21, dt.Rows[5]["ColumnSize"]); - Assert.AreEqual(20, dt.Rows[5]["NumericPrecision"]); - Assert.AreEqual(6, dt.Rows[5]["NumericScale"]); + Assert.That(dt.Rows[5]["ColumnSize"], Is.EqualTo(21)); + Assert.That(dt.Rows[5]["NumericPrecision"], Is.EqualTo(20)); + Assert.That(dt.Rows[5]["NumericScale"], Is.EqualTo(6)); // dec column - Assert.AreEqual(46, dt.Rows[6]["ColumnSize"]); - Assert.AreEqual(44, dt.Rows[6]["NumericPrecision"]); - Assert.AreEqual(3, dt.Rows[6]["NumericScale"]); + Assert.That(dt.Rows[6]["ColumnSize"], Is.EqualTo(46)); + Assert.That(dt.Rows[6]["NumericPrecision"], Is.EqualTo(44)); + Assert.That(dt.Rows[6]["NumericScale"], Is.EqualTo(3)); } } @@ -211,9 +212,9 @@ public void CloseConnectionBehavior() MySqlCommand cmd = new MySqlCommand("SELECT * FROM Test", c2); using (MySqlDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection)) { - Assert.True(reader.Read()); + Assert.That(reader.Read()); reader.Close(); - Assert.True(c2.State == ConnectionState.Closed); + Assert.That(c2.State == ConnectionState.Closed); } } } @@ -229,18 +230,18 @@ public void SingleRowBehavior() MySqlCommand cmd = new MySqlCommand("SELECT * FROM Test", Connection); using (MySqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SingleRow)) { - Assert.True(reader.Read(), "First read"); - Assert.False(reader.Read(), "Second read"); - Assert.False(reader.NextResult(), "Trying NextResult"); + Assert.That(reader.Read(), "First read"); + Assert.That(reader.Read(), Is.False, "Second read"); + Assert.That(reader.NextResult(), Is.False, "Trying NextResult"); } cmd.CommandText = "SELECT * FROM Test where id=1"; using (MySqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SingleRow)) { - Assert.True(reader.Read()); - Assert.AreEqual("test1", reader.GetString(1)); - Assert.False(reader.Read()); - Assert.False(reader.NextResult()); + Assert.That(reader.Read()); + Assert.That(reader.GetString(1), Is.EqualTo("test1")); + Assert.That(reader.Read(), Is.False); + Assert.That(reader.NextResult(), Is.False); } } @@ -255,23 +256,23 @@ public void SingleRowBehaviorWithLimit() MySqlCommand cmd = new MySqlCommand("SELECT * FROM Test LIMIT 2", Connection); using (MySqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SingleRow)) { - Assert.True(reader.Read(), "First read"); - Assert.False(reader.Read(), "Second read"); - Assert.False(reader.NextResult(), "Trying NextResult"); + Assert.That(reader.Read(), "First read"); + Assert.That(reader.Read(), Is.False, "Second read"); + Assert.That(reader.NextResult(), Is.False, "Trying NextResult"); } using (MySqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SingleRow)) { - Assert.True(reader.Read(), "First read"); - Assert.False(reader.Read(), "Second read"); - Assert.False(reader.NextResult(), "Trying NextResult"); + Assert.That(reader.Read(), "First read"); + Assert.That(reader.Read(), Is.False, "Second read"); + Assert.That(reader.NextResult(), Is.False, "Trying NextResult"); } using (MySqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SingleRow)) { - Assert.True(reader.Read(), "First read"); - Assert.False(reader.Read(), "Second read"); - Assert.False(reader.NextResult(), "Trying NextResult"); + Assert.That(reader.Read(), "First read"); + Assert.That(reader.Read(), Is.False, "Second read"); + Assert.That(reader.NextResult(), Is.False, "Trying NextResult"); } } @@ -284,11 +285,11 @@ public void SimpleSingleRow() MySqlCommand cmd = new MySqlCommand("SELECT * FROM Test", Connection); using (MySqlDataReader reader = cmd.ExecuteReader()) { - Assert.True(reader.Read(), "First read"); - Assert.AreEqual(1, reader.GetInt32(0)); - Assert.AreEqual("test1", reader.GetString(1)); - Assert.False(reader.Read(), "Second read"); - Assert.False(reader.NextResult(), "Trying NextResult"); + Assert.That(reader.Read(), "First read"); + Assert.That(reader.GetInt32(0), Is.EqualTo(1)); + Assert.That(reader.GetString(1), Is.EqualTo("test1")); + Assert.That(reader.Read(), Is.False, "Second read"); + Assert.That(reader.NextResult(), Is.False, "Trying NextResult"); } } @@ -304,25 +305,25 @@ public void ConsecutiveNulls() using (MySqlDataReader reader = cmd.ExecuteReader()) { reader.Read(); - Assert.AreEqual(1, reader.GetValue(0)); - Assert.AreEqual("Test", reader.GetValue(1)); - Assert.AreEqual("Test", reader.GetString(1)); - Assert.AreEqual(DBNull.Value, reader.GetValue(2)); + Assert.That(reader.GetValue(0), Is.EqualTo(1)); + Assert.That(reader.GetValue(1), Is.EqualTo("Test")); + Assert.That(reader.GetString(1), Is.EqualTo("Test")); + Assert.That(reader.GetValue(2), Is.EqualTo(DBNull.Value)); reader.Read(); - Assert.AreEqual(2, reader.GetValue(0)); - Assert.AreEqual(DBNull.Value, reader.GetValue(1)); + Assert.That(reader.GetValue(0), Is.EqualTo(2)); + Assert.That(reader.GetValue(1), Is.EqualTo(DBNull.Value)); Exception ex = Assert.Throws(() => reader.GetString(1)); - Assert.AreEqual("Data is Null. This method or property cannot be called on Null values.", ex.Message); - Assert.False(reader.IsDBNull(2)); + Assert.That(ex.Message, Is.EqualTo("Data is Null. This method or property cannot be called on Null values.")); + Assert.That(reader.IsDBNull(2), Is.False); reader.Read(); - Assert.AreEqual(3, reader.GetValue(0)); - Assert.AreEqual("Test2", reader.GetValue(1)); - Assert.AreEqual("Test2", reader.GetString(1)); - Assert.AreEqual(DBNull.Value, reader.GetValue(2)); + Assert.That(reader.GetValue(0), Is.EqualTo(3)); + Assert.That(reader.GetValue(1), Is.EqualTo("Test2")); + Assert.That(reader.GetString(1), Is.EqualTo("Test2")); + Assert.That(reader.GetValue(2), Is.EqualTo(DBNull.Value)); ex = Assert.Throws(() => reader.GetMySqlDateTime(2)); - Assert.AreEqual("Data is Null. This method or property cannot be called on Null values.", ex.Message); - Assert.False(reader.Read()); - Assert.False(reader.NextResult()); + Assert.That(ex.Message, Is.EqualTo("Data is Null. This method or property cannot be called on Null values.")); + Assert.That(reader.Read(), Is.False); + Assert.That(reader.NextResult(), Is.False); } } @@ -351,16 +352,16 @@ public void SequentialAccessBehavior() MySqlCommand cmd = new MySqlCommand("SELECT * FROM Test", Connection); using (MySqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess)) { - Assert.True(reader.Read()); - Assert.False(reader.IsDBNull(0)); + Assert.That(reader.Read()); + Assert.That(reader.IsDBNull(0), Is.False); int i = reader.GetInt32(0); string s = reader.GetString(1); - Assert.AreEqual(1, i); - Assert.AreEqual("test1", s); + Assert.That(i, Is.EqualTo(1)); + Assert.That(s, Is.EqualTo("test1")); // this next line should throw an exception Exception ex = Assert.Throws(() => i = reader.GetInt32(0)); - Assert.AreEqual("Invalid attempt to read a prior column using SequentialAccess", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Invalid attempt to read a prior column using SequentialAccess")); } } @@ -376,7 +377,7 @@ public void ReadingTextFields() { reader.Read(); string s = reader["t1"].ToString(); - Assert.AreEqual("Text value", s); + Assert.That(s, Is.EqualTo("Text value")); } } @@ -407,7 +408,7 @@ public void GetChar() { reader.Read(); char achar = reader.GetChar(1); - Assert.AreEqual('a', achar); + Assert.That(achar, Is.EqualTo('a')); } } @@ -418,12 +419,12 @@ public void ReaderOnNonQuery() MySqlCommand cmd = new MySqlCommand("INSERT INTO Test (id,name) VALUES (1,'Test')", Connection); using (MySqlDataReader reader = cmd.ExecuteReader()) { - Assert.False(reader.Read()); + Assert.That(reader.Read(), Is.False); reader.Close(); cmd.CommandText = "SELECT name FROM Test"; object v = cmd.ExecuteScalar(); - Assert.AreEqual("Test", v); + Assert.That(v, Is.EqualTo("Test")); } } @@ -455,69 +456,69 @@ public void TestManyDifferentResultsets() { //First ResultSet, should have 49 rows. //SELECT id FROM Test WHERE id= ?param1; - Assert.True(reader.NextResult()); - Assert.True(reader.HasRows); - Assert.AreEqual(5, reader.FieldCount); + Assert.That(reader.NextResult()); + Assert.That(reader.HasRows); + Assert.That(reader.FieldCount, Is.EqualTo(5)); for (int i = 0; i < 51; i++) { - Assert.True(reader.Read()); + Assert.That(reader.Read()); } - Assert.False(reader.Read()); + Assert.That(reader.Read(), Is.False); //Fourth ResultSet, should have no rows. //SELECT id, dt, b1 FROM Test WHERE id = -50; - Assert.True(reader.NextResult()); - Assert.False(reader.HasRows); - Assert.AreEqual(3, reader.FieldCount); //Will Fail if uncommented expected 3 returned 5 - Assert.False(reader.Read()); + Assert.That(reader.NextResult()); + Assert.That(reader.HasRows, Is.False); + Assert.That(reader.FieldCount, Is.EqualTo(3)); //Will Fail if uncommented expected 3 returned 5 + Assert.That(reader.Read(), Is.False); //Fifth ResultSet, should have no rows. //SELECT b1 FROM Test WHERE id = -50; - Assert.True(reader.NextResult()); - Assert.False(reader.HasRows); - Assert.AreEqual(1, reader.FieldCount); //Will Fail if uncommented expected 1 returned 5 - Assert.False(reader.Read()); + Assert.That(reader.NextResult()); + Assert.That(reader.HasRows, Is.False); + Assert.That(reader.FieldCount, Is.EqualTo(1)); //Will Fail if uncommented expected 1 returned 5 + Assert.That(reader.Read(), Is.False); //Sixth ResultSet, should have 49 rows. //SELECT id, dt, b1 FROM Test WHERE id < ?param1; - Assert.True(reader.NextResult()); - Assert.True(reader.HasRows); - Assert.AreEqual(3, reader.FieldCount); //Will Fail if uncommented expected 3 returned 5 + Assert.That(reader.NextResult()); + Assert.That(reader.HasRows); + Assert.That(reader.FieldCount, Is.EqualTo(3)); //Will Fail if uncommented expected 3 returned 5 for (int i = 0; i < 49; i++) { - Assert.True(reader.Read()); + Assert.That(reader.Read()); } - Assert.False(reader.Read()); + Assert.That(reader.Read(), Is.False); //Seventh ResultSet, should have 51 rows. //SELECT b1 FROM Test WHERE id >= ?param1; - Assert.True(reader.NextResult()); - Assert.True(reader.HasRows); - Assert.AreEqual(1, reader.FieldCount); //Will Fail if uncommented expected 1 returned 5 + Assert.That(reader.NextResult()); + Assert.That(reader.HasRows); + Assert.That(reader.FieldCount, Is.EqualTo(1)); //Will Fail if uncommented expected 1 returned 5 for (int i = 0; i < 51; i++) { - Assert.True(reader.Read()); + Assert.That(reader.Read()); } - Assert.False(reader.Read()); + Assert.That(reader.Read(), Is.False); } } @@ -538,25 +539,25 @@ public void TestMultipleResultsWithQueryCacheOn() using (MySqlDataReader reader = cmd.ExecuteReader()) { - Assert.NotNull(reader); - Assert.True(reader.HasRows); - Assert.True(reader.Read()); - Assert.AreEqual(1, reader.FieldCount); - Assert.True(reader.NextResult()); - Assert.True(reader.HasRows); - Assert.AreEqual(5, reader.FieldCount); + Assert.That(reader, Is.Not.Null); + Assert.That(reader.HasRows); + Assert.That(reader.Read()); + Assert.That(reader.FieldCount, Is.EqualTo(1)); + Assert.That(reader.NextResult()); + Assert.That(reader.HasRows); + Assert.That(reader.FieldCount, Is.EqualTo(5)); } // now do it again using (MySqlDataReader reader = cmd.ExecuteReader()) { - Assert.NotNull(reader); - Assert.True(reader.HasRows); - Assert.True(reader.Read()); - Assert.AreEqual(1, reader.FieldCount); - Assert.True(reader.NextResult()); - Assert.True(reader.HasRows); - Assert.AreEqual(5, reader.FieldCount); + Assert.That(reader, Is.Not.Null); + Assert.That(reader.HasRows); + Assert.That(reader.Read()); + Assert.That(reader.FieldCount, Is.EqualTo(1)); + Assert.That(reader.NextResult()); + Assert.That(reader.HasRows); + Assert.That(reader.FieldCount, Is.EqualTo(5)); } } @@ -571,7 +572,7 @@ public void AffectedRows() { reader.Read(); reader.Close(); - Assert.AreEqual(-1, reader.RecordsAffected); + Assert.That(reader.RecordsAffected, Is.EqualTo(-1)); } } @@ -590,7 +591,7 @@ public void InvalidTimestamp() Assert.Throws(() => reader = cmd.ExecuteReader()); else { - CollectionAssert.IsEmpty(reader = cmd.ExecuteReader()); + Assert.That(reader = cmd.ExecuteReader(), Is.Empty); reader.Close(); } } @@ -628,7 +629,7 @@ public void GetSchemaTableOnEmptyResultset() using (MySqlDataReader reader = cmd.ExecuteReader()) { DataTable dt = reader.GetSchemaTable(); - Assert.Null(dt); + Assert.That(dt, Is.Null); } } @@ -644,8 +645,8 @@ public void IsDbNullOnNonNullFields() MySqlCommand cmd = new MySqlCommand("SELECT * FROM Test", Connection); using (MySqlDataReader reader = cmd.ExecuteReader()) { - Assert.True(reader.Read()); - Assert.False(reader.IsDBNull(1)); + Assert.That(reader.Read()); + Assert.That(reader.IsDBNull(1), Is.False); } } @@ -690,7 +691,7 @@ public void CloseConnectionBehavior2() MySqlCommand cmd = new MySqlCommand("SELECT * FROM Test", c2); using (MySqlDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection)) { - Assert.True(reader.Read()); + Assert.That(reader.Read()); } } } @@ -709,26 +710,26 @@ public void CommandBehaviorSchemaOnly() MySqlCommand cmd = new MySqlCommand("select * from doesnotexist", Connection); MySqlDataReader reader; Exception ex = Assert.Throws(() => reader = cmd.ExecuteReader(CommandBehavior.SchemaOnly)); - StringAssert.Contains(".doesnotexist' doesn't exist", ex.Message); + Assert.That(ex.Message, Does.Contain(".doesnotexist' doesn't exist")); // Check that failed ExecuteReader did not leave SQL_SELECT_LIMIT // set to 0. cmd.CommandText = "select now()"; reader = cmd.ExecuteReader(); - Assert.True(reader.Read()); + Assert.That(reader.Read()); reader.Close(); // Check that CommandBehavior.SchemaOnly does not return rows reader = cmd.ExecuteReader(CommandBehavior.SchemaOnly); - Assert.False(reader.Read()); + Assert.That(reader.Read(), Is.False); reader.Close(); reader = cmd.ExecuteReader(); // Check that prior setting of CommandBehavior did not // leave SQL_SELECT_LIMIT set to 0 - Assert.True(reader.Read()); + Assert.That(reader.Read()); reader.Close(); } @@ -747,8 +748,8 @@ public void ColumnsWithSameName() reader.Read(); string name1 = reader.GetString(0); string name2 = reader.GetString(1); - Assert.AreEqual(name1, name2); - Assert.AreEqual("test", name1); + Assert.That(name2, Is.EqualTo(name1)); + Assert.That(name1, Is.EqualTo("test")); } cmd.CommandText = "SELECT 'a' AS XYZ, 'b' as Xyz"; @@ -772,7 +773,7 @@ public void Bug47467() reader.Read(); Type t = reader.GetFieldType("c1"); Exception ex = Assert.Throws(() => reader.GetOrdinal("nocol")); - Assert.True(ex.Message.IndexOf("nocol") != -1); + Assert.That(ex.Message.IndexOf("nocol") != -1); } } @@ -801,7 +802,7 @@ public void GetStream() using (var stream = reader.GetStream(0)) { string result = UTF8Encoding.UTF8.GetString(((MemoryStream)stream).ToArray()); - StringAssert.AreEqualIgnoringCase(str, result); + Assert.That(result, Is.EqualTo(str).IgnoreCase); } } } @@ -834,12 +835,12 @@ public void GetFieldValue() using (var reader = cmd.ExecuteReader()) { reader.Read(); - Assert.AreEqual(1, reader.GetFieldValue(0)); - Assert.AreEqual(1.23, reader.GetFieldValue(1)); - Assert.AreEqual("test", reader.GetFieldValue(2)); - Assert.AreEqual(dateTime.ToShortDateString(), reader.GetFieldValue(3).ToShortDateString()); - Assert.AreEqual(true, reader.GetFieldValue(4)); - StringAssert.AreEqualIgnoringCase(str, Encoding.UTF8.GetString(((MemoryStream)reader.GetFieldValue(5)).ToArray())); + Assert.That(reader.GetFieldValue(0), Is.EqualTo(1)); + Assert.That(reader.GetFieldValue(1), Is.EqualTo(1.23)); + Assert.That(reader.GetFieldValue(2), Is.EqualTo("test")); + Assert.That(reader.GetFieldValue(3).ToShortDateString(), Is.EqualTo(dateTime.ToShortDateString())); + Assert.That(reader.GetFieldValue(4), Is.EqualTo(true)); + Assert.That(Encoding.UTF8.GetString(((MemoryStream)reader.GetFieldValue(5)).ToArray()), Is.EqualTo(str).IgnoreCase); } } } diff --git a/MySQL.Data/tests/MySql.Data.Tests/OutputParametersBatch.cs b/MySQL.Data/tests/MySql.Data.Tests/OutputParametersBatch.cs index 49cc00a37..9e264e4b6 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/OutputParametersBatch.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/OutputParametersBatch.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2022, Oracle and/or its affiliates. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -27,6 +27,7 @@ // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA using NUnit.Framework; +using NUnit.Framework.Legacy; using System; using System.Data; @@ -57,7 +58,7 @@ protected override void Cleanup() public void OutputParameters() { // we don't want to run this test under no access - Assert.True(Settings.CheckParameters); + Assert.That(Settings.CheckParameters); // create our procedure ExecuteSQL("CREATE PROCEDURE spTest(out value VARCHAR(350), OUT intVal INT, " + @@ -88,14 +89,13 @@ public void OutputParameters() if (prepare) cmd.Prepare(); int rowsAffected = cmd.ExecuteNonQuery(); - Assert.AreEqual(0, rowsAffected); - Assert.AreEqual("42", cmd.Parameters[0].Value); - Assert.AreEqual(33, cmd.Parameters[1].Value); - Assert.AreEqual(new DateTime(2004, 6, 5, 7, 58, 9), - Convert.ToDateTime(cmd.Parameters[2].Value)); - Assert.AreEqual((decimal)1.2, (decimal)(float)cmd.Parameters[3].Value); - Assert.AreEqual("test", cmd.Parameters[4].Value); - Assert.AreEqual(66, cmd.Parameters[5].Value); + Assert.That(rowsAffected, Is.EqualTo(0)); + Assert.That(cmd.Parameters[0].Value, Is.EqualTo("42")); + Assert.That(cmd.Parameters[1].Value, Is.EqualTo(33)); + Assert.That(Convert.ToDateTime(cmd.Parameters[2].Value), Is.EqualTo(new DateTime(2004, 6, 5, 7, 58, 9))); + Assert.That((decimal)(float)cmd.Parameters[3].Value, Is.EqualTo((decimal)1.2)); + Assert.That(cmd.Parameters[4].Value, Is.EqualTo("test")); + Assert.That(cmd.Parameters[5].Value, Is.EqualTo(66)); } [Test] @@ -115,10 +115,10 @@ public void InputOutputParameters() cmd.Parameters[2].Direction = ParameterDirection.Output; if (prepare) cmd.Prepare(); int rowsAffected = cmd.ExecuteNonQuery(); - Assert.AreEqual(0, rowsAffected); - Assert.AreEqual("beginningending", cmd.Parameters[0].Value); - Assert.AreEqual(66, cmd.Parameters[1].Value); - Assert.AreEqual(99, cmd.Parameters[2].Value); + Assert.That(rowsAffected, Is.EqualTo(0)); + Assert.That(cmd.Parameters[0].Value, Is.EqualTo("beginningending")); + Assert.That(cmd.Parameters[1].Value, Is.EqualTo(66)); + Assert.That(cmd.Parameters[2].Value, Is.EqualTo(99)); } [Test] @@ -135,8 +135,8 @@ public void ExecuteScalar() cmd.Parameters[1].Direction = ParameterDirection.Output; if (prepare) cmd.Prepare(); object result = cmd.ExecuteScalar(); - Assert.AreEqual("Test", result); - Assert.AreEqual("valuein", cmd.Parameters[1].Value); + Assert.That(result, Is.EqualTo("Test")); + Assert.That(cmd.Parameters[1].Value, Is.EqualTo("valuein")); } [Test] @@ -153,11 +153,11 @@ public void ExecuteReaderTest() if (prepare) cmd.Prepare(); using (MySqlDataReader reader = cmd.ExecuteReader()) { - Assert.True(reader.Read()); - Assert.False(reader.NextResult()); - Assert.False(reader.Read()); + Assert.That(reader.Read()); + Assert.That(reader.NextResult(), Is.False); + Assert.That(reader.Read(), Is.False); } - Assert.AreEqual(2, cmd.Parameters[0].Value); + Assert.That(cmd.Parameters[0].Value, Is.EqualTo(2)); } [Test] @@ -170,7 +170,7 @@ public void FunctionNoParams() cmd.CommandType = CommandType.Text; if (prepare) cmd.Prepare(); object result = cmd.ExecuteScalar(); - Assert.AreEqual("Test", result); + Assert.That(result, Is.EqualTo("Test")); } [Test] @@ -183,7 +183,7 @@ public void FunctionParams() cmd.CommandType = CommandType.Text; if (prepare) cmd.Prepare(); object result = cmd.ExecuteScalar(); - Assert.AreEqual(26, result); + Assert.That(result, Is.EqualTo(26)); } /// @@ -205,7 +205,7 @@ public void CallingStoredFunctionasProcedure() cmd.Parameters.Add(retVal); if (prepare) cmd.Prepare(); cmd.ExecuteNonQuery(); - Assert.AreEqual(44, cmd.Parameters[1].Value); + Assert.That(cmd.Parameters[1].Value, Is.EqualTo(44)); } [Test] @@ -259,8 +259,8 @@ public void UnsignedOutputParameters() cmd.ExecuteNonQuery(); object o = cmd.Parameters[0].Value; - Assert.True(o is ulong); - Assert.AreEqual(1, Convert.ToInt32(o)); + Assert.That(o is ulong); + Assert.That(Convert.ToInt32(o), Is.EqualTo(1)); } [Test] @@ -275,7 +275,7 @@ public void CallingFunctionWithoutReturnParameter() cmd.Parameters.AddWithValue("?p_kiosk", 2); cmd.Parameters.AddWithValue("?p_user", 4); Exception ex = Assert.Throws(() => { if (prepare) cmd.Prepare(); cmd.ExecuteNonQuery(); }); - Assert.AreEqual(ex.Message, "Attempt to call stored function 'fnTest' without specifying a return parameter"); + Assert.That("Attempt to call stored function 'fnTest' without specifying a return parameter", Is.EqualTo(ex.Message)); } /// @@ -317,16 +317,16 @@ public void BinaryAndVarBinaryParameters() cmd.ExecuteNonQuery(); byte[] out1 = (byte[])cmd.Parameters[0].Value; - Assert.AreEqual('o', (char)out1[0]); - Assert.AreEqual('u', (char)out1[1]); - Assert.AreEqual('t', (char)out1[2]); - Assert.AreEqual('1', (char)out1[3]); + Assert.That((char)out1[0], Is.EqualTo('o')); + Assert.That((char)out1[1], Is.EqualTo('u')); + Assert.That((char)out1[2], Is.EqualTo('t')); + Assert.That((char)out1[3], Is.EqualTo('1')); out1 = (byte[])cmd.Parameters[1].Value; - Assert.AreEqual('o', (char)out1[0]); - Assert.AreEqual('u', (char)out1[1]); - Assert.AreEqual('t', (char)out1[2]); - Assert.AreEqual('2', (char)out1[3]); + Assert.That((char)out1[0], Is.EqualTo('o')); + Assert.That((char)out1[1], Is.EqualTo('u')); + Assert.That((char)out1[2], Is.EqualTo('t')); + Assert.That((char)out1[3], Is.EqualTo('2')); } /// @@ -349,7 +349,7 @@ RETURNS double NOT DETERMINISTIC CONTAINS SQL SQL SECURITY DEFINER if (prepare) command.Prepare(); command.ExecuteNonQuery(); double balance = Convert.ToDouble(command.Parameters["?Balance"].Value); - Assert.AreEqual(1.0, balance); + Assert.That(balance, Is.EqualTo(1.0)); } /// @@ -372,8 +372,8 @@ public void OutputParametersWithNewParamHandling() if (prepare) cmd.Prepare(); int rowsAffected = cmd.ExecuteNonQuery(); - Assert.AreEqual(0, rowsAffected); - Assert.AreEqual("42", cmd.Parameters[0].Value); + Assert.That(rowsAffected, Is.EqualTo(0)); + Assert.That(cmd.Parameters[0].Value, Is.EqualTo("42")); } } @@ -398,8 +398,8 @@ public void FunctionWithNewParamHandling() if (prepare) cmd.Prepare(); int rowsAffected = cmd.ExecuteNonQuery(); - Assert.AreEqual(0, rowsAffected); - Assert.AreEqual(22, cmd.Parameters[1].Value); + Assert.That(rowsAffected, Is.EqualTo(0)); + Assert.That(cmd.Parameters[1].Value, Is.EqualTo(22)); } } @@ -420,7 +420,7 @@ public void BitTypeAsOutParameter() cmd.Parameters.Add("x", MySqlDbType.Bit).Direction = ParameterDirection.Output; if (prepare) cmd.Prepare(); cmd.ExecuteNonQuery(); - Assert.AreEqual(0, Convert.ToInt32(cmd.Parameters[0].Value)); + Assert.That(Convert.ToInt32(cmd.Parameters[0].Value), Is.EqualTo(0)); } /// @@ -462,12 +462,12 @@ public void RunWithoutSelectPrivsThrowException() if (prepare) cmd.Prepare(); cmd.ExecuteNonQuery(); - Assert.AreEqual(6, cmd.Parameters[1].Value); - Assert.AreEqual(6, cmd.Parameters[2].Value); + Assert.That(cmd.Parameters[1].Value, Is.EqualTo(6)); + Assert.That(cmd.Parameters[2].Value, Is.EqualTo(6)); } catch (InvalidOperationException iex) { - StringAssert.StartsWith("Unable to retrieve", iex.Message); + Assert.That(iex.Message, Does.StartWith("Unable to retrieve")); } finally { @@ -499,8 +499,8 @@ public void NoAccessToProcedureBodies() if (prepare) cmd.Prepare(); cmd.ExecuteNonQuery(); - Assert.AreEqual(6, cmd.Parameters[1].Value); - Assert.AreEqual(3, cmd.Parameters[2].Value); + Assert.That(cmd.Parameters[1].Value, Is.EqualTo(6)); + Assert.That(cmd.Parameters[2].Value, Is.EqualTo(3)); } } } diff --git a/MySQL.Data/tests/MySql.Data.Tests/ParameterTests.cs b/MySQL.Data/tests/MySql.Data.Tests/ParameterTests.cs index fccf44018..c2a6b7d69 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/ParameterTests.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/ParameterTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2022, Oracle and/or its affiliates. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -27,10 +27,12 @@ // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA using NUnit.Framework; +using NUnit.Framework.Legacy; using System; using System.Data; using System.Diagnostics; using System.IO; +using System.Text; namespace MySql.Data.MySqlClient.Tests { @@ -74,19 +76,19 @@ public void TestQuoting() { reader = cmd.ExecuteReader(); reader.Read(); - Assert.AreEqual("my ' value", reader.GetString(1)); + Assert.That(reader.GetString(1), Is.EqualTo("my ' value")); reader.Read(); - Assert.AreEqual(@"my "" value", reader.GetString(1)); + Assert.That(reader.GetString(1), Is.EqualTo(@"my "" value")); reader.Read(); - Assert.AreEqual("my ` value", reader.GetString(1)); + Assert.That(reader.GetString(1), Is.EqualTo("my ` value")); reader.Read(); - Assert.AreEqual("my ´ value", reader.GetString(1)); + Assert.That(reader.GetString(1), Is.EqualTo("my ´ value")); reader.Read(); - Assert.AreEqual(@"my \ value", reader.GetString(1)); + Assert.That(reader.GetString(1), Is.EqualTo(@"my \ value")); } catch (Exception ex) { - Assert.False(ex.Message == String.Empty, ex.Message); + Assert.That(ex.Message == String.Empty, Is.False, ex.Message); } finally { @@ -107,41 +109,41 @@ public void TestDateTimeParameter() cmd.Parameters.Add(new MySqlParameter("?time", time)); cmd.Parameters.Add(new MySqlParameter("?dt", dt)); int cnt = cmd.ExecuteNonQuery(); - Assert.True(cnt == 1, "Insert count"); + Assert.That(cnt == 1, "Insert count"); cmd = new MySqlCommand("SELECT tm, dt, ts FROM Test WHERE id=1", Connection); MySqlDataReader reader = cmd.ExecuteReader(); reader.Read(); TimeSpan time2 = (TimeSpan)reader.GetValue(0); - Assert.AreEqual(time, time2); + Assert.That(time2, Is.EqualTo(time)); DateTime dt2 = reader.GetDateTime(1); - Assert.AreEqual(dt, dt2); + Assert.That(dt2, Is.EqualTo(dt)); DateTime ts2 = reader.GetDateTime(2); reader.Close(); // now check the timestamp column. We won't check the minute or second for obvious reasons DateTime now = DateTime.Now; - Assert.AreEqual(now.Year, ts2.Year); - Assert.AreEqual(now.Month, ts2.Month); - Assert.AreEqual(now.Day, ts2.Day); - Assert.AreEqual(now.Hour, ts2.Hour); + Assert.That(ts2.Year, Is.EqualTo(now.Year)); + Assert.That(ts2.Month, Is.EqualTo(now.Month)); + Assert.That(ts2.Day, Is.EqualTo(now.Day)); + Assert.That(ts2.Hour, Is.EqualTo(now.Hour)); // now we'll set some nulls and see how they are handled cmd = new MySqlCommand("UPDATE Test SET tm=?ts, dt=?dt WHERE id=1", Connection); cmd.Parameters.Add(new MySqlParameter("?ts", DBNull.Value)); cmd.Parameters.Add(new MySqlParameter("?dt", DBNull.Value)); cnt = cmd.ExecuteNonQuery(); - Assert.True(cnt == 1, "Update null count"); + Assert.That(cnt == 1, "Update null count"); cmd = new MySqlCommand("SELECT tm, dt FROM Test WHERE id=1", Connection); reader = cmd.ExecuteReader(); reader.Read(); object tso = reader.GetValue(0); object dto = reader.GetValue(1); - Assert.True(tso == DBNull.Value, "Time column"); - Assert.True(dto == DBNull.Value, "DateTime column"); + Assert.That(tso == DBNull.Value, "Time column"); + Assert.That(dto == DBNull.Value, "DateTime column"); reader.Close(); @@ -157,7 +159,7 @@ public void NestedQuoting() MySqlCommand cmd = new MySqlCommand("INSERT INTO Test (id, name) " + "VALUES(1, 'this is ?\"my value\"')", Connection); int count = cmd.ExecuteNonQuery(); - Assert.AreEqual(1, count); + Assert.That(count, Is.EqualTo(1)); } [Test] @@ -166,16 +168,16 @@ public void SetDbType() IDbCommand cmd = Connection.CreateCommand(); IDbDataParameter prm = cmd.CreateParameter(); prm.DbType = DbType.Int64; - Assert.AreEqual(DbType.Int64, prm.DbType); + Assert.That(prm.DbType, Is.EqualTo(DbType.Int64)); prm.Value = 3; - Assert.AreEqual(DbType.Int64, prm.DbType); + Assert.That(prm.DbType, Is.EqualTo(DbType.Int64)); MySqlParameter p = new MySqlParameter("name", MySqlDbType.Int64); - Assert.AreEqual(DbType.Int64, p.DbType); - Assert.AreEqual(MySqlDbType.Int64, p.MySqlDbType); + Assert.That(p.DbType, Is.EqualTo(DbType.Int64)); + Assert.That(p.MySqlDbType, Is.EqualTo(MySqlDbType.Int64)); p.Value = 3; - Assert.AreEqual(DbType.Int64, p.DbType); - Assert.AreEqual(MySqlDbType.Int64, p.MySqlDbType); + Assert.That(p.DbType, Is.EqualTo(DbType.Int64)); + Assert.That(p.MySqlDbType, Is.EqualTo(MySqlDbType.Int64)); } [Test] @@ -234,9 +236,9 @@ public void MemoryStreamAsParameterValue() using (MySqlDataReader reader = cmd.ExecuteReader()) { reader.Read(); - Assert.AreEqual("abcd", reader.GetString(0)); - Assert.AreEqual("efgh", reader.GetString(1)); - Assert.AreEqual("5678", reader.GetString(2)); + Assert.That(Convert.ToString(reader[0]), Is.EqualTo("abcd")); + Assert.That(Encoding.Default.GetString((byte[])reader[1]), Is.EqualTo("efgh")); + Assert.That(Convert.ToString(reader[2]), Is.EqualTo("5678")); } } } @@ -249,8 +251,8 @@ public void ParameterClone2() { var param = new MySqlParameter("@param", MySqlDbType.MediumText); var clone = param.Clone(); - Assert.AreEqual(MySqlDbType.MediumText, param.MySqlDbType); // Prints "MediumText" - Assert.AreEqual(MySqlDbType.MediumText, clone.MySqlDbType); // Prints "VarChar" + Assert.That(param.MySqlDbType, Is.EqualTo(MySqlDbType.MediumText)); // Prints "MediumText" + Assert.That(clone.MySqlDbType, Is.EqualTo(MySqlDbType.MediumText)); // Prints "VarChar" } @@ -277,17 +279,17 @@ public void ParameterClone() var clonedparam = param.Clone(); - Assert.AreEqual(DbType.Int32, clonedparam.DbType); - Assert.AreEqual(ParameterDirection.Output, clonedparam.Direction); - Assert.AreEqual(System.Text.Encoding.UTF8, clonedparam.Encoding); - Assert.IsTrue(clonedparam.IsNullable); - Assert.AreEqual(MySqlDbType.Int32, clonedparam.MySqlDbType); - Assert.AreEqual("test", clonedparam.ParameterName); - Assert.AreEqual((byte)3, clonedparam.Precision); - Assert.AreEqual((byte)2, clonedparam.Scale); - Assert.AreEqual(1, clonedparam.Size); - Assert.IsTrue(clonedparam.SourceColumnNullMapping); - Assert.AreEqual(1, clonedparam.Value); + Assert.That(clonedparam.DbType, Is.EqualTo(DbType.Int32)); + Assert.That(clonedparam.Direction, Is.EqualTo(ParameterDirection.Output)); + Assert.That(clonedparam.Encoding, Is.EqualTo(System.Text.Encoding.UTF8)); + Assert.That(clonedparam.IsNullable); + Assert.That(clonedparam.MySqlDbType, Is.EqualTo(MySqlDbType.Int32)); + Assert.That(clonedparam.ParameterName, Is.EqualTo("test")); + Assert.That(clonedparam.Precision, Is.EqualTo((byte)3)); + Assert.That(clonedparam.Scale, Is.EqualTo((byte)2)); + Assert.That(clonedparam.Size, Is.EqualTo(1)); + Assert.That(clonedparam.SourceColumnNullMapping); + Assert.That(clonedparam.Value, Is.EqualTo(1)); } /// @@ -309,7 +311,7 @@ public void ParameterDirectionOutputTextCommand(bool preparedCommand) if (preparedCommand) cmd.Prepare(); cmd.ExecuteNonQuery(); - Assert.AreEqual(1234, cmd.Parameters["@outputParam"].Value); + Assert.That(cmd.Parameters["@outputParam"].Value, Is.EqualTo(1234)); } } @@ -336,10 +338,10 @@ public void AllowUnnamedParameters() cmd.ExecuteNonQuery(); cmd.CommandText = "SELECT id FROM Test"; - Assert.AreEqual(1, cmd.ExecuteScalar()); + Assert.That(cmd.ExecuteScalar(), Is.EqualTo(1)); cmd.CommandText = "SELECT name FROM Test"; - Assert.AreEqual("test", cmd.ExecuteScalar()); + Assert.That(cmd.ExecuteScalar(), Is.EqualTo("test")); } [Test] @@ -353,7 +355,7 @@ public void NullParameterValue() cmd.CommandText = "SELECT name FROM Test WHERE id=1"; object name = cmd.ExecuteScalar(); - Assert.AreEqual(DBNull.Value, name); + Assert.That(name, Is.EqualTo(DBNull.Value)); } /// @@ -367,7 +369,7 @@ public void DefaultType() p.ParameterName = "?boo"; p.Value = "test"; MySqlParameter mp = (MySqlParameter)p; - Assert.AreEqual(MySqlDbType.VarChar, mp.MySqlDbType); + Assert.That(mp.MySqlDbType, Is.EqualTo(MySqlDbType.VarChar)); } [Test] @@ -391,15 +393,15 @@ public void OddCharsInParameterNames() cmd.CommandText = "SELECT name FROM Test WHERE id=1"; object name = cmd.ExecuteScalar(); - Assert.AreEqual("Test", name); + Assert.That(name, Is.EqualTo("Test")); cmd.CommandText = "SELECT name FROM Test WHERE id=2"; name = cmd.ExecuteScalar(); - Assert.AreEqual("Test2", name); + Assert.That(name, Is.EqualTo("Test2")); cmd.CommandText = "SELECT name FROM Test WHERE id=3"; name = cmd.ExecuteScalar(); - Assert.AreEqual("Test3", name); + Assert.That(name, Is.EqualTo("Test3")); } /// @@ -427,10 +429,10 @@ public void UnTypedParameterBeingReused() using (MySqlDataReader reader = cmd.ExecuteReader()) { reader.Read(); - Assert.True(reader.IsDBNull(2)); + Assert.That(reader.IsDBNull(2)); reader.Read(); - Assert.False(reader.IsDBNull(2)); - Assert.False(reader.Read()); + Assert.That(reader.IsDBNull(2), Is.False); + Assert.That(reader.Read(), Is.False); } } @@ -459,19 +461,19 @@ public void WithAndWithoutMarker() MySqlCommand cmd = new MySqlCommand("INSERT INTO Test (id, name) VALUES (?id, ?name)", Connection); cmd.Parameters.AddWithValue("id", 1); - Assert.AreEqual(-1, cmd.Parameters.IndexOf("?id")); + Assert.That(cmd.Parameters.IndexOf("?id"), Is.EqualTo(-1)); cmd.Parameters.AddWithValue("name", "test"); cmd.ExecuteNonQuery(); cmd.Parameters.Clear(); cmd.Parameters.AddWithValue("?id", 2); - Assert.AreEqual(-1, cmd.Parameters.IndexOf("id")); + Assert.That(cmd.Parameters.IndexOf("id"), Is.EqualTo(-1)); cmd.Parameters.AddWithValue("?name", "test2"); cmd.ExecuteNonQuery(); cmd.CommandText = "SELECT COUNT(*) FROM Test"; object count = cmd.ExecuteScalar(); - Assert.AreEqual(2, Convert.ToInt32(count)); + Assert.That(Convert.ToInt32(count), Is.EqualTo(2)); } [Test] @@ -480,11 +482,11 @@ public void DoubleAddingParameters() ExecuteSQL("CREATE TABLE Test (id INT NOT NULL, name VARCHAR(100), dt DATETIME, tm TIME, ts TIMESTAMP, PRIMARY KEY(id))"); MySqlCommand cmd = new MySqlCommand("INSERT INTO Test (id, name) VALUES (?id, ?name)", Connection); cmd.Parameters.AddWithValue("id", 1); - Assert.AreEqual(-1, cmd.Parameters.IndexOf("?id")); - Assert.AreEqual(-1, cmd.Parameters.IndexOf("@id")); + Assert.That(cmd.Parameters.IndexOf("?id"), Is.EqualTo(-1)); + Assert.That(cmd.Parameters.IndexOf("@id"), Is.EqualTo(-1)); cmd.Parameters.AddWithValue("name", "test"); Exception ex = Assert.Throws(() => cmd.Parameters.AddWithValue("?id", 2)); - Assert.AreEqual("Parameter '?id' has already been defined.", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Parameter '?id' has already been defined")); } /// @@ -517,7 +519,7 @@ public void AddingParametersUsingInsert() MySqlCommand cmd = new MySqlCommand(); cmd.Parameters.Insert(0, new MySqlParameter("?id", MySqlDbType.Int32)); MySqlParameter p = cmd.Parameters["?id"]; - Assert.AreEqual("?id", p.ParameterName); + Assert.That(p.ParameterName, Is.EqualTo("?id")); } /// @@ -536,7 +538,7 @@ public void FindParameterAfterRemoval() cmd.Parameters.Add("?id6", MySqlDbType.Int32); cmd.Parameters.RemoveAt("?id1"); MySqlParameter p = cmd.Parameters["?id6"]; - Assert.AreEqual("?id6", p.ParameterName); + Assert.That(p.ParameterName, Is.EqualTo("?id6")); } /// @@ -574,7 +576,7 @@ public void StringParameterSizeSetAfterValue() MySqlDataAdapter da = new MySqlDataAdapter("SELECT * FROM Test", Connection); DataTable dt = new DataTable(); da.Fill(dt); - Assert.AreEqual("123", dt.Rows[0][0]); + Assert.That(dt.Rows[0][0], Is.EqualTo("123")); cmd.Parameters.Clear(); cmd.Parameters.Add("?p1", MySqlDbType.VarChar); @@ -584,7 +586,7 @@ public void StringParameterSizeSetAfterValue() dt.Clear(); da.Fill(dt); - Assert.AreEqual("1234567890", dt.Rows[1][0]); + Assert.That(dt.Rows[1][0], Is.EqualTo("1234567890")); } /// @@ -595,11 +597,11 @@ public void NonInputParametersToCtor() { MySqlParameter p = new MySqlParameter("?p1", MySqlDbType.VarChar, 20, ParameterDirection.InputOutput, true, 0, 0, "id", DataRowVersion.Current, 0); - Assert.AreEqual(ParameterDirection.InputOutput, p.Direction); + Assert.That(p.Direction, Is.EqualTo(ParameterDirection.InputOutput)); MySqlParameter p1 = new MySqlParameter("?p1", MySqlDbType.VarChar, 20, ParameterDirection.Output, true, 0, 0, "id", DataRowVersion.Current, 0); - Assert.AreEqual(ParameterDirection.Output, p1.Direction); + Assert.That(p1.Direction, Is.EqualTo(ParameterDirection.Output)); } [Test] @@ -616,8 +618,8 @@ public void UseAtSignForParameters() using (MySqlDataReader reader = cmd.ExecuteReader()) { reader.Read(); - Assert.AreEqual(33, reader.GetInt32(0)); - Assert.AreEqual("Test", reader.GetString(1)); + Assert.That(reader.GetInt32(0), Is.EqualTo(33)); + Assert.That(reader.GetString(1), Is.EqualTo("Test")); } } @@ -632,7 +634,7 @@ public void CanCreateMySQLParameterWithNullability() MySqlParameter p = new MySqlParameter("?id", MySqlDbType.Decimal, 2, ParameterDirection.Input, true, 1, 1, "sourceColumn", DataRowVersion.Default, 1); - Assert.True(p.IsNullable); + Assert.That(p.IsNullable); } /// @@ -645,7 +647,7 @@ public void CanCreateMySQLParameterWithPrecision() MySqlParameter p = new MySqlParameter("?id", MySqlDbType.Decimal, 2, ParameterDirection.Input, true, Byte.MaxValue, 1, "sourceColumn", DataRowVersion.Default, 1); - Assert.AreEqual(p.Precision, Byte.MaxValue); + Assert.That(Byte.MaxValue, Is.EqualTo(p.Precision)); } @@ -660,7 +662,7 @@ public void CanCreateMySQLParameterWithScale() MySqlParameter p = new MySqlParameter("?id", MySqlDbType.Decimal, 2, ParameterDirection.Input, true, 1, Byte.MaxValue, "sourceColumn", DataRowVersion.Default, 1); - Assert.AreEqual(p.Scale, Byte.MaxValue); + Assert.That(Byte.MaxValue, Is.EqualTo(p.Scale)); } /// @@ -678,10 +680,10 @@ public void CanIdentifyParameterWithOutName() cmd.ExecuteNonQuery(); cmd.CommandText = "SELECT id FROM Test"; - Assert.AreEqual(1, cmd.ExecuteScalar()); + Assert.That(cmd.ExecuteScalar(), Is.EqualTo(1)); cmd.CommandText = "SELECT name FROM Test"; - Assert.AreEqual("test", cmd.ExecuteScalar()); + Assert.That(cmd.ExecuteScalar(), Is.EqualTo("test")); } /// @@ -694,7 +696,7 @@ public void CanThrowAnExceptionWhenMixingParameterNaming() cmd.Parameters.AddWithValue("?Id", 1); cmd.Parameters.AddWithValue("?name", "test"); Exception ex = Assert.Throws(() => cmd.ExecuteNonQuery()); - Assert.AreEqual("Fatal error encountered during command execution.", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Fatal error encountered during command execution")); } /// @@ -716,7 +718,7 @@ public void TreatTinyAsBooleanWhenNull() while (reader.Read()) { if (!(reader["testcol"] is DBNull)) - Assert.True(reader["testcol"] is bool); + Assert.That(reader["testcol"] is bool); } } } @@ -748,7 +750,7 @@ public void TreatTinyAsBooleanWhenCallingPrepare() using (var reader = cmd.ExecuteReader(CommandBehavior.SingleRow)) { reader.Read(); - Assert.False(reader["test_val"] is bool); + Assert.That(reader["test_val"] is bool, Is.False); } } @@ -767,7 +769,7 @@ public void TreatTinyAsBooleanWhenCallingPrepare() using (var reader = cmd.ExecuteReader(CommandBehavior.SingleRow)) { reader.Read(); - Assert.True(reader["test_val"] is bool); + Assert.That(reader["test_val"] is bool); } } @@ -788,7 +790,7 @@ public void ZeroParameterAsNull() var query = "SELECT * FROM audit t1 WHERE t1.Permanent = ?IsFalse"; MySqlParameter[] parameters = { new MySqlParameter() { ParameterName = "IsFalse", Value = 0 } }; var ds = MySqlHelper.ExecuteDataset(Connection.ConnectionString, query, parameters); - Assert.AreEqual(ds.Tables[0].Rows.Count, 1); + Assert.That(1, Is.EqualTo(ds.Tables[0].Rows.Count)); } /// @@ -811,7 +813,7 @@ public void DefaultNullValue() { while (reader.Read()) { - Assert.IsTrue(reader.IsDBNull(0)); + Assert.That(reader.IsDBNull(0)); } } } @@ -849,7 +851,7 @@ public void CastingEnum(Enum name, string typeName) MySqlCommand command = new MySqlCommand(sql, conn); command.Parameters.AddWithValue("@ID", name); MySqlDataReader rdr = command.ExecuteReader(); - Assert.IsNotNull(rdr); + Assert.That(rdr, Is.Not.Null); } } @@ -867,16 +869,16 @@ public void InvalidParameterIndex() cmd.Parameters.Insert(1, new MySqlParameter("test1", "test1")); cmd.Parameters.Insert(0, new MySqlParameter("testNew0", "test2")); - Assert.True(cmd.Parameters.IndexOf("testNew0") == 0); - Assert.True(cmd.Parameters.IndexOf("test0") == 1); - Assert.True(cmd.Parameters.IndexOf("test1") == 2); + Assert.That(cmd.Parameters.IndexOf("testNew0") == 0); + Assert.That(cmd.Parameters.IndexOf("test0") == 1); + Assert.That(cmd.Parameters.IndexOf("test1") == 2); cmd.Parameters.AddWithValue("", "test3"); - Assert.True(cmd.Parameters.Count == 4); - Assert.True(cmd.Parameters.IndexOf("Parameter4") == 3); + Assert.That(cmd.Parameters.Count == 4); + Assert.That(cmd.Parameters.IndexOf("Parameter4") == 3); cmd.Parameters.Insert(1, new MySqlParameter("lastTest", "test4")); - Assert.True(cmd.Parameters.IndexOf("lastTest") == 1); + Assert.That(cmd.Parameters.IndexOf("lastTest") == 1); } /// @@ -903,8 +905,8 @@ public void InsertValueAfterNull() dt.Clear(); da.Fill(dt); - Assert.AreEqual(2, dt.Rows.Count); - Assert.AreEqual(2, dt.Rows[1]["foo"]); + Assert.That(dt.Rows.Count, Is.EqualTo(2)); + Assert.That(dt.Rows[1]["foo"], Is.EqualTo(2)); } /// @@ -924,15 +926,15 @@ public void CloneParameterAssignSourceColumnNullMapping() dataAdapter.Fill(dataTable); using (var cmd = new MySqlCommand(query, Connection)) - Assert.AreEqual(1, cmd.ExecuteScalar()); - Assert.AreEqual(1, dataTable.Rows.Count); + Assert.That(cmd.ExecuteScalar(), Is.EqualTo(1)); + Assert.That(dataTable.Rows.Count, Is.EqualTo(1)); dataTable.Rows[0].Delete(); dataAdapter.Update(dataTable); using (var cmd = new MySqlCommand(query, Connection)) - Assert.IsNull(cmd.ExecuteScalar()); - Assert.AreEqual(0, dataTable.Rows.Count); + Assert.That(cmd.ExecuteScalar(), Is.Null); + Assert.That(dataTable.Rows.Count, Is.EqualTo(0)); } /// @@ -946,10 +948,10 @@ public void InitializeParameter() var newParam = cmd.CreateParameter(); var newIntParam = new MySqlParameter("newIntParam", 3); - Assert.AreEqual(MySqlDbType.VarChar, newParam.MySqlDbType); - Assert.AreEqual(DbType.String, newParam.DbType); - Assert.AreEqual(MySqlDbType.Int32, newIntParam.MySqlDbType); - Assert.AreEqual(DbType.Int32, newIntParam.DbType); + Assert.That(newParam.MySqlDbType, Is.EqualTo(MySqlDbType.VarChar)); + Assert.That(newParam.DbType, Is.EqualTo(DbType.String)); + Assert.That(newIntParam.MySqlDbType, Is.EqualTo(MySqlDbType.Int32)); + Assert.That(newIntParam.DbType, Is.EqualTo(DbType.Int32)); } /// @@ -986,8 +988,8 @@ public void AddObjectPerformance() sw2.Stop(); Console.Write(sw2.Elapsed); - Assert.True(sw1.Elapsed.TotalSeconds < 1); - Assert.True(sw2.Elapsed.TotalSeconds < 1); + Assert.That(sw1.Elapsed.TotalSeconds < 1); + Assert.That(sw2.Elapsed.TotalSeconds < 1); } } -} \ No newline at end of file +} diff --git a/MySQL.Data/tests/MySql.Data.Tests/PoolingTests.cs b/MySQL.Data/tests/MySql.Data.Tests/PoolingTests.cs index 7a6f01a75..2db1373ce 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/PoolingTests.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/PoolingTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2022, Oracle and/or its affiliates. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -28,12 +28,14 @@ using MySql.Data.Common; using NUnit.Framework; +using NUnit.Framework.Legacy; using System; using System.Collections.Generic; using System.Data; using System.Net.NetworkInformation; using System.Reflection; using System.Threading; +using System.Threading.Tasks; namespace MySql.Data.MySqlClient.Tests { @@ -58,7 +60,7 @@ public void BasicConnection() { c = new MySqlConnection(Settings.ConnectionString); c.Open(); - Assert.AreEqual(serverThread, c.ServerThread); + Assert.That(c.ServerThread, Is.EqualTo(serverThread)); c.Close(); } @@ -80,7 +82,7 @@ public void BasicConnection() for (int j = 0; j < connArray.Length; j++) { if (i != j) - Assert.True(connArray[i].ServerThread != connArray[j].ServerThread); + Assert.That(connArray[i].ServerThread != connArray[j].ServerThread); } } @@ -109,7 +111,7 @@ public void OpenKilled() int secondThreadId = c.ServerThread; KillConnection(c); c.Close(); - Assert.False(threadId == secondThreadId); + Assert.That(threadId == secondThreadId, Is.False); } [Test] @@ -125,7 +127,7 @@ public void ReclaimBrokenConnection() // now attempting to open a connection should fail MySqlConnection c2 = new MySqlConnection(connStr); Exception ex = Assert.Throws(() => c2.Open()); - StringAssert.Contains("error connecting: Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool.", ex.Message); + Assert.That(ex.Message, Does.Contain("error connecting: Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool")); // we now kill the first connection to simulate a server stoppage KillConnection(c); @@ -133,7 +135,7 @@ public void ReclaimBrokenConnection() // now we do something on the first connection ex = Assert.Throws(() => c.ChangeDatabase("mysql")); - StringAssert.Contains("The connection is not open.", ex.Message); + Assert.That(ex.Message, Does.Contain("The connection is not open")); // Opening a connection now should work MySqlConnection connection = new MySqlConnection(connStr); @@ -154,12 +156,12 @@ public void TestUserReset() cmd.CommandText = "SELECT @testvar"; object var = cmd.ExecuteScalar(); - Assert.AreEqual("5", var); + Assert.That(var, Is.EqualTo("5")); c.Close(); c.Open(); object var2 = cmd.ExecuteScalar(); - Assert.AreEqual(DBNull.Value, var2); + Assert.That(var2, Is.EqualTo(DBNull.Value)); KillConnection(c); } } @@ -181,7 +183,7 @@ public void TestAbort() using (MySqlConnection c1 = new MySqlConnection(connStr)) { c1.Open(); - Assert.True(c1.ServerThread != threadId); + Assert.That(c1.ServerThread != threadId); KillConnection(c1); } } @@ -210,7 +212,7 @@ public void UTF8AfterClosing() cmd = new MySqlCommand("SELECT value FROM test WHERE id = 1", con); string firstS = cmd.ExecuteScalar().ToString(); - Assert.AreEqual(originalValue, firstS); + Assert.That(firstS, Is.EqualTo(originalValue)); con.Close(); con.Open(); @@ -221,7 +223,7 @@ public void UTF8AfterClosing() KillConnection(con); con.Close(); - Assert.AreEqual(firstS, secondS); + Assert.That(secondS, Is.EqualTo(firstS)); } } @@ -284,7 +286,7 @@ public void NewTest() if (recdr.Read()) { int x = recdr.GetOrdinal("name"); - Assert.AreEqual(1, x); + Assert.That(x, Is.EqualTo(1)); } } } @@ -464,7 +466,7 @@ public void TestBadConnections() using (MySqlConnection connection = new MySqlConnection(builder.ConnectionString)) { Exception ex = Assert.Throws(() => connection.Open()); - if (Platform.IsWindows()) Assert.True(ex.InnerException.GetType() == typeof(ArgumentException)); + if (Platform.IsWindows()) Assert.That(ex.InnerException.GetType() == typeof(ArgumentException)); } Thread.Sleep(50); } @@ -557,7 +559,7 @@ private void CacheServerPropertiesInternal(bool cache) KillConnection(c); } int count = listener.CountLinesContaining("SHOW VARIABLES"); - Assert.AreEqual(cache ? 1 : 2, count); + Assert.That(count, Is.EqualTo(cache ? 1 : 2)); } [Test] @@ -587,7 +589,7 @@ public void CacheServerPropertiesCausePacketTooLarge() c1.Open(); MySqlCommand cmd = new MySqlCommand("SELECT Count(*) from test", c1); var count = cmd.ExecuteScalar(); - Assert.AreEqual(3, Convert.ToInt32(count)); + Assert.That(Convert.ToInt32(count), Is.EqualTo(3)); } ExecuteSQL("DROP TABLE test "); @@ -611,6 +613,86 @@ void InsertSmallBlobInTestTableUsingPoolingConnection() } } + /// + /// Bug #37462116 + /// Connector/Net Not honouring MinPoolSize Configuration + /// + [Test] + public async Task MinPoolSizeNotCorrect() + { + int minPoolSize = 5; + var connectionString = $"server={Host};user={Settings.UserID};password={Settings.Password};port={Port};Max Pool Size=10;Min Pool Size={minPoolSize};sslmode=none;"; + + try + { + //change wait_timeout to force idle connections to close faster + using (var connection = new MySqlConnection(connectionString)) + { + connection.Open(); + using (var command = new MySqlCommand("SET GLOBAL wait_timeout = 10;", connection)) + { + command.ExecuteNonQuery(); + } + } + + //create connection pool using Min Pool Size of 5 + for (int i = 0; i < minPoolSize; i++) // Match MinPoolSize + { + using (var connection = new MySqlConnection(connectionString)) + { + connection.Open(); + using (var command = new MySqlCommand("SELECT CONNECTION_ID();", connection)) + { + command.ExecuteNonQuery(); + } + } + } + + //check that connection pool maintains the Min Pool Size + int cycleCounter = 0; + while (cycleCounter < minPoolSize * 2) + { + using (var connection = new MySqlConnection(connectionString)) + { + await connection.OpenAsync(); + + // Query all active connections + using (var command = new MySqlCommand("SHOW PROCESSLIST;", connection)) + using (var reader = await command.ExecuteReaderAsync()) + { + int connectionCount = 0; + + while (await reader.ReadAsync()) + { + //count the connections tied to the test user + string user = reader["User"].ToString(); + if (user == Settings.UserID) + { + connectionCount++; + } + } + // check that the ConnectionCount is equal or greater than the Min Pool Size + Assert.That(connectionCount, Is.GreaterThanOrEqualTo(minPoolSize)); + } + } + cycleCounter++; + await Task.Delay(2000); + } + } + finally + { + //change wait_timeout to default value; + using (var connection = new MySqlConnection(connectionString)) + { + connection.Open(); + using (var command = new MySqlCommand("SET GLOBAL wait_timeout = 28800;", connection)) + { + command.ExecuteNonQuery(); + } + } + } + } + #region WL14389 [Test, Description("Check Pooling Connection works correctly")] @@ -625,13 +707,13 @@ public void MultipleConnectionWithPooling() // Get a connection out of the pool. myConnection1.Open(); - Assert.AreEqual(ConnectionState.Open, myConnection1.State); + Assert.That(myConnection1.State, Is.EqualTo(ConnectionState.Open)); // Get a second connection out of the pool. myConnection2.Open(); - Assert.AreEqual(ConnectionState.Open, myConnection2.State); + Assert.That(myConnection2.State, Is.EqualTo(ConnectionState.Open)); // Open a third connection. myConnection3.Open(); - Assert.AreEqual(ConnectionState.Open, myConnection3.State); + Assert.That(myConnection3.State, Is.EqualTo(ConnectionState.Open)); // Return the all connections to the pool. myConnection1.Close(); myConnection2.Close(); @@ -643,7 +725,7 @@ public void MultipleConnectionWithPooling() myConnection3.Open(); myConnection4.Open(); Exception ex = Assert.Throws(() => myConnection5.Open()); - StringAssert.Contains("Timeout", ex.Message); + Assert.That(ex.Message, Does.Contain("Timeout")); myConnection1.Close(); myConnection2.Close(); @@ -658,7 +740,7 @@ public void MultipleConnectionWithPooling() [Test, Description("Verify the connection is not in CLOSE_WAIT state after failed connection due to Connection Limit")] public void CloseWaitScenario1() { - if (!Platform.IsWindows()) Assert.Ignore("This test is only for Windows OS"); + Assume.That(Platform.IsWindows(), "This test is only for Windows OS"); var poolSize = 5; var connectionString = $"server={Host};user={Settings.UserID};database={Settings.Database};port={Port};password={Settings.Password};Pooling=true;Max Pool Size={poolSize};SSL Mode=None;ConnectionTimeout=5"; List connectionList = new(); @@ -676,7 +758,7 @@ public void CloseWaitScenario1() var tcpConnections = ipProperties.GetActiveTcpConnections(); foreach (var info in tcpConnections) if (info.LocalEndPoint.Address.ToString() == "127.0.0.1" && info.LocalEndPoint.Port.ToString() == Port.ToString()) - Assert.True(info.State.ToString() != "CLOSE_WAIT"); + Assert.That(info.State.ToString() != "CLOSE_WAIT"); } foreach (var item in connectionList) { diff --git a/MySQL.Data/tests/MySql.Data.Tests/PreparedStatementCompressed.cs b/MySQL.Data/tests/MySql.Data.Tests/PreparedStatementCompressed.cs index aa3b18569..049abdd9a 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/PreparedStatementCompressed.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/PreparedStatementCompressed.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/tests/MySql.Data.Tests/PreparedStatements.cs b/MySQL.Data/tests/MySql.Data.Tests/PreparedStatements.cs index 42985fe16..a58dbeb53 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/PreparedStatements.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/PreparedStatements.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2022, Oracle and/or its affiliates. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -27,6 +27,7 @@ // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA using NUnit.Framework; +using NUnit.Framework.Legacy; using System; using System.Data; using System.Linq; @@ -54,11 +55,11 @@ public void Simple() cmd.Prepare(); using (MySqlDataReader reader = cmd.ExecuteReader()) { - Assert.True(reader.Read()); - Assert.AreEqual(1, reader.GetInt32(0)); - Assert.AreEqual((decimal)345.12, reader.GetDecimal(1)); - Assert.AreEqual("abcd", reader.GetString(2)); - Assert.AreEqual(2019, reader.GetInt16(3)); + Assert.That(reader.Read()); + Assert.That(reader.GetInt32(0), Is.EqualTo(1)); + Assert.That(reader.GetDecimal(1), Is.EqualTo((decimal)345.12)); + Assert.That(reader.GetString(2), Is.EqualTo("abcd")); + Assert.That(reader.GetInt16(3), Is.EqualTo(2019)); } } @@ -88,8 +89,8 @@ public void SimplePrepareBeforeParms() { // Fetch the first record reader.Read(); - Assert.AreEqual(1, reader.GetInt32(0)); - Assert.AreEqual(2, reader.GetInt32(1)); + Assert.That(reader.GetInt32(0), Is.EqualTo(1)); + Assert.That(reader.GetInt32(1), Is.EqualTo(2)); } } @@ -119,7 +120,7 @@ public void DateAndTimes() cmd.Parameters.AddWithValue("?tm", timeSp); cmd.Prepare(); int count = cmd.ExecuteNonQuery(); - Assert.True(count == 1, "Records affected by insert"); + Assert.That(count == 1, "Records affected by insert"); cmd.CommandText = "SELECT * FROM Test"; cmd.Prepare(); @@ -127,21 +128,21 @@ public void DateAndTimes() using (MySqlDataReader reader = cmd.ExecuteReader()) { reader.Read(); - Assert.True(reader.GetInt32(0) == 1, "Id column"); - Assert.True(dt.Date == reader.GetDateTime(1).Date, "Date column"); + Assert.That(reader.GetInt32(0) == 1, "Id column"); + Assert.That(dt.Date == reader.GetDateTime(1).Date, "Date column"); DateTime dt2 = reader.GetDateTime(2); - Assert.AreEqual(dt.Date, dt2.Date); - Assert.AreEqual(dt.Hour, dt2.Hour); - Assert.AreEqual(dt.Minute, dt2.Minute); - Assert.AreEqual(dt.Second, dt2.Second); + Assert.That(dt2.Date, Is.EqualTo(dt.Date)); + Assert.That(dt2.Hour, Is.EqualTo(dt.Hour)); + Assert.That(dt2.Minute, Is.EqualTo(dt.Minute)); + Assert.That(dt2.Second, Is.EqualTo(dt.Second)); TimeSpan ts2 = reader.GetTimeSpan(3); - Assert.AreEqual(timeSp.Days, ts2.Days); - Assert.AreEqual(timeSp.Hours, ts2.Hours); - Assert.AreEqual(timeSp.Minutes, ts2.Minutes); - Assert.AreEqual(timeSp.Seconds, ts2.Seconds); - Assert.True(dt.Date == reader.GetDateTime(4).Date, "Timestamp column"); + Assert.That(ts2.Days, Is.EqualTo(timeSp.Days)); + Assert.That(ts2.Hours, Is.EqualTo(timeSp.Hours)); + Assert.That(ts2.Minutes, Is.EqualTo(timeSp.Minutes)); + Assert.That(ts2.Seconds, Is.EqualTo(timeSp.Seconds)); + Assert.That(dt.Date == reader.GetDateTime(4).Date, "Timestamp column"); } } @@ -154,12 +155,12 @@ public void ResetCommandText() MySqlCommand cmd = new MySqlCommand("SELECT id FROM Test", Connection); cmd.Prepare(); object o = cmd.ExecuteScalar(); - Assert.AreEqual(1, o); + Assert.That(o, Is.EqualTo(1)); cmd.CommandText = "SELECT name FROM Test"; cmd.Prepare(); o = cmd.ExecuteScalar(); - Assert.AreEqual("Test", o); + Assert.That(o, Is.EqualTo("Test")); } @@ -198,7 +199,7 @@ public void DifferentParameterOrder() cmd.Parameters.Add(name); cmd.Parameters.Add(id3); cmd.Prepare(); - Assert.AreEqual(1, cmd.ExecuteNonQuery()); + Assert.That(cmd.ExecuteNonQuery(), Is.EqualTo(1)); cmd.Parameters.Clear(); @@ -210,13 +211,13 @@ public void DifferentParameterOrder() cmd.Parameters.Add(name); cmd.Prepare(); - Assert.AreEqual(1, cmd.ExecuteNonQuery()); + Assert.That(cmd.ExecuteNonQuery(), Is.EqualTo(1)); cmd.CommandText = "SELECT id3 FROM Test WHERE id=1"; - Assert.AreEqual(3, cmd.ExecuteScalar()); + Assert.That(cmd.ExecuteScalar(), Is.EqualTo(3)); cmd.CommandText = "SELECT name FROM Test WHERE id=2"; - Assert.AreEqual(DBNull.Value, cmd.ExecuteScalar()); + Assert.That(cmd.ExecuteScalar(), Is.EqualTo(DBNull.Value)); } [Test] @@ -234,20 +235,20 @@ public void Blobs() cmd.Parameters.AddWithValue("?text1", inStr); cmd.Prepare(); int count = cmd.ExecuteNonQuery(); - Assert.AreEqual(1, count); + Assert.That(count, Is.EqualTo(1)); cmd.CommandText = "SELECT * FROM Test"; cmd.Prepare(); using (MySqlDataReader reader = cmd.ExecuteReader()) { - Assert.True(reader.Read()); - Assert.AreEqual(1, reader.GetInt32(0)); - Assert.AreEqual(bytes.Length, reader.GetBytes(1, 0, null, 0, 0)); + Assert.That(reader.Read()); + Assert.That(reader.GetInt32(0), Is.EqualTo(1)); + Assert.That(reader.GetBytes(1, 0, null, 0, 0), Is.EqualTo(bytes.Length)); byte[] outBytes = new byte[bytes.Length]; reader.GetBytes(1, 0, outBytes, 0, bytes.Length); for (int x = 0; x < bytes.Length; x++) - Assert.AreEqual(bytes[x], outBytes[x]); - Assert.AreEqual(inStr, reader.GetString(2)); + Assert.That(outBytes[x], Is.EqualTo(bytes[x])); + Assert.That(reader.GetString(2), Is.EqualTo(inStr)); } } @@ -267,13 +268,13 @@ public void SimpleTest2() // Fetch the first record reader.Read(); - Assert.AreEqual(1, reader.GetInt32(0)); - Assert.AreEqual(2, reader.GetInt32(1)); - Assert.AreEqual(3, reader.GetInt32(2)); - Assert.AreEqual(4, reader.GetInt32(3)); - Assert.AreEqual(5, reader.GetInt32(4)); - Assert.AreEqual(6, reader.GetInt32(5)); - Assert.AreEqual(7, reader.GetInt32(6)); + Assert.That(reader.GetInt32(0), Is.EqualTo(1)); + Assert.That(reader.GetInt32(1), Is.EqualTo(2)); + Assert.That(reader.GetInt32(2), Is.EqualTo(3)); + Assert.That(reader.GetInt32(3), Is.EqualTo(4)); + Assert.That(reader.GetInt32(4), Is.EqualTo(5)); + Assert.That(reader.GetInt32(5), Is.EqualTo(6)); + Assert.That(reader.GetInt32(6), Is.EqualTo(7)); } } @@ -313,23 +314,23 @@ public void Bug6271() cmd.Parameters.AddWithValue("?dt", dt); cmd.Prepare(); int count = cmd.ExecuteNonQuery(); - Assert.AreEqual(1, count); + Assert.That(count, Is.EqualTo(1)); cmd.CommandText = "SELECT * FROM Test2"; using (MySqlDataReader reader = cmd.ExecuteReader()) { - Assert.True(reader.Read()); - Assert.AreEqual("Ceci est un nom", reader.GetString(1)); - Assert.AreEqual(dt.ToString("G"), reader.GetDateTime(4).ToString("G")); - Assert.AreEqual("Ceci est une description facile à plantouiller", reader.GetString(2)); + Assert.That(reader.Read()); + Assert.That(reader.GetString(1), Is.EqualTo("Ceci est un nom")); + Assert.That(reader.GetDateTime(4).ToString("G"), Is.EqualTo(dt.ToString("G"))); + Assert.That(reader.GetString(2), Is.EqualTo("Ceci est une description facile à plantouiller")); long len = reader.GetBytes(3, 0, null, 0, 0); - Assert.AreEqual(xpDOSG_Avatar.Length, len); + Assert.That(len, Is.EqualTo(xpDOSG_Avatar.Length)); byte[] outBytes = new byte[len]; reader.GetBytes(3, 0, outBytes, 0, (int)len); for (int x = 0; x < xpDOSG_Avatar.Length; x++) - Assert.AreEqual(xpDOSG_Avatar[x], outBytes[x]); + Assert.That(outBytes[x], Is.EqualTo(xpDOSG_Avatar[x])); } } @@ -386,8 +387,7 @@ public void InsertAccentedCharacters() cmd.ExecuteNonQuery(); MySqlCommand cmd2 = new MySqlCommand("SELECT input FROM Test", conn2); - Assert.AreEqual("irache martínez@yahoo.es aol.com", - cmd2.ExecuteScalar()); + Assert.That(cmd2.ExecuteScalar(), Is.EqualTo("irache martínez@yahoo.es aol.com")); } } @@ -412,17 +412,17 @@ public void UsingParametersTwice() cmd.Parameters["?st"].Value = 1; cmd.Parameters["?sc"].Value = 42; int result = cmd.ExecuteNonQuery(); - Assert.AreEqual(1, result); + Assert.That(result, Is.EqualTo(1)); MySqlCommand cmd2 = new MySqlCommand("SELECT * FROM Test", Connection); using (var reader = cmd2.ExecuteReader()) { - Assert.True(reader.Read()); - Assert.AreEqual("test", reader.GetString("input")); - Assert.AreEqual(1, reader.GetValue(reader.GetOrdinal("state"))); - Assert.AreEqual(42, reader.GetValue(reader.GetOrdinal("score"))); + Assert.That(reader.Read()); + Assert.That(reader.GetString("input"), Is.EqualTo("test")); + Assert.That(reader.GetValue(reader.GetOrdinal("state")), Is.EqualTo(1)); + Assert.That(reader.GetValue(reader.GetOrdinal("score")), Is.EqualTo(42)); - Assert.False(reader.Read()); + Assert.That(reader.Read(), Is.False); } } @@ -469,7 +469,7 @@ public void MoreParametersOutOfOrder() cmd.Prepare(); int cnt = cmd.ExecuteNonQuery(); - Assert.AreEqual(1, cnt); + Assert.That(cnt, Is.EqualTo(1)); } /// @@ -493,11 +493,11 @@ public void ParameterLengths() MySqlCommand cmd2 = new MySqlCommand("SELECT * FROM Test", Connection); using (var reader = cmd2.ExecuteReader()) { - Assert.True(reader.Read()); - Assert.AreEqual(1, reader.GetValue(reader.GetOrdinal("id"))); - Assert.AreEqual("short string", reader.GetString("name")); + Assert.That(reader.Read()); + Assert.That(reader.GetValue(reader.GetOrdinal("id")), Is.EqualTo(1)); + Assert.That(reader.GetString("name"), Is.EqualTo("short string")); - Assert.False(reader.Read()); + Assert.That(reader.Read(), Is.False); } } @@ -524,22 +524,22 @@ public void UnsignedTinyInt() command.Parameters.AddWithValue("?id", (byte)127); command.Prepare(); int count = Convert.ToInt32(command.ExecuteScalar()); - Assert.AreEqual(1, count); + Assert.That(count, Is.EqualTo(1)); command.Parameters.Clear(); command.Parameters.AddWithValue("?id", (byte)128); count = Convert.ToInt32(command.ExecuteScalar()); - Assert.AreEqual(1, count); + Assert.That(count, Is.EqualTo(1)); command.Parameters.Clear(); command.Parameters.AddWithValue("?id", (byte)255); count = Convert.ToInt32(command.ExecuteScalar()); - Assert.AreEqual(1, count); + Assert.That(count, Is.EqualTo(1)); command.Parameters.Clear(); command.Parameters.AddWithValue("?id", "255"); count = Convert.ToInt32(command.ExecuteScalar()); - Assert.AreEqual(1, count); + Assert.That(count, Is.EqualTo(1)); } /// @@ -562,16 +562,16 @@ public void UnsignedValues() cmd.Parameters[1].Value = UInt32.MaxValue; cmd.Parameters[2].Value = 16777215; cmd.Parameters[3].Value = UInt16.MaxValue; - Assert.AreEqual(1, cmd.ExecuteNonQuery()); + Assert.That(cmd.ExecuteNonQuery(), Is.EqualTo(1)); cmd.CommandText = "SELECT * FROM Test"; cmd.CommandType = CommandType.Text; using (MySqlDataReader reader = cmd.ExecuteReader()) { reader.Read(); - Assert.AreEqual(UInt64.MaxValue, reader.GetUInt64(0)); - Assert.AreEqual(UInt32.MaxValue, reader.GetUInt32(1)); - Assert.AreEqual(16777215, Convert.ToInt32(reader.GetUInt32(2))); - Assert.AreEqual(UInt16.MaxValue, reader.GetUInt16(3)); + Assert.That(reader.GetUInt64(0), Is.EqualTo(UInt64.MaxValue)); + Assert.That(reader.GetUInt32(1), Is.EqualTo(UInt32.MaxValue)); + Assert.That(Convert.ToInt32(reader.GetUInt32(2)), Is.EqualTo(16777215)); + Assert.That(reader.GetUInt16(3), Is.EqualTo(UInt16.MaxValue)); } } @@ -607,7 +607,7 @@ PRIMARY KEY(`one`) cmd.Parameters.AddWithValue("@One", "test").MySqlDbType = MySqlDbType.VarChar; cmd.Prepare(); var result = cmd.ExecuteNonQuery(); - Assert.AreEqual(1, result); + Assert.That(result, Is.EqualTo(1)); } } @@ -620,7 +620,7 @@ public void PrepareEmptyString() MySqlCommand cmd = new MySqlCommand("", Connection); cmd.Prepare(); Exception ex = Assert.Throws(() => cmd.ExecuteNonQuery()); - Assert.AreEqual("The CommandText property has not been properly initialized.", ex.Message); + Assert.That(ex.Message, Is.EqualTo("The CommandText property has not been properly initialized")); } /// @@ -639,7 +639,7 @@ public void CompoundStatements() cmd.Parameters.Add("?t1", MySqlDbType.Int32); cmd.Parameters.Add("?t2", MySqlDbType.Int32); Exception ex = Assert.Throws(() => cmd.Prepare()); - StringAssert.Contains("You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version", ex.Message); + Assert.That(ex.Message, Does.Contain("You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version")); } [Test] @@ -692,7 +692,7 @@ public void ClosingCommandsProperly() } } c.Ping(); - Assert.AreEqual(initialCount, GetPreparedStatementCount()); + Assert.That(GetPreparedStatementCount(), Is.EqualTo(initialCount)); } } @@ -722,13 +722,13 @@ public void InsertingUnsignedTinyInt() MySqlCommand cmd2 = new MySqlCommand("SELECT * FROM Test", Connection); using (var reader = cmd2.ExecuteReader()) { - Assert.True(reader.Read()); - Assert.AreEqual(127, Convert.ToInt32(reader.GetValue(0))); - Assert.AreEqual(1, Convert.ToInt32(reader.GetValue(1))); - Assert.AreEqual(2, Convert.ToInt32(reader.GetValue(2))); - Assert.AreEqual(3, Convert.ToInt32(reader.GetValue(3))); + Assert.That(reader.Read()); + Assert.That(Convert.ToInt32(reader.GetValue(0)), Is.EqualTo(127)); + Assert.That(Convert.ToInt32(reader.GetValue(1)), Is.EqualTo(1)); + Assert.That(Convert.ToInt32(reader.GetValue(2)), Is.EqualTo(2)); + Assert.That(Convert.ToInt32(reader.GetValue(3)), Is.EqualTo(3)); - Assert.False(reader.Read()); + Assert.That(reader.Read(), Is.False); } } @@ -783,7 +783,7 @@ internal void NegativeTime(bool prepared) { reader.Read(); TimeSpan t = reader.GetTimeSpan(1); - Assert.AreEqual(ts, t); + Assert.That(t, Is.EqualTo(ts)); } } } @@ -801,9 +801,9 @@ private void ReadNegativeTime(bool prepared) { reader.Read(); TimeSpan ts = reader.GetTimeSpan(1); - Assert.AreEqual(0, ts.Hours); - Assert.AreEqual(-10, ts.Minutes); - Assert.AreEqual(0, ts.Seconds); + Assert.That(ts.Hours, Is.EqualTo(0)); + Assert.That(ts.Minutes, Is.EqualTo(-10)); + Assert.That(ts.Seconds, Is.EqualTo(0)); } } @@ -824,12 +824,12 @@ public void ZeroTimePrepared() { reader.Read(); var t = reader.GetValue(0); - Assert.AreEqual("00:00:00", t.ToString()); + Assert.That(t.ToString(), Is.EqualTo("00:00:00")); TimeSpan timeSpan = reader.GetTimeSpan(0); - Assert.AreEqual(0, timeSpan.Hours); - Assert.AreEqual(0, timeSpan.Minutes); - Assert.AreEqual(0, timeSpan.Seconds); + Assert.That(timeSpan.Hours, Is.EqualTo(0)); + Assert.That(timeSpan.Minutes, Is.EqualTo(0)); + Assert.That(timeSpan.Seconds, Is.EqualTo(0)); } } @@ -846,17 +846,17 @@ public void SprocOutputParams() cmd.Prepare(); cmd.Parameters[0].Value = 20; - Assert.AreEqual(0, cmd.ExecuteNonQuery()); - Assert.AreEqual(20, cmd.Parameters[1].Value); + Assert.That(cmd.ExecuteNonQuery(), Is.EqualTo(0)); + Assert.That(cmd.Parameters[1].Value, Is.EqualTo(20)); ExecuteSQL("DROP PROCEDURE IF EXISTS spOutTest"); ExecuteSQL("CREATE PROCEDURE spOutTest(id INT, OUT age INT) BEGIN SET age=age*2; END"); cmd.Parameters[0].Value = 1; cmd.Parameters[1].Value = 20; - Assert.AreEqual(0, cmd.ExecuteNonQuery()); + Assert.That(cmd.ExecuteNonQuery(), Is.EqualTo(0)); - Assert.IsInstanceOf(cmd.Parameters[1].Value); + Assert.That(cmd.Parameters[1].Value, Is.InstanceOf()); } @@ -873,8 +873,8 @@ public void SprocInputOutputParams() cmd.Parameters[0].Value = 1; cmd.Parameters[1].Value = 20; - Assert.AreEqual(0, cmd.ExecuteNonQuery()); - Assert.AreEqual(40, cmd.Parameters[1].Value); + Assert.That(cmd.ExecuteNonQuery(), Is.EqualTo(0)); + Assert.That(cmd.Parameters[1].Value, Is.EqualTo(40)); } /// @@ -897,7 +897,7 @@ public void BigIntUnsigned() { rdr.Read(); UInt64 v = rdr.GetUInt64(0); - Assert.AreEqual(3000000000, v); + Assert.That(v, Is.EqualTo(3000000000)); } } @@ -923,7 +923,7 @@ public void InconsistentBehaviorForSelectLimit() int rows = 0; while (result.Read()) rows += 1; - Assert.AreEqual(3, rows); + Assert.That(rows, Is.EqualTo(3)); } } @@ -952,7 +952,7 @@ public void MySqlDbTypeEnumParameter() command.CommandText = "SELECT * FROM Test"; using var reader = command.ExecuteReader(); while (reader.Read()) - Assert.True(dataEnum.Contains(reader.GetString(0))); + Assert.That(dataEnum.Contains(reader.GetString(0))); } } } diff --git a/MySQL.Data/tests/MySql.Data.Tests/Properties/AssemblyInfo.cs b/MySQL.Data/tests/MySql.Data.Tests/Properties/AssemblyInfo.cs index 42b344ad7..9a48da313 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/Properties/AssemblyInfo.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/Properties/AssemblyInfo.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2004, 2019, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2004, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -40,7 +40,7 @@ [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Oracle")] [assembly: AssemblyProduct("MySql.Data.Tests")] -[assembly: AssemblyCopyright("Copyright © 2004, 2019, Oracle and/or its affiliates. All rights reserved.")] +[assembly: AssemblyCopyright("Copyright © 2004, 2025, Oracle and/or its affiliates.")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/MySQL.Data/tests/MySql.Data.Tests/Resources/KerberosConfig.txt b/MySQL.Data/tests/MySql.Data.Tests/Resources/KerberosConfig.txt deleted file mode 100644 index d5e2dd534..000000000 --- a/MySQL.Data/tests/MySql.Data.Tests/Resources/KerberosConfig.txt +++ /dev/null @@ -1,68 +0,0 @@ - -------- CLIENT -------- -Linux prerequisites: -libsasl2.4-2 -libsasl2-modules-gssapi-mit -krb5-config -krb5-user - -Windows prerequisites: -There's a quick guide to follow: https://confluence.oraclecorp.com/confluence/display/MYSQL/MySQL+windows+client+support+for+kerberos -Step 3 is really important for this to work. - --------- SERVER -------- -krb5.conf structure: -[libdefaults] - default_realm = MYSQL.LOCAL - dns_lookup_realm = false - dns_lookup_kdc = false - dns_fallback = false - -[realms] - MYSQL.LOCAL = { - kdc = ldapauth.appad3iad.mysql2iad.oraclevcn.com - admin_server = ldapauth.appad3iad.mysql2iad.oraclevcn.com - default_domain = MYSQL.LOCAL - } - -[domain_realm] - .no.oracle.com = MYSQL.LOCAL - - -Add following line to /etc/hosts: -100.103.18.98 ldapauth ldapauth.appad3iad.mysql2iad.oraclevcn.com - - --------------------------- GSSAPI -------------------------- - -In case my.ini is not working, start server as follow: -sudo ./bin/mysqld --port=3306 --bind-address=localhost --user=mysql --basedir=/usr --datadir=/var/lib/mysql --plugin_dir=/usr/local/mysql/lib/plugin ---plugin-load=authentication_ldap_sasl.so --authentication_ldap_sasl_server_host=ldapauth.appad3iad.mysql2iad.oraclevcn.com ---authentication_ldap_sasl_group_search_attr='cn' --authentication_ldap_sasl_auth_method_name='GSSAPI' --authentication_ldap_sasl_log_status=5 ---log_error_verbosity=3 --authentication_ldap_sasl_bind_root_pwd="Testpw1" --authentication_ldap_sasl_bind_root_dn="CN=test2,CN=Users,DC=mysql,DC=local" ---authentication_ldap_sasl_bind_base_dn='CN=Users,DC=mysql,DC=local' - - -Create LDAP SASL User: -INSTALL PLUGIN authentication_ldap_sasl SONAME 'authentication_ldap_sasl.so'; -CREATE USER 'test1@MYSQL.LOCAL' IDENTIFIED WITH authentication_ldap_sasl; - -sudo AUTHENTICATION_LDAP_CLIENT_LOG=5 ./bin/mysql --user=test1@MYSQL.LOCAL --password=Testpw1 --port 3306 - --------------------------- KERBEROS -------------------------- - -sudo ./bin/mysqld --port=3306 --user=mysql --basedir=/usr --datadir=/var/lib/mysql --plugin_dir=/usr/local/mysql/lib/plugin --log_error_verbosity=3 ---plugin-load=authentication_kerberos.so --authentication_kerberos_service_principal='mysql_service/kerberos_auth_host@MYSQL.LOCAL' ---authentication_kerberos_service_key_tab=/usr/local/mysql/mysql.keytab - -Create the following MySQL accounts: - -CREATE USER 'test1'@'%' IDENTIFIED WITH authentication_kerberos BY 'MYSQL.LOCAL'; -GRANT ALL ON *.* to 'test1'@'%'; - -CREATE USER 'test2'@'%' IDENTIFIED WITH authentication_kerberos BY 'MYSQL.LOCAL'; -GRANT ALL ON *.* to 'test2'@'%'; - -CREATE USER 'test3'@'%' IDENTIFIED WITH authentication_kerberos BY 'MYSQL.LOCAL'; -GRANT ALL ON *.* to 'test3'@'%'; - -sudo AUTHENTICATION_KERBEROS_CLIENT_LOG=5 ./bin/mysql --user=test1 --password=Testpw1 \ No newline at end of file diff --git a/MySQL.Data/tests/MySql.Data.Tests/Resources/mtr.keytab b/MySQL.Data/tests/MySql.Data.Tests/Resources/mtr.keytab new file mode 100644 index 000000000..e62515972 Binary files /dev/null and b/MySQL.Data/tests/MySql.Data.Tests/Resources/mtr.keytab differ diff --git a/MySQL.Data/tests/MySql.Data.Tests/Resources/my.ini b/MySQL.Data/tests/MySql.Data.Tests/Resources/my.ini index 82e5f7670..9cc75dd70 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/Resources/my.ini +++ b/MySQL.Data/tests/MySql.Data.Tests/Resources/my.ini @@ -29,18 +29,3 @@ authentication_ldap_sasl_auth_method_name='SCRAM-SHA-256' authentication_ldap_sasl_log_status=6 authentication_ldap_sasl_group_search_attr='' authentication_ldap_sasl_user_search_attr='cn' - -### GSSAPI -plugin-load-add=authentication_ldap_sasl.so -authentication_ldap_sasl_server_host='ldapauth.appad3iad.mysql2iad.oraclevcn.com' -authentication_ldap_sasl_bind_base_dn='CN=Users,DC=mysql,DC=local' -authentication_ldap_sasl_auth_method_name='GSSAPI' -authentication_ldap_sasl_bind_root_dn='CN=test2,CN=Users,DC=mysql,DC=local' -authentication_ldap_sasl_log_status=6 -authentication_ldap_sasl_group_search_attr='cn' -authentication_ldap_sasl_bind_root_pwd='Testpw1' - -### KERBEROS -plugin-load-add = authentication_kerberos.so -authentication_kerberos_service_principal = "mysql_service/kerberos_auth_host@MYSQL.LOCAL" -authentication_kerberos_service_key_tab = "{full_path_to:mysql.keytab}" \ No newline at end of file diff --git a/MySQL.Data/tests/MySql.Data.Tests/Resources/mysql.keytab b/MySQL.Data/tests/MySql.Data.Tests/Resources/mysql.keytab deleted file mode 100644 index 91ab57a93..000000000 Binary files a/MySQL.Data/tests/MySql.Data.Tests/Resources/mysql.keytab and /dev/null differ diff --git a/MySQL.Data/tests/MySql.Data.Tests/ScriptExecution.cs b/MySQL.Data/tests/MySql.Data.Tests/ScriptExecution.cs index 531ea1d48..8df02c17a 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/ScriptExecution.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/ScriptExecution.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2021, Oracle and/or its affiliates. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -30,6 +30,7 @@ using System.Text; using System.Threading.Tasks; using NUnit.Framework; +using NUnit.Framework.Legacy; namespace MySql.Data.MySqlClient.Tests { @@ -57,19 +58,19 @@ public void ExecuteScriptWithProcedures() script.Connection = Connection; script.Delimiter = "$$"; int count = script.Execute(); - Assert.AreEqual(10, count); + Assert.That(count, Is.EqualTo(10)); MySqlCommand cmd = new MySqlCommand( String.Format(@"SELECT COUNT(*) FROM information_schema.routines WHERE routine_schema = '{0}' AND routine_name LIKE 'spTest1-%'", Connection.Database), Connection); - Assert.AreEqual(10, Convert.ToInt32(cmd.ExecuteScalar())); + Assert.That(Convert.ToInt32(cmd.ExecuteScalar()), Is.EqualTo(10)); } void ExecuteScriptWithProcedures_QueryExecuted(object sender, MySqlScriptEventArgs e) { string stmt = String.Format(statementTemplate1, statementCount++, null); - Assert.AreEqual(stmt, e.StatementText); + Assert.That(e.StatementText, Is.EqualTo(stmt)); } private string statementTemplate2 = @"INSERT INTO Test (id, name) VALUES ({0}, 'a "" na;me'){1}"; @@ -88,16 +89,16 @@ public void ExecuteScriptWithInserts() script.Connection = Connection; script.StatementExecuted += new MySqlStatementExecutedEventHandler(ExecuteScriptWithInserts_StatementExecuted); int count = script.Execute(); - Assert.AreEqual(10, count); + Assert.That(count, Is.EqualTo(10)); MySqlCommand cmd = new MySqlCommand("SELECT COUNT(*) FROM Test", Connection); - Assert.AreEqual(10, Convert.ToInt32(cmd.ExecuteScalar())); + Assert.That(Convert.ToInt32(cmd.ExecuteScalar()), Is.EqualTo(10)); } void ExecuteScriptWithInserts_StatementExecuted(object sender, MySqlScriptEventArgs e) { string stmt = String.Format(statementTemplate2, statementCount++, null); - Assert.AreEqual(stmt, e.StatementText); + Assert.That(e.StatementText, Is.EqualTo(stmt)); } [Test] @@ -115,11 +116,11 @@ public void ExecuteScriptContinueOnFailure() script.Connection = Connection; script.Error += new MySqlScriptErrorEventHandler(ExecuteScript_ContinueOnError); int count = script.Execute(); - Assert.AreEqual((int)10, count); - Assert.AreEqual((int)1, statementCount); + Assert.That(count, Is.EqualTo((int)10)); + Assert.That(statementCount, Is.EqualTo((int)1)); MySqlCommand cmd = new MySqlCommand("SELECT COUNT(*) FROM Test", Connection); - Assert.AreEqual(10, Convert.ToInt32(cmd.ExecuteScalar())); + Assert.That(Convert.ToInt32(cmd.ExecuteScalar()), Is.EqualTo(10)); } void ExecuteScript_ContinueOnError(object sender, MySqlScriptErrorEventArgs args) @@ -143,11 +144,11 @@ public void ExecuteScriptNotContinueOnFailure() script.Connection = Connection; script.Error += new MySqlScriptErrorEventHandler(ExecuteScript_NotContinueOnError); int count = script.Execute(); - Assert.AreEqual(5, count); - Assert.AreEqual(1, statementCount); + Assert.That(count, Is.EqualTo(5)); + Assert.That(statementCount, Is.EqualTo(1)); MySqlCommand cmd = new MySqlCommand("SELECT COUNT(*) FROM Test", Connection); - Assert.AreEqual(5, Convert.ToInt32(cmd.ExecuteScalar())); + Assert.That(Convert.ToInt32(cmd.ExecuteScalar()), Is.EqualTo(5)); } void ExecuteScript_NotContinueOnError(object sender, MySqlScriptErrorEventArgs args) @@ -169,7 +170,7 @@ public void ExecuteScriptWithUserVariables() MySqlScript script = new MySqlScript(scriptText); script.Connection = c; int count = script.Execute(); - Assert.AreEqual(1, count); + Assert.That(count, Is.EqualTo(1)); } } @@ -255,17 +256,17 @@ public async Task ExecuteScriptWithProceduresAsync() script.StatementExecuted += new MySqlStatementExecutedEventHandler(delegate(object sender, MySqlScriptEventArgs e) { string stmt = String.Format(spTpl, statementCount++, null); - Assert.AreEqual(stmt, e.StatementText); + Assert.That(e.StatementText, Is.EqualTo(stmt)); }); script.Connection = Connection; script.Delimiter = "$$"; int count = await script.ExecuteAsync(); - Assert.AreEqual(10, count); + Assert.That(count, Is.EqualTo(10)); MySqlCommand cmd = new MySqlCommand( String.Format(@"SELECT COUNT(*) FROM information_schema.routines WHERE routine_schema = '{0}' AND routine_name LIKE 'SEScriptWithProceduresAsyncSpTest%'", Connection.Database), Connection); - Assert.AreEqual(10, Convert.ToInt32(cmd.ExecuteScalar())); + Assert.That(Convert.ToInt32(cmd.ExecuteScalar()), Is.EqualTo(10)); } [Test] @@ -284,13 +285,13 @@ public async Task ExecuteScriptWithInsertsAsync() script.StatementExecuted += new MySqlStatementExecutedEventHandler(delegate(object sender, MySqlScriptEventArgs e) { string stmt = String.Format(queryTpl, statementCount++, null); - Assert.AreEqual(stmt, e.StatementText); + Assert.That(e.StatementText, Is.EqualTo(stmt)); }); int count = await script.ExecuteAsync(); - Assert.AreEqual(10, count); + Assert.That(count, Is.EqualTo(10)); MySqlCommand cmd = new MySqlCommand("SELECT COUNT(*) FROM SEScriptWithInsertsAsyncTest", Connection); - Assert.AreEqual(10, Convert.ToInt32(cmd.ExecuteScalar())); + Assert.That(Convert.ToInt32(cmd.ExecuteScalar()), Is.EqualTo(10)); } #endregion @@ -312,7 +313,7 @@ public void ScriptDelimiter() script.Query = sql; script.Delimiter = "??"; var count = script.Execute(); - Assert.AreEqual(3, count); + Assert.That(count, Is.EqualTo(3)); } } diff --git a/MySQL.Data/tests/MySql.Data.Tests/SimpleTransactions.cs b/MySQL.Data/tests/MySql.Data.Tests/SimpleTransactions.cs index d3a209a02..00d1d4148 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/SimpleTransactions.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/SimpleTransactions.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2021, Oracle and/or its affiliates. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -28,6 +28,7 @@ using System; using NUnit.Framework; +using NUnit.Framework.Legacy; using System.Data; using System.Reflection; @@ -48,11 +49,11 @@ public void TestReader() MySqlTransaction txn = Connection.BeginTransaction(); MySqlConnection c = txn.Connection; - Assert.AreEqual(Connection, c); + Assert.That(c, Is.EqualTo(Connection)); MySqlCommand cmd = new MySqlCommand("SELECT name, name2 FROM Test WHERE key2='P'", Connection, txn); MySqlTransaction t2 = cmd.Transaction; - Assert.AreEqual(txn, t2); + Assert.That(t2, Is.EqualTo(txn)); MySqlDataReader reader = null; try { @@ -62,7 +63,7 @@ public void TestReader() } catch (Exception ex) { - Assert.False(ex.Message != string.Empty, ex.Message); + Assert.That(ex.Message != string.Empty, Is.False, ex.Message); txn.Rollback(); } finally @@ -80,7 +81,7 @@ public void NestedTransactions() MySqlTransaction t1 = Connection.BeginTransaction(); Exception ex = Assert.Throws(() => { Connection.BeginTransaction(); }); - Assert.AreEqual("Nested transactions are not supported.", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Nested transactions are not supported")); t1.Rollback(); } @@ -98,7 +99,7 @@ public void BeginTransactionOnPreviouslyOpenConnection() } catch (Exception ex) { - Assert.AreEqual("The connection is not open.", ex.Message); + Assert.That(ex.Message, Is.EqualTo("The connection is not open")); } } @@ -127,12 +128,12 @@ public void CommitAfterConnectionDead() //try //{ Exception ex = Assert.Throws(() => trans.Commit()); - Assert.AreEqual("Connection must be valid and open to commit transaction", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Connection must be valid and open to commit transaction")); //} //catch (Exception) //{ //} - Assert.AreEqual(ConnectionState.Closed, c.State); + Assert.That(c.State, Is.EqualTo(ConnectionState.Closed)); c.Close(); // this should work even though we are closed } } @@ -154,7 +155,7 @@ public void DisposingCallsRollback() Type t = txn.GetType(); FieldInfo fi = t.GetField("open", BindingFlags.Instance | BindingFlags.NonPublic); bool isOpen = (bool)fi.GetValue(txn); - Assert.False(isOpen); + Assert.That(isOpen, Is.False); } [Test] @@ -196,7 +197,7 @@ public void TransactionScope() myTransaction.Rollback(); // to rollback actions cmdtoexec.CommandText = "select count(*) from transactiontable"; var count = cmdtoexec.ExecuteScalar(); - Assert.AreEqual(0,count); + Assert.That(count, Is.EqualTo(0)); } } diff --git a/MySQL.Data/tests/MySql.Data.Tests/SqlServerMode.cs b/MySQL.Data/tests/MySql.Data.Tests/SqlServerMode.cs index 3e031740d..bbf289029 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/SqlServerMode.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/SqlServerMode.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -27,6 +27,7 @@ // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA using NUnit.Framework; +using NUnit.Framework.Legacy; namespace MySql.Data.MySqlClient.Tests { @@ -47,9 +48,9 @@ public void Simple() using (MySqlDataReader reader = cmd.ExecuteReader()) { reader.Read(); - Assert.AreEqual(1, reader.GetInt32(0)); - Assert.AreEqual("A", reader.GetString(1)); + Assert.That(reader.GetInt32(0), Is.EqualTo(1)); + Assert.That(reader.GetString(1), Is.EqualTo("A")); } } } -} \ No newline at end of file +} diff --git a/MySQL.Data/tests/MySql.Data.Tests/SqlTokenizer.cs b/MySQL.Data/tests/MySql.Data.Tests/SqlTokenizer.cs index 32e4eb244..a512bfb2f 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/SqlTokenizer.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/SqlTokenizer.cs @@ -1,16 +1,16 @@ -// Copyright © 2013, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/tests/MySql.Data.Tests/SslTests.cs b/MySQL.Data/tests/MySql.Data.Tests/SslTests.cs index b0c0987c6..54276c39d 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/SslTests.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/SslTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2018, 2022, Oracle and/or its affiliates. +// Copyright © 2018, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -29,6 +29,7 @@ using MySql.Data.Common; using MySqlX.XDevAPI; using NUnit.Framework; +using NUnit.Framework.Legacy; using System; using System.Collections.Generic; using System.Data; @@ -63,8 +64,8 @@ public void SslModePreferredByDefault() MySqlCommand command = new MySqlCommand("SHOW SESSION STATUS LIKE 'Ssl_version';", Connection); using (MySqlDataReader reader = command.ExecuteReader()) { - Assert.True(reader.Read()); - StringAssert.StartsWith("TLSv1", reader.GetString(1)); + Assert.That(reader.Read()); + Assert.That(reader.GetString(1), Does.StartWith("TLSv1")); } } @@ -82,8 +83,8 @@ public void SslModeOverriden() MySqlCommand command = new MySqlCommand("SHOW SESSION STATUS LIKE 'Ssl_version';", connection); using (MySqlDataReader reader = command.ExecuteReader()) { - Assert.True(reader.Read()); - Assert.AreEqual(string.Empty, reader.GetString(1)); + Assert.That(reader.Read()); + Assert.That(reader.GetString(1), Is.EqualTo(string.Empty)); } } } @@ -97,42 +98,42 @@ public void RepeatedSslConnectionOptions() var builder = new MySqlConnectionStringBuilder(Settings.ConnectionString); builder.SslCa = _sslCa; var conn = new MySqlConnection($"{builder.ConnectionString};sslca={repeatedOption}"); - Assert.AreEqual(repeatedOption, conn.Settings.SslCa); + Assert.That(conn.Settings.SslCa, Is.EqualTo(repeatedOption)); builder = new MySqlConnectionStringBuilder(Settings.ConnectionString); builder.CertificateFile = _sslCa; conn = new MySqlConnection($"{builder.ConnectionString};certificatefile={repeatedOption}"); - Assert.AreEqual(repeatedOption, conn.Settings.CertificateFile); + Assert.That(conn.Settings.CertificateFile, Is.EqualTo(repeatedOption)); builder = new MySqlConnectionStringBuilder(Settings.ConnectionString); builder.SslCa = _sslCa; conn = new MySqlConnection($"{builder.ConnectionString};certificatefile={repeatedOption}"); - Assert.AreEqual(repeatedOption, conn.Settings.CertificateFile); + Assert.That(conn.Settings.CertificateFile, Is.EqualTo(repeatedOption)); builder = new MySqlConnectionStringBuilder(Settings.ConnectionString); builder.CertificateFile = _sslCa; conn = new MySqlConnection($"{builder.ConnectionString};sslca={repeatedOption}"); - Assert.AreEqual(repeatedOption, conn.Settings.SslCa); + Assert.That(conn.Settings.SslCa, Is.EqualTo(repeatedOption)); builder = new MySqlConnectionStringBuilder(Settings.ConnectionString); builder.SslCa = _sslCa; conn = new MySqlConnection($"{builder.ConnectionString};sslcert={_sslCert};sslkey={_sslKey};sslca={repeatedOption}"); - Assert.AreEqual(repeatedOption, conn.Settings.SslCa); + Assert.That(conn.Settings.SslCa, Is.EqualTo(repeatedOption)); builder = new MySqlConnectionStringBuilder(Settings.ConnectionString); builder.CertificatePassword = "pass"; conn = new MySqlConnection($"{builder.ConnectionString};certificatepassword={repeatedOption}"); - Assert.AreEqual(repeatedOption, conn.Settings.CertificatePassword); + Assert.That(conn.Settings.CertificatePassword, Is.EqualTo(repeatedOption)); builder = new MySqlConnectionStringBuilder(Settings.ConnectionString); builder.SslCert = _sslCert; conn = new MySqlConnection($"{builder.ConnectionString};sslcert={repeatedOption}"); - Assert.AreEqual(repeatedOption, conn.Settings.SslCert); + Assert.That(conn.Settings.SslCert, Is.EqualTo(repeatedOption)); builder = new MySqlConnectionStringBuilder(Settings.ConnectionString); builder.SslKey = _sslKey; conn = new MySqlConnection($"{builder.ConnectionString};sslkey={repeatedOption}"); - Assert.AreEqual(repeatedOption, conn.Settings.SslKey); + Assert.That(conn.Settings.SslKey, Is.EqualTo(repeatedOption)); } [Test] @@ -172,8 +173,8 @@ public void SslPreferredByDefault() MySqlCommand command = new MySqlCommand("SHOW SESSION STATUS LIKE 'Ssl_version';", Connection); using (MySqlDataReader reader = command.ExecuteReader()) { - Assert.True(reader.Read()); - StringAssert.StartsWith("TLSv1", reader.GetString(1)); + Assert.That(reader.Read()); + Assert.That(reader.GetString(1), Does.StartWith("TLSv1")); } } @@ -191,14 +192,15 @@ public void SslOverrided() MySqlCommand command = new MySqlCommand("SHOW SESSION STATUS LIKE 'Ssl_version';", connection); using (MySqlDataReader reader = command.ExecuteReader()) { - Assert.True(reader.Read()); - Assert.AreEqual(string.Empty, reader.GetString(1)); + Assert.That(reader.Read()); + Assert.That(reader.GetString(1), Is.EqualTo(string.Empty)); } } } /// /// WL14811 - Remove support for TLS 1.0 and 1.1 + /// WL16176 - Add support for TLS 1.3 /// [TestCase("[]", 1)] [TestCase("Tlsv1, Tlsv1.1", 2)] @@ -208,39 +210,30 @@ public void SslOverrided() [TestCase("foo, bar", 3)] [TestCase("Tlsv1.0, Tlsv1.2", 0)] [TestCase("foo, Tlsv1.2", 0)] - //#if NET48 || NETCOREAPP3_1 || NET5_0 || NET6_0 - // [TestCase("Tlsv1.3", "Tlsv1.3")] - // [TestCase("Tlsv1.0, Tlsv1.1, Tlsv1.2, Tlsv1.3", "Tlsv1.3")] - //#endif -#if NET452 [TestCase("Tlsv1.3", 4)] - [TestCase("Tlsv1.0, Tlsv1.1, Tlsv1.2, Tlsv1.3", 0)] -#endif [Property("Category", "Security")] public void TlsVersionTest(string tlsVersion, int error) { + Assume.That(error != 4 || !Platform.IsMacOSX()); + var builder = new MySqlConnectionStringBuilder(Connection.ConnectionString); void SetTlsVersion() { builder.TlsVersion = tlsVersion; } string ex; - string tls = "TLSv1.2"; + string tlsdefault = "TLSv1.2"; switch (error) { case 1: ex = Assert.Throws(SetTlsVersion).Message; - StringAssert.AreEqualIgnoringCase(Resources.TlsVersionsEmpty, ex); + Assert.That(ex, Is.EqualTo(Resources.TlsVersionsEmpty).IgnoreCase); break; case 2: ex = Assert.Throws(SetTlsVersion).Message; - StringAssert.AreEqualIgnoringCase(Resources.TlsUnsupportedVersions, ex); + Assert.That(ex, Is.EqualTo(Resources.TlsUnsupportedVersions).IgnoreCase); break; case 3: ex = Assert.Throws(SetTlsVersion).Message; - StringAssert.AreEqualIgnoringCase(Resources.TlsNonValidProtocols, ex); - break; - case 4: - SetTlsVersion(); - Assert.Throws(() => new MySqlConnection(builder.ConnectionString).Open()); + Assert.That(ex, Is.EqualTo(Resources.TlsNonValidProtocols).IgnoreCase); break; default: SetTlsVersion(); @@ -249,16 +242,18 @@ public void TlsVersionTest(string tlsVersion, int error) using (conn) { conn.Open(); - Assert.AreEqual(ConnectionState.Open, conn.State); + Assert.That(conn.State, Is.EqualTo(ConnectionState.Open)); MySqlCommand cmd = conn.CreateCommand(); cmd.CommandText = "SHOW SESSION STATUS LIKE 'ssl_version'"; using MySqlDataReader dr = cmd.ExecuteReader(); - Assert.True(dr.Read()); - StringAssert.AreEqualIgnoringCase(tls, dr[1].ToString()); + Assert.That(dr.Read()); + if (error==4) + Assert.That(dr[1].ToString(), Is.EqualTo(tlsVersion).IgnoreCase); + else + Assert.That(dr[1].ToString(), Is.EqualTo(tlsdefault).IgnoreCase); } - break; } } @@ -279,14 +274,14 @@ public void TlsVersionNoSslTest(string tlsVersion) using (var conn = new MySqlConnection(builder.ConnectionString)) { conn.Open(); - Assert.AreEqual(ConnectionState.Open, conn.State); + Assert.That(conn.State, Is.EqualTo(ConnectionState.Open)); MySqlCommand cmd = conn.CreateCommand(); cmd.CommandText = "SHOW SESSION STATUS LIKE 'ssl_version'"; using MySqlDataReader dr = cmd.ExecuteReader(); - Assert.True(dr.Read()); - Assert.IsEmpty(dr[1].ToString()); + Assert.That(dr.Read()); + Assert.That(dr[1].ToString(), Is.Empty); } } #endregion @@ -310,12 +305,12 @@ public void CanConnectUsingFileBasedCertificate() using (MySqlConnection c = new MySqlConnection(connstr)) { c.Open(); - Assert.AreEqual(ConnectionState.Open, c.State); + Assert.That(c.State, Is.EqualTo(ConnectionState.Open)); MySqlCommand command = new MySqlCommand("SHOW SESSION STATUS LIKE 'Ssl_version';", c); using (MySqlDataReader reader = command.ExecuteReader()) { - Assert.True(reader.Read()); - StringAssert.StartsWith("TLSv1", reader.GetString(1)); + Assert.That(reader.Read()); + Assert.That(reader.GetString(1), Does.StartWith("TLSv1")); } } } @@ -329,26 +324,19 @@ public void ConnectUsingPFXCertificates() using (MySqlConnection c = new MySqlConnection(connstr)) { c.Open(); - Assert.AreEqual(ConnectionState.Open, c.State); + Assert.That(c.State, Is.EqualTo(ConnectionState.Open)); MySqlCommand command = new MySqlCommand("SHOW SESSION STATUS LIKE 'Ssl_version';", c); using (MySqlDataReader reader = command.ExecuteReader()) { - Assert.True(reader.Read()); - StringAssert.StartsWith("TLSv1", reader.GetString(1)); - } - - command = new MySqlCommand("show variables like 'have_ssl';", c); - using (MySqlDataReader reader = command.ExecuteReader()) - { - Assert.True(reader.Read()); - StringAssert.AreEqualIgnoringCase("YES", reader.GetString(1)); + Assert.That(reader.Read()); + Assert.That(reader.GetString(1), Does.StartWith("TLSv1")); } command = new MySqlCommand("show variables like 'tls_version'", c); using (MySqlDataReader reader = command.ExecuteReader()) { - Assert.True(reader.Read()); - StringAssert.Contains("TLS", reader.GetString(1)); + Assert.That(reader.Read()); + Assert.That(reader.GetString(1), Does.Contain("TLS")); } } @@ -375,7 +363,7 @@ public void ConnectUsingPFXCertificates() public void InvalidCertificateThumbprint() { #if !NETFRAMEWORK - if (!System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows)) Assert.Ignore(); + Assume.That(System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows)); #endif // Create a mock of certificate store @@ -397,7 +385,7 @@ public void InvalidCertificateThumbprint() using (var conn = new MySqlConnection(csb.ConnectionString)) { conn.Open(); - Assert.AreEqual(ConnectionState.Open, conn.connectionState); + Assert.That(conn.connectionState, Is.EqualTo(ConnectionState.Open)); } } @@ -412,20 +400,20 @@ public void SslCertificateConnectionOptionsExistAndDefaultToNull() var builder = new MySqlConnectionStringBuilder(); // Options exist. - Assert.True(builder.values.ContainsKey("sslca")); - Assert.True(builder.values.ContainsKey("sslcert")); - Assert.True(builder.values.ContainsKey("sslkey")); + Assert.That(builder.values.ContainsKey("sslca")); + Assert.That(builder.values.ContainsKey("sslcert")); + Assert.That(builder.values.ContainsKey("sslkey")); // Options default to null. - Assert.Null(builder["sslca"]); - Assert.Null(builder["sslcert"]); - Assert.Null(builder["sslkey"]); - Assert.Null(builder["ssl-ca"]); - Assert.Null(builder["ssl-cert"]); - Assert.Null(builder["ssl-key"]); - Assert.Null(builder.SslCa); - Assert.Null(builder.SslCert); - Assert.Null(builder.SslKey); + Assert.That(builder["sslca"], Is.Null); + Assert.That(builder["sslcert"], Is.Null); + Assert.That(builder["sslkey"], Is.Null); + Assert.That(builder["ssl-ca"], Is.Null); + Assert.That(builder["ssl-cert"], Is.Null); + Assert.That(builder["ssl-key"], Is.Null); + Assert.That(builder.SslCa, Is.Null); + Assert.That(builder.SslCert, Is.Null); + Assert.That(builder.SslKey, Is.Null); // Null or whitespace options are ignored. var connectionString = $"host={Settings.Server};user={Settings.UserID};port={Settings.Port};password={Settings.Password};"; @@ -435,9 +423,9 @@ public void SslCertificateConnectionOptionsExistAndDefaultToNull() builder.SslKey = " "; using (var connection = new MySqlConnection(builder.ConnectionString)) { - Assert.Null(connection.Settings.SslCa); - Assert.Null(connection.Settings.SslCert); - Assert.AreEqual(" ", connection.Settings.SslKey); + Assert.That(connection.Settings.SslCa, Is.Null); + Assert.That(connection.Settings.SslCert, Is.Null); + Assert.That(connection.Settings.SslKey, Is.EqualTo(" ")); connection.Open(); connection.Close(); } @@ -446,9 +434,9 @@ public void SslCertificateConnectionOptionsExistAndDefaultToNull() connectionString = $"{connectionString}sslca=;sslcert=;sslkey="; using (var connection = new MySqlConnection(connectionString)) { - Assert.Null(connection.Settings.SslCa); - Assert.Null(connection.Settings.SslCert); - Assert.Null(connection.Settings.SslKey); + Assert.That(connection.Settings.SslCa, Is.Null); + Assert.That(connection.Settings.SslCert, Is.Null); + Assert.That(connection.Settings.SslKey, Is.Null); connection.Open(); connection.Close(); } @@ -463,16 +451,16 @@ public void MissingSslCaConnectionOption() using (var connection = new MySqlConnection(builder.ConnectionString)) { var exception = Assert.Throws(() => connection.Open()); - Assert.AreEqual(Resources.SslConnectionError, exception.Message); - Assert.AreEqual(string.Format(Resources.FilePathNotSet, nameof(Settings.SslCa)), exception.InnerException.Message); + Assert.That(exception.Message, Is.EqualTo(Resources.SslConnectionError)); + Assert.That(exception.InnerException.Message, Is.EqualTo(string.Format(Resources.FilePathNotSet, nameof(Settings.SslCa)))); } builder.SslMode = MySqlSslMode.VerifyFull; using (var connection = new MySqlConnection(builder.ConnectionString)) { var exception = Assert.Throws(() => connection.Open()); - Assert.AreEqual(Resources.SslConnectionError, exception.Message); - Assert.AreEqual(string.Format(Resources.FilePathNotSet, nameof(Settings.SslCa)), exception.InnerException.Message); + Assert.That(exception.Message, Is.EqualTo(Resources.SslConnectionError)); + Assert.That(exception.InnerException.Message, Is.EqualTo(string.Format(Resources.FilePathNotSet, nameof(Settings.SslCa)))); } } @@ -487,8 +475,8 @@ public void MissingSslCertConnectionOption() using (var connection = new MySqlConnection(builder.ConnectionString)) { var exception = Assert.Throws(() => connection.Open()); - Assert.AreEqual(Resources.SslConnectionError, exception.Message); - Assert.AreEqual(string.Format(Resources.FilePathNotSet, nameof(Settings.SslCert)), exception.InnerException.Message); + Assert.That(exception.Message, Is.EqualTo(Resources.SslConnectionError)); + Assert.That(exception.InnerException.Message, Is.EqualTo(string.Format(Resources.FilePathNotSet, nameof(Settings.SslCert)))); } } @@ -504,8 +492,8 @@ public void MissingSslKeyConnectionOption() using (var connection = new MySqlConnection(builder.ConnectionString)) { var exception = Assert.Throws(() => connection.Open()); - Assert.AreEqual(Resources.SslConnectionError, exception.Message); - Assert.AreEqual(string.Format(Resources.FilePathNotSet, nameof(Settings.SslKey)), exception.InnerException.Message); + Assert.That(exception.Message, Is.EqualTo(Resources.SslConnectionError)); + Assert.That(exception.InnerException.Message, Is.EqualTo(string.Format(Resources.FilePathNotSet, nameof(Settings.SslKey)))); } } @@ -519,8 +507,8 @@ public void InvalidFileNameForSslCaConnectionOption() using (var connection = new MySqlConnection(builder.ConnectionString)) { var exception = Assert.Throws(() => connection.Open()); - Assert.AreEqual(Resources.SslConnectionError, exception.Message); - Assert.AreEqual(Resources.FileNotFound, exception.InnerException.Message); + Assert.That(exception.Message, Is.EqualTo(Resources.SslConnectionError)); + Assert.That(exception.InnerException.Message, Is.EqualTo(Resources.FileNotFound)); } } @@ -535,8 +523,8 @@ public void InvalidFileNameForSslCertConnectionOption() using (var connection = new MySqlConnection(builder.ConnectionString)) { var exception = Assert.Throws(() => connection.Open()); - Assert.AreEqual(Resources.SslConnectionError, exception.Message); - Assert.AreEqual(Resources.FileNotFound, exception.InnerException.Message); + Assert.That(exception.Message, Is.EqualTo(Resources.SslConnectionError)); + Assert.That(exception.InnerException.Message, Is.EqualTo(Resources.FileNotFound)); } } @@ -552,8 +540,8 @@ public void InvalidFileNameForSslKeyConnectionOption() using (var connection = new MySqlConnection(builder.ConnectionString)) { var exception = Assert.Throws(() => connection.Open()); - Assert.AreEqual(Resources.SslConnectionError, exception.Message); - Assert.AreEqual(Resources.FileNotFound, exception.InnerException.Message); + Assert.That(exception.Message, Is.EqualTo(Resources.SslConnectionError)); + Assert.That(exception.InnerException.Message, Is.EqualTo(Resources.FileNotFound)); } } @@ -593,7 +581,7 @@ public void ConnectUsingAllCertificates() try { connection.Open(); } catch (Exception ex) { - Assert.True(ex is MySqlException || + Assert.That(ex is MySqlException || ex is AuthenticationException || ex is FormatException, ex.Message); } @@ -644,8 +632,8 @@ public void AttemptConnectionWithDummyPemCertificates() using (var connection = new MySqlConnection(builder.ConnectionString)) { var exception = Assert.Throws(() => connection.Open()); - Assert.AreEqual(Resources.SslConnectionError, exception.Message); - Assert.AreEqual(Resources.FileIsNotACertificate, exception.InnerException.Message, $"Cert. path: {_sslCa}"); + Assert.That(exception.Message, Is.EqualTo(Resources.SslConnectionError)); + Assert.That(exception.InnerException.Message, Is.EqualTo(Resources.FileIsNotACertificate), $"Cert. path: {_sslCa}"); } builder.SslCa = _sslCa; @@ -654,8 +642,8 @@ public void AttemptConnectionWithDummyPemCertificates() using (var connection = new MySqlConnection(builder.ConnectionString)) { var exception = Assert.Throws(() => connection.Open()); - Assert.AreEqual(Resources.SslConnectionError, exception.Message); - Assert.AreEqual(Resources.FileIsNotACertificate, exception.InnerException.Message); + Assert.That(exception.Message, Is.EqualTo(Resources.SslConnectionError)); + Assert.That(exception.InnerException.Message, Is.EqualTo(Resources.FileIsNotACertificate)); } builder.SslCa = _sslCa; @@ -665,8 +653,8 @@ public void AttemptConnectionWithDummyPemCertificates() using (var connection = new MySqlConnection(builder.ConnectionString)) { var exception = Assert.Throws(() => connection.Open()); - Assert.AreEqual(Resources.SslConnectionError, exception.Message); - Assert.AreEqual(Resources.FileIsNotAKey, exception.InnerException.Message); + Assert.That(exception.Message, Is.EqualTo(Resources.SslConnectionError)); + Assert.That(exception.InnerException.Message, Is.EqualTo(Resources.FileIsNotAKey)); } } @@ -680,8 +668,8 @@ public void AttemptConnectionWithSwitchedPemCertificates() using (var connection = new MySqlConnection(builder.ConnectionString)) { var exception = Assert.Throws(() => connection.Open()); - Assert.AreEqual(Resources.SslConnectionError, exception.Message); - Assert.AreEqual(Resources.SslCertificateIsNotCA, exception.InnerException.Message); + Assert.That(exception.Message, Is.EqualTo(Resources.SslConnectionError)); + Assert.That(exception.InnerException.Message, Is.EqualTo(Resources.SslCertificateIsNotCA)); } builder.SslCa = _sslKey; @@ -689,8 +677,8 @@ public void AttemptConnectionWithSwitchedPemCertificates() using (var connection = new MySqlConnection(builder.ConnectionString)) { var exception = Assert.Throws(() => connection.Open()); - Assert.AreEqual(Resources.SslConnectionError, exception.Message); - Assert.AreEqual(Resources.FileIsNotACertificate, exception.InnerException.Message); + Assert.That(exception.Message, Is.EqualTo(Resources.SslConnectionError)); + Assert.That(exception.InnerException.Message, Is.EqualTo(Resources.FileIsNotACertificate)); } builder.SslCa = _sslCa; @@ -699,8 +687,8 @@ public void AttemptConnectionWithSwitchedPemCertificates() using (var connection = new MySqlConnection(builder.ConnectionString)) { var exception = Assert.Throws(() => connection.Open()); - Assert.AreEqual(Resources.SslConnectionError, exception.Message); - Assert.AreEqual(Resources.InvalidSslCertificate, exception.InnerException.Message); + Assert.That(exception.Message, Is.EqualTo(Resources.SslConnectionError)); + Assert.That(exception.InnerException.Message, Is.EqualTo(Resources.InvalidSslCertificate)); } builder.SslCert = _sslCert; @@ -709,8 +697,8 @@ public void AttemptConnectionWithSwitchedPemCertificates() using (var connection = new MySqlConnection(builder.ConnectionString)) { var exception = Assert.Throws(() => connection.Open()); - Assert.AreEqual(Resources.SslConnectionError, exception.Message); - Assert.AreEqual(Resources.FileIsNotAKey, exception.InnerException.Message); + Assert.That(exception.Message, Is.EqualTo(Resources.SslConnectionError)); + Assert.That(exception.InnerException.Message, Is.EqualTo(Resources.FileIsNotAKey)); } } @@ -733,7 +721,7 @@ public void MaxConnectionsWithPersistAndGlobalVariables() connectionList.Add(c1); } Exception ex = Assert.Throws(() => conn.Open()); - StringAssert.Contains("Too many connections", ex.Message); + Assert.That(ex.Message, Does.Contain("Too many connections")); } foreach (var item in connectionList) { @@ -753,7 +741,7 @@ public void MaxConnectionsWithPersistAndGlobalVariables() connectionList.Add(c1); } Exception ex = Assert.Throws(() => conn.Open()); - StringAssert.Contains("Too many connections", ex.Message); + Assert.That(ex.Message, Does.Contain("Too many connections")); } foreach (var item in connectionList) { @@ -771,14 +759,14 @@ public void ShowVariablesRemoved() using (var dbConn = new MySqlConnection(Settings.ConnectionString)) { dbConn.Open();//Manually verify in server log that show variables is not present - Assert.AreEqual(ConnectionState.Open, dbConn.State); + Assert.That(dbConn.State, Is.EqualTo(ConnectionState.Open)); } } [Test] public void ConnectUsingCertificateFileAndTlsVersion() { - if (Version <= new Version(8, 0, 16)) Assert.Ignore("This test for MySql server 8.0.16 or higher"); + Assume.That(Version >= new Version(8, 0, 16), "This test for MySql server 8.0.16 or higher"); var builder = new MySqlConnectionStringBuilder(Settings.ConnectionString); builder.SslMode = MySqlSslMode.Required; builder.CertificateFile = "client.pfx"; @@ -790,22 +778,22 @@ public void ConnectUsingCertificateFileAndTlsVersion() MySqlCommand cmd = new MySqlCommand("show variables like '%tls_version%'", connection); using (MySqlDataReader reader = cmd.ExecuteReader()) { - Assert.True(reader.Read()); - StringAssert.Contains("TLSv1", reader.GetString(1)); + Assert.That(reader.Read()); + Assert.That(reader.GetString(1), Does.Contain("TLSv1")); } cmd = new MySqlCommand("show status like 'Ssl_cipher'", connection); using (MySqlDataReader reader = cmd.ExecuteReader()) { - Assert.True(reader.Read()); - Assert.True(reader.GetString(1).ToString().Length > 0); + Assert.That(reader.Read()); + Assert.That(reader.GetString(1).ToString().Length > 0); } cmd = new MySqlCommand("show status like 'Ssl_version'", connection); using (MySqlDataReader reader = cmd.ExecuteReader()) { - Assert.True(reader.Read()); - StringAssert.AreEqualIgnoringCase("TLSv1.2", reader.GetString(1)); + Assert.That(reader.Read()); + Assert.That(reader.GetString(1), Is.EqualTo("TLSv1.2").IgnoreCase); } } } @@ -813,8 +801,8 @@ public void ConnectUsingCertificateFileAndTlsVersion() [Test, Description("Classic-Scenario(correct ssl-ca,wrong ssl-key/ssl-cert,ssl-mode required and default)")] public void CorrectSslcaWrongSslkeySslcertRequiredMode() { - if (!Platform.IsWindows()) Assert.Ignore("This test is only for Windows OS"); - if (Version <= new Version(8, 0, 16)) Assert.Ignore("This test for MySql server 8.0.16 or higher"); + Assume.That(Platform.IsWindows(), "This test is only for Windows OS"); + Assume.That(Version >= new Version(8, 0, 16), "This test for MySql server 8.0.16 or higher"); string[] sslcertlist = new string[] { "", " ", null, "file", "file.pem" }; string[] sslkeylist = new string[] { "", " ", null, "file", "file.pem" }; for (int i = 0; i < sslcertlist.Length; i++) @@ -832,7 +820,7 @@ public void CorrectSslcaWrongSslkeySslcertRequiredMode() using (var c = new MySqlConnection(connClassic.ConnectionString)) { c.Open(); - Assert.AreEqual(ConnectionState.Open, c.State); + Assert.That(c.State, Is.EqualTo(ConnectionState.Open)); } connClassic = new MySqlConnectionStringBuilder(); @@ -846,7 +834,7 @@ public void CorrectSslcaWrongSslkeySslcertRequiredMode() using (var c = new MySqlConnection(connClassic.ConnectionString)) { c.Open(); - Assert.AreEqual(ConnectionState.Open, c.State); + Assert.That(c.State, Is.EqualTo(ConnectionState.Open)); } connClassic = new MySqlConnectionStringBuilder(); @@ -861,7 +849,7 @@ public void CorrectSslcaWrongSslkeySslcertRequiredMode() using (var c = new MySqlConnection(connClassic.ConnectionString)) { c.Open(); - Assert.AreEqual(ConnectionState.Open, c.State); + Assert.That(c.State, Is.EqualTo(ConnectionState.Open)); } var conn = new MySqlXConnectionStringBuilder(); @@ -876,7 +864,7 @@ public void CorrectSslcaWrongSslkeySslcertRequiredMode() using (var c = new MySqlConnection(connClassic.ConnectionString)) { c.Open(); - Assert.AreEqual(ConnectionState.Open, c.State); + Assert.That(c.State, Is.EqualTo(ConnectionState.Open)); } conn = new MySqlXConnectionStringBuilder(); @@ -890,7 +878,7 @@ public void CorrectSslcaWrongSslkeySslcertRequiredMode() using (var c = new MySqlConnection(connClassic.ConnectionString)) { c.Open(); - Assert.AreEqual(ConnectionState.Open, c.State); + Assert.That(c.State, Is.EqualTo(ConnectionState.Open)); } } } @@ -898,8 +886,8 @@ public void CorrectSslcaWrongSslkeySslcertRequiredMode() [Test, Description("Clasic-Scenario(correct ssl-ca,no ssl-key/ssl-cert,ssl-mode required and default)")] public void CorrectSslcaNoSslkeyorCertRequiredMode() { - if (!Platform.IsWindows()) Assert.Ignore("This test is only for Windows OS"); - if (Version <= new Version(8, 0, 16)) Assert.Ignore("This test for MySql server 8.0.16 or higher"); + Assume.That(Platform.IsWindows(), "This test is only for Windows OS"); + Assume.That(Version >= new Version(8, 0, 16), "This test for MySql server 8.0.16 or higher"); var connClassic = new MySqlConnectionStringBuilder(); connClassic.Server = Host; connClassic.Port = Convert.ToUInt32(Port); @@ -910,7 +898,7 @@ public void CorrectSslcaNoSslkeyorCertRequiredMode() using (var c = new MySqlConnection(connClassic.ConnectionString)) { c.Open(); - Assert.AreEqual(ConnectionState.Open, c.State); + Assert.That(c.State, Is.EqualTo(ConnectionState.Open)); } connClassic = new MySqlConnectionStringBuilder(); @@ -922,7 +910,7 @@ public void CorrectSslcaNoSslkeyorCertRequiredMode() using (var c = new MySqlConnection(connClassic.ConnectionString)) { c.Open(); - Assert.AreEqual(ConnectionState.Open, c.State); + Assert.That(c.State, Is.EqualTo(ConnectionState.Open)); } connClassic = new MySqlConnectionStringBuilder(); @@ -935,7 +923,7 @@ public void CorrectSslcaNoSslkeyorCertRequiredMode() using (var c = new MySqlConnection(connClassic.ConnectionString)) { c.Open(); - Assert.AreEqual(ConnectionState.Open, c.State); + Assert.That(c.State, Is.EqualTo(ConnectionState.Open)); } connClassic = new MySqlConnectionStringBuilder(); @@ -948,7 +936,7 @@ public void CorrectSslcaNoSslkeyorCertRequiredMode() using (var c = new MySqlConnection(connClassic.ConnectionString)) { c.Open(); - Assert.AreEqual(ConnectionState.Open, c.State); + Assert.That(c.State, Is.EqualTo(ConnectionState.Open)); } var conn = new MySqlXConnectionStringBuilder(); @@ -961,7 +949,7 @@ public void CorrectSslcaNoSslkeyorCertRequiredMode() using (var c = new MySqlConnection(conn.ConnectionString)) { c.Open(); - Assert.AreEqual(ConnectionState.Open, c.State); + Assert.That(c.State, Is.EqualTo(ConnectionState.Open)); } conn = new MySqlXConnectionStringBuilder(); @@ -973,16 +961,16 @@ public void CorrectSslcaNoSslkeyorCertRequiredMode() using (var c = new MySqlConnection(conn.ConnectionString)) { c.Open(); - Assert.AreEqual(ConnectionState.Open, c.State); + Assert.That(c.State, Is.EqualTo(ConnectionState.Open)); } } [Test, Description("checking different versions of TLS versions")] public void SecurityTlsCheck() { - if (!Platform.IsWindows()) Assert.Ignore("This test is only for Windows OS"); - if (Version <= new Version(8, 0, 16)) Assert.Ignore("This test for MySql server 8.0.16 or higher"); - if (!ServerHaveSsl()) Assert.Ignore("Server doesn't have Ssl support"); + Assume.That(Platform.IsWindows(), "This test is only for Windows OS"); + Assume.That(Version >= new Version(8, 0, 16), "This test for MySql server 8.0.16 or higher"); + Assume.That(ServerHaveSsl(), "Server doesn't have Ssl support"); MySqlSslMode[] modes = { MySqlSslMode.Required, MySqlSslMode.VerifyCA, MySqlSslMode.VerifyFull }; String[] version; @@ -998,7 +986,7 @@ public void SecurityTlsCheck() conn.Open(); MySqlCommand cmd = new MySqlCommand("SELECT variable_value FROM performance_schema.session_status WHERE VARIABLE_NAME='Ssl_version'", conn); object result = cmd.ExecuteScalar(); - Assert.AreEqual(tlsVersion, result); + Assert.That(result, Is.EqualTo(tlsVersion)); } } @@ -1009,10 +997,10 @@ public void SecurityTlsCheck() { // TLSv1.0 and TLSv1.1 has been deprecated in Ubuntu 20.04 so an exception is thrown try { conn.Open(); } - catch (Exception ex) { Assert.True(ex is AuthenticationException); return; } + catch (Exception ex) { Assert.That(ex is AuthenticationException); return; } MySqlCommand cmd = new MySqlCommand("SELECT variable_value FROM performance_schema.session_status WHERE VARIABLE_NAME='Ssl_version'", conn); object result = cmd.ExecuteScalar(); - Assert.True(result.ToString().StartsWith("TLSv1")); + Assert.That(result.ToString().StartsWith("TLSv1")); } } } @@ -1021,8 +1009,8 @@ public void SecurityTlsCheck() [Test, Description("checking errors when invalid values are used ")] public void InvalidTlsversionValues() { - if (Version <= new Version(8, 0, 16)) Assert.Ignore("This test for MySql server 8.0.16 or higher"); - if (!ServerHaveSsl()) Assert.Ignore("Server doesn't have Ssl support"); + Assume.That(Version >= new Version(8, 0, 16), "This test for MySql server 8.0.16 or higher"); + Assume.That(ServerHaveSsl(), "Server doesn't have Ssl support"); string[] version = new string[] { "null", "v1", "[ ]", "[TLSv1.9]", "[TLSv1.1,TLSv1.7]", "ui9" };//blank space is considered as default value var conStr = $"server={Host};port={Port};userid={Settings.UserID};password={Settings.Password};SslCa={_sslCa};SslCert={_sslCert};SslKey={_sslKey};ssl-ca-pwd=pass"; @@ -1034,7 +1022,7 @@ public void InvalidTlsversionValues() // Not supported protocols var ex = Assert.Throws(() => conn = new MySqlConnection(conStr + $";ssl-mode={MySqlSslMode.Required};tls-version=[TLSv1];tls-version=[TLSv1]")); - StringAssert.AreEqualIgnoringCase("TLS protocols TLSv1 and TLSv1.1 are no longer supported. Accepted values are TLSv1.2 and TLSv1.3", ex.Message); + Assert.That(ex.Message, Is.EqualTo("TLS protocols TLSv1 and TLSv1.1 are no longer supported. Accepted values are TLSv1.2 and TLSv1.3").IgnoreCase); // Repeated options are allowed Assert.DoesNotThrow(() => conn = new MySqlConnection(conStr + $";ssl-mode={MySqlSslMode.Required};tls-version=[TLSv1.1,TLSv1.2];tls-version=[TLSv1.2]")); @@ -1043,7 +1031,7 @@ public void InvalidTlsversionValues() [Test, Description("Default SSL user with SSL but without SSL Parameters")] public void SslUserWithoutSslParams() { - if (!ServerHaveSsl()) Assert.Ignore("Server doesn't have Ssl support"); + Assume.That(ServerHaveSsl(), "Server doesn't have Ssl support"); MySqlCommand cmd = new MySqlCommand(); string connstr = $"server={Host};user={Settings.UserID};port={Port};password={Settings.Password};sslmode={MySqlSslMode.Disabled}"; using (var c = new MySqlConnection(connstr)) @@ -1054,7 +1042,7 @@ public void SslUserWithoutSslParams() cmd.ExecuteNonQuery(); var rdr1 = cmd.ExecuteReader(); while (rdr1.Read()) - Assert.True(rdr1.GetValue(1).ToString().Trim() == ""); + Assert.That(rdr1.GetValue(1).ToString().Trim() == ""); } connstr = $"server={Host};user={Settings.UserID};port={Port};password=;sslmode={MySqlSslMode.Disabled}"; @@ -1067,8 +1055,8 @@ public void SslUserWithoutSslParams() [Test] public void PositiveSslConnectionWithCertificates() { - if (Version < new Version(5, 7, 0)) Assert.Ignore("This test is for MySql Server 5.7 or higher"); - if (!ServerHaveSsl()) Assert.Ignore("Server doesn't have Ssl support"); + Assume.That(Version >= new Version(5, 7, 0), "This test for MySql server 5.7 or higher"); + Assume.That(ServerHaveSsl(), "Server doesn't have Ssl support"); MySqlCommand cmd = new MySqlCommand(); var connStr = $"server={Host};port={Port};user={Settings.UserID};password={Settings.Password};CertificateFile={_sslCa};CertificatePassword=pass;SSL Mode=Required;"; @@ -1081,7 +1069,7 @@ public void PositiveSslConnectionWithCertificates() { while (rdr.Read()) { - Assert.True(rdr.GetValue(1).ToString().Trim().Contains("TLSv1")); + Assert.That(rdr.GetValue(1).ToString().Trim().Contains("TLSv1")); } } @@ -1090,7 +1078,7 @@ public void PositiveSslConnectionWithCertificates() { while (rdr.Read()) { - Assert.True(rdr.GetValue(1).ToString().Trim().Length > 0); + Assert.That(rdr.GetValue(1).ToString().Trim().Length > 0); } } @@ -1099,7 +1087,7 @@ public void PositiveSslConnectionWithCertificates() { while (rdr.Read()) { - Assert.True(rdr.GetValue(1).ToString().StartsWith("TLSv1")); + Assert.That(rdr.GetValue(1).ToString().StartsWith("TLSv1")); } } } @@ -1114,7 +1102,7 @@ public void PositiveSslConnectionWithCertificates() { while (rdr.Read()) { - Assert.True(rdr.GetValue(1).ToString().Trim().Contains("TLSv1")); + Assert.That(rdr.GetValue(1).ToString().Trim().Contains("TLSv1")); } } @@ -1124,7 +1112,7 @@ public void PositiveSslConnectionWithCertificates() { while (rdr.Read()) { - Assert.True(rdr.GetValue(1).ToString().Trim().Length > 0); + Assert.That(rdr.GetValue(1).ToString().Trim().Length > 0); } } cmd.Connection = c; @@ -1133,7 +1121,7 @@ public void PositiveSslConnectionWithCertificates() { while (rdr.Read()) { - Assert.True(rdr.GetValue(1).ToString().StartsWith("TLSv1")); + Assert.That(rdr.GetValue(1).ToString().StartsWith("TLSv1")); } } } @@ -1160,8 +1148,8 @@ public void SslOptionsCombinedWhenDisabled(MySqlSslMode sslMode, string sslOptio reader.Read(); string encryption = reader.GetString(1); - Assert.IsEmpty(encryption); - Assert.AreEqual(ConnectionState.Open, conn.State); + Assert.That(encryption, Is.Empty); + Assert.That(conn.State, Is.EqualTo(ConnectionState.Open)); } [Test] @@ -1176,8 +1164,8 @@ public void SslRequiredOverDisabled() reader.Read(); string encryption = reader.GetString(1); - Assert.IsNotEmpty(encryption); - Assert.AreEqual(ConnectionState.Open, conn.State); + Assert.That(encryption, Is.Not.Empty); + Assert.That(conn.State, Is.EqualTo(ConnectionState.Open)); } /// @@ -1205,7 +1193,7 @@ public void SslChainedCertificates(MySqlSslMode sslMode) using var conn = new MySqlConnection(stringBuilder.ConnectionString); conn.Open(); - Assert.IsTrue(conn.State == ConnectionState.Open); + Assert.That(conn.State == ConnectionState.Open); } #region Methods @@ -1213,7 +1201,7 @@ public bool ServerHaveSsl() { Dictionary strValues = new(); - var commandList = new string[] { "show variables like 'have_ssl'", "show status like '%Ssl_version'", "show variables like 'tls_version'" }; + var commandList = new string[] { "show status like '%Ssl_version'", "show variables like 'tls_version'" }; foreach (var item in commandList) { var cmd = Connection.CreateCommand(); @@ -1226,7 +1214,7 @@ public bool ServerHaveSsl() } } } - return (strValues["have_ssl"] == "YES" && strValues["Ssl_version"].StartsWith("TLS") && !string.IsNullOrEmpty(strValues["tls_version"])) ? true : false; + return (strValues["Ssl_version"].StartsWith("TLS") && !string.IsNullOrEmpty(strValues["tls_version"])) ? true : false; } #endregion Methods } diff --git a/MySQL.Data/tests/MySql.Data.Tests/StoredProcedure.cs b/MySQL.Data/tests/MySql.Data.Tests/StoredProcedure.cs index 4fff00534..87bda77c9 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/StoredProcedure.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/StoredProcedure.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2022, Oracle and/or its affiliates. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -27,6 +27,7 @@ // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA using NUnit.Framework; +using NUnit.Framework.Legacy; using System; using System.Data; using System.Data.Common; @@ -64,7 +65,7 @@ public void ReturningResultset() p.Value = 21; decimal id = (decimal)cmd.ExecuteScalar(); - Assert.AreEqual(21, id); + Assert.That(id, Is.EqualTo(21)); } } @@ -80,17 +81,17 @@ public void NonQuery() cmd.CommandType = CommandType.StoredProcedure; cmd.Parameters.AddWithValue("?value", 2); int rowsAffected = cmd.ExecuteNonQuery(); - Assert.AreEqual(1, rowsAffected); + Assert.That(rowsAffected, Is.EqualTo(1)); cmd.CommandText = "SELECT * FROM Test"; cmd.CommandType = CommandType.Text; using (MySqlDataReader reader = cmd.ExecuteReader()) { - Assert.True(reader.Read()); - Assert.AreEqual(2, reader.GetInt32(0)); - Assert.AreEqual("Test", reader.GetString(1)); - Assert.False(reader.Read()); - Assert.False(reader.NextResult()); + Assert.That(reader.Read()); + Assert.That(reader.GetInt32(0), Is.EqualTo(2)); + Assert.That(reader.GetString(1), Is.EqualTo("Test")); + Assert.That(reader.Read(), Is.False); + Assert.That(reader.NextResult(), Is.False); } } @@ -122,7 +123,7 @@ public void NoInOutMarker() cmd.CommandType = CommandType.StoredProcedure; cmd.Parameters.AddWithValue("?valin", "myvalue"); object val = cmd.ExecuteScalar(); - Assert.AreEqual("myvalue", val); + Assert.That(val, Is.EqualTo("myvalue")); } [Test] @@ -146,8 +147,8 @@ public void ExecuteScalar2() MySqlCommand cmd = new MySqlCommand("spTest", Connection); cmd.CommandType = CommandType.StoredProcedure; object result = cmd.ExecuteScalar(); - Assert.AreEqual(1, result); - Assert.True(result is Int32); + Assert.That(result, Is.EqualTo(1)); + Assert.That(result is Int32); } [Test] @@ -173,11 +174,11 @@ private void MultipleResultsetsImpl(bool prepare) if (prepare) cmd.Prepare(); cmd.CommandType = CommandType.StoredProcedure; MySqlDataReader reader = cmd.ExecuteReader(); - Assert.True(reader.Read()); - Assert.True(reader.NextResult()); - Assert.True(reader.Read()); - Assert.False(reader.NextResult()); - Assert.False(reader.Read()); + Assert.That(reader.Read()); + Assert.That(reader.NextResult()); + Assert.That(reader.Read()); + Assert.That(reader.NextResult(), Is.False); + Assert.That(reader.Read(), Is.False); reader.Close(); DataSet ds = new DataSet(); @@ -187,12 +188,12 @@ private void MultipleResultsetsImpl(bool prepare) da.FillError += new FillErrorEventHandler(da_FillError); fillError = null; da.Fill(ds); - Assert.AreEqual(2, ds.Tables.Count); - Assert.AreEqual(1, Convert.ToInt32(ds.Tables[0].Rows.Count)); - Assert.AreEqual(1, Convert.ToInt32(ds.Tables[1].Rows.Count)); - Assert.AreEqual(1, Convert.ToInt32(ds.Tables[0].Rows[0][0])); - Assert.AreEqual(2, Convert.ToInt32(ds.Tables[1].Rows[0][0])); - Assert.Null(fillError); + Assert.That(ds.Tables.Count, Is.EqualTo(2)); + Assert.That(Convert.ToInt32(ds.Tables[0].Rows.Count), Is.EqualTo(1)); + Assert.That(Convert.ToInt32(ds.Tables[1].Rows.Count), Is.EqualTo(1)); + Assert.That(Convert.ToInt32(ds.Tables[0].Rows[0][0]), Is.EqualTo(1)); + Assert.That(Convert.ToInt32(ds.Tables[1].Rows[0][0]), Is.EqualTo(2)); + Assert.That(fillError, Is.Null); } private static string fillError = null; @@ -212,7 +213,7 @@ public void ExecuteWithCreate() MySqlCommand cmd = new MySqlCommand(sql, Connection); cmd.Parameters.Add(new MySqlParameter("?v", 33)); object val = cmd.ExecuteScalar(); - Assert.AreEqual(33, val); + Assert.That(val, Is.EqualTo(33)); } /// @@ -231,14 +232,14 @@ public void OtherProcSigs() cmd.Parameters.AddWithValue("?val2", 4); decimal val = (decimal)cmd.ExecuteScalar(); Decimal d = new Decimal(20.4); - Assert.AreEqual(d, val); + Assert.That(val, Is.EqualTo(d)); // create our second procedure ExecuteSQL("DROP PROCEDURE IF EXISTS spTest"); ExecuteSQL("CREATE PROCEDURE spTest( \r\n) BEGIN SELECT 4; END"); cmd.Parameters.Clear(); object val1 = cmd.ExecuteScalar(); - Assert.AreEqual(4, Convert.ToInt32(val1)); + Assert.That(Convert.ToInt32(val1), Is.EqualTo(4)); } /// @@ -254,7 +255,7 @@ public void NoDefaultDatabase() MySqlCommand cmd = new MySqlCommand("spTest", Connection); cmd.CommandType = CommandType.StoredProcedure; object val = cmd.ExecuteScalar(); - Assert.AreEqual(4, Convert.ToInt32(val)); + Assert.That(Convert.ToInt32(val), Is.EqualTo(4)); cmd.CommandText = String.Format("USE `{0}`", dbName); cmd.CommandType = CommandType.Text; @@ -263,7 +264,7 @@ public void NoDefaultDatabase() cmd.CommandText = String.Format("`{0}`.spTest", Connection.Database); cmd.CommandType = CommandType.StoredProcedure; val = cmd.ExecuteScalar(); - Assert.AreEqual(4, Convert.ToInt32(val)); + Assert.That(Convert.ToInt32(val), Is.EqualTo(4)); cmd.CommandText = String.Format("USE `{0}`", Connection.Database); cmd.CommandType = CommandType.Text; @@ -299,7 +300,7 @@ public void DecimalAsParameter() cmd.CommandType = CommandType.StoredProcedure; cmd.Parameters.AddWithValue("?d", 21); decimal d = (decimal)cmd.ExecuteScalar(); - Assert.AreEqual(21, d); + Assert.That(d, Is.EqualTo(21)); } /// @@ -315,7 +316,7 @@ public void ParmWithCharacterSet() cmd.CommandType = CommandType.StoredProcedure; cmd.Parameters.AddWithValue("?P", "This is my value"); string p = (string)cmd.ExecuteScalar(); - Assert.AreEqual("This is my value", p); + Assert.That(p, Is.EqualTo("This is my value")); } /// @@ -334,7 +335,7 @@ public void SpecialCharacters() cmd.CommandType = CommandType.StoredProcedure; string val = (string)cmd.ExecuteScalar(); - Assert.AreEqual("This is my value", val); + Assert.That(val, Is.EqualTo("This is my value")); } finally { @@ -353,7 +354,7 @@ public void CallingSPWithPrepare() cmd.Prepare(); int p = (int)cmd.ExecuteScalar(); - Assert.AreEqual(33, p); + Assert.That(p, Is.EqualTo(33)); } /// @@ -382,10 +383,10 @@ public void MultipleRecords() DataTable dt = new DataTable(); da.Fill(dt); - Assert.AreEqual(1, dt.Rows[0]["id"]); - Assert.AreEqual(2, dt.Rows[1]["id"]); - Assert.AreEqual("First record", dt.Rows[0]["name"]); - Assert.AreEqual("Second record", dt.Rows[1]["name"]); + Assert.That(dt.Rows[0]["id"], Is.EqualTo(1)); + Assert.That(dt.Rows[1]["id"], Is.EqualTo(2)); + Assert.That(dt.Rows[0]["name"], Is.EqualTo("First record")); + Assert.That(dt.Rows[1]["name"], Is.EqualTo("Second record")); } /// @@ -439,8 +440,8 @@ public void ProcedureCache() System.Diagnostics.Trace.Listeners.Remove(myListener); // now see how many times our listener recorded a cache hit - Assert.AreEqual(190, myListener.Find("from procedure cache")); - Assert.AreEqual(10, myListener.Find("from server")); + Assert.That(myListener.Find("from procedure cache"), Is.EqualTo(190)); + Assert.That(myListener.Find("from server"), Is.EqualTo(10)); } } @@ -541,7 +542,7 @@ public void ProcEnumParamTest() using (MySqlDataReader reader = cmd.ExecuteReader()) { reader.Read(); - Assert.AreEqual("P", reader.GetString(0)); + Assert.That(reader.GetString(0), Is.EqualTo("P")); } } @@ -564,7 +565,7 @@ public void GetSchema() MySqlDataAdapter da = new MySqlDataAdapter(cmd); DataTable schema = new DataTable(); da.FillSchema(schema, SchemaType.Source); - Assert.AreEqual(2, schema.Columns.Count); + Assert.That(schema.Columns.Count, Is.EqualTo(2)); } /// @@ -621,14 +622,14 @@ public void UsingUInt64AsParam() public void CatalogWithHyphens() { // make sure this test is valid - Assert.True(Connection.Database.IndexOf('-') != -1); + Assert.That(Connection.Database.IndexOf('-') != -1); MySqlCommand cmd = new MySqlCommand("CREATE PROCEDURE spTest() BEGIN SELECT 1; END", Connection); cmd.ExecuteNonQuery(); cmd.CommandText = "spTest"; cmd.CommandType = CommandType.StoredProcedure; - Assert.AreEqual(1, Convert.ToInt32(cmd.ExecuteScalar())); + Assert.That(Convert.ToInt32(cmd.ExecuteScalar()), Is.EqualTo(1)); } [Test] @@ -676,7 +677,7 @@ public void SPWithSpaceInParameterType() cmd.Parameters.Add("@myparam", MySqlDbType.Decimal).Value = 20; cmd.CommandType = CommandType.StoredProcedure; object o = cmd.ExecuteScalar(); - Assert.AreEqual(1, Convert.ToInt32(o)); + Assert.That(Convert.ToInt32(o), Is.EqualTo(1)); } private void ParametersInReverseOrderInternal(bool isOwner) @@ -704,13 +705,13 @@ private void ParametersInReverseOrderInternal(bool isOwner) da.Fill(dt); if (!isOwner) { - Assert.AreEqual("World", dt.Rows[0][0]); - Assert.AreEqual("Hello", dt.Rows[0][1]); + Assert.That(dt.Rows[0][0], Is.EqualTo("World")); + Assert.That(dt.Rows[0][1], Is.EqualTo("Hello")); } else { - Assert.AreEqual("Hello", dt.Rows[0]["P1"]); - Assert.AreEqual("World", dt.Rows[0]["P2"]); + Assert.That(dt.Rows[0]["P1"], Is.EqualTo("Hello")); + Assert.That(dt.Rows[0]["P2"], Is.EqualTo("World")); } } } @@ -736,7 +737,7 @@ public void DeriveParameters() MySqlCommand cmd = new MySqlCommand("spTest", Connection); cmd.CommandType = CommandType.StoredProcedure; MySqlCommandBuilder.DeriveParameters(cmd); - Assert.AreEqual(2, cmd.Parameters.Count); + Assert.That(cmd.Parameters.Count, Is.EqualTo(2)); } /// @@ -745,7 +746,6 @@ public void DeriveParameters() [Test] public void ProcedureCacheMiss() { - if (Version.Major == new Version(5, 7, 43).Major && Version.Minor == new Version(5, 7, 43).Minor) Assert.Ignore("Test temporaly deactivated for MySQL Server version 5.7.x due to a possible bug"); ExecuteSQL("CREATE PROCEDURE spTest(id INT) BEGIN SELECT 1; END"); @@ -794,7 +794,7 @@ public void GetProcedureParametersDoesNotRequireSelectFromMySqlProceduresTable() MySqlSchemaCollection parametersTable = isp.GetProcedureParametersAsync(rest, new MySqlSchemaCollection(procTable), false).GetAwaiter().GetResult(); - Assert.NotNull(parametersTable); + Assert.That(parametersTable, Is.Not.Null); } } @@ -815,7 +815,7 @@ public void NamesWithPeriods() cmd.Parameters.AddWithValue("?p", 2); cmd.CommandType = CommandType.StoredProcedure; var result = cmd.ExecuteScalar(); - Assert.AreEqual(2, result); + Assert.That(result, Is.EqualTo(2)); } } //Database and stored procedure contains "." @@ -829,7 +829,7 @@ public void NamesWithPeriods() cmd.Parameters.AddWithValue("?p", 3); cmd.CommandType = CommandType.StoredProcedure; var result = cmd.ExecuteScalar(); - Assert.AreEqual(3, result); + Assert.That(result, Is.EqualTo(3)); } } } @@ -848,7 +848,7 @@ public void GetSchemaProcedures() if (table.Rows.Count > 0) { var column = table.Rows[0]["ROUTINE_DEFINITION"]; - Assert.IsNotEmpty(column.ToString()); + Assert.That(column.ToString(), Is.Not.Empty); } } } @@ -869,11 +869,11 @@ public void ProcedureWithoutDbNameInConnString() MySqlCommand command = conn.CreateCommand(); command.CommandText = $"test_prepare.spTest"; command.CommandType = CommandType.StoredProcedure; - Assert.AreEqual(1, command.ExecuteScalar()); + Assert.That(command.ExecuteScalar(), Is.EqualTo(1)); command.CommandText = $"`test_prepare`.`spTest`"; command.CommandType = CommandType.StoredProcedure; - Assert.AreEqual(1, command.ExecuteScalar()); + Assert.That(command.ExecuteScalar(), Is.EqualTo(1)); } } @@ -912,7 +912,7 @@ public void VerifyParametersType() cmd.Prepare(); cmd.ExecuteNonQuery(); var result = cmd.Parameters["@value"].Value; - Assert.AreEqual("test value", result); + Assert.That(result, Is.EqualTo("test value")); //call Prepare() when SP and MySqlParameter have different data types cmd = new MySqlCommand("spTest", connection); @@ -931,7 +931,7 @@ public void VerifyParametersType() [Test] public void PassJsonParameter() { - if (Version < new Version(5, 7, 8)) Assert.Ignore("JSON data type was included in MySQL Server from v5.7.8"); + Assume.That(Version >= new Version(5, 7, 8), "JSON data type was included in MySQL Server from v5.7.8"); ExecuteSQL("CREATE TABLE Test(jsonValue json NOT NULL)"); ExecuteSQL("CREATE PROCEDURE spTest(IN p_jsonValue JSON) BEGIN INSERT INTO Test VALUES(p_jsonValue); END"); @@ -949,7 +949,7 @@ public void PassJsonParameter() cmd = new MySqlCommand("SELECT jsonValue FROM Test", conn); cmd.CommandType = CommandType.Text; - StringAssert.AreEqualIgnoringCase(json, cmd.ExecuteScalar().ToString().Replace(" ", "")); + Assert.That(cmd.ExecuteScalar().ToString().Replace(" ", ""), Is.EqualTo(json).IgnoreCase); } } @@ -966,7 +966,7 @@ public void PassBoolParameter() cmd.CommandType = CommandType.StoredProcedure; cmd.Parameters.Add(new MySqlParameter { ParameterName = "success", Value = true, MySqlDbType = MySqlDbType.Int32 }); cmd.Prepare(); - Assert.IsTrue(Convert.ToBoolean(cmd.ExecuteScalar())); + Assert.That(Convert.ToBoolean(cmd.ExecuteScalar())); } } @@ -993,7 +993,7 @@ public void PassDateTimeParameter() var result = cmd.Parameters["@value"].Value; DateTime dateTime = new DateTime(2020, 11, 27, 12, 25, 59); - Assert.AreEqual(dateTime, result); + Assert.That(result, Is.EqualTo(dateTime)); } ExecuteSQL("DROP PROCEDURE spTest"); @@ -1012,7 +1012,7 @@ public void PassDateTimeParameter() cmd = new MySqlCommand("SELECT dateTime FROM Test", conn); cmd.CommandType = CommandType.Text; - Assert.AreEqual(dateTime, cmd.ExecuteScalar()); + Assert.That(cmd.ExecuteScalar(), Is.EqualTo(dateTime)); } } @@ -1044,7 +1044,7 @@ public void PassEnumParameter() [Test] public void EventsStatementsHistory() { - if (Version < new Version(8, 0, 0)) Assert.Ignore("This test is for MySql 8.0 or higher"); + Assume.That(Version >= new Version(8, 0, 0), "This test is for MySql 8.0 or higher"); bool testResult = false; var spName = "spGetCount"; var cmd = new MySqlCommand(" show variables like 'general_log'", Connection); @@ -1052,7 +1052,7 @@ public void EventsStatementsHistory() { while (rdr.Read()) { - if (rdr.GetString(1) != "ON") Assert.Ignore("general_log is disabled"); + Assume.That(rdr.GetString(1) == "ON", "general_log is disabled"); } } @@ -1066,7 +1066,7 @@ public void EventsStatementsHistory() { while (rdr.Read()) { - Assert.AreEqual("5", rdr.GetString(0)); + Assert.That(rdr.GetString(0), Is.EqualTo("5")); } } @@ -1081,11 +1081,11 @@ public void EventsStatementsHistory() } } } - Assert.True(testResult); + Assert.That(testResult); cmd = new MySqlCommand($"SELECT count(*) FROM information_schema.routines WHERE 1=1 AND ROUTINE_SCHEMA='{Settings.Database}' AND ROUTINE_NAME='{spName}';", Connection); var count = cmd.ExecuteScalar(); - Assert.AreEqual(1, count); + Assert.That(count, Is.EqualTo(1)); } @@ -1105,11 +1105,11 @@ public void FullyQualifiedProcedures() MySqlCommand command = conn.CreateCommand(); command.CommandText = $"`Test`.`spTest`"; command.CommandType = CommandType.StoredProcedure; - Assert.AreEqual(1, command.ExecuteScalar()); + Assert.That(command.ExecuteScalar(), Is.EqualTo(1)); command.CommandText = $"Test.spTest"; command.CommandType = CommandType.StoredProcedure; - Assert.AreEqual(1, command.ExecuteScalar()); + Assert.That(command.ExecuteScalar(), Is.EqualTo(1)); } } @@ -1134,7 +1134,7 @@ public void StoredProceduresWithBackticks(string quotedName, string spNameCnet) command.CommandText = spNameCnet; command.CommandType = CommandType.StoredProcedure; - Assert.AreEqual(1, command.ExecuteScalar()); + Assert.That(command.ExecuteScalar(), Is.EqualTo(1)); } } @@ -1156,7 +1156,7 @@ public void StoredProceduresWithBackticks2(string schema, string spName, string command.CommandText = spNameCnet; command.CommandType = CommandType.StoredProcedure; - Assert.AreEqual(1, command.ExecuteScalar()); + Assert.That(command.ExecuteScalar(), Is.EqualTo(1)); } ExecuteSQL($"DROP SCHEMA {schema};", true); @@ -1219,7 +1219,7 @@ public void StoredProceduresWithBackticksExceptionRaised(string schema, string s [TestCase("` foo`.bar", true)] public void IsSyntacticallyCorrect(string spName, bool isIt) { - Assert.IsTrue(MySqlClient.StoredProcedure.IsSyntacticallyCorrect(spName) == isIt); + Assert.That(MySqlClient.StoredProcedure.IsSyntacticallyCorrect(spName) == isIt); } } -} \ No newline at end of file +} diff --git a/MySQL.Data/tests/MySql.Data.Tests/StoredProcedureWithAccess.cs b/MySQL.Data/tests/MySql.Data.Tests/StoredProcedureWithAccess.cs index 2dca28635..6b6d3f171 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/StoredProcedureWithAccess.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/StoredProcedureWithAccess.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -30,6 +30,7 @@ using System.Collections.Generic; using System.Text; using NUnit.Framework; +using NUnit.Framework.Legacy; using System.Data; using System.Globalization; diff --git a/MySQL.Data/tests/MySql.Data.Tests/StressTests.cs b/MySQL.Data/tests/MySql.Data.Tests/StressTests.cs index fa02eae96..1746e11bc 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/StressTests.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/StressTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2021, Oracle and/or its affiliates. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -29,6 +29,7 @@ using System; using System.Threading.Tasks; using NUnit.Framework; +using NUnit.Framework.Legacy; namespace MySql.Data.MySqlClient.Tests { @@ -75,12 +76,12 @@ public void TestMultiPacket() reader.Read(); byte[] dataOut = new byte[len]; long count = reader.GetBytes(2, 0, dataOut, 0, len); - Assert.AreEqual(len, count); + Assert.That(count, Is.EqualTo(len)); int i = 0; try { for (; i < len; i++) - Assert.AreEqual(dataIn[i], dataOut[i]); + Assert.That(dataOut[i], Is.EqualTo(dataIn[i])); } catch (Exception) { @@ -89,10 +90,10 @@ public void TestMultiPacket() reader.Read(); count = reader.GetBytes(2, 0, dataOut, 0, len); - Assert.AreEqual(len, count); + Assert.That(count, Is.EqualTo(len)); for (int x = 0; x < len; x++) - Assert.AreEqual(dataIn2[x], dataOut[x]); + Assert.That(dataOut[x], Is.EqualTo(dataIn2[x])); } } } @@ -120,12 +121,12 @@ public void TestSequence() { while (reader.Read()) { - Assert.True(i2 + 1 == reader.GetInt32(0), "Sequence out of order"); + Assert.That(i2 + 1 == reader.GetInt32(0), "Sequence out of order"); i2++; } reader.Close(); - Assert.AreEqual(8000, i2); + Assert.That(i2, Is.EqualTo(8000)); cmd = new MySqlCommand("delete from Test where id >= 100", Connection); cmd.ExecuteNonQuery(); } diff --git a/MySQL.Data/tests/MySql.Data.Tests/StressTestsCompressed.cs b/MySQL.Data/tests/MySql.Data.Tests/StressTestsCompressed.cs index 9df210478..15be16ca4 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/StressTestsCompressed.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/StressTestsCompressed.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -37,4 +37,4 @@ internal override void AdjustConnectionSettings(MySqlConnectionStringBuilder set settings.UseCompression = true; } } -} \ No newline at end of file +} diff --git a/MySQL.Data/tests/MySql.Data.Tests/Syntax.cs b/MySQL.Data/tests/MySql.Data.Tests/Syntax.cs index 4b26e969e..646cace02 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/Syntax.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/Syntax.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2022, Oracle and/or its affiliates. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -27,6 +27,7 @@ // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA using NUnit.Framework; +using NUnit.Framework.Legacy; using System; using System.Data; using System.IO; @@ -47,7 +48,7 @@ public void ShowCreateTable() DataTable dt = Utils.FillTable("SHOW CREATE TABLE Test", Connection); Assert.That(dt.Rows, Has.One.Items); - Assert.AreEqual(2, dt.Columns.Count); + Assert.That(dt.Columns.Count, Is.EqualTo(2)); } [Test] @@ -71,10 +72,10 @@ public void ProblemCharsInSQLUTF8() cmd.CommandText = "SELECT * FROM Test"; using (MySqlDataReader reader = cmd.ExecuteReader()) { - Assert.True(reader.Read()); - Assert.AreEqual(1, reader.GetInt32(0)); - Assert.AreEqual("This is my;test ? string–’‘’“”…", reader.GetString(1)); - Assert.AreEqual("My MT string: ?", reader.GetString(2)); + Assert.That(reader.Read()); + Assert.That(reader.GetInt32(0), Is.EqualTo(1)); + Assert.That(reader.GetString(1), Is.EqualTo("This is my;test ? string–’‘’“”…")); + Assert.That(reader.GetString(2), Is.EqualTo("My MT string: ?")); } } } @@ -95,10 +96,10 @@ public void ProblemCharsInSQL() cmd.CommandText = "SELECT * FROM Test"; using (MySqlDataReader reader = cmd.ExecuteReader()) { - Assert.True(reader.Read()); - Assert.AreEqual(1, reader.GetInt32(0)); - Assert.AreEqual("This is my;test ? string-'''\"\".", reader.GetString(1)); - Assert.AreEqual("My MT string: ?", reader.GetString(2)); + Assert.That(reader.Read()); + Assert.That(reader.GetInt32(0), Is.EqualTo(1)); + Assert.That(reader.GetString(1), Is.EqualTo("This is my;test ? string-'''\"\".")); + Assert.That(reader.GetString(2), Is.EqualTo("My MT string: ?")); } } @@ -135,11 +136,11 @@ private void LoadFile(MySqlConnection conn, string path) object cnt = 0; cnt = cmd.ExecuteNonQuery(); - Assert.AreEqual(200000, Convert.ToInt32(cnt)); + Assert.That(Convert.ToInt32(cnt), Is.EqualTo(200000)); cmd.CommandText = "SELECT COUNT(*) FROM Test"; cnt = cmd.ExecuteScalar(); - Assert.AreEqual(200000, Convert.ToInt32(cnt)); + Assert.That(Convert.ToInt32(cnt), Is.EqualTo(200000)); } } @@ -195,7 +196,7 @@ public void Sum() { reader.Read(); object o = reader[0]; - Assert.AreEqual(1, Convert.ToInt32(o)); + Assert.That(Convert.ToInt32(o), Is.EqualTo(1)); } } @@ -212,8 +213,8 @@ public void Sum2() using (MySqlDataReader reader = cmd.ExecuteReader()) { reader.Read(); - Assert.AreEqual(1, reader.GetInt32(0)); - Assert.AreEqual(110, reader.GetDouble(1)); + Assert.That(reader.GetInt32(0), Is.EqualTo(1)); + Assert.That(reader.GetDouble(1), Is.EqualTo(110)); } } @@ -238,11 +239,11 @@ public void SettingAutoIncrementColumns() MySqlCommand cmd = new MySqlCommand("SELECT name FROM Test WHERE id=1", Connection); object name = cmd.ExecuteScalar(); - Assert.AreEqual("One", name); + Assert.That(name, Is.EqualTo("One")); cmd.CommandText = "SELECT name FROM Test WHERE id=3"; name = cmd.ExecuteScalar(); - Assert.AreEqual("Two", name); + Assert.That(name, Is.EqualTo("Two")); Assert.Throws(() => ExecuteSQL("INSERT INTO Test (id, name2) values (5, 'Three')")); } @@ -261,7 +262,7 @@ public void FoundRows() cmd.ExecuteNonQuery(); cmd.CommandText = "SELECT FOUND_ROWS()"; object cnt = cmd.ExecuteScalar(); - Assert.AreEqual(1000, Convert.ToInt32(cnt)); + Assert.That(Convert.ToInt32(cnt), Is.EqualTo(1000)); } [Test] @@ -276,7 +277,7 @@ public void AutoIncrement() { reader.Read(); int ident = Int32.Parse(reader.GetValue(0).ToString()); - Assert.AreEqual(1, ident); + Assert.That(ident, Is.EqualTo(1)); } } @@ -311,7 +312,7 @@ public void ErrorMessage() catch (MySqlException ex) { string s = ex.Message; - Assert.False(s.StartsWith("#", StringComparison.Ordinal)); + Assert.That(s.StartsWith("#", StringComparison.Ordinal), Is.False); } } @@ -325,12 +326,12 @@ public void Describe() var reader = ExecuteReader("DESCRIBE Test"); using (reader) { - Assert.True(reader.GetFieldType(0) == typeof(string)); - Assert.True(reader.GetFieldType(1) == typeof(string)); - Assert.True(reader.GetFieldType(2) == typeof(string)); - Assert.True(reader.GetFieldType(3) == typeof(string)); - Assert.True(reader.GetFieldType(4) == typeof(string)); - Assert.True(reader.GetFieldType(5) == typeof(string)); + Assert.That(reader.GetFieldType(0) == typeof(string)); + Assert.That(reader.GetFieldType(1) == typeof(string)); + Assert.That(reader.GetFieldType(2) == typeof(string)); + Assert.That(reader.GetFieldType(3) == typeof(string)); + Assert.That(reader.GetFieldType(4) == typeof(string)); + Assert.That(reader.GetFieldType(5) == typeof(string)); } } @@ -342,7 +343,7 @@ public void ShowTableStatus() using (reader) { reader.Read(); - Assert.True(reader[0].GetType() == typeof(string)); + Assert.That(reader[0].GetType() == typeof(string)); } } @@ -354,9 +355,9 @@ public void NullAsAType() { DataTable dt = Utils.FillTable(@"SELECT 'localhost' as SERVER_NAME, null as CATALOG_NAME, database() as SCHEMA_NAME", Connection); - Assert.True(dt.Rows[0][0].GetType() == typeof(string)); - Assert.AreEqual(DBNull.Value, dt.Rows[0][1]); - Assert.True(dt.Rows[0][2].GetType() == typeof(string)); + Assert.That(dt.Rows[0][0].GetType() == typeof(string)); + Assert.That(dt.Rows[0][1], Is.EqualTo(DBNull.Value)); + Assert.That(dt.Rows[0][2].GetType() == typeof(string)); } [Test] @@ -395,9 +396,9 @@ public void ShowProcessList() } DataRow row = dt.Rows[0]; - Assert.True(row["User"].GetType().Name == "String"); - Assert.True(row["Host"].GetType().Name == "String"); - Assert.True(row["Command"].GetType().Name == "String"); + Assert.That(row["User"].GetType().Name == "String"); + Assert.That(row["Host"].GetType().Name == "String"); + Assert.That(row["Command"].GetType().Name == "String"); } } @@ -406,7 +407,7 @@ public void SemisAtStartAndEnd() { using (MySqlCommand cmd = new MySqlCommand(";;SELECT 1;;;", Connection)) { - Assert.AreEqual(1, Convert.ToInt32(cmd.ExecuteScalar())); + Assert.That(Convert.ToInt32(cmd.ExecuteScalar()), Is.EqualTo(1)); } } @@ -420,23 +421,23 @@ public void Bug51610() using (MySqlDataReader reader = cmd.ExecuteReader()) { reader.Read(); - Assert.AreEqual("ABC", reader.GetString(0)); - Assert.AreEqual(0, reader.GetInt32(1)); + Assert.That(reader.GetString(0), Is.EqualTo("ABC")); + Assert.That(reader.GetInt32(1), Is.EqualTo(0)); } cmd.CommandText = "SELECT 'ABC', (0-`QOH`) from (SELECT 1 as `QOH`) `d1`"; using (MySqlDataReader reader = cmd.ExecuteReader()) { reader.Read(); - Assert.AreEqual("ABC", reader.GetString(0)); - Assert.AreEqual(-1, reader.GetInt32(1)); + Assert.That(reader.GetString(0), Is.EqualTo("ABC")); + Assert.That(reader.GetInt32(1), Is.EqualTo(-1)); } cmd.CommandText = "SELECT 'test 2010-03-04 @ 10:14'"; using (MySqlDataReader reader = cmd.ExecuteReader()) { reader.Read(); - Assert.AreEqual("test 2010-03-04 @ 10:14", reader.GetString(0)); + Assert.That(reader.GetString(0), Is.EqualTo("test 2010-03-04 @ 10:14")); } } @@ -533,7 +534,7 @@ public void QueryNormalizerCrash2() public void TokenizerBatching() { #if !NETFRAMEWORK - if (!System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows)) Assert.Ignore(); + Assume.That(System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows)); #endif ExecuteSQL("CREATE TABLE Test (id INT, expr INT,name VARCHAR(20), PRIMARY KEY(id))"); diff --git a/MySQL.Data/tests/MySql.Data.Tests/Syntax2.cs b/MySQL.Data/tests/MySql.Data.Tests/Syntax2.cs index b3896ece4..5f8180d24 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/Syntax2.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/Syntax2.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2021, Oracle and/or its affiliates. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -27,6 +27,7 @@ // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA using NUnit.Framework; +using NUnit.Framework.Legacy; using System; using System.Data; @@ -57,11 +58,11 @@ public void CommentsInSQL() MySqlDataAdapter da = new MySqlDataAdapter("SELECT * FROM Test", Connection); DataTable table = new DataTable(); da.Fill(table); - Assert.AreEqual(1, table.Rows[0]["id"]); - Assert.AreEqual("Test", table.Rows[0]["name"]); - Assert.AreEqual(2, table.Rows.Count); - Assert.AreEqual(2, table.Rows[1]["id"]); - Assert.AreEqual("Test2", table.Rows[1]["name"]); + Assert.That(table.Rows[0]["id"], Is.EqualTo(1)); + Assert.That(table.Rows[0]["name"], Is.EqualTo("Test")); + Assert.That(table.Rows.Count, Is.EqualTo(2)); + Assert.That(table.Rows[1]["id"], Is.EqualTo(2)); + Assert.That(table.Rows[1]["name"], Is.EqualTo("Test2")); } [Test] @@ -70,17 +71,17 @@ public void LastInsertid() ExecuteSQL("CREATE TABLE Test(id int auto_increment, name varchar(20), primary key(id))"); MySqlCommand cmd = new MySqlCommand("INSERT INTO Test VALUES(NULL, 'test')", Connection); cmd.ExecuteNonQuery(); - Assert.AreEqual(1, cmd.LastInsertedId); + Assert.That(cmd.LastInsertedId, Is.EqualTo(1)); using (MySqlDataReader reader = cmd.ExecuteReader()) { reader.Read(); } - Assert.AreEqual(2, cmd.LastInsertedId); + Assert.That(cmd.LastInsertedId, Is.EqualTo(2)); cmd.CommandText = "SELECT id FROM Test"; cmd.ExecuteScalar(); - Assert.AreEqual(-1, cmd.LastInsertedId); + Assert.That(cmd.LastInsertedId, Is.EqualTo(-1)); } [Test] diff --git a/MySQL.Data/tests/MySql.Data.Tests/TableCaching.cs b/MySQL.Data/tests/MySql.Data.Tests/TableCaching.cs index 960c9e581..656843ff2 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/TableCaching.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/TableCaching.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -27,6 +27,7 @@ // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA using NUnit.Framework; +using NUnit.Framework.Legacy; using System.Data; using System.Threading; using System.Diagnostics; @@ -57,7 +58,7 @@ public void SimpleTableCaching() // now run the query again but this time it shouldn't generate a call to the database ConsumeReader(cmd); } - Assert.AreEqual(1, listener.Find("Resultset Opened: field(s) = 3")); + Assert.That(listener.Find("Resultset Opened: field(s) = 3"), Is.EqualTo(1)); } [Test] @@ -82,7 +83,7 @@ public void ConnectionStringExpiry() // since our next query is past the cache age of 1 second ConsumeReader(cmd); } - Assert.AreEqual(2, listener.Find("Resultset Opened: field(s) = 3")); + Assert.That(listener.Find("Resultset Opened: field(s) = 3"), Is.EqualTo(2)); } [Test] @@ -110,7 +111,7 @@ public void SettingAgeOnCommand() // to 20 seconds on our command ConsumeReader(cmd); } - Assert.AreEqual(1, listener.Find("Resultset Opened: field(s) = 3")); + Assert.That(listener.Find("Resultset Opened: field(s) = 3"), Is.EqualTo(1)); } private void ConsumeReader(MySqlCommand cmd) @@ -118,18 +119,18 @@ private void ConsumeReader(MySqlCommand cmd) using (MySqlDataReader reader = cmd.ExecuteReader()) { reader.Read(); - Assert.AreEqual(1, reader.GetInt32(0)); - Assert.AreEqual("boo", reader.GetString(1)); - Assert.AreEqual("hoo", reader.GetString(2)); + Assert.That(reader.GetInt32(0), Is.EqualTo(1)); + Assert.That(reader.GetString(1), Is.EqualTo("boo")); + Assert.That(reader.GetString(2), Is.EqualTo("hoo")); reader.Read(); - Assert.AreEqual(2, reader.GetInt32(0)); - Assert.AreEqual("first", reader.GetString(1)); - Assert.AreEqual("last", reader.GetString(2)); + Assert.That(reader.GetInt32(0), Is.EqualTo(2)); + Assert.That(reader.GetString(1), Is.EqualTo("first")); + Assert.That(reader.GetString(2), Is.EqualTo("last")); reader.Read(); - Assert.AreEqual(3, reader.GetInt32(0)); - Assert.AreEqual("fred", reader.GetString(1)); - Assert.AreEqual("flintstone", reader.GetString(2)); - Assert.False(reader.Read()); + Assert.That(reader.GetInt32(0), Is.EqualTo(3)); + Assert.That(reader.GetString(1), Is.EqualTo("fred")); + Assert.That(reader.GetString(2), Is.EqualTo("flintstone")); + Assert.That(reader.Read(), Is.False); } } } diff --git a/MySQL.Data/tests/MySql.Data.Tests/TestBase.cs b/MySQL.Data/tests/MySql.Data.Tests/TestBase.cs index 0dcf501fd..49109a360 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/TestBase.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/TestBase.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2016, 2022, Oracle and/or its affiliates. +// Copyright © 2016, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -28,6 +28,7 @@ using MySql.Data.Common; using NUnit.Framework; +using NUnit.Framework.Legacy; using System; using System.Data; using System.Diagnostics; @@ -183,6 +184,28 @@ protected virtual void Cleanup() { } #endregion #region Public Methods + + #if !NETFRAMEWORK + public static ActivityListener TestListener(Action activityCheck) + { + ActivityListener activity_listener = new ActivityListener + { + ShouldListenTo = source => + { + return source.Name == "connector-net"; + }, + ActivityStopped = activity => + { + if (activityCheck != null) + activityCheck(activity); + }, + Sample = (ref ActivityCreationOptions options) => ActivitySamplingResult.AllData, + }; + ActivitySource.AddActivityListener(activity_listener); + return activity_listener; + } + #endif + public MySqlConnection GetConnection(bool asRoot = false) { var s = asRoot ? RootSettings : Settings; @@ -208,7 +231,7 @@ public string CreateUser(string postfix, string password) { string userName = String.Format("{0}{1}", BaseUserName, postfix); - ExecuteSQL($"CREATE USER '{userName}'@'{host}' IDENTIFIED WITH mysql_native_password BY '{password}'", connection); + ExecuteSQL($"CREATE USER '{userName}'@'{host}' IDENTIFIED BY '{password}'", connection); ExecuteSQL($"GRANT ALL ON *.* TO '{userName}'@'{host}'", connection); ExecuteSQL("FLUSH PRIVILEGES", connection); return userName; @@ -333,6 +356,14 @@ public string GetMySqlServerIp(bool isIpV6 = false) return isIpV6 ? ipv6 : ipv4; } + + public bool Check_Plugin_Enabled(string pluginname) + { + using (var rdr = ExecuteReader($"SELECT PLUGIN_STATUS FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME = '{pluginname}' AND plugin_status = 'ACTIVE';")) + { + return rdr.HasRows; + } + } #endregion } } diff --git a/MySQL.Data/tests/MySql.Data.Tests/Tokenizer.cs b/MySQL.Data/tests/MySql.Data.Tests/Tokenizer.cs index f7e89b8dc..76b01d3cf 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/Tokenizer.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/Tokenizer.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -28,6 +28,7 @@ using System; using NUnit.Framework; +using NUnit.Framework.Legacy; namespace MySql.Data.MySqlClient.Tests { @@ -37,11 +38,11 @@ public class Tokenizer : TestBase public void Simple() { SqlTokenizer tokenizer = new SqlTokenizer("SELECT * FROM Test"); - Assert.AreEqual("SELECT", tokenizer.NextToken()); - Assert.AreEqual("*", tokenizer.NextToken()); - Assert.AreEqual("FROM", tokenizer.NextToken()); - Assert.AreEqual("Test", tokenizer.NextToken()); - Assert.Null(tokenizer.NextToken()); + Assert.That(tokenizer.NextToken(), Is.EqualTo("SELECT")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("*")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("FROM")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("Test")); + Assert.That(tokenizer.NextToken(), Is.Null); } [Test] @@ -51,20 +52,20 @@ public void DashSingleLineComment() string sql = String.Format("SELECT {0} * FROM Test", comment); SqlTokenizer tokenizer = new SqlTokenizer(sql); tokenizer.ReturnComments = true; - Assert.AreEqual("SELECT", tokenizer.NextToken()); - Assert.AreEqual(comment, tokenizer.NextToken()); - Assert.AreEqual("*", tokenizer.NextToken()); - Assert.AreEqual("FROM", tokenizer.NextToken()); - Assert.AreEqual("Test", tokenizer.NextToken()); - Assert.Null(tokenizer.NextToken()); + Assert.That(tokenizer.NextToken(), Is.EqualTo("SELECT")); + Assert.That(tokenizer.NextToken(), Is.EqualTo(comment)); + Assert.That(tokenizer.NextToken(), Is.EqualTo("*")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("FROM")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("Test")); + Assert.That(tokenizer.NextToken(), Is.Null); tokenizer = new SqlTokenizer(sql); tokenizer.ReturnComments = false; - Assert.AreEqual("SELECT", tokenizer.NextToken()); - Assert.AreEqual("*", tokenizer.NextToken()); - Assert.AreEqual("FROM", tokenizer.NextToken()); - Assert.AreEqual("Test", tokenizer.NextToken()); - Assert.Null(tokenizer.NextToken()); + Assert.That(tokenizer.NextToken(), Is.EqualTo("SELECT")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("*")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("FROM")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("Test")); + Assert.That(tokenizer.NextToken(), Is.Null); } [Test] @@ -74,20 +75,20 @@ public void HashSingleLineComment() string sql = String.Format("SELECT {0} * FROM Test", comment); SqlTokenizer tokenizer = new SqlTokenizer(sql); tokenizer.ReturnComments = true; - Assert.AreEqual("SELECT", tokenizer.NextToken()); - Assert.AreEqual(comment, tokenizer.NextToken()); - Assert.AreEqual("*", tokenizer.NextToken()); - Assert.AreEqual("FROM", tokenizer.NextToken()); - Assert.AreEqual("Test", tokenizer.NextToken()); - Assert.Null(tokenizer.NextToken()); + Assert.That(tokenizer.NextToken(), Is.EqualTo("SELECT")); + Assert.That(tokenizer.NextToken(), Is.EqualTo(comment)); + Assert.That(tokenizer.NextToken(), Is.EqualTo("*")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("FROM")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("Test")); + Assert.That(tokenizer.NextToken(), Is.Null); tokenizer = new SqlTokenizer(sql); tokenizer.ReturnComments = false; - Assert.AreEqual("SELECT", tokenizer.NextToken()); - Assert.AreEqual("*", tokenizer.NextToken()); - Assert.AreEqual("FROM", tokenizer.NextToken()); - Assert.AreEqual("Test", tokenizer.NextToken()); - Assert.Null(tokenizer.NextToken()); + Assert.That(tokenizer.NextToken(), Is.EqualTo("SELECT")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("*")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("FROM")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("Test")); + Assert.That(tokenizer.NextToken(), Is.Null); } [Test] @@ -97,20 +98,20 @@ public void MultiLineComment() string sql = String.Format("SELECT{0} * FROM Test", comment); SqlTokenizer tokenizer = new SqlTokenizer(sql); tokenizer.ReturnComments = true; - Assert.AreEqual("SELECT", tokenizer.NextToken()); - Assert.AreEqual(comment.Trim(), tokenizer.NextToken()); - Assert.AreEqual("*", tokenizer.NextToken()); - Assert.AreEqual("FROM", tokenizer.NextToken()); - Assert.AreEqual("Test", tokenizer.NextToken()); - Assert.Null(tokenizer.NextToken()); + Assert.That(tokenizer.NextToken(), Is.EqualTo("SELECT")); + Assert.That(tokenizer.NextToken(), Is.EqualTo(comment.Trim())); + Assert.That(tokenizer.NextToken(), Is.EqualTo("*")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("FROM")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("Test")); + Assert.That(tokenizer.NextToken(), Is.Null); tokenizer = new SqlTokenizer(sql); tokenizer.ReturnComments = false; - Assert.AreEqual("SELECT", tokenizer.NextToken()); - Assert.AreEqual("*", tokenizer.NextToken()); - Assert.AreEqual("FROM", tokenizer.NextToken()); - Assert.AreEqual("Test", tokenizer.NextToken()); - Assert.Null(tokenizer.NextToken()); + Assert.That(tokenizer.NextToken(), Is.EqualTo("SELECT")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("*")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("FROM")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("Test")); + Assert.That(tokenizer.NextToken(), Is.Null); } [Test] @@ -119,19 +120,19 @@ public void Parameter() string sql = "SELECT * FROM Test WHERE id=@id AND id2=?id2"; SqlTokenizer tokenizer = new SqlTokenizer(sql); tokenizer.ReturnComments = true; - Assert.AreEqual("SELECT", tokenizer.NextToken()); - Assert.AreEqual("*", tokenizer.NextToken()); - Assert.AreEqual("FROM", tokenizer.NextToken()); - Assert.AreEqual("Test", tokenizer.NextToken()); - Assert.AreEqual("WHERE", tokenizer.NextToken()); - Assert.AreEqual("id", tokenizer.NextToken()); - Assert.AreEqual("=", tokenizer.NextToken()); - Assert.AreEqual("@id", tokenizer.NextToken()); - Assert.AreEqual("AND", tokenizer.NextToken()); - Assert.AreEqual("id2", tokenizer.NextToken()); - Assert.AreEqual("=", tokenizer.NextToken()); - Assert.AreEqual("?id2", tokenizer.NextToken()); - Assert.Null(tokenizer.NextToken()); + Assert.That(tokenizer.NextToken(), Is.EqualTo("SELECT")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("*")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("FROM")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("Test")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("WHERE")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("id")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("=")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("@id")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("AND")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("id2")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("=")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("?id2")); + Assert.That(tokenizer.NextToken(), Is.Null); } [Test] @@ -140,9 +141,9 @@ public void NextParameter() string sql = "SELECT * FROM Test WHERE id=@id AND id2=?id2"; SqlTokenizer tokenizer = new SqlTokenizer(sql); tokenizer.ReturnComments = true; - Assert.AreEqual("@id", tokenizer.NextParameter()); - Assert.AreEqual("?id2", tokenizer.NextParameter()); - Assert.Null(tokenizer.NextParameter()); + Assert.That(tokenizer.NextParameter(), Is.EqualTo("@id")); + Assert.That(tokenizer.NextParameter(), Is.EqualTo("?id2")); + Assert.That(tokenizer.NextParameter(), Is.Null); } [Test] @@ -151,15 +152,15 @@ public void ParameterWithSpecialCharacters() string sql = "SELECT * FROM Test WHERE id=@id_$123"; SqlTokenizer tokenizer = new SqlTokenizer(sql); tokenizer.ReturnComments = true; - Assert.AreEqual("SELECT", tokenizer.NextToken()); - Assert.AreEqual("*", tokenizer.NextToken()); - Assert.AreEqual("FROM", tokenizer.NextToken()); - Assert.AreEqual("Test", tokenizer.NextToken()); - Assert.AreEqual("WHERE", tokenizer.NextToken()); - Assert.AreEqual("id", tokenizer.NextToken()); - Assert.AreEqual("=", tokenizer.NextToken()); - Assert.AreEqual("@id_$123", tokenizer.NextToken()); - Assert.Null(tokenizer.NextToken()); + Assert.That(tokenizer.NextToken(), Is.EqualTo("SELECT")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("*")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("FROM")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("Test")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("WHERE")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("id")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("=")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("@id_$123")); + Assert.That(tokenizer.NextToken(), Is.Null); } [Test] @@ -168,13 +169,13 @@ public void StringLiteral() string sql = "SELECT 'a', 1, 'b'"; SqlTokenizer tokenizer = new SqlTokenizer(sql); tokenizer.ReturnComments = false; - Assert.AreEqual("SELECT", tokenizer.NextToken()); - Assert.AreEqual("'a'", tokenizer.NextToken()); - Assert.AreEqual(",", tokenizer.NextToken()); - Assert.AreEqual("1", tokenizer.NextToken()); - Assert.AreEqual(",", tokenizer.NextToken()); - Assert.AreEqual("'b'", tokenizer.NextToken()); - Assert.Null(tokenizer.NextToken()); + Assert.That(tokenizer.NextToken(), Is.EqualTo("SELECT")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("'a'")); + Assert.That(tokenizer.NextToken(), Is.EqualTo(",")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("1")); + Assert.That(tokenizer.NextToken(), Is.EqualTo(",")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("'b'")); + Assert.That(tokenizer.NextToken(), Is.Null); } [Test] @@ -183,13 +184,13 @@ public void UserVariable() string sql = "SELECT 'a', 1, @@myVar"; SqlTokenizer tokenizer = new SqlTokenizer(sql); tokenizer.ReturnComments = false; - Assert.AreEqual("SELECT", tokenizer.NextToken()); - Assert.AreEqual("'a'", tokenizer.NextToken()); - Assert.AreEqual(",", tokenizer.NextToken()); - Assert.AreEqual("1", tokenizer.NextToken()); - Assert.AreEqual(",", tokenizer.NextToken()); - Assert.AreEqual("@@myVar", tokenizer.NextToken()); - Assert.Null(tokenizer.NextToken()); + Assert.That(tokenizer.NextToken(), Is.EqualTo("SELECT")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("'a'")); + Assert.That(tokenizer.NextToken(), Is.EqualTo(",")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("1")); + Assert.That(tokenizer.NextToken(), Is.EqualTo(",")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("@@myVar")); + Assert.That(tokenizer.NextToken(), Is.Null); } [Test] @@ -198,16 +199,16 @@ public void AnsiQuotes() string sql = "SELECT 'a', \"a\", `a`"; SqlTokenizer tokenizer = new SqlTokenizer(sql); tokenizer.AnsiQuotes = false; - Assert.AreEqual("SELECT", tokenizer.NextToken()); - Assert.AreEqual("'a'", tokenizer.NextToken()); - Assert.True(tokenizer.Quoted); - Assert.AreEqual(",", tokenizer.NextToken()); - Assert.AreEqual("\"a\"", tokenizer.NextToken()); - Assert.True(tokenizer.Quoted); - Assert.AreEqual(",", tokenizer.NextToken()); - Assert.AreEqual("`a`", tokenizer.NextToken()); - Assert.True(tokenizer.Quoted); - Assert.Null(tokenizer.NextToken()); + Assert.That(tokenizer.NextToken(), Is.EqualTo("SELECT")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("'a'")); + Assert.That(tokenizer.Quoted); + Assert.That(tokenizer.NextToken(), Is.EqualTo(",")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("\"a\"")); + Assert.That(tokenizer.Quoted); + Assert.That(tokenizer.NextToken(), Is.EqualTo(",")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("`a`")); + Assert.That(tokenizer.Quoted); + Assert.That(tokenizer.NextToken(), Is.Null); } [Test] @@ -216,25 +217,25 @@ public void ParseProcBody() string sql = "CREATE PROCEDURE spTest(testid INT, testname VARCHAR(20)) BEGIN SELECT 1; END"; SqlTokenizer tokenizer = new SqlTokenizer(sql); tokenizer.AnsiQuotes = false; - Assert.AreEqual("CREATE", tokenizer.NextToken()); - Assert.AreEqual("PROCEDURE", tokenizer.NextToken()); - Assert.AreEqual("spTest", tokenizer.NextToken()); - Assert.AreEqual("(", tokenizer.NextToken()); - Assert.AreEqual("testid", tokenizer.NextToken()); - Assert.AreEqual("INT", tokenizer.NextToken()); - Assert.AreEqual(",", tokenizer.NextToken()); - Assert.AreEqual("testname", tokenizer.NextToken()); - Assert.AreEqual("VARCHAR", tokenizer.NextToken()); - Assert.AreEqual("(", tokenizer.NextToken()); - Assert.AreEqual("20", tokenizer.NextToken()); - Assert.AreEqual(")", tokenizer.NextToken()); - Assert.AreEqual(")", tokenizer.NextToken()); - Assert.AreEqual("BEGIN", tokenizer.NextToken()); - Assert.AreEqual("SELECT", tokenizer.NextToken()); - Assert.AreEqual("1", tokenizer.NextToken()); - Assert.AreEqual(";", tokenizer.NextToken()); - Assert.AreEqual("END", tokenizer.NextToken()); - Assert.Null(tokenizer.NextToken()); + Assert.That(tokenizer.NextToken(), Is.EqualTo("CREATE")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("PROCEDURE")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("spTest")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("(")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("testid")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("INT")); + Assert.That(tokenizer.NextToken(), Is.EqualTo(",")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("testname")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("VARCHAR")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("(")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("20")); + Assert.That(tokenizer.NextToken(), Is.EqualTo(")")); + Assert.That(tokenizer.NextToken(), Is.EqualTo(")")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("BEGIN")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("SELECT")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("1")); + Assert.That(tokenizer.NextToken(), Is.EqualTo(";")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("END")); + Assert.That(tokenizer.NextToken(), Is.Null); } /// @@ -250,13 +251,13 @@ public void NoSpaceAroundEquals() cmd.ExecuteNonQuery(); cmd.CommandText = "SELECT name FROM Test"; object o = cmd.ExecuteScalar(); - Assert.AreEqual("test -- test", o); + Assert.That(o, Is.EqualTo("test -- test")); cmd.CommandText = "UPDATE Test SET name='Can you explain this ?';"; cmd.ExecuteNonQuery(); cmd.CommandText = "SELECT name FROM Test"; o = cmd.ExecuteScalar(); - Assert.AreEqual("Can you explain this ?", o); + Assert.That(o, Is.EqualTo("Can you explain this ?")); } [Test] @@ -265,11 +266,11 @@ public void Slash() string sql = "AND // OR"; SqlTokenizer tokenizer = new SqlTokenizer(sql); tokenizer.AnsiQuotes = false; - Assert.AreEqual("AND", tokenizer.NextToken()); - Assert.AreEqual("/", tokenizer.NextToken()); - Assert.AreEqual("/", tokenizer.NextToken()); - Assert.AreEqual("OR", tokenizer.NextToken()); - Assert.Null(tokenizer.NextToken()); + Assert.That(tokenizer.NextToken(), Is.EqualTo("AND")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("/")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("/")); + Assert.That(tokenizer.NextToken(), Is.EqualTo("OR")); + Assert.That(tokenizer.NextToken(), Is.Null); } [Test] @@ -279,17 +280,17 @@ public void SqlServerMode() SqlTokenizer tokenizer = new SqlTokenizer(sql); tokenizer.SqlServerMode = true; tokenizer.NextToken(); - Assert.AreEqual("`a`", tokenizer.NextToken()); - Assert.True(tokenizer.Quoted); + Assert.That(tokenizer.NextToken(), Is.EqualTo("`a`")); + Assert.That(tokenizer.Quoted); tokenizer.NextToken(); // read , - Assert.AreEqual("[id]", tokenizer.NextToken()); - Assert.True(tokenizer.Quoted); + Assert.That(tokenizer.NextToken(), Is.EqualTo("[id]")); + Assert.That(tokenizer.Quoted); tokenizer.NextToken(); // read , - Assert.AreEqual("[name]", tokenizer.NextToken()); - Assert.True(tokenizer.Quoted); + Assert.That(tokenizer.NextToken(), Is.EqualTo("[name]")); + Assert.That(tokenizer.Quoted); tokenizer.NextToken(); // read FROM - Assert.AreEqual("[Test]", tokenizer.NextToken()); - Assert.True(tokenizer.Quoted); + Assert.That(tokenizer.NextToken(), Is.EqualTo("[Test]")); + Assert.That(tokenizer.Quoted); } } } diff --git a/MySQL.Data/tests/MySql.Data.Tests/Transactions.cs b/MySQL.Data/tests/MySql.Data.Tests/Transactions.cs index 639b2a038..7b0c331ce 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/Transactions.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/Transactions.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2022, Oracle and/or its affiliates. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -27,6 +27,7 @@ // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA using NUnit.Framework; +using NUnit.Framework.Legacy; using System; using System.Data; using System.Data.Common; @@ -56,7 +57,7 @@ void TransactionScopeInternal(bool commit) cmd.CommandText = "SELECT COUNT(*) FROM Test"; object count = cmd.ExecuteScalar(); - Assert.AreEqual(commit ? 1 : 0, Convert.ToInt32(count)); + Assert.That(Convert.ToInt32(count), Is.EqualTo(commit ? 1 : 0)); } } @@ -95,7 +96,7 @@ public void TransactionScopeWithIsolationLevel() { reader.Read(); string level = reader.GetString(1); - Assert.AreEqual("READ-COMMITTED", level); + Assert.That(level, Is.EqualTo("READ-COMMITTED")); } } } @@ -115,7 +116,7 @@ public void TransactionScopeWithIsolationLevel() { reader.Read(); string level = reader.GetString(1); - Assert.AreEqual("READ-UNCOMMITTED", level); + Assert.That(level, Is.EqualTo("READ-UNCOMMITTED")); } } } @@ -136,7 +137,7 @@ public void TransactionReadOnlyIsAvailable() { reader.Read(); if (Connection.driver.Version.isAtLeast(5, 7, 0)) - Assert.AreEqual("OFF", reader.GetString(1)); + Assert.That(reader.GetString(1), Is.EqualTo("OFF")); } } } @@ -169,7 +170,7 @@ public void RollingBackOnClose() MySqlCommand cmd2 = new MySqlCommand("SELECT COUNT(*) from Test", c2); c2.BeginTransaction(); object count = cmd2.ExecuteScalar(); - Assert.AreEqual(0, Convert.ToInt32(count)); + Assert.That(Convert.ToInt32(count), Is.EqualTo(0)); } MySqlConnection connection = new MySqlConnection(connStr); @@ -252,7 +253,7 @@ public void EnlistTransactionWNestedTrxTest() public void ManualEnlistment() { #if !NETFRAMEWORK - if (!System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows)) Assert.Ignore(); + Assume.That(System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows)); #endif ExecuteSQL("DROP TABLE IF EXISTS Test"); ExecuteSQL("CREATE TABLE Test (key2 VARCHAR(1), name VARCHAR(100), name2 VARCHAR(100))"); @@ -269,7 +270,7 @@ public void ManualEnlistment() ExecuteSQL("UNLOCK TABLES"); } MySqlCommand cmd2 = new MySqlCommand("LOCK TABLES test READ; SELECT COUNT(*) FROM test", c); - Assert.AreEqual(1, Convert.ToInt32(cmd2.ExecuteScalar())); + Assert.That(Convert.ToInt32(cmd2.ExecuteScalar()), Is.EqualTo(1)); ExecuteSQL("UNLOCK TABLES"); c.Dispose(); KillPooledConnection(connStr); @@ -431,8 +432,8 @@ private void NestedScopeInternalTest( ((long)MySqlHelper.ExecuteScalar(Connection, "select count(*) from T where str = 'inner'") == 1); bool outerChangesVisible = ((long)MySqlHelper.ExecuteScalar(Connection, "select count(*) from T where str = 'outer'") == 1); - Assert.AreEqual(innerChangesVisible, expectInnerChangesVisible); - Assert.AreEqual(outerChangesVisible, expectOuterChangesVisible); + Assert.That(expectInnerChangesVisible, Is.EqualTo(innerChangesVisible)); + Assert.That(expectOuterChangesVisible, Is.EqualTo(outerChangesVisible)); } finally { @@ -525,7 +526,7 @@ private void ReusingSameConnection(bool pooling, bool complete) c2.Open(); MySqlCommand cmd2 = new MySqlCommand("INSERT INTO Test (key2) VALUES ('b')", c2); cmd2.ExecuteNonQuery(); - Assert.AreEqual(c1Thread, c2.ServerThread); + Assert.That(c2.ServerThread, Is.EqualTo(c1Thread)); } if (complete) @@ -537,13 +538,13 @@ private void ReusingSameConnection(bool pooling, bool complete) da.Fill(dt); if (complete) { - Assert.AreEqual(2, dt.Rows.Count); - Assert.AreEqual("a", dt.Rows[0][0]); - Assert.AreEqual("b", dt.Rows[1][0]); + Assert.That(dt.Rows.Count, Is.EqualTo(2)); + Assert.That(dt.Rows[0][0], Is.EqualTo("a")); + Assert.That(dt.Rows[1][0], Is.EqualTo("b")); } else { - Assert.AreEqual(0, dt.Rows.Count); + Assert.That(dt.Rows.Count, Is.EqualTo(0)); } } @@ -566,7 +567,7 @@ public void ReusingSameConnectionTest() public void ScopeTimeoutWithMySqlHelper() { #if !NETFRAMEWORK - if (!System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows)) Assert.Ignore(); + Assume.That(System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows)); #endif ExecuteSQL("DROP TABLE IF EXISTS Test"); ExecuteSQL("CREATE TABLE Test (id int)"); @@ -585,7 +586,7 @@ public void ScopeTimeoutWithMySqlHelper() } } long count = (long)MySqlHelper.ExecuteScalar(connStr, "select count(*) from test"); - Assert.AreEqual(0, count); + Assert.That(count, Is.EqualTo(0)); } /// @@ -628,10 +629,10 @@ public void AttemptToUseConnectionAfterScopeTimeout() Thread.Sleep(500); Assert.Throws(() => cmd.ExecuteNonQuery()); } - Assert.True(c.State == ConnectionState.Open); + Assert.That(c.State == ConnectionState.Open); cmd.CommandText = "select count(*) from Test"; long count = (long)cmd.ExecuteScalar(); - Assert.AreEqual(0, count); + Assert.That(count, Is.EqualTo(0)); } } @@ -660,7 +661,7 @@ public void SnapshotIsolationLevelThrowsNotSupportedException() { newcon.Open(); var ex = Assert.Throws(() => newcon.BeginTransaction(System.Data.IsolationLevel.Snapshot)); - Assert.AreEqual("Snapshot isolation level is not supported.", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Snapshot isolation level is not supported")); } } @@ -705,7 +706,7 @@ public void Bug26035791() cmd2 = new MySqlCommand(@"select count(*) from TransTest", db, transaction); int.TryParse(cmd2.ExecuteScalar().ToString(), out int n1); // If ReadUncommitted is applied we should be able to read inserted record before commit - Assert.True(n1 == 2); + Assert.That(n1 == 2); transaction.Commit(); } ExecuteSQL("drop table TransTest"); @@ -715,7 +716,7 @@ public void Bug26035791() reader.Read(); finalLevel = reader.GetString(1); } - Assert.AreEqual(initialLevel, finalLevel); // Isolation level should be the same after the transaction + Assert.That(finalLevel, Is.EqualTo(initialLevel)); // Isolation level should be the same after the transaction } } @@ -765,7 +766,7 @@ public void TransactionWithAutoCommit() { connection.Open(); var transaction = connection.BeginTransaction(); - Assert.IsNotNull(transaction); + Assert.That(transaction, Is.Not.Null); var myCommand = connection.CreateCommand(); myCommand.CommandText = "INSERT INTO `Test` VALUES (1);"; var result = myCommand.ExecuteNonQuery(); @@ -874,4 +875,4 @@ private static async Task SelectStarLimit1(string connectionString, string table } } } -} \ No newline at end of file +} diff --git a/MySQL.Data/tests/MySql.Data.Tests/UnixSockets.cs b/MySQL.Data/tests/MySql.Data.Tests/UnixSockets.cs index 2c2dae067..1ab79fb24 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/UnixSockets.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/UnixSockets.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2017, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -28,6 +28,7 @@ using MySql.Data.Common; using NUnit.Framework; +using NUnit.Framework.Legacy; using System; using System.Data; @@ -41,17 +42,13 @@ public void ConnectionTest() { string unixConnectionString = $"server={UnixSocket};user={Settings.UserID};password={Settings.Password};protocol=unix;"; - if (Platform.IsWindows()) - { - Console.Error.WriteLine($"{nameof(ConnectionTest)} ignored because it's a Windows system."); - Assert.Ignore(); - } + Assume.That(!Platform.IsWindows()); using (MySqlConnection conn = new MySqlConnection(unixConnectionString)) { conn.Open(); - Assert.AreEqual(ConnectionState.Open, conn.State); + Assert.That(conn.State, Is.EqualTo(ConnectionState.Open)); } } } -} \ No newline at end of file +} diff --git a/MySQL.Data/tests/MySql.Data.Tests/Utils.cs b/MySQL.Data/tests/MySql.Data.Tests/Utils.cs index 7c3637646..16b0cc5bc 100644 --- a/MySQL.Data/tests/MySql.Data.Tests/Utils.cs +++ b/MySQL.Data/tests/MySql.Data.Tests/Utils.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2021, Oracle and/or its affiliates. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -70,4 +70,4 @@ public static bool TableExists(string tableName, MySqlConnection conn) } } } -} \ No newline at end of file +} diff --git a/MySQL.Data/tests/MySqlX.Data.Performance.Console.Tests/App.config b/MySQL.Data/tests/MySqlX.Data.Performance.Console.Tests/App.config deleted file mode 100644 index 4bfa00561..000000000 --- a/MySQL.Data/tests/MySqlX.Data.Performance.Console.Tests/App.config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/MySQL.Data/tests/MySqlX.Data.Performance.Console.Tests/InstrumentationSession.psess b/MySQL.Data/tests/MySqlX.Data.Performance.Console.Tests/InstrumentationSession.psess deleted file mode 100644 index 2937c6df6..000000000 --- a/MySQL.Data/tests/MySqlX.Data.Performance.Console.Tests/InstrumentationSession.psess +++ /dev/null @@ -1,122 +0,0 @@ - - - - ..\..\MySql.Data.sln - Instrumentation - None - Reports\InstrumentationReport.vsp - true - true - Timestamp - Cycles - 10000000 - 10 - 10 - - false - /include:MySqlX.Data.Tests.BaseTest::*;MySqlX.Data.Tests.BasicFindTests::*;MySqlX.Data.Tests.BasicSelectTests::*;MySqlX.Data.Tests.CharsetAndCollationTests::*;MySqlX.Data.Tests.CollectionIndexTests::*;MySqlX.Data.Tests.CollectionTests::*;MySqlX.Data.Tests.CollectionAsyncTests::*;MySqlX.Data.Tests.CrudInsertTests::*;MySqlX.Data.Tests.CrudRemoveTests::*;MySqlX.Data.Tests.CrudUpdateTests::*;MySqlX.Data.Tests.MergePatch::*;MySqlX.Data.Tests.SchemaTests::*;MySqlX.Data.Tests.SessionTests::*;MySqlX.Data.Tests.TransactionTests::*;MySqlX.Data.Tests.ExprParserTests::*;MySqlX.Data.Tests.DbDocTests::*;MySqlX.Data.Tests.JsonParserTests::*;MySqlX.Data.Tests.RelationalTests.ColumnMetadataTests::*;MySqlX.Data.Tests.RelationalTests.DataTypeTests::*;MySqlX.Data.Tests.RelationalTests.RowBufferingTests::*;MySqlX.Data.Tests.RelationalTests.DateTimeTests::*;MySqlX.Data.Tests.RelationalTests.SqlTests::*;MySqlX.Data.Tests.RelationalTests.TableAsyncTests::*;MySqlX.Data.Tests.RelationalTests.TableDeleteTests::*;MySqlX.Data.Tests.RelationalTests.TableInsertTests::*;MySqlX.Data.Tests.RelationalTests.TableSelectTests::*;MySqlX.Data.Tests.RelationalTests.TableUpdateTests::*;MySqlX.Data.Tests.RelationalTests.ViewTests::*;MySqlX.Data.Tests.ResultTests.RelationalGCTests::*;MySqlX.Data.Tests.ResultTests.CrudGCTests::*;MySqlX.Data.Tests.CrudTests.DocBufferingTests::*;MySqlX.Data.Tests.PerformanceTests::*; - - - - false - 500 - - \Memory\Pages/sec - \PhysicalDisk(_Total)\Avg. Disk Queue Length - \Processor(_Total)\% Processor Time - - - - true - false - false - - false - - - false - - - - bin\Release\MySql.Data.dll - 08/17/2018 18:41:24 - true - true - false - false - false - false - false - true - false - Executable - IIS - InternetExplorer - true - false - - false - - - false - - - - bin\Release\MySqlX.Data.Performance.Console.Tests.exe - 08/17/2018 18:41:24 - true - true - false - false - false - false - false - false - true - Executable - bin\Release\MySqlX.Data.Performance.Console.Tests.exe - - - 2 - IIS - InternetExplorer - true - false - - false - - - false - - - - bin\Release\MySqlX.Data.Tests.dll - 08/17/2018 18:41:24 - true - true - false - false - false - false - false - true - false - Executable - IIS - InternetExplorer - true - false - - false - - - false - - - - - - bin\Release\MySqlX.Data.Performance.Console.Tests.exe - - - \ No newline at end of file diff --git a/MySQL.Data/tests/MySqlX.Data.Performance.Console.Tests/MySqlX.Data.Performance.Console.Tests.csproj b/MySQL.Data/tests/MySqlX.Data.Performance.Console.Tests/MySqlX.Data.Performance.Console.Tests.csproj deleted file mode 100644 index 07faa6cef..000000000 --- a/MySQL.Data/tests/MySqlX.Data.Performance.Console.Tests/MySqlX.Data.Performance.Console.Tests.csproj +++ /dev/null @@ -1,88 +0,0 @@ - - - - - Debug - AnyCPU - {9D5EDC76-5A1C-46C9-A4F2-CF57F276E537} - Exe - MySqlX.Data.Performance.Console.Tests - MySqlX.Data.Performance.Console.Tests - v4.8 - 512 - true - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - false - true - - - AnyCPU - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - - - - - - - - - Properties\VersionInfo.cs - - - - - - - - - - {c411c777-fbe2-4f27-bde1-2b69001320bc} - MySqlX.Data.Tests - - - - - False - Microsoft .NET Framework 4.8 %28x86 and x64%29 - true - - - False - .NET Framework 3.5 SP1 - false - - - - \ No newline at end of file diff --git a/MySQL.Data/tests/MySqlX.Data.Performance.Console.Tests/Program.cs b/MySQL.Data/tests/MySqlX.Data.Performance.Console.Tests/Program.cs deleted file mode 100644 index 9311b64ef..000000000 --- a/MySQL.Data/tests/MySqlX.Data.Performance.Console.Tests/Program.cs +++ /dev/null @@ -1,165 +0,0 @@ -// Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using System; -using System.Reflection; - -namespace MySqlX.Data.Performance.Console.Tests -{ - public class Program - { - /// - /// Number of times to execute the operation. - /// - private const int EXECUTION_COUNT = 1; - - /// - /// Namespaces. - /// - private const string X_DEVAPI_TESTS_MAIN_NAMESPACE = "MySqlX.Data.Tests"; - private const string X_DEVAPI_RELATIONAL_TESTS_NAMESPACE = "MySqlX.Data.Tests.RelationalTests"; - private const string X_DEVAPI_CRUD_TESTS_NAMESPACE = "MySqlX.Data.Tests.CrudTests"; - private const string X_DEVAPI_RESULT_TESTS_NAMESPACE = "MySqlX.Data.Tests.ResultTests"; - - static void Main(string[] args) - { - if (args.Length > 0) - { - switch (args.Length) - { - case 1: - Program.ExecuteCase(Convert.ToInt32(args[0])); - break; - case 2: - case 3: - Program.ExecuteCase(1, args); - break; - default: - break; - } - } - else - { - System.Console.WriteLine("No arguments were found."); - Program.ExecuteCase(2); - } - - System.Console.WriteLine("Execution completed."); - System.Console.ReadKey(); - } - - static void ExecuteCase(int caseToExecute, string[] args = null) - { - switch (caseToExecute) - { - case 0: - System.Console.WriteLine("Run tests from the PerformanceTests class."); - ExecuteAllClassTests("PerformanceTests", X_DEVAPI_TESTS_MAIN_NAMESPACE, EXECUTION_COUNT); - break; - case 1: - System.Console.WriteLine("Run tests from a specific class."); - ExecuteAllClassTests( - args[0], args.Length == 3 ? - args[1] : X_DEVAPI_TESTS_MAIN_NAMESPACE, - args.Length == 2 ? - Convert.ToInt32(args[1]) : args.Length == 3 ? - Convert.ToInt32(args[2]) : EXECUTION_COUNT); - break; - case 2: - System.Console.WriteLine("Run all unit tests."); - ExecuteAllClassTests("BasicFindTests", X_DEVAPI_TESTS_MAIN_NAMESPACE, EXECUTION_COUNT); - ExecuteAllClassTests("BasicSelectTests", X_DEVAPI_TESTS_MAIN_NAMESPACE, EXECUTION_COUNT); - ExecuteAllClassTests("CharsetAndCollationTests", X_DEVAPI_TESTS_MAIN_NAMESPACE, EXECUTION_COUNT); - ExecuteAllClassTests("CollectionIndexTests", X_DEVAPI_TESTS_MAIN_NAMESPACE, EXECUTION_COUNT); - ExecuteAllClassTests("CollectionTests", X_DEVAPI_TESTS_MAIN_NAMESPACE, EXECUTION_COUNT); - ExecuteAllClassTests("CollectionAsyncTests", X_DEVAPI_TESTS_MAIN_NAMESPACE, EXECUTION_COUNT); - ExecuteAllClassTests("CrudInsertTests", X_DEVAPI_TESTS_MAIN_NAMESPACE, EXECUTION_COUNT); - ExecuteAllClassTests("CrudRemoveTests", X_DEVAPI_TESTS_MAIN_NAMESPACE, EXECUTION_COUNT); - ExecuteAllClassTests("CrudUpdateTests", X_DEVAPI_TESTS_MAIN_NAMESPACE, EXECUTION_COUNT); - ExecuteAllClassTests("MergePatch", X_DEVAPI_TESTS_MAIN_NAMESPACE, EXECUTION_COUNT); - ExecuteAllClassTests("SchemaTests", X_DEVAPI_TESTS_MAIN_NAMESPACE, EXECUTION_COUNT); - ExecuteAllClassTests("SessionTests", X_DEVAPI_TESTS_MAIN_NAMESPACE, EXECUTION_COUNT); - ExecuteAllClassTests("TransactionTests", X_DEVAPI_TESTS_MAIN_NAMESPACE, EXECUTION_COUNT); - ExecuteAllClassTests("ExprParserTests", X_DEVAPI_TESTS_MAIN_NAMESPACE, EXECUTION_COUNT); - ExecuteAllClassTests("DbDocTests", X_DEVAPI_TESTS_MAIN_NAMESPACE, EXECUTION_COUNT); - ExecuteAllClassTests("JsonParserTests", X_DEVAPI_TESTS_MAIN_NAMESPACE, EXECUTION_COUNT); - ExecuteAllClassTests("ColumnMetadataTests", X_DEVAPI_RELATIONAL_TESTS_NAMESPACE, EXECUTION_COUNT); - ExecuteAllClassTests("DataTypeTests", X_DEVAPI_RELATIONAL_TESTS_NAMESPACE, EXECUTION_COUNT); - ExecuteAllClassTests("RowBufferingTests", X_DEVAPI_RELATIONAL_TESTS_NAMESPACE, EXECUTION_COUNT); - ExecuteAllClassTests("DateTimeTests", X_DEVAPI_RELATIONAL_TESTS_NAMESPACE, EXECUTION_COUNT); - ExecuteAllClassTests("SqlTests", X_DEVAPI_RELATIONAL_TESTS_NAMESPACE, EXECUTION_COUNT); - ExecuteAllClassTests("TableAsyncTests", X_DEVAPI_RELATIONAL_TESTS_NAMESPACE, EXECUTION_COUNT); - ExecuteAllClassTests("TableDeleteTests", X_DEVAPI_RELATIONAL_TESTS_NAMESPACE, EXECUTION_COUNT); - ExecuteAllClassTests("TableInsertTests", X_DEVAPI_RELATIONAL_TESTS_NAMESPACE, EXECUTION_COUNT); - ExecuteAllClassTests("TableSelectTests", X_DEVAPI_RELATIONAL_TESTS_NAMESPACE, EXECUTION_COUNT); - ExecuteAllClassTests("TableUpdateTests", X_DEVAPI_RELATIONAL_TESTS_NAMESPACE, EXECUTION_COUNT); - ExecuteAllClassTests("ViewTests", X_DEVAPI_RELATIONAL_TESTS_NAMESPACE, EXECUTION_COUNT); - ExecuteAllClassTests("RelationalGCTests", X_DEVAPI_RESULT_TESTS_NAMESPACE, EXECUTION_COUNT); - ExecuteAllClassTests("CrudGCTests", X_DEVAPI_RESULT_TESTS_NAMESPACE, EXECUTION_COUNT); - ExecuteAllClassTests("DocBufferingTests", X_DEVAPI_CRUD_TESTS_NAMESPACE, EXECUTION_COUNT); - ExecuteAllClassTests("PerformanceTests", X_DEVAPI_TESTS_MAIN_NAMESPACE, EXECUTION_COUNT); - ExecuteAllClassTests("UnixSocketsTests", X_DEVAPI_TESTS_MAIN_NAMESPACE, EXECUTION_COUNT); - ExecuteAllClassTests("ClientSideFailoverTests", X_DEVAPI_TESTS_MAIN_NAMESPACE, EXECUTION_COUNT); - break; - default: - System.Console.WriteLine("Invalid value. Use 0 to execute PerformanceTests tests," + - "1 to execute tests from a specific class or 2 to execute all tests."); - break; - } - } - - static void ExecuteAllClassTests(string className, string nameSpace, int executionCount) - { - System.Console.WriteLine(string.Format("{0} -------------------------- ", className)); - var type = Type.GetType(string.Format("{0}.{1},{2}", nameSpace, className, X_DEVAPI_TESTS_MAIN_NAMESPACE)); - var methodInfos = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly); - foreach (var methodInfo in methodInfos) - { - int i = 0; - try - { - for (; i < executionCount; i++) - { - methodInfo.Invoke(Activator.CreateInstance(type), null); - } - System.Console.WriteLine(string.Format("\t{0} <-- Success({1})", methodInfo.Name, i)); - } - catch (Exception ex) - { - System.Console.WriteLine(string.Format("\t{0} <-- Not executed({1}): Exception: {2}, Inner exception: {3}", - methodInfo.Name, - i, - ex.Message, - ex.InnerException != null ? - ex.InnerException.Message : - "N/A")); - } - } - } - } -} \ No newline at end of file diff --git a/MySQL.Data/tests/MySqlX.Data.Performance.Console.Tests/Properties/AssemblyInfo.cs b/MySQL.Data/tests/MySqlX.Data.Performance.Console.Tests/Properties/AssemblyInfo.cs deleted file mode 100644 index 53a3ec6a6..000000000 --- a/MySQL.Data/tests/MySqlX.Data.Performance.Console.Tests/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("MySqlX.Data.Performance.Console.Tests")] -[assembly: AssemblyDescription("Console application to run Performance Profiling tests for MySQL Connector/NET")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Oracle")] -[assembly: AssemblyProduct("MySqlX.Data.Performance.Console.Tests")] -[assembly: AssemblyCopyright("Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("9d5edc76-5a1c-46c9-a4f2-cf57f276e537")] diff --git a/MySQL.Data/tests/MySqlX.Data.Tests/BaseTest.cs b/MySQL.Data/tests/MySqlX.Data.Tests/BaseTest.cs index 1c8ab9e5e..f5fc415f0 100644 --- a/MySQL.Data/tests/MySqlX.Data.Tests/BaseTest.cs +++ b/MySQL.Data/tests/MySqlX.Data.Tests/BaseTest.cs @@ -1,282 +1,289 @@ -// Copyright (c) 2015, 2023, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data.MySqlClient; -using MySqlX.XDevAPI; -using MySqlX.XDevAPI.Common; -using MySqlX.XDevAPI.CRUD; -using MySqlX.XDevAPI.Relational; -using NUnit.Framework; -using System; -using System.Data; -using System.IO; -using System.Net; -using System.Net.Sockets; -using System.Reflection; - -namespace MySqlX.Data.Tests -{ - public class BaseTest - { - protected Session session; - protected Schema testSchema; - protected static readonly string schemaName = "test"; - public static readonly string sslCa = "ca.pem"; - public static readonly string sslCert = "client-cert.pem"; - public static readonly string sslKey = "client-key.pem"; - public static readonly string clientPfxIncorrect = "client-incorrect.pfx"; - public static readonly string clientPfx = "client.pfx"; - public static readonly string sslCertificatePassword = "pass"; - - #region Properties - internal static string Port { get; private set; } = Environment.GetEnvironmentVariable("MYSQL_PORT") ?? "3306"; - internal static string XPort { get; private set; } = Environment.GetEnvironmentVariable("MYSQLX_PORT") ?? "33060"; - internal static string Host { get; private set; } = Environment.GetEnvironmentVariable("MYSQL_HOST") ?? "localhost"; - internal static string RootUser { get; private set; } = Environment.GetEnvironmentVariable("MYSQL_ROOT_USER") ?? "root"; - internal static string RootPassword { get; private set; } = Environment.GetEnvironmentVariable("MYSQL_ROOT_PASSWORD") ?? string.Empty; - public static string ConnectionString { get; private set; } - public static string ConnectionStringUri { get; private set; } - public static string ConnectionStringNoPassword { get; private set; } - public static string ConnectionStringRoot { get; private set; } - public static string ConnectionStringUriNative { get; private set; } - public static string ConnectionStringUserWithSSLPEM { get; private set; } - public static string connSSLURI { get; private set; } - public static bool ServerIsDown { get; set; } - #endregion - - #region Ctor - static BaseTest() - { - ConnectionStringRoot = $"server={Host};port={Port};uid={RootUser};password={RootPassword}"; - ConnectionString = $"server={Host};port={XPort};uid=test;password=test"; - ConnectionStringNoPassword = $"server={Host};port={XPort};uid=testNoPass;"; - ConnectionStringUri = $"mysqlx://test:test@{Host}:{XPort}"; - ConnectionStringUriNative = $"mysqlx://testNative:test@{Host}:{XPort}"; - ConnectionStringUserWithSSLPEM = $"server={Host};user=test;port={XPort};password=test;SslCa={sslCa};SslCert={sslCert};SslKey={sslKey}"; - connSSLURI = ConnectionStringUri + $"?Ssl-ca={sslCa}&SslCert={sslCert}&SslKey={sslKey}&Auth=AUTO"; - } - #endregion - - #region SetUp - [OneTimeSetUp] - public virtual void BaseSetUp() - { - Assembly executingAssembly = typeof(BaseTest).GetTypeInfo().Assembly; - Stream stream = executingAssembly.GetManifestResourceStream("MySqlX.Data.Tests.Properties.CreateUsers.sql"); - StreamReader sr = new StreamReader(stream); - string sql = sr.ReadToEnd(); - sr.Dispose(); - ExecuteSqlAsRoot(sql); - session = GetSession(); - testSchema = session.GetSchema(schemaName); - if (SchemaExistsInDatabase(testSchema)) - session.DropSchema(schemaName); - session.CreateSchema(schemaName); - } - #endregion - - #region TearDown - [OneTimeTearDown] - public virtual void BaseTearDown() - { - using (Session s = GetSession()) - { - Schema schema = s.GetSchema(schemaName); - if (SchemaExistsInDatabase(schema)) - s.DropSchema(schemaName); - schema.Session.DropSchema(schemaName); - Assert.False(SchemaExistsInDatabase(schema)); - } - - DropUsers(); - } - #endregion - - #region Methods - private void DropUsers() - { - var users = FillTable("SELECT user, host FROM mysql.user WHERE user NOT LIKE 'mysql%' AND user NOT LIKE 'root'"); - foreach (DataRow row in users.Rows) - ExecuteSqlAsRoot(string.Format("DROP USER '{0}'@'{1}'", row[0].ToString(), row[1].ToString())); - ExecuteSqlAsRoot("FLUSH PRIVILEGES"); - } - - public DataTable FillTable(string sql) - { - DataTable dt = new DataTable(); - using (var conn = new MySqlConnection(ConnectionStringRoot)) - { - conn.Open(); - MySqlDataAdapter da = new MySqlDataAdapter(sql, conn); - da.Fill(dt); - } - return dt; - } - - protected Table GetTable(string schema, string table) - { - return GetSession().GetSchema(schema).GetTable(table); - } - - protected SqlResult ExecuteSQL(string sql) - { - Session session = GetSession(); - session.SetCurrentSchema(schemaName); - SqlResult r = ExecuteSQLStatement(session.SQL(sql)); - var rows = r.HasData ? r.FetchAll() : null; - return r; - } - - protected Collection CreateCollection(string name, string schema = null) - { - if (schema == null) - schema = schemaName; - Schema test = session.GetSchema(schema); - test.DropCollection(name); - return test.CreateCollection(name); - } - - public Session GetSession(bool setCurrentSchema = false) - { - if (session == null) - { - session = MySQLX.GetSession(ConnectionString); - if (setCurrentSchema) - session.SetCurrentSchema(schemaName); - } - return session; - } - - protected void ExecuteSqlAsRoot(string sql) - { - using (var conn = new MySqlConnection(ConnectionStringRoot + ";ssl mode=none")) - { - conn.Open(); - MySqlScript s = new(conn, sql); - s.Execute(); - } - } - - protected Result ExecuteAddStatement(AddStatement stmt) - { - return stmt.Execute(); - } - - protected Result ExecuteModifyStatement(ModifyStatement stmt) - { - return stmt.Execute(); - } - - protected DocResult ExecuteFindStatement(FindStatement stmt) - { - return stmt.Execute(); - } - - protected SqlResult ExecuteSQLStatement(SqlStatement stmt) - { - return stmt.Execute(); - } - - protected Result ExecuteRemoveStatement(RemoveStatement stmt) - { - return stmt.Execute(); - } - - protected RowResult ExecuteSelectStatement(TableSelectStatement stmt) - { - return stmt.Execute(); - } - - protected Result ExecuteInsertStatement(TableInsertStatement stmt) - { - return stmt.Execute(); - } - - protected Result ExecuteUpdateStatement(TableUpdateStatement stmt) - { - return stmt.Execute(); - } - - protected Result ExecuteDeleteStatement(TableDeleteStatement stmt) - { - return stmt.Execute(); - } - - protected bool SchemaExistsInDatabase(Schema schema) - { - return schema.ExistsInDatabase(); - } - - protected bool CollectionExistsInDatabase(Collection collection) - { - return collection.ExistsInDatabase(); - } - - protected bool TableExistsInDatabase(Table table) - { - return table.ExistsInDatabase(); - } - - public string GetIPV6Address() - { - string strHostName = System.Net.Dns.GetHostName(); - IPHostEntry ipEntry = System.Net.Dns.GetHostEntry(strHostName); - IPAddress[] addr = ipEntry.AddressList; - return addr[0].ToString(); - } - - /// - /// Method to get the local ip address of the active MySql Server - /// - /// when is true return IPv6(::1), otherwise return IPv4(127.0.0.1) which is the default - /// Return the ip address as string - public string GetMySqlServerIp(bool isIpV6 = false) - { - var hostname = session.SQL("Select SUBSTRING_INDEX(host, ':', 1) as 'ip' From information_schema.processlist WHERE ID = connection_id()").Execute().FetchOne()[0].ToString(); - string ipv4 = string.Empty; - string ipv6 = string.Empty; - - foreach (var item in Dns.GetHostEntry(hostname).AddressList) - { - switch (item.AddressFamily) - { - case AddressFamily.InterNetwork: - ipv4 = item.ToString(); - break; - case AddressFamily.InterNetworkV6: - ipv6 = item.ToString(); - break; - } - } - - return isIpV6 ? ipv6 : ipv4; - } - - #endregion - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data.MySqlClient; +using MySqlX.XDevAPI; +using MySqlX.XDevAPI.Common; +using MySqlX.XDevAPI.CRUD; +using MySqlX.XDevAPI.Relational; +using NUnit.Framework; +using NUnit.Framework.Legacy; +using System; +using System.Data; +using System.IO; +using System.Net; +using System.Net.Sockets; +using System.Reflection; + +namespace MySqlX.Data.Tests +{ + public class BaseTest + { + protected Session session; + protected Schema testSchema; + protected static readonly string schemaName = "test"; + public static readonly string sslCa = "ca.pem"; + public static readonly string sslCert = "client-cert.pem"; + public static readonly string sslKey = "client-key.pem"; + public static readonly string clientPfxIncorrect = "client-incorrect.pfx"; + public static readonly string clientPfx = "client.pfx"; + public static readonly string sslCertificatePassword = "pass"; + + #region Properties + internal static string Port { get; private set; } = Environment.GetEnvironmentVariable("MYSQL_PORT") ?? "3306"; + internal static string XPort { get; private set; } = Environment.GetEnvironmentVariable("MYSQLX_PORT") ?? "33060"; + internal static string Host { get; private set; } = Environment.GetEnvironmentVariable("MYSQL_HOST") ?? "localhost"; + internal static string RootUser { get; private set; } = Environment.GetEnvironmentVariable("MYSQL_ROOT_USER") ?? "root"; + internal static string RootPassword { get; private set; } = Environment.GetEnvironmentVariable("MYSQL_ROOT_PASSWORD") ?? string.Empty; + public static string ConnectionString { get; private set; } + public static string ConnectionStringUri { get; private set; } + public static string ConnectionStringNoPassword { get; private set; } + public static string ConnectionStringRoot { get; private set; } + public static string ConnectionStringUriNative { get; private set; } + public static string ConnectionStringUserWithSSLPEM { get; private set; } + public static string connSSLURI { get; private set; } + public static bool ServerIsDown { get; set; } + #endregion + + #region Ctor + static BaseTest() + { + ConnectionStringRoot = $"server={Host};port={Port};uid={RootUser};password={RootPassword}"; + ConnectionString = $"server={Host};port={XPort};uid=test;password=test"; + ConnectionStringNoPassword = $"server={Host};port={XPort};uid=testNoPass;"; + ConnectionStringUri = $"mysqlx://test:test@{Host}:{XPort}"; + ConnectionStringUriNative = $"mysqlx://testNative:test@{Host}:{XPort}"; + ConnectionStringUserWithSSLPEM = $"server={Host};user=test;port={XPort};password=test;SslCa={sslCa};SslCert={sslCert};SslKey={sslKey}"; + connSSLURI = ConnectionStringUri + $"?Ssl-ca={sslCa}&SslCert={sslCert}&SslKey={sslKey}&Auth=AUTO"; + } + #endregion + + #region SetUp + [OneTimeSetUp] + public virtual void BaseSetUp() + { + Assembly executingAssembly = typeof(BaseTest).GetTypeInfo().Assembly; + Stream stream = executingAssembly.GetManifestResourceStream("MySqlX.Data.Tests.Properties.CreateUsers.sql"); + StreamReader sr = new StreamReader(stream); + string sql = sr.ReadToEnd(); + sr.Dispose(); + ExecuteSqlAsRoot(sql); + session = GetSession(); + testSchema = session.GetSchema(schemaName); + if (SchemaExistsInDatabase(testSchema)) + session.DropSchema(schemaName); + session.CreateSchema(schemaName); + } + #endregion + + #region TearDown + [OneTimeTearDown] + public virtual void BaseTearDown() + { + using (Session s = GetSession()) + { + Schema schema = s.GetSchema(schemaName); + if (SchemaExistsInDatabase(schema)) + s.DropSchema(schemaName); + schema.Session.DropSchema(schemaName); + Assert.That(SchemaExistsInDatabase(schema), Is.False); + } + + DropUsers(); + } + #endregion + + #region Methods + private void DropUsers() + { + var users = FillTable("SELECT user, host FROM mysql.user WHERE user NOT LIKE 'mysql%' AND user NOT LIKE 'root'"); + foreach (DataRow row in users.Rows) + ExecuteSqlAsRoot(string.Format("DROP USER '{0}'@'{1}'", row[0].ToString(), row[1].ToString())); + ExecuteSqlAsRoot("FLUSH PRIVILEGES"); + } + + public DataTable FillTable(string sql) + { + DataTable dt = new DataTable(); + using (var conn = new MySqlConnection(ConnectionStringRoot)) + { + conn.Open(); + MySqlDataAdapter da = new MySqlDataAdapter(sql, conn); + da.Fill(dt); + } + return dt; + } + + protected Table GetTable(string schema, string table) + { + return GetSession().GetSchema(schema).GetTable(table); + } + + protected SqlResult ExecuteSQL(string sql) + { + Session session = GetSession(); + session.SetCurrentSchema(schemaName); + SqlResult r = ExecuteSQLStatement(session.SQL(sql)); + var rows = r.HasData ? r.FetchAll() : null; + return r; + } + + protected Collection CreateCollection(string name, string schema = null) + { + if (schema == null) + schema = schemaName; + Schema test = session.GetSchema(schema); + test.DropCollection(name); + return test.CreateCollection(name); + } + + public Session GetSession(bool setCurrentSchema = false) + { + if (session == null) + { + session = MySQLX.GetSession(ConnectionString); + if (setCurrentSchema) + session.SetCurrentSchema(schemaName); + } + return session; + } + + protected void ExecuteSqlAsRoot(string sql) + { + using (var conn = new MySqlConnection(ConnectionStringRoot + ";ssl mode=none")) + { + conn.Open(); + MySqlScript s = new(conn, sql); + s.Execute(); + } + } + + protected Result ExecuteAddStatement(AddStatement stmt) + { + return stmt.Execute(); + } + + protected Result ExecuteModifyStatement(ModifyStatement stmt) + { + return stmt.Execute(); + } + + protected DocResult ExecuteFindStatement(FindStatement stmt) + { + return stmt.Execute(); + } + + protected SqlResult ExecuteSQLStatement(SqlStatement stmt) + { + return stmt.Execute(); + } + + protected Result ExecuteRemoveStatement(RemoveStatement stmt) + { + return stmt.Execute(); + } + + protected RowResult ExecuteSelectStatement(TableSelectStatement stmt) + { + return stmt.Execute(); + } + + protected Result ExecuteInsertStatement(TableInsertStatement stmt) + { + return stmt.Execute(); + } + + protected Result ExecuteUpdateStatement(TableUpdateStatement stmt) + { + return stmt.Execute(); + } + + protected Result ExecuteDeleteStatement(TableDeleteStatement stmt) + { + return stmt.Execute(); + } + + protected bool SchemaExistsInDatabase(Schema schema) + { + return schema.ExistsInDatabase(); + } + + protected bool CollectionExistsInDatabase(Collection collection) + { + return collection.ExistsInDatabase(); + } + + protected bool TableExistsInDatabase(Table table) + { + return table.ExistsInDatabase(); + } + + public string GetIPV6Address() + { + string strHostName = System.Net.Dns.GetHostName(); + IPHostEntry ipEntry = System.Net.Dns.GetHostEntry(strHostName); + IPAddress[] addr = ipEntry.AddressList; + return addr[0].ToString(); + } + + /// + /// Method to get the local ip address of the active MySql Server + /// + /// when is true return IPv6(::1), otherwise return IPv4(127.0.0.1) which is the default + /// Return the ip address as string + public string GetMySqlServerIp(bool isIpV6 = false) + { + var hostname = session.SQL("Select SUBSTRING_INDEX(host, ':', 1) as 'ip' From information_schema.processlist WHERE ID = connection_id()").Execute().FetchOne()[0].ToString(); + string ipv4 = string.Empty; + string ipv6 = string.Empty; + + foreach (var item in Dns.GetHostEntry(hostname).AddressList) + { + switch (item.AddressFamily) + { + case AddressFamily.InterNetwork: + ipv4 = item.ToString(); + break; + case AddressFamily.InterNetworkV6: + ipv6 = item.ToString(); + break; + } + } + + return isIpV6 ? ipv6 : ipv4; + } + + public bool Check_Plugin_Enabled(string pluginname) + { + var checkplugin = session.SQL($"SELECT * FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME = '{pluginname}' AND PLUGIN_STATUS='ACTIVE';").Execute().FetchOne(); + return checkplugin != null; + } + + #endregion + } +} diff --git a/MySQL.Data/tests/MySqlX.Data.Tests/BasicFindTests.cs b/MySQL.Data/tests/MySqlX.Data.Tests/BasicFindTests.cs index 2e20b5fec..89549ee2a 100644 --- a/MySQL.Data/tests/MySqlX.Data.Tests/BasicFindTests.cs +++ b/MySQL.Data/tests/MySqlX.Data.Tests/BasicFindTests.cs @@ -1,2284 +1,2285 @@ -// Copyright (c) 2015, 2023, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data.Common; -using MySql.Data.MySqlClient; -using MySqlX.XDevAPI; -using MySqlX.XDevAPI.Common; -using MySqlX.XDevAPI.CRUD; -using NUnit.Framework; -using System; - -namespace MySqlX.Data.Tests -{ - public class BasicFindTests : BaseTest - { - [Test] - public void SimpleFind() - { - Collection coll = CreateCollection("test"); - var docs = new[] - { - new { _id = 1, title = "Book 1", pages = 20 }, - new { _id = 2, title = "Book 2", pages = 30 }, - new { _id = 3, title = "Book 3", pages = 40 }, - new { _id = 4, title = "Book 4", pages = 50 }, - }; - Result r = ExecuteAddStatement(coll.Add(docs)); - Assert.AreEqual(4, r.AffectedItemsCount); - - var foundDocs = ExecuteFindStatement(coll.Find("pages > 20")); - Assert.True(foundDocs.Next()); - Assert.True(foundDocs.Current["title"].ToString() == "Book 2"); - Assert.True(foundDocs.Next()); - Assert.True(foundDocs.Current["title"].ToString() == "Book 3"); - Assert.True(foundDocs.Next()); - Assert.True(foundDocs.Current["title"].ToString() == "Book 4"); - Assert.False(foundDocs.Next()); - } - - [Test] - public void SimpleFindWithSort() - { - Collection coll = CreateCollection("test"); - var docs = new[] - { - new { _id = 1, title = "Book 1", pages = 20 }, - new { _id = 2, title = "Book 2", pages = 30 }, - new { _id = 3, title = "Book 3", pages = 40 }, - new { _id = 4, title = "Book 4", pages = 50 }, - }; - Result r = ExecuteAddStatement(coll.Add(docs)); - Assert.AreEqual(4, r.AffectedItemsCount); - - var foundDocs = ExecuteFindStatement(coll.Find("pages > 20").Sort("pages DESC")); - Assert.True(foundDocs.Next()); - Assert.True(foundDocs.Current["title"].ToString() == "Book 4"); - Assert.True(foundDocs.Next()); - Assert.True(foundDocs.Current["title"].ToString() == "Book 3"); - Assert.True(foundDocs.Next()); - Assert.True(foundDocs.Current["title"].ToString() == "Book 2"); - Assert.False(foundDocs.Next()); - } - - [Test] - public void SimpleFindWithLimitAndOffset() - { - Collection coll = CreateCollection("test"); - var docs = new[] - { - new { _id = 1, title = "Book 1", pages = 20 }, - new { _id = 2, title = "Book 2", pages = 30 }, - new { _id = 3, title = "Book 3", pages = 40 }, - new { _id = 4, title = "Book 4", pages = 50 }, - }; - Result r = ExecuteAddStatement(coll.Add(docs)); - Assert.AreEqual(4, r.AffectedItemsCount); - - var foundDocs = ExecuteFindStatement(coll.Find("pages > 20").Limit(1)); - Assert.True(foundDocs.Next()); - Assert.True(foundDocs.Current["title"].ToString() == "Book 2"); - Assert.False(foundDocs.Next()); - - var resultDocs = ExecuteFindStatement(coll.Find("pages > 20").Offset(1).Limit(2)).FetchAll(); - Assert.AreEqual(40, resultDocs[0]["pages"]); - Assert.AreEqual(50, resultDocs[1]["pages"]); - - // Limit out of range. - Assert.Throws(() => ExecuteFindStatement(coll.Find().Limit(0))); - Assert.Throws(() => ExecuteFindStatement(coll.Find().Limit(-1))); - } - - [Test] - public void FindConditional() - { - Collection coll = CreateCollection("test"); - var docs = new[] - { - new { _id = 1, title = "Book 1", pages = 20 }, - new { _id = 2, title = "Book 2", pages = 30 }, - new { _id = 3, title = "Book 3", pages = 40 }, - new { _id = 4, title = "Book 4", pages = 50 }, - }; - Result r = ExecuteAddStatement(coll.Add(docs)); - Assert.AreEqual(4, r.AffectedItemsCount); - - var foundDocs = ExecuteFindStatement(coll.Find("pages = :Pages").Bind("pAges", 40)); - Assert.True(foundDocs.Next()); - Assert.True(foundDocs.Current["title"].ToString() == "Book 3"); - Assert.False(foundDocs.Next()); - } - - [Test] - public void BindDbDoc() - { - Collection coll = CreateCollection("test"); - var docs = new[] - { - new { _id = 1, title = "Book 1", pages = 20 }, - new { _id = 2, title = "Book 2", pages = 30 }, - new { _id = 3, title = "Book 3", pages = 40 }, - new { _id = 4, title = "Book 4", pages = 50 }, - }; - Result r = ExecuteAddStatement(coll.Add(docs)); - Assert.AreEqual(4, r.AffectedItemsCount); - - DbDoc docParams = new DbDoc(new { pages1 = 30, pages2 = 40 }); - var foundDocs = ExecuteFindStatement(coll.Find("pages = :Pages1 || pages = :Pages2").Bind(docParams)); - Assert.True(foundDocs.Next()); - Assert.AreEqual("Book 2", foundDocs.Current["title"]); - Assert.True(foundDocs.Next()); - Assert.AreEqual("Book 3", foundDocs.Current["title"]); - Assert.False(foundDocs.Next()); - } - - [Test] - public void BindJsonAsAnonymous() - { - Collection coll = CreateCollection("test"); - var docs = new[] - { - new { _id = 1, title = "Book 1", pages = 20 }, - new { _id = 2, title = "Book 2", pages = 30 }, - new { _id = 3, title = "Book 3", pages = 40 }, - new { _id = 4, title = "Book 4", pages = 50 }, - }; - Result r = ExecuteAddStatement(coll.Add(docs)); - Assert.AreEqual(4, r.AffectedItemsCount); - - var jsonParams = new { pages1 = 30, pages2 = 40 }; - var foundDocs = ExecuteFindStatement(coll.Find("pages = :Pages1 || pages = :Pages2").Bind(jsonParams)); - Assert.True(foundDocs.Next()); - Assert.AreEqual("Book 2", foundDocs.Current["title"]); - Assert.True(foundDocs.Next()); - Assert.AreEqual("Book 3", foundDocs.Current["title"]); - Assert.False(foundDocs.Next()); - } - - [Test] - public void BindJsonAsString() - { - Collection coll = CreateCollection("test"); - var docs = new[] - { - new { _id = 1, title = "Book 1", pages = 20 }, - new { _id = 2, title = "Book 2", pages = 30 }, - new { _id = 3, title = "Book 3", pages = 40 }, - new { _id = 4, title = "Book 4", pages = 50 }, - }; - Result r = ExecuteAddStatement(coll.Add(docs)); - Assert.AreEqual(4, r.AffectedItemsCount); - - var jsonParams = "{ \"pages1\" : 30, \"pages2\" : 40 }"; - var foundDocs = ExecuteFindStatement(coll.Find("pages = :Pages1 || pages = :Pages2").Bind(jsonParams)); - Assert.True(foundDocs.Next()); - Assert.AreEqual("Book 2", foundDocs.Current["title"]); - Assert.True(foundDocs.Next()); - Assert.AreEqual("Book 3", foundDocs.Current["title"]); - Assert.False(foundDocs.Next()); - } - - [Test] - public void RowLockingNotSupportedInOlderVersions() - { - if (session.Version.isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql lower than 8.0.3."); - Collection coll = CreateCollection("test"); - - Exception ex = Assert.Throws(() => ExecuteFindStatement(coll.Find().LockShared())); - Assert.AreEqual("This functionality is only supported from server version 8.0.3 onwards.", ex.Message); - - ex = Assert.Throws(() => ExecuteFindStatement(coll.Find().LockExclusive())); - Assert.AreEqual("This functionality is only supported from server version 8.0.3 onwards.", ex.Message); - } - - [Test] - public void SimpleSharedLock() - { - if (!session.Version.isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher"); - - ExecuteSQLStatement(session.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); - using (var session2 = MySQLX.GetSession(ConnectionString)) - { - ExecuteSQLStatement(session2.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); - Collection coll = CreateCollection("test"); - var docs = new[] - { - new { _id = 1, a = 1 }, - new { _id = 2, a = 1 }, - new { _id = 3, a = 1 }, - }; - ExecuteAddStatement(coll.Add(docs)); - Collection coll2 = session2.GetSchema("test").GetCollection("test"); - - ExecuteSQLStatement(session.SQL("START TRANSACTION")); - var docResult = ExecuteFindStatement(coll.Find("_id = 1").LockShared()); - Assert.That(docResult.FetchAll(), Has.One.Items); - - ExecuteSQLStatement(session2.SQL("START TRANSACTION")); - // Should return immediately since document isn't locked. - docResult = ExecuteFindStatement(coll2.Find("_id = 2").LockShared()); - Assert.That(docResult.FetchAll(), Has.One.Items); - // Should return immediately due to LockShared() allows reading by other sessions. - docResult = ExecuteFindStatement(coll2.Find("_id = 1").LockShared()); - Assert.That(docResult.FetchAll(), Has.One.Items); - - ExecuteSQLStatement(session.SQL("ROLLBACK")); - ExecuteSQLStatement(session2.SQL("ROLLBACK")); - } - } - - [Test] - public void SharedLockForbidsToModifyDocuments() - { - if (!session.Version.isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher"); - - ExecuteSQLStatement(session.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); - using (var session2 = MySQLX.GetSession(ConnectionString)) - { - ExecuteSQLStatement(session2.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); - Collection coll = CreateCollection("test"); - var docs = new[] - { - new { _id = 1, a = 1 }, - new { _id = 2, a = 1 }, - new { _id = 3, a = 1 }, - }; - ExecuteAddStatement(coll.Add(docs)); - Collection coll2 = session2.GetSchema("test").GetCollection("test"); - - ExecuteSQLStatement(session.SQL("START TRANSACTION")); - var docResult = ExecuteFindStatement(coll.Find("_id = 1").LockShared()); - Assert.That(docResult.FetchAll(), Has.One.Items); - - ExecuteSQLStatement(session2.SQL("START TRANSACTION")); - // Reading the same document is allowed with LockShared(). - docResult = ExecuteFindStatement(coll2.Find("_id = 1")); - Assert.That(docResult.FetchAll(), Has.One.Items); - - // Modify() is allowed for non-locked documents. - Result result = ExecuteModifyStatement(coll2.Modify("_id = 2").Set("a", 2)); - Assert.AreEqual(1, result.AffectedItemsCount); - // Session1 blocks, Modify() is not allowed for locked documents. - ExecuteSQLStatement(session2.SQL("SET SESSION innodb_lock_wait_timeout=1")); - Exception ex = Assert.Throws(() => ExecuteModifyStatement(coll2.Modify("_id = 1").Set("a", 2))); - Assert.AreEqual("Lock wait timeout exceeded; try restarting transaction", ex.Message); - - ExecuteSQLStatement(session.SQL("ROLLBACK")); - // Modify() is allowed since document isn't locked anymore. - ExecuteModifyStatement(coll2.Modify("_id = 1").Set("a", 2)); - ExecuteSQLStatement(session2.SQL("COMMIT")); - } - } - - [Test] - public void ExclusiveLockForbidsToModifyDocuments() - { - if (!session.Version.isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher"); - - ExecuteSQLStatement(session.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); - using (var session2 = MySQLX.GetSession(ConnectionString)) - { - ExecuteSQLStatement(session2.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); - Collection coll = CreateCollection("test"); - var docs = new[] - { - new { _id = 1, a = 1 }, - new { _id = 2, a = 1 }, - new { _id = 3, a = 1 }, - }; - ExecuteAddStatement(coll.Add(docs)); - Collection coll2 = session2.GetSchema("test").GetCollection("test"); - - ExecuteSQLStatement(session.SQL("START TRANSACTION")); - var docResult = ExecuteFindStatement(coll.Find("_id = 1").LockExclusive()); - Assert.That(docResult.FetchAll(), Has.One.Items); - - ExecuteSQLStatement(session2.SQL("START TRANSACTION")); - - // Modify() is allowed for non-locked documents. - Result result = ExecuteModifyStatement(coll2.Modify("_id = 2").Set("a", 2)); - Assert.AreEqual(1, result.AffectedItemsCount); - // Session2 blocks, Modify() is not allowed for locked documents. - ExecuteSQLStatement(session2.SQL("SET SESSION innodb_lock_wait_timeout=1")); - Exception ex = Assert.Throws(() => ExecuteModifyStatement(coll2.Modify("_id = 1").Set("a", 2))); - Assert.AreEqual("Lock wait timeout exceeded; try restarting transaction", ex.Message); - ex = Assert.Throws(() => ExecuteModifyStatement(coll2.Modify("_id = 1").Change("a", 12))); - Assert.AreEqual("Lock wait timeout exceeded; try restarting transaction", ex.Message); - - ExecuteSQLStatement(session.SQL("ROLLBACK")); - // Modify() is allowed since document isn't locked anymore. - ExecuteModifyStatement(coll2.Modify("_id = 1").Set("a", 2)); - ExecuteSQLStatement(session2.SQL("COMMIT")); - } - } - - [Test] - public void SharedLockAfterExclusiveLock() - { - if (!session.Version.isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher"); - - ExecuteSQLStatement(session.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); - using (var session2 = MySQLX.GetSession(ConnectionString)) - { - ExecuteSQLStatement(session2.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); - Collection coll = CreateCollection("test"); - ExecuteSQLStatement(session2.SQL("ALTER TABLE `test`.`test` ADD COLUMN `$ix_i_r_index` INT GENERATED ALWAYS AS (JSON_UNQUOTE(JSON_EXTRACT(doc, '$._id'))) VIRTUAL NOT NULL, ADD UNIQUE INDEX `myIndex`(`$ix_i_r_index`)")); - var docs = new[] - { - new { _id = 1, a = 1 }, - new { _id = 2, a = 1 }, - new { _id = 3, a = 1 }, - }; - ExecuteAddStatement(coll.Add(docs)); - Collection coll2 = session2.GetSchema("test").GetCollection("test"); - - ExecuteSQLStatement(session.SQL("START TRANSACTION")); - var docResult = ExecuteFindStatement(coll.Find("_id = 1").LockExclusive()); - Assert.That(docResult.FetchAll(), Has.One.Items); - - ExecuteSQLStatement(session2.SQL("START TRANSACTION")); - // Should return immediately since document isn't locked. - docResult = ExecuteFindStatement(coll2.Find("_id = 2").LockShared()); - Assert.That(docResult.FetchAll(), Has.One.Items); - // Session2 blocks due to LockExclusive() not allowing to read locked documents. - ExecuteSQLStatement(session2.SQL("SET SESSION innodb_lock_wait_timeout=1")); - Exception ex = Assert.Throws(() => ExecuteFindStatement(coll2.Find("_id = 1").LockShared())); - Assert.AreEqual("Lock wait timeout exceeded; try restarting transaction", ex.Message); - - // Session unlocks documents. - ExecuteSQLStatement(session.SQL("ROLLBACK")); - // Document can now be recovered. - docResult = ExecuteFindStatement(coll2.Find("_id = 1").LockShared()); - Assert.That(docResult.FetchAll(), Has.One.Items); - ExecuteSQLStatement(session2.SQL("ROLLBACK")); - } - } - - [Test] - public void ExclusiveLockAfterSharedLock() - { - if (!session.Version.isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher"); - - ExecuteSQLStatement(session.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); - using (var session2 = MySQLX.GetSession(ConnectionString)) - { - ExecuteSQLStatement(session2.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); - Collection coll = CreateCollection("test"); - ExecuteSQLStatement(session2.SQL("ALTER TABLE `test`.`test` ADD COLUMN `$ix_i_r_index` INT GENERATED ALWAYS AS (JSON_UNQUOTE(JSON_EXTRACT(doc, '$._id'))) VIRTUAL NOT NULL, ADD UNIQUE INDEX `myIndex`(`$ix_i_r_index`)")); - var docs = new[] - { - new { _id = 1, a = 1 }, - new { _id = 2, a = 1 }, - new { _id = 3, a = 1 }, - }; - ExecuteAddStatement(coll.Add(docs)); - Collection coll2 = session2.GetSchema("test").GetCollection("test"); - - ExecuteSQLStatement(session.SQL("START TRANSACTION")); - var docResult = ExecuteFindStatement(coll.Find("_id in (1, 3)").LockShared()); - Assert.AreEqual(2, docResult.FetchAll().Count); - - ExecuteSQLStatement(session2.SQL("START TRANSACTION")); - // Should return immediately since document isn't locked. - docResult = ExecuteFindStatement(coll2.Find("_id = 2").LockExclusive()); - // Should return immediately due to LockShared() allows reading by other sessions. - docResult = ExecuteFindStatement(coll2.Find("_id = 2").LockShared()); - Assert.That(docResult.FetchAll(), Has.One.Items); - // Session2 blocks due to to LockExclusive() not allowing to read locked documents. - ExecuteSQLStatement(session2.SQL("SET SESSION innodb_lock_wait_timeout=1")); - Exception ex = Assert.Throws(() => ExecuteFindStatement(coll2.Find("_id = 1").LockExclusive())); - Assert.AreEqual("Lock wait timeout exceeded; try restarting transaction", ex.Message); - - // Session unlocks documents. - ExecuteSQLStatement(session.SQL("ROLLBACK")); - docResult = ExecuteFindStatement(coll2.Find("_id = 1").LockExclusive()); - Assert.That(docResult.FetchAll(), Has.One.Items); - ExecuteSQLStatement(session2.SQL("ROLLBACK")); - } - } - - [Test] - public void ExclusiveLockAfterExclusiveLock() - { - if (!session.Version.isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher"); - - ExecuteSQLStatement(session.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); - using (var session2 = MySQLX.GetSession(ConnectionString)) - { - ExecuteSQLStatement(session2.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); - Collection coll = CreateCollection("test"); - ExecuteSQLStatement(session2.SQL("ALTER TABLE `test`.`test` ADD COLUMN `$ix_i_r_index` INT GENERATED ALWAYS AS (JSON_UNQUOTE(JSON_EXTRACT(doc, '$._id'))) VIRTUAL NOT NULL, ADD UNIQUE INDEX `myIndex`(`$ix_i_r_index`)")); - var docs = new[] - { - new { _id = 1, a = 1 }, - new { _id = 2, a = 1 }, - new { _id = 3, a = 1 } - }; - ExecuteAddStatement(coll.Add(docs)); - Collection coll2 = session2.GetSchema("test").GetCollection("test"); - - ExecuteSQLStatement(session.SQL("START TRANSACTION")); - var docResult = ExecuteFindStatement(coll.Find("_id = 1").LockExclusive()); - Assert.That(docResult.FetchAll(), Has.One.Items); - - ExecuteSQLStatement(session2.SQL("START TRANSACTION")); - // Should return immediately since document isn't locked. - docResult = ExecuteFindStatement(coll2.Find("_id = 2").LockExclusive()); - Assert.That(docResult.FetchAll(), Has.One.Items); - // Session2 blocks due to to LockExclusive() not allowing to read locked documents. - ExecuteSQLStatement(session2.SQL("SET SESSION innodb_lock_wait_timeout=1")); - Exception ex = Assert.Throws(() => ExecuteFindStatement(coll2.Find("_id = 1").LockExclusive())); - Assert.AreEqual("Lock wait timeout exceeded; try restarting transaction", ex.Message); - - // Session unlocks documents. - ExecuteSQLStatement(session.SQL("ROLLBACK")); - docResult = ExecuteFindStatement(coll2.Find("_id = 1").LockExclusive()); - Assert.That(docResult.FetchAll(), Has.One.Items); - ExecuteSQLStatement(session2.SQL("ROLLBACK")); - } - } - - [Test] - public void InOperatorWithListOfValues() - { - if (!session.Version.isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher"); - - // Validates the IN operator allows expressions of the type - // ( compExpr ["NOT"] "IN" "(" argsList ")" ) | ( compExpr ["NOT"] "IN" "[" argsList "]" ) - Collection coll = CreateCollection("test"); - ExecuteAddStatement(coll.Add(new DbDoc("{ \"a\": 1, \"b\": [ 1, \"value\" ], \"d\":\"\" }"))); - - Assert.That(ExecuteFindStatement(coll.Find("a IN (1,2,3)")).FetchAll(), Has.One.Items); - Assert.That(ExecuteFindStatement(coll.Find("a not in (0,2,3)")).FetchAll(), Has.One.Items); - Assert.That(ExecuteFindStatement(coll.Find("b[0] in (1,2,3)")).FetchAll(), Has.One.Items); - Assert.That(ExecuteFindStatement(coll.Find("b[1] in (\"a\", \"b\", \"value\")")).FetchAll(), Has.One.Items); - Assert.That(ExecuteFindStatement(coll.Find("b[0] NOT IN (0,2,3)")).FetchAll(), Has.One.Items); - Assert.That(ExecuteFindStatement(coll.Find("b[1] not in (\"a\", \"b\", \"c\")")).FetchAll(), Has.One.Items); - Assert.That(ExecuteFindStatement(coll.Find("a in [1,2,3]")).FetchAll(), Has.One.Items); - CollectionAssert.IsEmpty(ExecuteFindStatement(coll.Find("a in [2,3,4]")).FetchAll()); - Assert.That(ExecuteFindStatement(coll.Find("a NOT in [0,2,3]")).FetchAll(), Has.One.Items); - Assert.That(ExecuteFindStatement(coll.Find("b not IN [1,2,3]")).FetchAll(), Has.One.Items); - CollectionAssert.IsEmpty(ExecuteFindStatement(coll.Find("b[0] not IN [1,2,3]")).FetchAll()); - CollectionAssert.IsEmpty(ExecuteFindStatement(coll.Find("c NOT IN [1,2,3]")).FetchAll()); - CollectionAssert.IsEmpty(ExecuteFindStatement(coll.Find("a IN ('', ' ')")).FetchAll()); - CollectionAssert.IsEmpty(ExecuteFindStatement(coll.Find("'' IN (1,2,3)")).FetchAll()); - Assert.That(ExecuteFindStatement(coll.Find("d IN ('')")).FetchAll(), Has.One.Items); - - Collection movies = CreateCollection("movies"); - var docString = "{ \"_id\" : \"a6f4b93e1a264a108393524f29546a8c\", \"title\" : \"AFRICAN EGG\", \"description\" : \"A Fast-Paced Documentary of a Pastry Chef And a Dentist who must Pursue a Forensic Psychologist in The Gulf of Mexico\", \"releaseyear\" : 2006, \"language\" : \"English\", \"duration\" : 130, \"rating\" : \"G\", \"genre\" : \"Science fiction\", \"actors\" : [{ \"name\" : \"MILLA PECK\", \"country\" : \"Mexico\", \"birthdate\": \"12 Jan 1984\"}, { \"name\" : \"VAL BOLGER\", \"country\" : \"Botswana\", \"birthdate\": \"26 Jul 1975\" }, { \"name\" : \"SCARLETT BENING\", \"country\" : \"Syria\", \"birthdate\": \"16 Mar 1978\" }], \"additionalinfo\" : { \"director\" : \"Sharice Legaspi\", \"writers\" : [\"Rusty Couturier\", \"Angelic Orduno\", \"Carin Postell\"], \"productioncompanies\" : [\"Qvodrill\", \"Indigoholdings\"] } }"; - ExecuteAddStatement(movies.Add(new DbDoc(docString))); - - Assert.That(ExecuteFindStatement(movies.Find("(1>5) in (true, false)")).FetchAll(), Has.One.Items); - CollectionAssert.IsEmpty(ExecuteFindStatement(movies.Find("(1+5) in (1, 2, 3, 4, 5)")).FetchAll()); - Assert.That(ExecuteFindStatement(movies.Find("('a'>'b') in (true, false)")).FetchAll(), Has.One.Items); - Assert.Throws(() => ExecuteFindStatement(movies.Find("(1>5) in [true, false]")).FetchAll()); - Assert.Throws(() => ExecuteFindStatement(movies.Find("(1+5) in [1, 2, 3, 4, 5]")).FetchAll()); - Assert.Throws(() => ExecuteFindStatement(movies.Find("('a'>'b') in [true, false]")).FetchAll()); - Assert.That(ExecuteFindStatement(movies.Find("true IN [(1>5), !(false), (true || false), (false && true)]")).FetchAll(), Has.One.Items); - Assert.That(ExecuteFindStatement(movies.Find("true IN ((1>5), !(false), (true || false), (false && true))")).FetchAll(), Has.One.Items); - CollectionAssert.IsEmpty(ExecuteFindStatement(movies.Find("{\"field\":true} IN (\"mystring\", 124, myvar, othervar.jsonobj)")).FetchAll()); - CollectionAssert.IsEmpty(ExecuteFindStatement(movies.Find("actor.name IN ['a name', null, (1<5-4), myvar.jsonobj.name]")).FetchAll()); - Assert.That(ExecuteFindStatement(movies.Find("!false && true IN [true]")).FetchAll(), Has.One.Items); - Assert.Throws(() => ExecuteFindStatement(movies.Find("1-5/2*2 > 3-2/1*2 IN [true, false]")).FetchAll()); - CollectionAssert.IsEmpty(ExecuteFindStatement(movies.Find("true IN [1-5/2*2 > 3-2/1*2]")).FetchAll()); - Assert.That(ExecuteFindStatement(movies.Find(" 'African Egg' IN ('African Egg', 1, true, NULL, [0,1,2], { 'title' : 'Atomic Firefighter' }) ")).FetchAll(), Has.One.Items); - Assert.That(ExecuteFindStatement(movies.Find(" 1 IN ('African Egg', 1, true, NULL, [0,1,2], { 'title' : 'Atomic Firefighter' }) ")).FetchAll(), Has.One.Items); - Assert.That(ExecuteFindStatement(movies.Find(" [0,1,2] IN ('African Egg', 1, true, NULL, [0,1,2], { 'title' : 'Atomic Firefighter' }) ")).FetchAll(), Has.One.Items); - Assert.That(ExecuteFindStatement(movies.Find(" { 'title' : 'Atomic Firefighter' } IN ('African Egg', 1, true, NULL, [0,1,2], { 'title' : 'Atomic Firefighter' }) ")).FetchAll(), Has.One.Items); - CollectionAssert.IsEmpty(ExecuteFindStatement(movies.Find("title IN ('African Egg', 'The Witcher', 'Jurassic Perk')")).FetchAll()); - Assert.That(ExecuteFindStatement(movies.Find("releaseyear IN (2006, 2010, 2017)")).FetchAll(), Has.One.Items); - Assert.That(ExecuteFindStatement(movies.Find("1 IN [1,2,3]")).FetchAll(), Has.One.Items); - CollectionAssert.IsEmpty(ExecuteFindStatement(movies.Find("0 IN [1,2,3]")).FetchAll()); - Assert.That(ExecuteFindStatement(movies.Find("0 NOT IN [1,2,3]")).FetchAll(), Has.One.Items); - CollectionAssert.IsEmpty(ExecuteFindStatement(movies.Find("1 NOT IN [1,2,3]")).FetchAll()); - Assert.That(ExecuteFindStatement(movies.Find("releaseyear IN [2006, 2007, 2008]")).FetchAll(), Has.One.Items); - } - - [Test] - public void InOperatorWithCompExpr() - { - if (!session.Version.isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher"); - - // Validates the IN operator allows expressions of the type: compExpr ["NOT"] "IN" compExpr - Collection coll = CreateCollection("test"); - var docString = "{ \"a\": 1, \"b\": \"foo\", \"c\": { \"d\": true, \"e\": [1,2,3] }, \"f\": [ {\"x\":5}, {\"x\":7 } ] }"; - ExecuteAddStatement(coll.Add(new DbDoc(docString))); - - Assert.That(ExecuteFindStatement(coll.Find("a in [1,2,3]")).FetchAll(), Has.One.Items); - Assert.That(ExecuteFindStatement(coll.Find("c.e[0] in [1,2,3]")).FetchAll(), Has.One.Items); - Assert.That(ExecuteFindStatement(coll.Find("5 in f[*].x")).FetchAll(), Has.One.Items); - Assert.That(ExecuteFindStatement(coll.Find("3 in c.e")).FetchAll(), Has.One.Items); - CollectionAssert.IsEmpty(ExecuteFindStatement(coll.Find("5 in c.e")).FetchAll()); - CollectionAssert.IsEmpty(ExecuteFindStatement(coll.Find("\"foo\" in " + docString)).FetchAll()); - CollectionAssert.IsEmpty(ExecuteFindStatement(coll.Find("\"a\" in " + docString)).FetchAll()); - CollectionAssert.IsEmpty(ExecuteFindStatement(coll.Find("a in " + docString)).FetchAll()); - Assert.That(ExecuteFindStatement(coll.Find("{\"a\":1} in " + docString)).FetchAll(), Has.One.Items); - Assert.That(ExecuteFindStatement(coll.Find("\"foo\" in b")).FetchAll(), Has.One.Items); - - Collection movies = CreateCollection("movies"); - docString = "{ \"_id\" : \"a6f4b93e1a264a108393524f29546a8c\", \"title\" : \"AFRICAN EGG\", \"description\" : \"A Fast-Paced Documentary of a Pastry Chef And a Dentist who must Pursue a Forensic Psychologist in The Gulf of Mexico\", \"releaseyear\" : 2006, \"language\" : \"English\", \"duration\" : 130, \"rating\" : \"G\", \"genre\" : \"Science fiction\", \"actors\" : [{ \"name\" : \"MILLA PECK\", \"country\" : \"Mexico\", \"birthdate\": \"12 Jan 1984\"}, { \"name\" : \"VAL BOLGER\", \"country\" : \"Botswana\", \"birthdate\": \"26 Jul 1975\" }, { \"name\" : \"SCARLETT BENING\", \"country\" : \"Syria\", \"birthdate\": \"16 Mar 1978\" }], \"additionalinfo\" : { \"director\" : \"Sharice Legaspi\", \"writers\" : [\"Rusty Couturier\", \"Angelic Orduno\", \"Carin Postell\"], \"productioncompanies\" : [\"Qvodrill\", \"Indigoholdings\"] } }"; - ExecuteAddStatement(movies.Add(new DbDoc(docString))); - - Assert.That(ExecuteFindStatement(movies.Find("{ \"name\" : \"MILLA PECK\" } IN actors")).FetchAll(), Has.One.Items); - CollectionAssert.IsEmpty(ExecuteFindStatement(movies.Find("'African Egg' in movietitle")).FetchAll()); - Assert.Throws(() => ExecuteFindStatement(movies.Find("(1 = NULL) IN title")).FetchAll()); - Assert.Throws(() => ExecuteFindStatement(movies.Find("NOT NULL IN title")).FetchAll()); - Assert.That(ExecuteFindStatement(movies.Find("[\"Rusty Couturier\", \"Angelic Orduno\", \"Carin Postell\"] IN additionalinfo.writers")).FetchAll(), Has.One.Items); - Assert.That(ExecuteFindStatement(movies.Find("{ \"name\" : \"MILLA PECK\", \"country\" : \"Mexico\", \"birthdate\": \"12 Jan 1984\"} IN actors")).FetchAll(), Has.One.Items); - CollectionAssert.IsEmpty(ExecuteFindStatement(movies.Find("true IN title")).FetchAll()); - CollectionAssert.IsEmpty(ExecuteFindStatement(movies.Find("false IN genre")).FetchAll()); - Assert.That(ExecuteFindStatement(movies.Find("'Sharice Legaspi' IN additionalinfo.director")).FetchAll(), Has.One.Items); - Assert.That(ExecuteFindStatement(movies.Find("'Mexico' IN actors[*].country")).FetchAll(), Has.One.Items); - Assert.That(ExecuteFindStatement(movies.Find("'Angelic Orduno' IN additionalinfo.writers")).FetchAll(), Has.One.Items); - } - - [Test] - public void InOperatorWithJsonArrays() - { - if (!session.Version.isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher"); - - Collection coll = CreateCollection("test"); - var docString = "{ \"_id\": \"1001\", \"ARR\":[1,2,3], \"ARR1\":[\"name\", \"name2\", \"name3\"]}"; - ExecuteAddStatement(coll.Add(new DbDoc(docString))); - - Assert.That(ExecuteFindStatement(coll.Find("\"1001\" in $._id")).FetchAll(), Has.One.Items); - CollectionAssert.IsEmpty(ExecuteFindStatement(coll.Find("\"1002\" in $._id")).FetchAll()); - Assert.That(ExecuteFindStatement(coll.Find("(1+2) in (1, 2, 3)")).FetchAll(), Has.One.Items); - Assert.Throws(() => ExecuteFindStatement(coll.Find("(1+2) in [1, 2, 3]")).FetchAll()); - Assert.Throws(() => ExecuteFindStatement(coll.Find("(1+2) in $.ARR")).FetchAll()); - } - - [Test] - public void GetOne() - { - Collection coll = CreateCollection("test"); - var docs = new[] - { - new { _id = 1, title = "Book 1", pages = 20 }, - new { _id = 2, title = "Book 2", pages = 30 }, - new { _id = 3, title = "Book 3", pages = 40 }, - new { _id = 4, title = "Book 4", pages = 50 }, - }; - Result r = ExecuteAddStatement(coll.Add(docs)); - Assert.AreEqual(4, r.AffectedItemsCount); - - // Expected exceptions. - Assert.Throws(() => coll.GetOne(null)); - Assert.Throws(() => coll.GetOne("")); - Assert.Throws(() => coll.GetOne(string.Empty)); - - // Get document using numeric parameter. - DbDoc document = coll.GetOne(1); - Assert.AreEqual(1, document.Id); - Assert.AreEqual("Book 1", document["title"]); - Assert.AreEqual(20, Convert.ToInt32(document["pages"])); - - // Get document using string parameter. - document = coll.GetOne("3"); - Assert.AreEqual(3, document.Id); - Assert.AreEqual("Book 3", document["title"]); - Assert.AreEqual(40, Convert.ToInt32(document["pages"])); - - // Get a non-existing document. - document = coll.GetOne(5); - Assert.Null(document); - } - - public enum LockMode { Exclusive, Shared } - - [TestCase(LockContention.Default, LockMode.Exclusive)] - [TestCase(LockContention.NoWait, LockMode.Exclusive)] - [TestCase(LockContention.SkipLocked, LockMode.Exclusive)] - [TestCase(LockContention.Default, LockMode.Shared)] - [TestCase(LockContention.NoWait, LockMode.Shared)] - [TestCase(LockContention.SkipLocked, LockMode.Shared)] - public void LockExclusiveAndSharedWithWaitingOptions(LockContention lockOption, LockMode lockMode) - { - if (!session.Version.isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher."); - - string collectionName = "test"; - var coll = CreateCollection(collectionName); - ExecuteAddStatement(coll.Add(new { _id = 1, name = "Jonh" })); - - // first session locks the row - using (Session s1 = MySQLX.GetSession(ConnectionString)) - { - var coll1 = s1.GetSchema(schemaName).GetCollection(collectionName); - s1.StartTransaction(); - var r1 = ExecuteFindStatement(coll1.Find("_id = :id").Bind("id", 1).LockExclusive()); - Assert.That(r1.FetchAll(), Has.One.Items); - - // second session tries to read the locked row - using (Session s2 = MySQLX.GetSession(ConnectionString)) - { - var coll2 = s2.GetSchema(schemaName).GetCollection(collectionName); - ExecuteSQLStatement(s2.SQL("SET innodb_lock_wait_timeout = 1")); - s2.StartTransaction(); - var stmt2 = coll2.Find("_id = :id").Bind("id", 1); - if (lockMode == LockMode.Exclusive) - stmt2.LockExclusive(lockOption); - else - stmt2.LockShared(lockOption); - - switch (lockOption) - { - case LockContention.Default: - // error 1205 Lock wait timeout exceeded; try restarting transaction - Assert.AreEqual(1205u, Assert.Throws(() => ExecuteFindStatement(stmt2).FetchAll()).Code); - break; - case LockContention.NoWait: - // error 1205 Lock wait timeout exceeded; try restarting transaction - uint expectedError = 1205; - if (session.XSession.GetServerVersion().isAtLeast(8, 0, 5)) - // error 3572 Statement aborted because lock(s) could not be acquired immediately and NOWAIT is set - expectedError = 3572; - Assert.AreEqual(expectedError, Assert.Throws(() => ExecuteFindStatement(stmt2).FetchAll()).Code); - break; - case LockContention.SkipLocked: - if (!session.XSession.GetServerVersion().isAtLeast(8, 0, 5)) - { - // error 1205 Lock wait timeout exceeded; try restarting transaction - Assert.AreEqual(1205u, Assert.Throws(() => ExecuteFindStatement(stmt2).FetchAll()).Code); - break; - } - CollectionAssert.IsEmpty(ExecuteFindStatement(stmt2).FetchAll()); - break; - default: - throw new NotImplementedException(lockOption.ToString()); - } - } - // first session frees the lock - s1.Commit(); - } - } - - [Test] - public void Grouping() - { - ExecuteSQLStatement(GetSession().SQL("SET GLOBAL sql_mode=(SELECT REPLACE(@@sql_mode, 'ONLY_FULL_GROUP_BY', '')); ")); - Collection collection = CreateCollection("test"); - var docs = new[] - { - new { _id = 1, name = "jonh doe", age = 38 }, - new { _id = 2, name = "milton green", age = 45 }, - new { _id = 3, name = "larry smith", age = 24}, - new { _id = 4, name = "mary weinstein", age = 24 }, - new { _id = 5, name = "jerry pratt", age = 45 }, - new { _id = 6, name = "hugh jackman", age = 20}, - new { _id = 7, name = "elizabeth olsen", age = 31} - }; - Result r = ExecuteAddStatement(collection.Add(docs)); - Assert.AreEqual(7, r.AffectedItemsCount); - - // GroupBy operation. - // GroupBy returns 5 rows since age 45 and 24 is repeated. - var result = ExecuteFindStatement(collection.Find().Fields("_id as ID", "name as Name", "age as Age").GroupBy("age")); - Assert.AreEqual(5, result.FetchAll().Count); - - // GroupBy with null. - result = ExecuteFindStatement(collection.Find().Fields("_id as ID", "name as Name", "age as Age").GroupBy(null)); - Assert.AreEqual(7, result.FetchAll().Count); - result = ExecuteFindStatement(collection.Find().Fields("_id as ID", "name as Name", "age as Age").GroupBy(null, null)); - Assert.AreEqual(7, result.FetchAll().Count); - result = ExecuteFindStatement(collection.Find().Fields("_id as ID", "name as Name", "age as Age").GroupBy(null, "age")); - Assert.AreEqual(5, result.FetchAll().Count); - - // Having operation. - // Having reduces the original 5 rows to 3 since 2 rows have a cnt=2, due to the repeated names. - result = ExecuteFindStatement(collection.Find().Fields("_id as ID", "count(name) as cnt", "age as Age").GroupBy("age").Having("cnt = 1")); - Assert.AreEqual(3, result.FetchAll().Count); - - // Having with null. - result = ExecuteFindStatement(collection.Find().Fields("_id as ID", "count(name) as cnt", "age as Age").GroupBy("age").Having(null)); - Assert.AreEqual(5, result.FetchAll().Count); - - // GroupBy with invalid field name. - var ex = Assert.Throws(() => ExecuteFindStatement(collection.Find().Fields("_id as ID", "name as Name", "age as Age").GroupBy("none"))); - Assert.AreEqual("Unknown column 'none' in 'group statement'", ex.Message); - - // GroupBy with empty strings. - var ex2 = Assert.Throws(() => ExecuteFindStatement(collection.Find().Fields("_id as ID", "name as Name", "age as Age").GroupBy(""))); - Assert.AreEqual("No more tokens when expecting one at token pos 0", ex2.Message); - ex2 = Assert.Throws(() => ExecuteFindStatement(collection.Find().Fields("_id as ID", "name as Name", "age as Age").GroupBy(" "))); - Assert.AreEqual("No more tokens when expecting one at token pos 0", ex2.Message); - ex2 = Assert.Throws(() => ExecuteFindStatement(collection.Find().Fields("_id as ID", "name as Name", "age as Age").GroupBy(string.Empty))); - Assert.AreEqual("No more tokens when expecting one at token pos 0", ex2.Message); - - // Having with invalid field name. - ex = Assert.Throws(() => ExecuteFindStatement(collection.Find().Fields("_id as ID", "count(name) as cnt", "age as Age").GroupBy("age").Having("none = 1"))); - Assert.AreEqual("Invalid expression in grouping criteria", ex.Message); - - // Having with empty strings. - ex2 = Assert.Throws(() => ExecuteFindStatement(collection.Find().Fields("_id as ID", "count(name) as cnt", "age as Age").GroupBy("age").Having(""))); - Assert.AreEqual("Unable to parse query ''", ex2.Message); - Assert.AreEqual("No more tokens when expecting one at token pos 0", ex2.InnerException.Message); - ex2 = Assert.Throws(() => ExecuteFindStatement(collection.Find().Fields("_id as ID", "count(name) as cnt", "age as Age").GroupBy("age").Having(" "))); - Assert.AreEqual("Unable to parse query ' '", ex2.Message); - Assert.AreEqual("No more tokens when expecting one at token pos 0", ex2.InnerException.Message); - ex2 = Assert.Throws(() => ExecuteFindStatement(collection.Find().Fields("_id as ID", "count(name) as cnt", "age as Age").GroupBy("age").Having(string.Empty))); - Assert.AreEqual("Unable to parse query ''", ex2.Message); - Assert.AreEqual("No more tokens when expecting one at token pos 0", ex2.InnerException.Message); - } - - [Test] - public void Fields() - { - Collection coll = CreateCollection("test"); - var docs = new[] - { - new { _id = 1, title = "Book 1", pages = 20 }, - new { _id = 2, title = "Book 2", pages = 30 }, - new { _id = 3, title = "Book 3", pages = 40 }, - new { _id = 4, title = "Book 4", pages = 50 }, - }; - Result r = ExecuteAddStatement(coll.Add(docs)); - Assert.AreEqual(4ul, r.AffectedItemsCount); - - // Single field. - var result = ExecuteFindStatement(coll.Find("pages = :Pages").Bind("pAges", 40).Fields("title")); - var document = result.FetchOne(); - Assert.That(document.values, Has.One.Items); - Assert.AreEqual("Book 3", document["title"]); - - // Null values are ignored. - result = ExecuteFindStatement(coll.Find("pages = :Pages").Bind("pAges", 40).Fields(null)); - document = result.FetchOne(); - Assert.AreEqual(3, document.values.Count); - - // Null values are ignored. - result = ExecuteFindStatement(coll.Find("pages = :Pages").Bind("pAges", 40).Fields("title", null)); - document = result.FetchOne(); - Assert.That(document.values, Has.One.Items); - - // Single field in array. - result = ExecuteFindStatement(coll.Find("pages = :Pages").Bind("pAges", 40).Fields(new string[] { "title" })); - document = result.FetchOne(); - Assert.That(document.values, Has.One.Items); - Assert.AreEqual("Book 3", document["title"]); - - // Single field with alias. - result = ExecuteFindStatement(coll.Find("pages = :Pages").Bind("pages", 20).Fields("title as title2")); - document = result.FetchOne(); - Assert.That(document.values, Has.One.Items); - Assert.AreEqual("Book 1", document["title2"]); - Assert.False(document.values.ContainsKey("title")); - - // Unexistent field returns null. - result = ExecuteFindStatement(coll.Find("pages = :Pages").Bind("pages", 20).Fields("book")); - document = result.FetchOne(); - Assert.That(document.values, Has.One.Items); - Assert.Null(document["book"]); - - // Unexistent field with alias returns null. - result = ExecuteFindStatement(coll.Find("pages = :Pages").Bind("pages", 20).Fields("book as book1")); - document = result.FetchOne(); - Assert.That(document.values, Has.One.Items); - Assert.Null(document["book1"]); - - // Multiple fields. - result = ExecuteFindStatement(coll.Find("pages = :Pages").Bind("pAges", 40).Fields("title", "pages", "other")); - document = result.FetchOne(); - Assert.AreEqual(3, document.values.Count); - Assert.AreEqual("Book 3", document["title"]); - Assert.AreEqual(40, document["pages"]); - Assert.Null(document["other"]); - - // Multiple fields in array. - result = ExecuteFindStatement(coll.Find("pages = :Pages").Bind("pAges", 40).Fields(new string[] { "title", "pages" })); - document = result.FetchOne(); - Assert.AreEqual(2, document.values.Count); - Assert.AreEqual("Book 3", document["title"]); - Assert.AreEqual(40, document["pages"]); - - // Sending a document doesn't generate an error. - result = ExecuteFindStatement(coll.Find("pages = :Pages").Bind("pages", 20).Fields("{\"_id\":\"1004\",\"F1\": 1234 }")); - document = result.FetchOne(); - - // Empty string and white space raises error. - var ex = Assert.Throws(() => ExecuteFindStatement(coll.Find("pages = :Pages").Bind("pAges", 40).Fields(""))); - Assert.AreEqual("No more tokens when expecting one at token pos 0", ex.Message); - ex = Assert.Throws(() => ExecuteFindStatement(coll.Find("pages = :Pages").Bind("pAges", 40).Fields(" "))); - Assert.AreEqual("No more tokens when expecting one at token pos 0", ex.Message); - ex = Assert.Throws(() => ExecuteFindStatement(coll.Find("pages = :Pages").Bind("pAges", 40).Fields(string.Empty))); - Assert.AreEqual("No more tokens when expecting one at token pos 0", ex.Message); - - // Multiple word field name raises error. - ex = Assert.Throws(() => result = ExecuteFindStatement(coll.Find("pages = :Pages").Bind("pAges", 40).Fields("Book 1"))); - Assert.AreEqual("Expression has unexpected token '1' at position 1.", ex.Message); - } - - [TestCase("", "")] - [TestCase("'", "'")] - [TestCase("", "'")] - [TestCase("'", "")] - public void FindIdAsString(string prefix, string suffix) - { - Collection coll = CreateCollection("test"); - Result r = null; - var docs = new[] - { - new { _id = $"{prefix}1{suffix}", title = $"{prefix}Book 1{suffix}", pages = 20 }, - new { _id = $"{prefix}2{suffix}", title = $"{prefix}Book 2{suffix}", pages = 30 }, - new { _id = $"{prefix}3{suffix}", title = $"{prefix}Book 3{suffix}", pages = 40 }, - new { _id = $"{prefix}4{suffix}", title = $"{prefix}Book 4{suffix}", pages = 50 }, - }; - r = coll.Add(docs).Execute(); - Assert.AreEqual(4, r.AffectedItemsCount); - - var findStmt = coll.Find("_id = :id and pages = :pages").Bind("id", $"{prefix}3{suffix}").Bind("pages", 40); - var doc = ExecuteFindStatement(findStmt); - var books = doc.FetchAll(); - Assert.That(books, Has.One.Items); - Assert.AreEqual($"{prefix}3{suffix}", books[0]["_id"]); - - findStmt = coll.Find("_id = :id and pages = :pages").Bind("Id", $"{prefix}2{suffix}").Bind("Pages", 30); - doc = ExecuteFindStatement(findStmt); - books = doc.FetchAll(); - Assert.That(books, Has.One.Items); - Assert.AreEqual($"{prefix}2{suffix}", books[0]["_id"]); - - findStmt = coll.Find("title = :title").Bind("Title", $"{prefix}Book 4{suffix}"); - doc = ExecuteFindStatement(findStmt); - books = doc.FetchAll(); - Assert.That(books, Has.One.Items); - Assert.AreEqual($"{prefix}4{suffix}", books[0]["_id"]); - Assert.AreEqual(50, books[0]["pages"]); - } - - [TestCase(":hobbies IN $.additionalinfo.hobbies", "hobbies", "painting", 4)] - [TestCase(":hobbies IN $.additionalinfo.hobbies", "hobbies", "[\"playing\", \"listening\"]", 0)] - [TestCase("[\"playing\", \"listening\"] IN $.additionalinfo.hobbies", null, null, 3)] - public void InOperatorBindingJson(string condition, string bind, string value, int id) - { - Collection coll = CreateCollection("test"); - Result r = null; - var docs = new[] - { - new { _id = 1, title = $"Book 1", pages = 20, additionalinfo = new DbDoc("{\"company\":\"xyz\",\"vehicle\":\"bike\",\"hobbies\":\"reading\"}") }, - new { _id = 2, title = $"Book 2", pages = 30, additionalinfo = new DbDoc("{\"company\":\"abc\",\"vehicle\":\"car\",\"hobbies\":\"boxing\"}") }, - new { _id = 3, title = $"Book 3", pages = 40, additionalinfo = new DbDoc("{\"company\":\"qwe\",\"vehicle\":\"airplane\",\"hobbies\":[\"playing\", \"listening\"]}") }, - new { _id = 4, title = $"Book 4", pages = 50, additionalinfo = new DbDoc("{\"company\":\"zxc\",\"vehicle\":\"boat\",\"hobbies\":\"painting\"}") }, - }; - r = coll.Add(docs).Execute(); - Assert.AreEqual(4, r.AffectedItemsCount); - - var findStmt = coll.Find(condition); - if (bind != null) findStmt.Bind(bind, value); - var result = findStmt.Execute().FetchAll(); - Assert.AreEqual(id == 0 ? 0 : 1, result.Count); - if (id > 0) - { - Assert.AreEqual(id, result[0]["_id"]); - } - } - - [Test] - public void FindUsingOverlaps() - { - Collection coll = CreateCollection("test"); - - coll.Add("{ \"_id\":1, \"title\": \"Book 1\", \"list\":[1, 4]}").Execute(); - coll.Add("{ \"_id\":2, \"title\": \"Book 2\", \"list\":[5, 7]}").Execute(); - coll.Add("{ \"_id\":3, \"title\": \"Book 3\", \"list\":[4, 9]}").Execute(); - coll.Add("{ \"_id\":4, \"title\": \"Book 4\", \"list\":[2]}").Execute(); - coll.Add("{ \"_id\":5, \"title\": \"Book 5\",\"list\":[\"\"]}").Execute(); - coll.Add("{ \"_id\":6, \"title\": \"Book 6\",\"list\":[\" \"]}").Execute(); - - var result = ExecuteFindStatement(coll.Find("[7] OVERLAPS $.list")).FetchAll(); - Assert.AreEqual("Book 2", result[0]["title"]); - result = ExecuteFindStatement(coll.Find("[8] overlaps $.list")).FetchAll(); - CollectionAssert.IsEmpty(result); - result = ExecuteFindStatement(coll.Find("[1, 4] OVERLAPS $.list")).FetchAll(); - CollectionAssert.IsNotEmpty(result); - Assert.AreEqual("Book 1", result[0]["title"]); - Assert.AreEqual("Book 3", result[1]["title"]); - result = ExecuteFindStatement(coll.Find("$.list OVERLAPS [1, 2]")).FetchAll(); - CollectionAssert.IsNotEmpty(result); - Assert.AreEqual("Book 1", result[0]["title"]); - Assert.AreEqual("Book 4", result[1]["title"]); - result = ExecuteFindStatement(coll.Find("'Book 1' NOT OVERLAPS $.title").Fields("_id")).FetchAll(); - Assert.AreEqual(5, result.Count); - Assert.AreEqual(3, result[1].Id); - result = ExecuteFindStatement(coll.Find(":title NOT OVERLAPS $.title").Bind("title", "Book 1").Fields("_id")).FetchAll(); - Assert.AreEqual(5, result.Count); - Assert.AreEqual(4, result[2].Id); - result = ExecuteFindStatement(coll.Find("$.list OVERLAPS :list").Bind("list", 9)).FetchAll(); - Assert.AreEqual("Book 3", result[0]["title"]); - var jsonParams = new { list = 4 }; - result = ExecuteFindStatement(coll.Find("$.list OVERLAPS :list").Bind(jsonParams).Fields("count(_id) as ID", "title as Title", "list as List"). - GroupBy("title", "list").Having("ID > 0")).FetchAll(); - Assert.AreEqual(2, result.Count); - Assert.AreEqual("Book 1", result[0]["Title"]); - result = ExecuteFindStatement(coll.Find("[''] OVERLAPS $.list")).FetchAll(); - Assert.That(result, Has.One.Items); - Assert.AreEqual(5, result[0].Id); - result = ExecuteFindStatement(coll.Find("[' '] OVERLAPS $.list")).FetchAll(); - Assert.That(result, Has.One.Items); - Assert.AreEqual(6, result[0].Id); - - Assert.Throws(() => ExecuteFindStatement(coll.Find("$.list OVERLAPS -")).FetchAll()); - Assert.Throws(() => ExecuteFindStatement(coll.Find("[2, 9] OVERLAPS")).FetchAll()); - Assert.Throws(() => ExecuteFindStatement(coll.Find("[2, 9] OVERPS $.list")).FetchAll()); - } - - #region WL14389 - - [Test, Description("Collection.Find(condition).GroupBy(SearchExprStr).Having(SearchConditionStr)")] - public void FindGroupByHaving() - { - ExecuteSQLStatement(GetSession().SQL("set sql_mode = 'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';")); - - Collection collection = CreateCollection("test"); - var docs1 = new[] - { - new { _id = 1, name = "jonh doe", age = 38,profit = 100,test = 1.92,date="21/11/2011" }, - new { _id = 2, name = "milton green", age = 45,profit = 200,test = 12.08,date="21/11/2012" }, - new { _id = 3, name = "larry smith", age = 24,profit = 300,test = 12.1,date="21/11/2013" }, - new { _id = 4, name = "mary weinstein", age = 24 ,profit = 100,test = 12.0,date="21/11/2014" }, - new { _id = 5, name = "jerry pratt", age = 45 ,profit = 400,test = 20.87,date="21/11/2015" }, - new { _id = 6, name = "hugh jackman", age = 20,profit = 500,test = 20.65,date="21/11/2016"}, - new { _id = 7, name = "elizabeth olsen", age = 31,profit = 300,test = 20.45,date="21/11/2017" }, - new { _id = 8, name = "tommy h", age = 31,profit = 3000,test = 0.0,date="21/11/2018"} - }; - - Result r = collection.Add(docs1).Execute(); - Assert.AreEqual(8, r.AffectedItemsCount); - - // GroupBy operation. - // GroupBy returns 5 rows since age 45 and 24 is repeated. - var result = collection.Find().Fields("_id as ID", "name as Name", "age as Age").GroupBy("age").Execute(); - Assert.AreEqual(5, result.FetchAll().Count); - result = collection.Find().Fields("_id as ID", "name as Name", "profit as Profit", "test as test").GroupBy("test").Having("test=1.92").Execute(); - Assert.AreEqual(1, result.FetchAll().Count); - result = collection.Find().Fields("max($.age) as age", "max($.profit) as Profit", "max($.test) as test").GroupBy("$.test").Having("max($.age)>=31"). - Sort("profit DESC").Execute(); - Assert.AreEqual(result.FetchAll().Count, result.FetchAll().Count); - result = collection.Find().Fields("max($.age) as age", "max($.profit) as Profit", "max($.test) as test").GroupBy("$.test").Having("max($.age)>30 && max($.age)<32") - .Execute(); - Assert.AreEqual(2, result.FetchAll().Count); - result = collection.Find().Fields("max($.age) as age", "max($.profit) as Profit", "max($.test) as test").GroupBy("$.test").Having("max($.age)>300000000") - .Execute(); - Assert.AreEqual(0, result.FetchAll().Count); - - result = collection.Find().Fields("max($.age) as age", "max($.profit) as Profit", "max($.test) as test").GroupBy("$.test").Having("max($.age)>30"). - Having("max($.age)<32") - .Execute(); - Assert.AreEqual(5, result.FetchAll().Count); - - result = collection.Find().Fields("max($.age) as age", "max($.profit) as Profit", "max($.test) as test").GroupBy("$.test").Having("max($.age)>30"). - Having("max($.age)<32").Limit(5) - .Execute(); - Assert.AreEqual(5, result.FetchAll().Count); - - result = collection.Find().Fields("max($.age) as age", "max($.profit) as Profit", "max($.test) as test").GroupBy("$.test").Having("max($.age)>30"). - Having("max($.age)<32").Limit(3) - .Execute(); - Assert.AreEqual(3, result.FetchAll().Count); - - result = collection.Find().Fields("max($.age) as age", "max($.profit) as Profit", "max($.test) as test").GroupBy("$.test").Having("max($.age)>30"). - Having("max($.age)<32").Limit(3).Offset(2) - .Execute(); - Assert.AreEqual(3, result.FetchAll().Count); - - Assert.Throws(() => collection.Find().Fields("max($.age) as age", "max($.profit) as Profit", "max($.test) as test").GroupBy("$.test").Having("date=21/11/2011").Execute()); - } - - [Test, Description("Collection.Find().Limit(x).Offset(y)")] - public void FindLimitOffset() - { - ExecuteSQLStatement(GetSession().SQL("set sql_mode = 'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';")); - - Collection collection = CreateCollection("test"); - var docs1 = new[] - { - new { _id = 1, name = "jonh doe", age = 38,profit = 100,test = 1.92,date="21/11/2011" }, - new { _id = 2, name = "milton green", age = 45,profit = 200,test = 12.08,date="21/11/2012" }, - new { _id = 3, name = "larry smith", age = 24,profit = 300,test = 12.1,date="21/11/2013" }, - new { _id = 4, name = "mary weinstein", age = 24 ,profit = 100,test = 12.0,date="21/11/2014" }, - new { _id = 5, name = "jerry pratt", age = 45 ,profit = 400,test = 20.87,date="21/11/2015" }, - new { _id = 6, name = "hugh jackman", age = 20,profit = 500,test = 20.65,date="21/11/2016"}, - new { _id = 7, name = "elizabeth olsen", age = 31,profit = 300,test = 20.45,date="21/11/2017" }, - new { _id = 8, name = "tommy h", age = 31,profit = 3000,test = 0.0,date="21/11/2018"} - }; - - Result r = collection.Add(docs1).Execute(); - Assert.AreEqual(8, r.AffectedItemsCount); - - // GroupBy operation. - // GroupBy returns 5 rows since age 45 and 24 is repeated. - var result1 = collection.Find().Limit(2).Offset(-2378723).Execute(); - int k = result1.FetchAll().Count; - result1 = collection.Find().Limit(2).Offset(-1).Execute(); - k = result1.FetchAll().Count; - result1 = collection.Find().Limit(2).Offset(0).Execute(); - k = result1.FetchAll().Count; - - var result = collection.Find().Fields("_id as ID", "name as Name", "age as Age").GroupBy("age").Execute(); - Assert.AreEqual(5, result.FetchAll().Count); - result = collection.Find().Fields("_id as ID", "name as Name", "profit as Profit", "test as test").GroupBy("test").Having("test=1.92").Execute(); - Assert.AreEqual(1, result.FetchAll().Count); - result = collection.Find().Fields("max($.age) as age", "max($.profit) as Profit", "max($.test) as test").GroupBy("$.test").Having("max($.age)>=31"). - Sort("profit DESC").Execute(); - Assert.AreEqual(result.FetchAll().Count, result.FetchAll().Count); - result = collection.Find().Fields("max($.age) as age", "max($.profit) as Profit", "max($.test) as test").GroupBy("$.test").Having("max($.age)>30 && max($.age)<32") - .Execute(); - Assert.AreEqual(2, result.FetchAll().Count); - result = collection.Find().Fields("max($.age) as age", "max($.profit) as Profit", "max($.test) as test").GroupBy("$.test").Having("max($.age)>300000000") - .Execute(); - Assert.AreEqual(0, result.FetchAll().Count); - - result = collection.Find().Fields("max($.age) as age", "max($.profit) as Profit", "max($.test) as test").GroupBy("$.test").Having("max($.age)>30"). - Having("max($.age)<32") - .Execute(); - Assert.AreEqual(5, result.FetchAll().Count); - - result = collection.Find().Fields("max($.age) as age", "max($.profit) as Profit", "max($.test) as test").GroupBy("$.test").Having("max($.age)>30"). - Having("max($.age)<32").Limit(5) - .Execute(); - Assert.AreEqual(5, result.FetchAll().Count); - - result = collection.Find().Fields("max($.age) as age", "max($.profit) as Profit", "max($.test) as test").GroupBy("$.test").Having("max($.age)>30"). - Having("max($.age)<32").Limit(3) - .Execute(); - Assert.AreEqual(3, result.FetchAll().Count); - - result = collection.Find().Fields("max($.age) as age", "max($.profit) as Profit", "max($.test) as test").GroupBy("$.test").Having("max($.age)>30"). - Having("max($.age)<32").Limit(3).Offset(2) - .Execute(); - Assert.AreEqual(3, result.FetchAll().Count); - - result = collection.Find().Fields("$._id as _id", "$.test as test").GroupBy("$.test").Limit(5).Offset(1).Execute(); - Assert.AreEqual(5, result.FetchAll().Count); - - result = collection.Find().Fields("$._id as _id", "$.test as test").GroupBy("$.test").Limit(5).Offset(-1).Execute(); - Assert.AreEqual(5, result.FetchAll().Count); - - result = collection.Find().Fields("$._id as _id", "$.test as test").GroupBy("$.test").Limit(8).Execute(); - Assert.AreEqual(8, result.FetchAll().Count); - - result = collection.Find().Fields("max($.age) as age", "max($.profit) as Profit", "max($.test) as test").GroupBy("$.test").Having("max($.age)>30"). - Having("max($.age)<32").Limit(3).Offset(-1) - .Execute(); - Assert.AreEqual(3, result.FetchAll().Count); - - Assert.Throws(() => collection.Find().Fields("max($.age) as age", "max($.profit) as Profit", "max($.test) as test").GroupBy("$.test").Having("max($.age)>30"). - Having("max($.age)<32").Limit(-1).Offset(0) - .Execute()); - - DbDoc[] jsonlist = new DbDoc[2000]; - for (int i = 0; i < 2000; i++) - { - DbDoc newDoc2 = new DbDoc(); - newDoc2.SetValue("_id", (i + 1000).ToString()); - newDoc2.SetValue("F1", ("Field-1-Data-" + i)); - newDoc2.SetValue("F2", ("Field-2-Data-" + i)); - newDoc2.SetValue("F3", (300 + i).ToString()); - jsonlist[i] = newDoc2; - newDoc2 = null; - } - var res = collection.Add(jsonlist).Execute(); - - result = collection.Find().Fields("$.F1 as F1", "$.F2 as F2").GroupBy("$.F1").Limit(3).Offset(1).Execute(); - Assert.AreEqual(3, result.FetchAll().Count); - - result = collection.Find().Fields("$.F1 as F1", "$.F2 as F2").GroupBy("$.F1").Limit(3).Offset(1844674407370955161).Execute(); - Assert.AreEqual(0, result.FetchAll().Count); - } - - [Test, Description("Collection.Find().Limit(x,y)")] - public void FindLimitOffsetDeprecated() - { - ExecuteSQLStatement(GetSession().SQL("set sql_mode = 'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';")); - Collection collection = CreateCollection("test"); - var docs1 = new[] - { - new { _id = 1, name = "jonh doe", age = 38,profit = 100,test = 1.92,date="21/11/2011" }, - new { _id = 2, name = "milton green", age = 45,profit = 200,test = 12.08,date="21/11/2012" }, - new { _id = 3, name = "larry smith", age = 24,profit = 300,test = 12.1,date="21/11/2013" }, - new { _id = 4, name = "mary weinstein", age = 24 ,profit = 100,test = 12.0,date="21/11/2014" }, - new { _id = 5, name = "jerry pratt", age = 45 ,profit = 400,test = 20.87,date="21/11/2015" }, - new { _id = 6, name = "hugh jackman", age = 20,profit = 500,test = 20.65,date="21/11/2016"}, - new { _id = 7, name = "elizabeth olsen", age = 31,profit = 300,test = 20.45,date="21/11/2017" }, - new { _id = 8, name = "tommy h", age = 31,profit = 3000,test = 0.0,date="21/11/2018"} - }; - - Result r = collection.Add(docs1).Execute(); - Assert.AreEqual(8, r.AffectedItemsCount); - - // GroupBy operation. - var result1 = collection.Find().Limit(2).Offset(-2378723).Execute(); - int k = result1.FetchAll().Count; - result1 = collection.Find().Limit(2).Offset(-1).Execute(); - k = result1.FetchAll().Count; - result1 = collection.Find().Limit(2).Offset(0).Execute(); - k = result1.FetchAll().Count; - result1 = collection.Find().Limit(2).Offset(1000000000).Execute(); - k = result1.FetchAll().Count; - collection.Remove("true").Limit(2).Execute(); - - docs1 = new[] - { - new { _id = 1, name = "jonh doe", age = 38,profit = 100,test = 1.92,date="21/11/2011" }, - new { _id = 2, name = "milton green", age = 45,profit = 200,test = 12.08,date="21/11/2012" }, - }; - - r = collection.Add(docs1).Execute(); - Assert.Throws(() => collection.Remove("true").Limit(2).Offset(1).Execute()); - - collection.Remove("true").Limit(2).Offset(0).Execute(); - docs1 = new[] - { - new { _id = 1, name = "jonh doe", age = 38,profit = 100,test = 1.92,date="21/11/2011" }, - new { _id = 2, name = "milton green", age = 45,profit = 200,test = 12.08,date="21/11/2012" }, - }; - - r = collection.Add(docs1).Execute(); - Assert.Throws(() => collection.Modify("_id = 1 || _id = 2").Set("age", 34).Limit(1).Offset(1).Execute()); - - collection.Modify("_id = 1 || _id = 2").Set("age", 34).Limit(2).Offset(0).Execute(); - collection.Modify("_id = 1").Set("age", 38).Limit(2).Offset(0).Execute(); - collection.Modify("_id = 2").Set("age", 45).Limit(2).Offset(0).Execute(); - - var result = collection.Find().Fields("max($.age) as age", "max($.profit) as Profit", "max($.test) as test").GroupBy("$.test").Having("max($.age)>30"). - Having("max($.age)<32").Limit(3).Offset(2) - .Execute(); - Assert.AreEqual(3, result.FetchAll().Count); - - result = collection.Find().Fields("$._id as _id", "$.test as test").GroupBy("$.test").Limit(5).Offset(1).Execute(); - Assert.AreEqual(5, result.FetchAll().Count); - result = collection.Find().Fields("$._id as _id", "$.test as test").GroupBy("$.test").Limit(5).Offset(-1).Execute(); - Assert.AreEqual(5, result.FetchAll().Count); - - result = collection.Find().Fields("max($.age) as age", "max($.profit) as Profit", "max($.test) as test").GroupBy("$.test").Having("max($.age)>30"). - Having("max($.age)<32").Limit(3).Offset(-1) - .Execute(); - Assert.AreEqual(3, result.FetchAll().Count); - - Assert.Throws(() => collection.Find().Fields("max($.age) as age", "max($.profit) as Profit", "max($.test) as test").GroupBy("$.test").Having("max($.age)>30"). - Having("max($.age)<32").Limit(-1).Offset(0) - .Execute()); - } - - [Test, Description("Test MySQLX plugin Collection Dbdoc Scenarios")] - public void CollectionDbdoc() - { - Collection col = CreateCollection("my_collection_1"); - Collection col1 = CreateCollection("my_collection_2"); - var d1 = new DbDoc(); - d1.SetValue("_id", 1); - var docs1 = new[] - { - new { _id = 1, title = "Book 1" }, - new { _id = 2, title = "Book 2" }, - }; - - d1.SetValue("books", docs1); - d1.SetValue("pages", 20); - - var d2 = new DbDoc(); - d2.SetValue("_id", 2); - var docs2 = new[] - { - new { _id = 1, title = "Book 3" }, - new { _id = 2, title = "Book 4" }, - }; - - d2.SetValue("books", docs2); - d2.SetValue("pages", 30); - - var d3 = new DbDoc(); - d3.SetValue("_id", 3); - var docs3 = new[] - { - new { _id = 1, title = "Book 3" }, - new { _id = 2, title = "Book 4" }, - }; - - d3.SetValue("books", docs3); - d3.SetValue("pages", 40); - col.Add(d1).Add(d2).Add(d3).Execute(); - string[] test1 = new string[] { "_id=1" }; - string[] test2 = new string[] { "_id=2" }; - var res = col.Find("$._id = 1").Execute().FetchAll(); - Assert.AreEqual(1, res.Count, "Matching the find count"); - Assert.AreEqual(d1.ToString(), res[0].ToString(), "Matching the string"); - res = col.Find("$._id = 2").Execute().FetchAll(); - Assert.AreEqual(1, res.Count, "Matching the find count"); - Assert.AreEqual(d2.ToString(), res[0].ToString(), "Matching the string"); - res = col.Find("$._id = 3").Execute().FetchAll(); - Assert.AreEqual(1, res.Count, "Matching the find count"); - Assert.AreEqual(d3.ToString(), res[0].ToString(), "Matching the string"); - - } - - [Test, Description("Test MySQLX plugin Collection Dbdoc Scenarios - ID Present DbDoc Blank")] - public void CollectionIDPresentDbdocBlank() - { - Collection col = CreateCollection("my_collection_1"); - Collection col1 = CreateCollection("my_collection_2"); - var d1 = new DbDoc(); - d1.SetValue("_id", 1); - string[] a = { String.Empty }; - d1.SetValue("books", a); - d1.SetValue("pages", 20); - - var d2 = new DbDoc(); - d2.SetValue("_id", 2); - d2.SetValue("books", a); - d2.SetValue("pages", 30); - - var d3 = new DbDoc(); - d3.SetValue("_id", 3); - d3.SetValue("books", a); - d3.SetValue("pages", 40); - - col.Add(d1).Add(d2).Add(d3).Execute(); - string[] test1 = new string[] { "_id=1" }; - string[] test2 = new string[] { "_id=2" }; - var res = col.Find("$._id = 1").Execute().FetchAll(); - Assert.AreEqual(1, res.Count, "Matching the find count"); - Assert.AreEqual(d1.ToString(), res[0].ToString(), "Matching the string"); - res = col.Find("$._id = 2").Execute().FetchAll(); - Assert.AreEqual(1, res.Count, "Matching the find count"); - Assert.AreEqual(d2.ToString(), res[0].ToString(), "Matching the string"); - res = col.Find("$._id = 3").Execute().FetchAll(); - Assert.AreEqual(1, res.Count, "Matching the find count"); - Assert.AreEqual(d3.ToString(), res[0].ToString(), "Matching the string"); - } - - /// - /// Bug 23542055 - /// - [Test, Description("Test MySQLX plugin Find with Many conditions")] - [Ignore("Uncomment to execute")] - public void FindWithManyConditions() - { - int i = 0; - int Condition = 49; - String query = ""; - var col = CreateCollection("my_collection_1"); - - col.Add("{\"_id\":\"1002\",\"TEST1\":1111}").Execute(); - for (i = 0; i < Condition; i++) - { - if (i > 0) - query = query + " OR "; - query = query + "$.TEST1 > " + i; - } - var docs = col.Find(query).Execute(); - } - - [TestCase(1)] - [TestCase(2)] - [TestCase(3)] - [TestCase(4)] - [Test, Description("Reading exclusively locked anonymous object array using LockShared without waiting option. ")] - public void ExclusiveLocksAndCommit(int scenario) - { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher"); - - ExecuteSQLStatement(session.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); - using (var session2 = MySQLX.GetSession(ConnectionString)) - { - ExecuteSQLStatement(session2.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); - Collection coll = CreateCollection("test"); - ExecuteSQLStatement(session2.SQL("ALTER TABLE `test`.`test` ADD COLUMN `$ix_i_r_index` INT GENERATED ALWAYS AS (JSON_UNQUOTE(JSON_EXTRACT(doc, '$._id'))) VIRTUAL NOT NULL, ADD UNIQUE INDEX `myIndex`(`$ix_i_r_index`)")); - Result result1 = null; - switch (scenario) - { - case 1: // Anonymous Object - var docs = new[] - { - new {_id = 1, a = 1}, - new {_id = 2, a = 2}, - new {_id = 3, a = 3} - }; - coll.Add(docs).Execute(); - break; - case 2: // DbDoc - for (int i = 0; i < 3; i++) - { - DbDoc DbDocs = new DbDoc(); - DbDocs.SetValue("_id", i); - DbDocs.SetValue("a", i); - result1 = coll.Add(DbDocs).Execute(); - } - break; - case 3: // Chained Add - var docs1 = new { _id = 1, title = "Book 1", pages = 20, a = 1 }; - var docs2 = new { _id = 2, title = "Book 1", pages = 20, a = 2 }; - var docs3 = new { _id = 3, title = "Book 1", pages = 20, a = 3 }; - result1 = coll.Add(docs1).Add(docs2).Add(docs3).Execute(); - break; - case 4: //Json string - result1 = coll.Add(@"{ ""_id"": 1,""a"": 1 }", @"{""_id"": 2,""a"": 2 }", @"{""_id"": 3, ""a"": 3 }", @"{ ""_id"": 4,""a"": 4 }").Execute(); - break; - } - - var coll2 = session2.GetSchema("test").GetCollection("test"); - session.SQL("START TRANSACTION").Execute(); - var docResult = coll.Find("_id = 1").LockExclusive().Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID"); - - session2.SQL("START TRANSACTION").Execute(); - // Should return immediately since document isn't locked. - docResult = coll2.Find("_id = 2").LockExclusive().Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID"); - - // Session2 blocks due to to LockExclusive() not allowing to read locked documents. - session2.SQL("SET SESSION innodb_lock_wait_timeout=1").Execute(); - Exception ex = Assert.Throws(() => ExecuteFindStatement(coll2.Find("_id = :id").LockExclusive().Bind("id", 1))); - - Assert.Throws(() => ExecuteModifyStatement(coll2.Modify("a = 1").Change("a", 10))); - - session.Commit(); - var result = coll2.Modify("a = 1").Set("a", 12).Execute(); - Assert.AreEqual(1, result.AffectedItemsCount); - session.SQL("ROLLBACK").Execute(); - session2.SQL("ROLLBACK").Execute(); - } - } - - [TestCase(null)] - [TestCase(LockMode.Shared)] - [TestCase(LockMode.Exclusive)] - [Test, Description("Reading a document which was locked using lock_shared without waiting option")] - public void SharedLockAndCommit(LockMode? lockMode) - { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher"); - ExecuteSQLStatement(session.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); - using (var session2 = MySQLX.GetSession(ConnectionString)) - { - ExecuteSQLStatement(session2.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); - Collection coll = CreateCollection("test"); - session2.SQL("ALTER TABLE `test`.`test` ADD COLUMN `$ix_i_r_index` INT GENERATED ALWAYS AS (JSON_UNQUOTE(JSON_EXTRACT(doc, '$._id'))) VIRTUAL NOT NULL, ADD UNIQUE INDEX `myIndex`(`$ix_i_r_index`)").Execute(); - var docs = new[] - { - new {_id = 1, a = 1}, - new {_id = 2, a = 2}, - new {_id = 3, a = 3} - }; - - coll.Add(docs).Execute(); - var coll2 = session2.GetSchema("test").GetCollection("test"); - - session.SQL("START TRANSACTION").Execute(); - var docResult = coll.Find("_id = 1").LockShared().Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID"); - - session2.SQL("START TRANSACTION").Execute(); - // Should return immediately since document isn't locked. - switch (lockMode) - { - case LockMode.Shared: - docResult = coll2.Find("_id = 2").LockShared().Execute(); - break; - case LockMode.Exclusive: - docResult = coll2.Find("_id = 2").LockExclusive().Execute(); - break; - default: - docResult = coll2.Find("_id = 2").Execute(); - break; - } - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID"); - - // Session2 returns immediately. - session2.SQL("SET SESSION innodb_lock_wait_timeout=1").Execute(); - docResult = coll2.Find("_id = :id").Bind("id", 1).Execute(); - Assert.That(docResult.FetchAll(), Has.One.Items); - - // Session2 blocks due to to LockShared() not allowing to modify locked documents. - Exception ex = Assert.Throws(() => ExecuteModifyStatement(coll2.Modify("a = 1").Change("a", 10))); - - // Session2 returns immediately as session is committed. - session.Commit(); - var result = coll2.Modify("a = 1").Set("a", 12).Execute(); - Assert.AreEqual(1, result.AffectedItemsCount); - - session.SQL("ROLLBACK").Execute(); - session2.SQL("ROLLBACK").Execute(); - } - } - - [TestCase(LockMode.Shared)] - [TestCase(LockMode.Exclusive)] - [Test, Description("Reading a document using lock_shared using SKIPLOCK and NOWAIT options with CRUD operations happening parallely.")] - public void SharedAndExclusiveLockWithSkipAndNoWait(LockMode lockMode) - { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher"); - ExecuteSQLStatement(session.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); - using (var session2 = MySQLX.GetSession(ConnectionString)) - { - ExecuteSQLStatement(session2.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); - Collection coll = CreateCollection("test"); - session2.SQL("ALTER TABLE `test`.`test` ADD COLUMN `$ix_i_r_index` INT GENERATED ALWAYS AS (JSON_UNQUOTE(JSON_EXTRACT(doc, '$._id'))) VIRTUAL NOT NULL, ADD UNIQUE INDEX `myIndex`(`$ix_i_r_index`)").Execute(); - if (lockMode == LockMode.Shared) - session2.SQL("ALTER TABLE `test`.`test` ADD COLUMN `$ix_i_m_index` INT GENERATED ALWAYS AS (JSON_UNQUOTE(JSON_EXTRACT(doc, '$.a'))) VIRTUAL NOT NULL, ADD UNIQUE INDEX `myIndex1`(`$ix_i_m_index`)").Execute(); - - var docs = new[] - { - new {_id = 1, a = 1}, - new {_id = 2, a = 2}, - new {_id = 3, a = 3} - }; - - coll.Add(docs).Execute(); - var coll2 = session2.GetSchema("test").GetCollection("test"); - - session.SQL("START TRANSACTION").Execute(); - var result1 = coll.Modify("a = 1").Set("a", 10).Execute(); - - session2.SQL("START TRANSACTION").Execute(); - session2.SQL("SET SESSION innodb_lock_wait_timeout=1").Execute(); - DocResult docResult = null; - switch (lockMode) - { - case LockMode.Exclusive: - Assert.Throws(() => ExecuteFindStatement(coll2.Find("_id = :id").LockExclusive(LockContention.NoWait).Bind("id", 1))); - docResult = coll2.Find("_id = :id").LockExclusive(LockContention.SkipLocked).Bind("id", 1).Execute(); - break; - case LockMode.Shared: - Assert.Throws(() => ExecuteFindStatement(coll2.Find("_id = :id").LockShared(LockContention.NoWait).Bind("id", 1))); - docResult = coll2.Find("_id = :id").LockShared(LockContention.SkipLocked).Bind("id", 1).Execute(); - break; - } - Assert.AreEqual(0, docResult.FetchAll().Count, "Matching the document ID"); - - session.SQL("ROLLBACK").Execute(); - session2.SQL("ROLLBACK").Execute(); - } - } - - [Test, Description("Multiple lock calls using NOWAIT and SKIPLOCK waiting option. ")] - public void MultipleLocksWithNowaitAndSkiplock() - { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher"); - ExecuteSQLStatement(session.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); - using (var session2 = MySQLX.GetSession(ConnectionString)) - { - ExecuteSQLStatement(session2.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); - Collection coll = CreateCollection("test"); - session2.SQL("ALTER TABLE `test`.`test` ADD COLUMN `$ix_i_r_index` INT GENERATED ALWAYS AS (JSON_UNQUOTE(JSON_EXTRACT(doc, '$._id'))) VIRTUAL NOT NULL, ADD UNIQUE INDEX `myIndex`(`$ix_i_r_index`)").Execute(); - var docs = new[] - { - new {_id = 1, a = 1}, - new {_id = 2, a = 2}, - new {_id = 3, a = 3} - }; - - coll.Add(docs).Execute(); - var coll2 = session2.GetSchema("test").GetCollection("test"); - - session.SQL("START TRANSACTION").Execute(); - var docResult = coll.Find("_id = 1").LockShared().Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID"); - - session2.SQL("START TRANSACTION").Execute(); - - session2.SQL("SET SESSION innodb_lock_wait_timeout=1").Execute(); - Assert.Throws(() => ExecuteFindStatement(coll2.Find("_id = :id").LockExclusive(LockContention.SkipLocked).LockExclusive(LockContention.NoWait).Bind("id", 1))); - - docResult = coll2.Find("_id = :id").LockExclusive(LockContention.SkipLocked).LockShared(LockContention.NoWait).Bind("id", 1).Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID"); - - docResult = coll2.Find("_id = :id").LockExclusive(LockContention.SkipLocked).LockShared(LockContention.SkipLocked).Bind("id", 1).Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID"); - - docResult = coll2.Find("_id = :id").LockShared(LockContention.SkipLocked).LockExclusive(LockContention.SkipLocked).Bind("id", 1).Execute(); - Assert.AreEqual(0, docResult.FetchAll().Count, "Matching the document ID"); - - session.SQL("ROLLBACK").Execute(); - session2.SQL("ROLLBACK").Execute(); - } - } - - [Test, Description("Reading multiple rows in a locked document(lock_shared) using SKIPLOCK and NOWAIT ")] - public void LockSharedMultipleReads() - { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher"); - ExecuteSQLStatement(session.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); - using (var session2 = MySQLX.GetSession(ConnectionString)) - { - ExecuteSQLStatement(session2.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); - Collection coll = CreateCollection("test"); - session2.SQL("ALTER TABLE `test`.`test` ADD COLUMN `$ix_i_r_index` INT GENERATED ALWAYS AS (JSON_EXTRACT(doc, '$._id')) VIRTUAL NOT NULL, ADD UNIQUE INDEX `myIndex`(`$ix_i_r_index`)").Execute(); - var docs = new[] - { - new {_id = 1, a = 1}, - new {_id = 2, a = 2}, - new {_id = 3, a = 3} - }; - - coll.Add(docs).Execute(); - var coll2 = session2.GetSchema("test").GetCollection("test"); - - session.SQL("START TRANSACTION").Execute(); - var docResult = coll.Find("_id >1").LockShared().Execute(); - Assert.AreEqual(2, docResult.FetchAll().Count, "Matching the document ID"); - - session2.SQL("START TRANSACTION").Execute(); - session2.SQL("SET SESSION innodb_lock_wait_timeout=1").Execute(); - - docResult = coll2.Find("_id < 3").LockShared(LockContention.SkipLocked).Execute(); - Assert.AreEqual(2, docResult.FetchAll().Count, "Matching the document ID"); - - docResult = coll2.Find("_id < 3").LockShared(LockContention.NoWait).Execute(); - Assert.AreEqual(2, docResult.FetchAll().Count, "Matching the document ID"); - - docResult = coll2.Find("_id < 3").LockExclusive(LockContention.SkipLocked).Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID"); - - session.SQL("ROLLBACK").Execute(); - session2.SQL("ROLLBACK").Execute(); - } - } - - [Test, Description("Reading multiple rows in an exclusively locked document using SKIPLOCK and NOWAIT ")] - public void LockExclusiveMultipleReads() - { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher"); - ExecuteSQLStatement(session.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); - using (var session2 = MySQLX.GetSession(ConnectionString)) - { - ExecuteSQLStatement(session2.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); - Collection coll = CreateCollection("test"); - session2.SQL("ALTER TABLE `test`.`test` ADD COLUMN `$ix_i_r_index` INT GENERATED ALWAYS AS (JSON_EXTRACT(doc, '$._id')) VIRTUAL NOT NULL, ADD UNIQUE INDEX `myIndex`(`$ix_i_r_index`)").Execute(); - var docs = new[] - { - new {_id = 1, a = 1}, - new {_id = 2, a = 2}, - new {_id = 3, a = 3} - }; - - coll.Add(docs).Execute(); - var coll2 = session2.GetSchema("test").GetCollection("test"); - - session.SQL("START TRANSACTION").Execute(); - var docResult = coll.Find("_id >1").LockExclusive().Execute(); - Assert.AreEqual(2, docResult.FetchAll().Count, "Matching the document ID"); - - session2.SQL("START TRANSACTION").Execute(); - session2.SQL("SET SESSION innodb_lock_wait_timeout=1").Execute(); - - docResult = coll2.Find("_id < 3").LockShared(LockContention.SkipLocked).Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID"); - - docResult = coll2.Find("_id < 3").LockExclusive(LockContention.SkipLocked).Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID"); - - session.SQL("ROLLBACK").Execute(); - session2.SQL("ROLLBACK").Execute(); - } - } - - [Test, Description("Collection.Find() with shared lock and Collection.Modify() normal from two sessions. ")] - public void LockSharedAndModify() - { - if (!session.Version.isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher"); - ExecuteSQLStatement(session.SQL("SET autocommit = 0")); - using (var session2 = MySQLX.GetSession(ConnectionString)) - { - session2.SQL("SET autocommit = 0").Execute(); - Collection coll = CreateCollection("test"); - session2.SQL("ALTER TABLE `test`.`test` ADD COLUMN `$ix_i_r_index` INT GENERATED ALWAYS AS (JSON_UNQUOTE(JSON_EXTRACT(doc, '$._id'))) VIRTUAL NOT NULL, ADD UNIQUE INDEX `myIndex`(`$ix_i_r_index`)").Execute(); - var docs = new[] - { - new {_id = 1, a = 1}, - new {_id = 2, a = 2}, - new {_id = 3, a = 3} - }; - - coll.Add(docs).Execute(); - var coll2 = session2.GetSchema("test").GetCollection("test"); - - session.SQL("START TRANSACTION").Execute(); - var docResult = coll.Find("_id = 1").LockShared().Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID"); - session2.SQL("START TRANSACTION").Execute(); - // Should return immediately since document isn't locked. - docResult = coll2.Find("_id = 1").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID"); - session2.SQL("SET SESSION innodb_lock_wait_timeout=1").Execute(); - // Should allow to modify immediately since document isn't locked. - var result = coll2.Modify("_id = 2").Set("a", 10).Execute(); - Assert.AreEqual(1, (int)result.AffectedItemsCount, "Match being done"); - Assert.Throws(() => ExecuteModifyStatement(coll2.Modify("_id = 1").Change("a", 10))); - - session.SQL("ROLLBACK").Execute(); - session2.SQL("ROLLBACK").Execute(); - } - - ExecuteSQLStatement(session.SQL("SET autocommit = 1")); - } - - [Test, Description("Collection.Find() with shared lock from two sessions. ")] - public void LockSharedTwoSessions() - { - if (!session.Version.isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher"); - ExecuteSQLStatement(session.SQL("SET autocommit = 0")); - using (var session2 = MySQLX.GetSession(ConnectionString)) - { - session2.SQL("SET autocommit = 0").Execute(); - Collection coll = CreateCollection("test"); - session2.SQL("ALTER TABLE `test`.`test` ADD COLUMN `$ix_i_r_index` INT GENERATED ALWAYS AS (JSON_EXTRACT(doc, '$._id')) VIRTUAL NOT NULL, ADD UNIQUE INDEX `myIndex`(`$ix_i_r_index`)").Execute(); - var docs = new[] - { - new {_id = 1, a = 1}, - new {_id = 2, a = 1}, - new {_id = 3, a = 1} - }; - - coll.Add(docs).Execute(); - var coll2 = session2.GetSchema("test").GetCollection("test"); - - session.SQL("START TRANSACTION").Execute(); - var docResult = coll.Find("_id = 1").LockShared().Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID"); - session2.SQL("START TRANSACTION").Execute(); - // Should return immediately since document isn't locked. - docResult = coll2.Find("_id = 2").LockShared().Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID"); - // Should return immediately due to LockShared() allows reading by other sessions. - docResult = coll2.Find("_id = 1").LockShared().Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID"); - session.SQL("ROLLBACK").Execute(); - session2.SQL("ROLLBACK").Execute(); - } - - ExecuteSQLStatement(session.SQL("SET autocommit = 1")); - } - - [Test, Description("Collection.Find() with exclusive lock and Collection.Find() with shared lock from two sessions. ")] - public void LockExclusiveFindAndLockSharedFind() - { - if (!session.Version.isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher"); - ExecuteSQLStatement(session.SQL("SET autocommit = 0")); - using (var session2 = MySQLX.GetSession(ConnectionString)) - { - session2.SQL("SET autocommit = 0").Execute(); - Collection coll = CreateCollection("test"); - session2.SQL("ALTER TABLE `test`.`test` ADD COLUMN `$ix_i_r_index` INT GENERATED ALWAYS AS (JSON_UNQUOTE(JSON_EXTRACT(doc, '$._id'))) VIRTUAL NOT NULL, ADD UNIQUE INDEX `myIndex`(`$ix_i_r_index`)").Execute(); - var docs = new[] - { - new {_id = 1, a = 1}, - new {_id = 2, a = 1}, - new {_id = 3, a = 1} - }; - - coll.Add(docs).Execute(); - var coll2 = session2.GetSchema("test").GetCollection("test"); - - session.SQL("START TRANSACTION").Execute(); - var docResult = coll.Find("_id = 1").LockExclusive().Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID"); - session2.SQL("START TRANSACTION").Execute(); - // Should return immediately since document isn't locked. - docResult = coll2.Find("_id = 2").LockShared().Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID"); - session2.SQL("SET SESSION innodb_lock_wait_timeout=1").Execute(); - // Session2 blocks due to LockExclusive() not allowing to read locked documents. - Assert.Throws(() => ExecuteFindStatement(coll2.Find("_id = 1").LockShared())); - // Session unlocks documents. - session.SQL("ROLLBACK").Execute(); - docResult = coll2.Find("_id = 1").LockShared().Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID"); - docResult = coll.Find("_id = 1").LockShared().Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID"); - session2.SQL("ROLLBACK").Execute(); - } - - ExecuteSQLStatement(session.SQL("SET autocommit = 1")); - } - - [Test, Description("Collection.Find() with shared lock and Collection.Find() with exclusive lock from two sessions. ")] - public void LockSharedFindAndExclusiveLocks() - { - if (!session.Version.isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher"); - ExecuteSQLStatement(session.SQL("SET autocommit = 0")); - using (var session2 = MySQLX.GetSession(ConnectionString)) - { - session2.SQL("SET autocommit = 0").Execute(); - Collection coll = CreateCollection("test"); - session2.SQL("ALTER TABLE `test`.`test` ADD COLUMN `$ix_i_r_index` INT GENERATED ALWAYS AS (JSON_UNQUOTE(JSON_EXTRACT(doc, '$._id'))) VIRTUAL NOT NULL, ADD UNIQUE INDEX `myIndex`(`$ix_i_r_index`)").Execute(); - var docs = new[] - { - new {_id = 1, a = 1}, - new {_id = 2, a = 1}, - new {_id = 3, a = 1} - }; - - coll.Add(docs).Execute(); - var coll2 = session2.GetSchema("test").GetCollection("test"); - - session.SQL("START TRANSACTION").Execute(); - var docResult = coll.Find("_id = 1").LockShared().Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document IDs"); - docResult = coll.Find("_id = 3").LockShared().Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document IDs"); - session2.SQL("START TRANSACTION").Execute(); - - // Should return immediately since document isn't locked. - docResult = coll2.Find("_id = 2").LockExclusive().Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID"); - // Should return immediately due to LockShared() allows reading by other sessions. - docResult = coll2.Find("_id = 2").LockShared().Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID"); - session2.SQL("SET SESSION innodb_lock_wait_timeout=1").Execute(); - // Session1 blocks due to LockExclusive() not allowing to read locked documents. - coll2.Find("_id = 2").LockExclusive().Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID"); - Assert.Throws(() => ExecuteFindStatement(coll2.Find("_id = 1").LockExclusive())); - Assert.Throws(() => ExecuteModifyStatement(coll2.Modify("_id = 1").Set("a", 100))); - // Session unlocks documents. - session2.SQL("ROLLBACK").Execute(); - session.SQL("ROLLBACK").Execute(); - } - - ExecuteSQLStatement(session.SQL("SET autocommit = 1")); - } - - [Test, Description("Collection.Find() with exclusive lock and Collection.Find() with exclusive lock from two sessions. ")] - public void LockExclusiveWithRollback() - { - if (!session.Version.isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher"); - ExecuteSQLStatement(session.SQL("SET autocommit = 0")); - using (var session2 = MySQLX.GetSession(ConnectionString)) - { - session2.SQL("SET autocommit = 0").Execute(); - Collection coll = CreateCollection("test"); - session2.SQL("ALTER TABLE `test`.`test` ADD COLUMN `$ix_i_r_index` INT GENERATED ALWAYS AS (JSON_UNQUOTE(JSON_EXTRACT(doc, '$._id'))) VIRTUAL NOT NULL, ADD UNIQUE INDEX `myIndex`(`$ix_i_r_index`)").Execute(); - var docs = new[] - { - new {_id = 1, a = 1}, - new {_id = 2, a = 1}, - new {_id = 3, a = 1} - }; - - coll.Add(docs).Execute(); - var coll2 = session2.GetSchema("test").GetCollection("test"); - - session.SQL("START TRANSACTION").Execute(); - var docResult = coll.Find("_id = 1").LockExclusive().Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document IDs"); - session2.SQL("START TRANSACTION").Execute(); - // Should return immediately due to LockShared() allows reading by other sessions. - docResult = coll2.Find("_id = 2").LockExclusive().Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID"); - session.SQL("SET SESSION innodb_lock_wait_timeout=1").Execute(); - Assert.Throws(() => ExecuteFindStatement(coll.Find("_id = 2").LockExclusive())); - session2.SQL("SET SESSION innodb_lock_wait_timeout=1").Execute(); - // Session1 blocks due to LockExclusive() not allowing to read locked documents. - Assert.Throws(() => ExecuteFindStatement(coll2.Find("_id = 1").LockExclusive())); - // Session unlocks documents. - session2.SQL("ROLLBACK").Execute(); - docResult = coll.Find("_id = 2").LockExclusive().Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID"); - session.SQL("ROLLBACK").Execute(); - docResult = coll2.Find("_id = 1").LockExclusive().Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID"); - } - - ExecuteSQLStatement(session.SQL("SET autocommit = 1")); - } - - [Test, Description("Collection.Find() with exclusive lock and Collection.Find() with exclusive lock from two sessions--Select multiple records ")] - public void LockExclusiveWithINSelection() - { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher"); - ExecuteSQLStatement(session.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); - using (var session2 = MySQLX.GetSession(ConnectionString)) - { - ExecuteSQLStatement(session2.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); - Collection coll = CreateCollection("test"); - var docs = new[] - { - new {_id = 1, a = 1}, - new {_id = 2, a = 1}, - new {_id = 3, a = 1} - }; - - coll.Add(docs).Execute(); - session2.SQL("ALTER TABLE `test`.`test` ADD COLUMN `$ix_i_r_index` INT GENERATED ALWAYS AS (JSON_UNQUOTE(JSON_EXTRACT(doc, '$._id'))) VIRTUAL NOT NULL, ADD UNIQUE INDEX `myIndex`(`$ix_i_r_index`)").Execute(); - var coll2 = session2.GetSchema("test").GetCollection("test"); - session.SQL("START TRANSACTION").Execute(); - var docResult = coll.Find("_id in (1,3)").LockExclusive().Execute(); - Assert.AreEqual(2, docResult.FetchAll().Count, "Matching the document ID"); - session2.SQL("START TRANSACTION").Execute(); - // Should return immediately since document isn't locked. - docResult = coll2.Find("_id = 2").LockExclusive().Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID"); - // Should return immediately due to LockShared() allows reading by other sessions. - docResult = coll2.Find("_id = 2").LockShared().Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID"); - session2.SQL("SET SESSION innodb_lock_wait_timeout=1").Execute(); - // Session1 blocks due to LockExclusive() not allowing to read locked documents. - coll2.Find("_id = 2").LockExclusive().Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID"); - Assert.Throws(() => ExecuteFindStatement(coll2.Find("_id = 1").LockExclusive())); - Assert.Throws(() => ExecuteModifyStatement(coll2.Modify("_id = 1").Set("a", 100))); - // Session unlocks documents. - session2.SQL("ROLLBACK").Execute(); - session.SQL("ROLLBACK").Execute(); - } - - ExecuteSQLStatement(session.SQL("SET autocommit = 1")); - } - - [Test, Description("Collection.Find() with shared lock twice ")] - public void LockSharedReadTwice() - { - if (!session.Version.isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher"); - ExecuteSQLStatement(session.SQL("SET autocommit = 0")); - using (var session2 = MySQLX.GetSession(ConnectionString)) - { - session2.SQL("SET autocommit = 0").Execute(); - Collection coll = CreateCollection("test"); - session2.SQL("ALTER TABLE `test`.`test` ADD COLUMN `$ix_i_r_index` INT GENERATED ALWAYS AS (JSON_UNQUOTE(JSON_EXTRACT(doc, '$._id'))) VIRTUAL NOT NULL, ADD UNIQUE INDEX `myIndex`(`$ix_i_r_index`)").Execute(); - var docs = new[] - { - new {_id = 1, a = 1}, - new {_id = 2, a = 1}, - new {_id = 3, a = 1} - }; - coll.Add(docs).Execute(); - var coll2 = session2.GetSchema("test").GetCollection("test"); - - session.SQL("START TRANSACTION").Execute(); - var docResult = coll.Find("_id = 1").LockShared().Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID"); - session2.SQL("START TRANSACTION").Execute(); - - // Should return immediately since document isn't locked. - docResult = coll2.Find("_id = 2").LockExclusive().Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID"); - docResult = coll2.Find("_id = 2").LockExclusive().Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID"); - docResult = coll2.Find("_id = 2").LockShared().Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID"); - docResult = coll2.Find("_id = 2").LockShared().Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID"); - // Session unlocks documents. - session2.SQL("ROLLBACK").Execute(); - session.SQL("ROLLBACK").Execute(); - } - ExecuteSQLStatement(session.SQL("SET autocommit = 1")); - } - - [Test, Description("Test MySQLX plugin Collection Array or Object contains operator Scenarios-1")] - public void FindInJsonObjects() - { - if (!Platform.IsWindows()) Assert.Ignore("This test is for Windows OS only"); - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher."); - - var col = CreateCollection("my_collection_1"); - string json = @"{ ""_id"": 0, ""title"": ""Book 0"" ,""pages"": 10,""name"": ""Jeoff Archer""}"; - Result r = col.Add(json).Execute(); - Assert.AreEqual(1, (int)r.AffectedItemsCount, "Matching Affected Records Count"); - var foundDocs = col.Find("1 in (1,2,3,6)").Execute(); - Assert.AreEqual(1, foundDocs.FetchAll().Count, "Matching Count"); - //var result = col.Find("0 in $._id").Fields("$.name as name, $.pages as pages, $.title as title").Execute(); - foundDocs = col.Find("'Book 0' in $.title").Execute(); - Assert.AreEqual(1, foundDocs.FetchAll().Count, "Matching Count"); - foundDocs = col.Find("100 in _id").Execute(); - Assert.AreEqual(0, foundDocs.FetchAll().Count, "Matching Count"); - foundDocs = col.Find("100 not in _id").Execute(); - Assert.AreEqual(1, foundDocs.FetchAll().Count, "Matching Count"); - - json = @"{ ""_id"" : 99950, ""city"" : ""KETCHIKAN"", ""loc"" : ""[ -133.18479, 55.942471 ]"", ""pop"" : 422, ""state"" : ""AK"" }"; - r = col.Add(json).Execute(); - - - var d = new DbDoc(@"{ ""id"": 1, ""pages"": 20, - ""person"": { ""name"": ""Fred"", ""age"": 45 } - }"); - var d2 = new DbDoc(); - d2.SetValue("id", 1); - d2.SetValue("pages", 20); - d2.SetValue("person", new { name = "Fred", age = 45 }); - - Assert.AreEqual(d.Equals(d2), true, "Matching"); - col.Add(d).Execute(); - - - d = new DbDoc(@"{""id"":100,""FirstName"":""xyz"",""lastname"":""pqr"", - ""address"": - {""house"":44,""city"":""Delhi"",""country"":""india""}}"); - col.Add(d).Execute(); - - d = new DbDoc(@"{""customerId"":100,""FirstName"":""xyz"",""lastname"":""pqr"", - ""address"": - {""house"":44,""city"":""Delhi"",""country"":""india""}, - ""employer"": - {""cmpName"":""ABC"",""type"":""IT""}}"); - col.Add(d).Execute(); - - d = new DbDoc(@"{ ""id"": 1, ""pages"": 20, - ""books"": [ - {""_id"" : 1, ""title"" : ""Book 1""}, - { ""_id"" : 2, ""title"" : ""Book 2"" } - ] - }"); - col.Add(d).Execute(); - - var docs = new[] { new { _id = 1, title = "Book 1" }, new { _id = 2, title = "Book 2" } }; - d2 = new DbDoc(); - d2.SetValue("id", 100); - d2.SetValue("pages", 20); - d2.SetValue("books", docs); - col.Add(d2).Execute(); - - var result = col.Find("0 in $._id").Fields("$._id as _id,$.name as name, $.pages as pages, $.title as title").Execute(); - var res1 = result.FetchOne(); - Assert.AreEqual(0, res1["_id"]); - Assert.AreEqual("Jeoff Archer", res1["name"]); - Assert.AreEqual(10, res1["pages"]); - Assert.AreEqual("Book 0", res1["title"]); - - result = col.Find("0 in $._id OR 1 in $._id").Fields("$._id as _id,$.name as name, $.pages as pages, $.title as title").Execute(); - res1 = result.FetchOne(); - Assert.AreEqual(0, res1["_id"]); - Assert.AreEqual("Jeoff Archer", res1["name"]); - Assert.AreEqual(10, res1["pages"]); - Assert.AreEqual("Book 0", res1["title"]); - - result = col.Find("0 not in $._id").Fields("$._id as _id,$.name as name, $.pages as pages, $.title as title").Execute(); - var res2 = result.FetchAll(); - Assert.AreEqual(6, res2.Count, "Matching the find count"); - - result = col.Find("'Jeoff Archer' in $.name").Execute(); - res1 = result.FetchOne(); - Assert.AreEqual(0, res1["_id"]); - Assert.AreEqual("Jeoff Archer", res1["name"]); - Assert.AreEqual(10, res1["pages"]); - Assert.AreEqual("Book 0", res1["title"]); - - result = col.Find("0 not in $._id").Fields().Execute(); - res2 = result.FetchAll(); - Assert.IsNotNull(res2[0]["_id"]); - - var test = new DbDoc(); - test.SetValue("_id", 1); - test.SetValue("age", 3488888888.9); - test.SetValue("name", - "ABBBBBBBBBBBBBBXXXXXXXXXXXXXXXYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYTTTTTTYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYABBBBBBBBBBBBBBXXXXXXXXXXXXXXXYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYTTTTTTYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYABBBBBBBBBBBBBBXXXXXXXXXXXXXXXYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYTTTTTTYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYABBBBBBBBBBBBBBXXXXXXXXXXXXXXXYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYTTTTTTYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYABBBBBBBBBBBBBBXXXXXXXXXXXXXXXYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYTTTTTTYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY"); - - var coll = CreateCollection("my_collection_123456789"); - var res = coll.Add(test).Execute(); - var foundDocs2 = coll - .Find( - "'ABBBBBBBBBBBBBBXXXXXXXXXXXXXXXYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYTTTTTTYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYABBBBBBBBBBBBBBXXXXXXXXXXXXXXXYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYTTTTTTYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYABBBBBBBBBBBBBBXXXXXXXXXXXXXXXYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYTTTTTTYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYABBBBBBBBBBBBBBXXXXXXXXXXXXXXXYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYTTTTTTYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYABBBBBBBBBBBBBBXXXXXXXXXXXXXXXYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYTTTTTTYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY' in $.name") - .Execute(); - var docs1 = foundDocs2.FetchAll(); - Assert.AreEqual(1, docs1.Count); - foundDocs2 = coll.Find("3488888888.9 in $.age").Execute(); - docs1 = foundDocs2.FetchAll(); - Assert.AreEqual(1, docs1.Count); - } - - [Test, Description("Test MySQLX plugin Collection Array or Object contains operator Scenarios-3")] - public void FindAndCountJsonValues() - { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher."); - - var col = CreateCollection("my_collection_1"); - Result add; - add = col.Add("{ \"name\": \"abcdefghijk\", \"age\": 1 , \"misc\": \"10-15-2017\"}") - .Add("{ \"name\": \"xyz\", \"age\": 6 , \"misc\": \"19.5\"}").Execute(); - add = col.Add("{ \"name\": \"qwerty@#$%^&\", \"age\": 4 , \"misc\": \"11.9\"}").Execute(); - add = col.Add("{ \"name\": [\"name1\", \"name2\", \"name3\"], \"age\": 1 , \"misc\": \"1.2\"}").Execute(); - add = col.Add( - "{ \"name\": {\"first\" : \"ABCDEF1\", \"middle\" : \"ABCDEF2\", \"last\" : \"ABCDEF3\"}, " + - "\"age\": 1 , \"misc\": \"1.2\"}") - .Execute(); - add = col.Add( - "{ \"name\": {\"first\" : \"ABCDEF1\", \"middle\" : \"ABCDEF2\", \"last\" : \"ABCDEF3\"}, " + - "\"age\": 2, \"misc\": \"1.2\"}") - .Execute(); - var docs = col.Find().Execute(); - var result1 = col.Find("\"10-15-2017\" in $.misc").Execute().FetchAll().Count; - Assert.AreEqual(1, result1); - result1 = col.Find("\"10-15-2019\" in $.misc").Execute().FetchAll().Count; - Assert.AreEqual(0, result1); - var doc = docs.FetchOne(); - var result = col.Find("1 in $.age").Fields("$.name as name, $.age as age, $.misc as misc").Sort("name DESC").Execute(); - Assert.AreEqual(3, result.FetchAll().Count); - var coll = CreateCollection("test"); - coll.Add(new DbDoc("{ \"a\": 1, \"b\": [ 1, \"value\" ], \"d\":\"\", \"ARR1\":[\"Field-1-Data-0\"] }")).Execute(); - result = coll.Find("JSON_TYPE($.ARR1) = 'ARRAY' AND \"Field-1-Data-0\" in $.ARR1").Execute(); - var count = result.FetchAll().Count; - Assert.AreEqual(1, count); - - } - - [Test, Description("Test MySQLX plugin Collection Array or Object contains operator Scenarios-4")] - public void CheckCountAfterSort() - { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher."); - var coll = CreateCollection("test"); - coll.Add("{ \"name\": \"abcdefghijk\", \"age\": 1 , \"misc\": 1.2}") - .Add("{ \"name\": \"xyz\", \"age\": 6 , \"misc\": 19.59}").Execute(); - coll.Add("{ \"name\": \"qwerty@#$%^&\", \"age\": 4 , \"misc\": 11.9}").Execute(); - coll.Add("{ \"name\": \"name1\", \"age\": 4 , \"misc\": 11.9}").Execute(); - coll.Add("{ \"name\": [\"name1\", \"name2\", \"name3\"], \"age\": 1 , \"misc\": 1.2}").Execute(); - coll.Add("{ \"name\": {\"first\" : \"ABCDEF1\", \"middle\" : \"ABCDEF2\", \"last\" : \"ABCDEF3\"}, \"age\": 1 , \"misc\": 1.2}").Execute(); - var docs = coll.Find("4 in $.age").Execute().FetchAll().Count; - Assert.True(docs > 0); - var res3 = coll.Find("4 in $.age").Sort("name ASC").Execute().FetchAll(); - Assert.AreEqual(docs, res3.Count); - } - - [Test, Description("Test MySQLX plugin Find with overlap Bugs")] - public void FindUsingOverLapsBug() - { - if (!session.Version.isAtLeast(8, 0, 17)) Assert.Ignore("This test is for MySql 8.0.17 or higher."); - String json = ""; - String[] splName = { "+", "*", "/", "a+b", "#1", "%", "&", "@1", "!1", "~", "^", - "(", ")", "{", "}", "[", "]", "|", "JSON", "ADD", "JSON_EXTRACT", "JSON_OBJECT", - "?", "=", "+", ";", ",", ":", "<", ">", "-"}; - Collection coll = CreateCollection("test"); - for (int i = 0; i < splName.Length; i++) - { - coll.Add("{\"" + splName[i] + "\":\"data" + i + "\",\"ID\":" + i + "}").Execute(); - var docs2 = coll.Find("$.ID OVERLAPS " + i).Fields("$.`" + splName[i] + "` as col1,$.ID as Id").Execute(); - var res2 = docs2.FetchOne(); - Assert.AreEqual(i.ToString(), res2["Id"].ToString(), "Matching the ID"); - if (i == 30) - Assert.AreEqual("data" + i, "data30", "Matching the String"); - else - Assert.AreEqual("data" + i, res2["col1"].ToString(), "Matching the String"); - } - - coll = CreateCollection("test"); - json = "{\"_id\":\"1005\",\"F1\": 123,\"F2\":\"ABCD\" }"; - coll.Add(json).Execute(); - json = "{\"_id\":\"1006\",\"F1\": 123,\"F2\":\"1234\" }"; - coll.Add(json).Execute(); - json = "{\"_id\":\"1007\",\"F1\": 123,\"F2\":\"S()R%^\" }"; - coll.Add(json).Execute(); - - var docs1 = coll.Find().Fields("$._id as _id", "1 << 4 as tmp").Execute(); - var res = docs1.FetchAll(); - docs1 = coll.Find().Fields("$._id as _id", "$.F2 ^ 1 as tmp").Execute(); - res = docs1.FetchAll(); - coll.Add("{\"_id\":\"100001\",\"x1\":\"31\", \"x2\":\"13\", \"x3\":\"8\", \"x4\":\"18446744073709551614\"}").Execute(); - - docs1 = coll.Find("CAST($.x1 as SIGNED) | pow(2,$.x1) = $.x1").Fields("$._id as _id, $.x1 as x1, $.x2 as x2, $.x3 as x3 , $.x2 | pow(2,$.x1) as tmp").Execute(); - res = docs1.FetchAll(); - - docs1 = coll.Find("~16 = ~CAST($.F2 as SIGNED)").Fields("$._id as _id,$.F2 as f2, ~1 as tmp").Execute(); - res = docs1.FetchAll(); - int maxrec = 100; - DbDoc newDoc = new DbDoc(); - newDoc.SetValue("_id", maxrec + 1000); - newDoc.SetValue("F1", "Field-1-Data-" + maxrec); - newDoc.SetValue("F2", "Field-2-Data-" + maxrec); - newDoc.SetValue("F3", 300 + maxrec); - coll.Add(newDoc).Execute(); - - json = "{'_id':'" + (maxrec + 1000 + 1) + "','F1':'Field-1-Data-" + (maxrec + 1) + "','F2':'Field-2-Data-" + (maxrec + 1) + "','F3':" + (300 + maxrec + 1) + "}"; - json = json.Replace("'", "\""); - coll.Add(json).Execute(); - json = "{'F1': 'Field-1-Data-9999','F2': 'Field-2-Data-9999','F3': 'Field-3-Data-9999'}".Replace("'", "\""); - coll.Add(json).Add(json.Replace("9", "8")).Execute(); - - var docs = coll.Find("$._id OVERLAPS 1100").Fields("$_id as _id,$.F1 as f1, $.F2 as f2, $.F3 as f3").Execute(); - var res1 = docs.FetchOne(); - Assert.AreEqual("1100", res1["_id"].ToString()); - Assert.AreEqual("Field-1-Data-100", res1["f1"].ToString()); - Assert.AreEqual("Field-2-Data-100", res1["f2"].ToString()); - Assert.AreEqual("400", res1["f3"].ToString()); - Assert.Throws(() => ExecuteFindStatement(coll.Find("$.F2 OVERLAPS #").Fields("$_id as _id,$.F1 as f1, $.F2 as f2, $.F3 as f3"))); - - docs = coll.Find("$.F2 OVERLAPS 'ABCD'").Fields("$_id as _id,$.F1 as f1, $.F2 as f2, $.F3 as f3").Execute(); - res1 = docs.FetchOne(); - Assert.AreEqual("1005", res1["_id"]); - Assert.AreEqual(123, res1["f1"]); - Assert.AreEqual("ABCD", res1["f2"]); - Assert.Throws(() => ExecuteFindStatement(coll.Find("$.F2 OVERLAPS [1234").Fields("$_id as _id,$.F1 as f1, $.F2 as f2, $.F3 as f3"))); - Assert.Throws(() => ExecuteFindStatement(coll.Find("$.F2 OVERLAPS S()R%^").Fields("$_id as _id,$.F1 as f1, $.F2 as f2, $.F3 as f3"))); - - docs = coll.Find("$.F2 OVERLAPS 'S()R%^'").Fields("$_id as _id,$.F1 as f1, $.F2 as f2, $.F3 as f3").Execute(); - res1 = docs.FetchOne(); - Assert.AreEqual("1007", res1["_id"]); - Assert.AreEqual(123, res1["f1"]); - Assert.AreEqual("S()R%^", res1["f2"]); - } - - [Test, Description("Test MySQLX plugin Find with overlap and Many conditions")] - public void FindUsingOverLapsManyConditions() - { - if (!session.Version.isAtLeast(8, 0, 17)) Assert.Ignore("This test is for MySql 8.0.17 or higher."); - int Condition = 45; - int i, j = 0; - String query = ""; - Collection coll = CreateCollection("test"); - for (i = 0; i < 50; i++) - { - coll.Add("{\"_id\":\"" + i + "\",\"TEST1\":" + (1000 + j) + "}").Execute(); - j++; - } - j = 0; - for (i = 0; i < Condition; i++) - { - if (i > 0) - query = query + " OR "; - query = query + "$.TEST1 OVERLAPS " + (1000 + j); - j++; - } - var docs = coll.Find(query).Execute(); - Assert.True(docs.FetchAll().Count > 0); - } - - [Test, Description("Deprecated Find Where")] - public void FindWhere() - { - Collection collection = CreateCollection("test"); - var docs = new[] - { - new { _id = 1, title = "Book 1", pages = 20 }, - new { _id = 2, title = "Book 2", pages = 30 }, - new { _id = 3, title = "Book 3", pages = 40 }, - new { _id = 4, title = "Book 4", pages = 50 }, - }; - var result1 = collection.Add(docs).Execute(); - Assert.AreEqual(4, result1.AffectedItemsCount); - - //Deprecated Find().Where() in 8.0.17 - var result2 = collection.Find("$._id = 1").Where("true").Execute().FetchAll(); - Assert.AreEqual(4, result2.Count); - } - - [Test, Description("Test MySQLX plugin Collection match count")] - public void CollectionFindFieldMatchingCount() - { - Collection col = CreateCollection("my_collection_1"); - Collection col1 = CreateCollection("my_collection_2"); - - var d1 = new DbDoc(); - d1.SetValue("_id", 1); - d1.SetValue("books", "test1"); - d1.SetValue("count", 10); - - var d2 = new DbDoc(); - d2.SetValue("_id", 2); - d2.SetValue("books", "test2"); - d2.SetValue("count", 20); - - var d3 = new DbDoc(); - d3.SetValue("_id", 3); - d3.SetValue("books", "test3"); - d3.SetValue("count", 30); - - var d4 = new DbDoc(); - d4.SetValue("_id", 4); - d4.SetValue("books", "test4"); - d4.SetValue("count", 40); - - var d5 = new DbDoc(); - d5.SetValue("_id", 5); - d5.SetValue("books", "test5"); - d5.SetValue("count", 50); - - var d6 = new DbDoc(); - d6.SetValue("_id", 6); - d6.SetValue("books", "test6"); - d6.SetValue("count", 0); - - var d7 = new DbDoc(); - d7.SetValue("_id", 0); - d7.SetValue("books", "test7"); - d7.SetValue("count", 60); - - var final = col.Add(d1, d2).Add(d3).Execute(); - var res1 = col.Find().Fields("{\"_id\":\"1\",\"books\": \"test1\" }").Fields("{\"_id\":\"2\",\"books\": \"test2\" }").Fields("{\"_id\":\"3\",\"books\": \"test3\" }").Execute().FetchAll(); - res1 = col.Find().Fields(new string[] { "_id", "books", "count" }).Execute().FetchAll(); - Assert.AreEqual(3, res1.Count, "Matching the find count"); - Assert.AreEqual(d1.ToString(), res1[0].ToString(), "Matching the doc string 1"); - Assert.AreEqual(d2.ToString(), res1[1].ToString(), "Matching the doc string 2"); - Assert.AreEqual(d3.ToString(), res1[2].ToString(), "Matching the doc string 3"); - final = col.Add(new DbDoc[] { d4, d5 }).Execute(); - var res2 = col.Find().Fields("$._id as _id,$.books as books, $.count as count").Execute().FetchAll(); - Assert.AreEqual(5, res2.Count, "Matching the find count"); - Assert.AreEqual(d1.ToString(), res2[0].ToString(), "Matching the doc string 1"); - Assert.AreEqual(d2.ToString(), res2[1].ToString(), "Matching the doc string 2"); - Assert.AreEqual(d3.ToString(), res2[2].ToString(), "Matching the doc string 3"); - Assert.AreEqual(d4.ToString(), res2[3].ToString(), "Matching the doc string 4"); - Assert.AreEqual(d5.ToString(), res2[4].ToString(), "Matching the doc string 5"); - final = col.Add(d6, d7).Execute(); - var res3 = col.Find().Sort("count ASC").Execute().FetchAll(); - Assert.AreEqual(d6.ToString(), res3[0].ToString(), "Matching the doc string 7"); - Assert.AreEqual(d1.ToString(), res3[1].ToString(), "Matching the doc string 1"); - Assert.AreEqual(d2.ToString(), res3[2].ToString(), "Matching the doc string 2"); - Assert.AreEqual(d3.ToString(), res3[3].ToString(), "Matching the doc string 3"); - Assert.AreEqual(d4.ToString(), res3[4].ToString(), "Matching the doc string 4"); - Assert.AreEqual(d5.ToString(), res3[5].ToString(), "Matching the doc string 5"); - Assert.AreEqual(d7.ToString(), res3[6].ToString(), "Matching the doc string 6"); - var res4 = col.Find().Sort("count DESC").Execute().FetchAll(); - Assert.AreEqual(d7.ToString(), res4[0].ToString(), "Matching the doc string 6"); - Assert.AreEqual(d5.ToString(), res4[1].ToString(), "Matching the doc string 1"); - Assert.AreEqual(d4.ToString(), res4[2].ToString(), "Matching the doc string 2"); - Assert.AreEqual(d3.ToString(), res4[3].ToString(), "Matching the doc string 3"); - Assert.AreEqual(d2.ToString(), res4[4].ToString(), "Matching the doc string 4"); - Assert.AreEqual(d1.ToString(), res4[5].ToString(), "Matching the doc string 5"); - Assert.AreEqual(d6.ToString(), res4[6].ToString(), "Matching the doc string 7"); - col.Modify("_id = 1").Unset("count").Unset("books").Execute(); - col.Modify("_id = 1").Set("count", 10).Set("books", "test1").Execute(); - - } - - [Test, Description("GetName,Schema and Count")] - public void CollectionGetNameSchemaCount() - { - if (!session.Version.isAtLeast(5, 7, 0)) Assert.Ignore("This test is for MySql 5.7 or higher"); - var col = CreateCollection("my_collection_123456789"); - - Result r = col.Add(@"{ ""_id"": 1, ""foo"": 1 }").Execute(); - long count = col.Count(); - Assert.AreEqual(count, 1, "Matching the Collection Count"); - - var collectionName = col.Name; - Assert.AreEqual(collectionName, "my_collection_123456789", "Matching the collection Name"); - - var schema = col.Schema.Name; - Assert.AreEqual(schema, schemaName, "Matching the Schema Name"); - - r = col.Add(@"{ ""_id"": 2, ""foo"": 2 }").Execute(); - count = col.Count(); - Assert.AreEqual(count, 2, "Matching the Collection Count"); - - r = col.Remove("_id=2").Execute(); - count = col.Count(); - Assert.AreEqual(count, 1, "Matching the Collection Count"); - session.Schema.DropCollection("my_collection_123456789"); - } - - #endregion WL14389 - - } -} - +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data.Common; +using MySql.Data.MySqlClient; +using MySqlX.XDevAPI; +using MySqlX.XDevAPI.Common; +using MySqlX.XDevAPI.CRUD; +using NUnit.Framework; +using NUnit.Framework.Legacy; +using System; + +namespace MySqlX.Data.Tests +{ + public class BasicFindTests : BaseTest + { + [Test] + public void SimpleFind() + { + Collection coll = CreateCollection("test"); + var docs = new[] + { + new { _id = 1, title = "Book 1", pages = 20 }, + new { _id = 2, title = "Book 2", pages = 30 }, + new { _id = 3, title = "Book 3", pages = 40 }, + new { _id = 4, title = "Book 4", pages = 50 }, + }; + Result r = ExecuteAddStatement(coll.Add(docs)); + Assert.That(r.AffectedItemsCount, Is.EqualTo(4)); + + var foundDocs = ExecuteFindStatement(coll.Find("pages > 20")); + Assert.That(foundDocs.Next()); + Assert.That(foundDocs.Current["title"].ToString() == "Book 2"); + Assert.That(foundDocs.Next()); + Assert.That(foundDocs.Current["title"].ToString() == "Book 3"); + Assert.That(foundDocs.Next()); + Assert.That(foundDocs.Current["title"].ToString() == "Book 4"); + Assert.That(foundDocs.Next(), Is.False); + } + + [Test] + public void SimpleFindWithSort() + { + Collection coll = CreateCollection("test"); + var docs = new[] + { + new { _id = 1, title = "Book 1", pages = 20 }, + new { _id = 2, title = "Book 2", pages = 30 }, + new { _id = 3, title = "Book 3", pages = 40 }, + new { _id = 4, title = "Book 4", pages = 50 }, + }; + Result r = ExecuteAddStatement(coll.Add(docs)); + Assert.That(r.AffectedItemsCount, Is.EqualTo(4)); + + var foundDocs = ExecuteFindStatement(coll.Find("pages > 20").Sort("pages DESC")); + Assert.That(foundDocs.Next()); + Assert.That(foundDocs.Current["title"].ToString() == "Book 4"); + Assert.That(foundDocs.Next()); + Assert.That(foundDocs.Current["title"].ToString() == "Book 3"); + Assert.That(foundDocs.Next()); + Assert.That(foundDocs.Current["title"].ToString() == "Book 2"); + Assert.That(foundDocs.Next(), Is.False); + } + + [Test] + public void SimpleFindWithLimitAndOffset() + { + Collection coll = CreateCollection("test"); + var docs = new[] + { + new { _id = 1, title = "Book 1", pages = 20 }, + new { _id = 2, title = "Book 2", pages = 30 }, + new { _id = 3, title = "Book 3", pages = 40 }, + new { _id = 4, title = "Book 4", pages = 50 }, + }; + Result r = ExecuteAddStatement(coll.Add(docs)); + Assert.That(r.AffectedItemsCount, Is.EqualTo(4)); + + var foundDocs = ExecuteFindStatement(coll.Find("pages > 20").Limit(1)); + Assert.That(foundDocs.Next()); + Assert.That(foundDocs.Current["title"].ToString() == "Book 2"); + Assert.That(foundDocs.Next(), Is.False); + + var resultDocs = ExecuteFindStatement(coll.Find("pages > 20").Offset(1).Limit(2)).FetchAll(); + Assert.That(resultDocs[0]["pages"], Is.EqualTo(40)); + Assert.That(resultDocs[1]["pages"], Is.EqualTo(50)); + + // Limit out of range. + Assert.Throws(() => ExecuteFindStatement(coll.Find().Limit(0))); + Assert.Throws(() => ExecuteFindStatement(coll.Find().Limit(-1))); + } + + [Test] + public void FindConditional() + { + Collection coll = CreateCollection("test"); + var docs = new[] + { + new { _id = 1, title = "Book 1", pages = 20 }, + new { _id = 2, title = "Book 2", pages = 30 }, + new { _id = 3, title = "Book 3", pages = 40 }, + new { _id = 4, title = "Book 4", pages = 50 }, + }; + Result r = ExecuteAddStatement(coll.Add(docs)); + Assert.That(r.AffectedItemsCount, Is.EqualTo(4)); + + var foundDocs = ExecuteFindStatement(coll.Find("pages = :Pages").Bind("pAges", 40)); + Assert.That(foundDocs.Next()); + Assert.That(foundDocs.Current["title"].ToString() == "Book 3"); + Assert.That(foundDocs.Next(), Is.False); + } + + [Test] + public void BindDbDoc() + { + Collection coll = CreateCollection("test"); + var docs = new[] + { + new { _id = 1, title = "Book 1", pages = 20 }, + new { _id = 2, title = "Book 2", pages = 30 }, + new { _id = 3, title = "Book 3", pages = 40 }, + new { _id = 4, title = "Book 4", pages = 50 }, + }; + Result r = ExecuteAddStatement(coll.Add(docs)); + Assert.That(r.AffectedItemsCount, Is.EqualTo(4)); + + DbDoc docParams = new DbDoc(new { pages1 = 30, pages2 = 40 }); + var foundDocs = ExecuteFindStatement(coll.Find("pages = :Pages1 || pages = :Pages2").Bind(docParams)); + Assert.That(foundDocs.Next()); + Assert.That(foundDocs.Current["title"], Is.EqualTo("Book 2")); + Assert.That(foundDocs.Next()); + Assert.That(foundDocs.Current["title"], Is.EqualTo("Book 3")); + Assert.That(foundDocs.Next(), Is.False); + } + + [Test] + public void BindJsonAsAnonymous() + { + Collection coll = CreateCollection("test"); + var docs = new[] + { + new { _id = 1, title = "Book 1", pages = 20 }, + new { _id = 2, title = "Book 2", pages = 30 }, + new { _id = 3, title = "Book 3", pages = 40 }, + new { _id = 4, title = "Book 4", pages = 50 }, + }; + Result r = ExecuteAddStatement(coll.Add(docs)); + Assert.That(r.AffectedItemsCount, Is.EqualTo(4)); + + var jsonParams = new { pages1 = 30, pages2 = 40 }; + var foundDocs = ExecuteFindStatement(coll.Find("pages = :Pages1 || pages = :Pages2").Bind(jsonParams)); + Assert.That(foundDocs.Next()); + Assert.That(foundDocs.Current["title"], Is.EqualTo("Book 2")); + Assert.That(foundDocs.Next()); + Assert.That(foundDocs.Current["title"], Is.EqualTo("Book 3")); + Assert.That(foundDocs.Next(), Is.False); + } + + [Test] + public void BindJsonAsString() + { + Collection coll = CreateCollection("test"); + var docs = new[] + { + new { _id = 1, title = "Book 1", pages = 20 }, + new { _id = 2, title = "Book 2", pages = 30 }, + new { _id = 3, title = "Book 3", pages = 40 }, + new { _id = 4, title = "Book 4", pages = 50 }, + }; + Result r = ExecuteAddStatement(coll.Add(docs)); + Assert.That(r.AffectedItemsCount, Is.EqualTo(4)); + + var jsonParams = "{ \"pages1\" : 30, \"pages2\" : 40 }"; + var foundDocs = ExecuteFindStatement(coll.Find("pages = :Pages1 || pages = :Pages2").Bind(jsonParams)); + Assert.That(foundDocs.Next()); + Assert.That(foundDocs.Current["title"], Is.EqualTo("Book 2")); + Assert.That(foundDocs.Next()); + Assert.That(foundDocs.Current["title"], Is.EqualTo("Book 3")); + Assert.That(foundDocs.Next(), Is.False); + } + + [Test] + public void RowLockingNotSupportedInOlderVersions() + { + Assume.That(!session.Version.isAtLeast(8, 0, 3), "This test is for MySql lower than 8.0.3."); + Collection coll = CreateCollection("test"); + + Exception ex = Assert.Throws(() => ExecuteFindStatement(coll.Find().LockShared())); + Assert.That(ex.Message, Is.EqualTo("This functionality is only supported from server version 8.0.3 onwards")); + + ex = Assert.Throws(() => ExecuteFindStatement(coll.Find().LockExclusive())); + Assert.That(ex.Message, Is.EqualTo("This functionality is only supported from server version 8.0.3 onwards")); + } + + [Test] + public void SimpleSharedLock() + { + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); + + ExecuteSQLStatement(session.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); + using (var session2 = MySQLX.GetSession(ConnectionString)) + { + ExecuteSQLStatement(session2.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); + Collection coll = CreateCollection("test"); + var docs = new[] + { + new { _id = 1, a = 1 }, + new { _id = 2, a = 1 }, + new { _id = 3, a = 1 }, + }; + ExecuteAddStatement(coll.Add(docs)); + Collection coll2 = session2.GetSchema("test").GetCollection("test"); + + ExecuteSQLStatement(session.SQL("START TRANSACTION")); + var docResult = ExecuteFindStatement(coll.Find("_id = 1").LockShared()); + Assert.That(docResult.FetchAll(), Has.One.Items); + + ExecuteSQLStatement(session2.SQL("START TRANSACTION")); + // Should return immediately since document isn't locked. + docResult = ExecuteFindStatement(coll2.Find("_id = 2").LockShared()); + Assert.That(docResult.FetchAll(), Has.One.Items); + // Should return immediately due to LockShared() allows reading by other sessions. + docResult = ExecuteFindStatement(coll2.Find("_id = 1").LockShared()); + Assert.That(docResult.FetchAll(), Has.One.Items); + + ExecuteSQLStatement(session.SQL("ROLLBACK")); + ExecuteSQLStatement(session2.SQL("ROLLBACK")); + } + } + + [Test] + public void SharedLockForbidsToModifyDocuments() + { + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); + + ExecuteSQLStatement(session.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); + using (var session2 = MySQLX.GetSession(ConnectionString)) + { + ExecuteSQLStatement(session2.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); + Collection coll = CreateCollection("test"); + var docs = new[] + { + new { _id = 1, a = 1 }, + new { _id = 2, a = 1 }, + new { _id = 3, a = 1 }, + }; + ExecuteAddStatement(coll.Add(docs)); + Collection coll2 = session2.GetSchema("test").GetCollection("test"); + + ExecuteSQLStatement(session.SQL("START TRANSACTION")); + var docResult = ExecuteFindStatement(coll.Find("_id = 1").LockShared()); + Assert.That(docResult.FetchAll(), Has.One.Items); + + ExecuteSQLStatement(session2.SQL("START TRANSACTION")); + // Reading the same document is allowed with LockShared(). + docResult = ExecuteFindStatement(coll2.Find("_id = 1")); + Assert.That(docResult.FetchAll(), Has.One.Items); + + // Modify() is allowed for non-locked documents. + Result result = ExecuteModifyStatement(coll2.Modify("_id = 2").Set("a", 2)); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1)); + // Session1 blocks, Modify() is not allowed for locked documents. + ExecuteSQLStatement(session2.SQL("SET SESSION innodb_lock_wait_timeout=1")); + Exception ex = Assert.Throws(() => ExecuteModifyStatement(coll2.Modify("_id = 1").Set("a", 2))); + Assert.That(ex.Message, Is.EqualTo("Lock wait timeout exceeded; try restarting transaction")); + + ExecuteSQLStatement(session.SQL("ROLLBACK")); + // Modify() is allowed since document isn't locked anymore. + ExecuteModifyStatement(coll2.Modify("_id = 1").Set("a", 2)); + ExecuteSQLStatement(session2.SQL("COMMIT")); + } + } + + [Test] + public void ExclusiveLockForbidsToModifyDocuments() + { + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); + + ExecuteSQLStatement(session.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); + using (var session2 = MySQLX.GetSession(ConnectionString)) + { + ExecuteSQLStatement(session2.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); + Collection coll = CreateCollection("test"); + var docs = new[] + { + new { _id = 1, a = 1 }, + new { _id = 2, a = 1 }, + new { _id = 3, a = 1 }, + }; + ExecuteAddStatement(coll.Add(docs)); + Collection coll2 = session2.GetSchema("test").GetCollection("test"); + + ExecuteSQLStatement(session.SQL("START TRANSACTION")); + var docResult = ExecuteFindStatement(coll.Find("_id = 1").LockExclusive()); + Assert.That(docResult.FetchAll(), Has.One.Items); + + ExecuteSQLStatement(session2.SQL("START TRANSACTION")); + + // Modify() is allowed for non-locked documents. + Result result = ExecuteModifyStatement(coll2.Modify("_id = 2").Set("a", 2)); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1)); + // Session2 blocks, Modify() is not allowed for locked documents. + ExecuteSQLStatement(session2.SQL("SET SESSION innodb_lock_wait_timeout=1")); + Exception ex = Assert.Throws(() => ExecuteModifyStatement(coll2.Modify("_id = 1").Set("a", 2))); + Assert.That(ex.Message, Is.EqualTo("Lock wait timeout exceeded; try restarting transaction")); + ex = Assert.Throws(() => ExecuteModifyStatement(coll2.Modify("_id = 1").Change("a", 12))); + Assert.That(ex.Message, Is.EqualTo("Lock wait timeout exceeded; try restarting transaction")); + + ExecuteSQLStatement(session.SQL("ROLLBACK")); + // Modify() is allowed since document isn't locked anymore. + ExecuteModifyStatement(coll2.Modify("_id = 1").Set("a", 2)); + ExecuteSQLStatement(session2.SQL("COMMIT")); + } + } + + [Test] + public void SharedLockAfterExclusiveLock() + { + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); + + ExecuteSQLStatement(session.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); + using (var session2 = MySQLX.GetSession(ConnectionString)) + { + ExecuteSQLStatement(session2.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); + Collection coll = CreateCollection("test"); + ExecuteSQLStatement(session2.SQL("ALTER TABLE `test`.`test` ADD COLUMN `$ix_i_r_index` INT GENERATED ALWAYS AS (JSON_UNQUOTE(JSON_EXTRACT(doc, '$._id'))) VIRTUAL NOT NULL, ADD UNIQUE INDEX `myIndex`(`$ix_i_r_index`)")); + var docs = new[] + { + new { _id = 1, a = 1 }, + new { _id = 2, a = 1 }, + new { _id = 3, a = 1 }, + }; + ExecuteAddStatement(coll.Add(docs)); + Collection coll2 = session2.GetSchema("test").GetCollection("test"); + + ExecuteSQLStatement(session.SQL("START TRANSACTION")); + var docResult = ExecuteFindStatement(coll.Find("_id = 1").LockExclusive()); + Assert.That(docResult.FetchAll(), Has.One.Items); + + ExecuteSQLStatement(session2.SQL("START TRANSACTION")); + // Should return immediately since document isn't locked. + docResult = ExecuteFindStatement(coll2.Find("_id = 2").LockShared()); + Assert.That(docResult.FetchAll(), Has.One.Items); + // Session2 blocks due to LockExclusive() not allowing to read locked documents. + ExecuteSQLStatement(session2.SQL("SET SESSION innodb_lock_wait_timeout=1")); + Exception ex = Assert.Throws(() => ExecuteFindStatement(coll2.Find("_id = 1").LockShared())); + Assert.That(ex.Message, Is.EqualTo("Lock wait timeout exceeded; try restarting transaction")); + + // Session unlocks documents. + ExecuteSQLStatement(session.SQL("ROLLBACK")); + // Document can now be recovered. + docResult = ExecuteFindStatement(coll2.Find("_id = 1").LockShared()); + Assert.That(docResult.FetchAll(), Has.One.Items); + ExecuteSQLStatement(session2.SQL("ROLLBACK")); + } + } + + [Test] + public void ExclusiveLockAfterSharedLock() + { + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); + + ExecuteSQLStatement(session.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); + using (var session2 = MySQLX.GetSession(ConnectionString)) + { + ExecuteSQLStatement(session2.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); + Collection coll = CreateCollection("test"); + ExecuteSQLStatement(session2.SQL("ALTER TABLE `test`.`test` ADD COLUMN `$ix_i_r_index` INT GENERATED ALWAYS AS (JSON_UNQUOTE(JSON_EXTRACT(doc, '$._id'))) VIRTUAL NOT NULL, ADD UNIQUE INDEX `myIndex`(`$ix_i_r_index`)")); + var docs = new[] + { + new { _id = 1, a = 1 }, + new { _id = 2, a = 1 }, + new { _id = 3, a = 1 }, + }; + ExecuteAddStatement(coll.Add(docs)); + Collection coll2 = session2.GetSchema("test").GetCollection("test"); + + ExecuteSQLStatement(session.SQL("START TRANSACTION")); + var docResult = ExecuteFindStatement(coll.Find("_id in (1, 3)").LockShared()); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(2)); + + ExecuteSQLStatement(session2.SQL("START TRANSACTION")); + // Should return immediately since document isn't locked. + docResult = ExecuteFindStatement(coll2.Find("_id = 2").LockExclusive()); + // Should return immediately due to LockShared() allows reading by other sessions. + docResult = ExecuteFindStatement(coll2.Find("_id = 2").LockShared()); + Assert.That(docResult.FetchAll(), Has.One.Items); + // Session2 blocks due to to LockExclusive() not allowing to read locked documents. + ExecuteSQLStatement(session2.SQL("SET SESSION innodb_lock_wait_timeout=1")); + Exception ex = Assert.Throws(() => ExecuteFindStatement(coll2.Find("_id = 1").LockExclusive())); + Assert.That(ex.Message, Is.EqualTo("Lock wait timeout exceeded; try restarting transaction")); + + // Session unlocks documents. + ExecuteSQLStatement(session.SQL("ROLLBACK")); + docResult = ExecuteFindStatement(coll2.Find("_id = 1").LockExclusive()); + Assert.That(docResult.FetchAll(), Has.One.Items); + ExecuteSQLStatement(session2.SQL("ROLLBACK")); + } + } + + [Test] + public void ExclusiveLockAfterExclusiveLock() + { + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); + + ExecuteSQLStatement(session.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); + using (var session2 = MySQLX.GetSession(ConnectionString)) + { + ExecuteSQLStatement(session2.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); + Collection coll = CreateCollection("test"); + ExecuteSQLStatement(session2.SQL("ALTER TABLE `test`.`test` ADD COLUMN `$ix_i_r_index` INT GENERATED ALWAYS AS (JSON_UNQUOTE(JSON_EXTRACT(doc, '$._id'))) VIRTUAL NOT NULL, ADD UNIQUE INDEX `myIndex`(`$ix_i_r_index`)")); + var docs = new[] + { + new { _id = 1, a = 1 }, + new { _id = 2, a = 1 }, + new { _id = 3, a = 1 } + }; + ExecuteAddStatement(coll.Add(docs)); + Collection coll2 = session2.GetSchema("test").GetCollection("test"); + + ExecuteSQLStatement(session.SQL("START TRANSACTION")); + var docResult = ExecuteFindStatement(coll.Find("_id = 1").LockExclusive()); + Assert.That(docResult.FetchAll(), Has.One.Items); + + ExecuteSQLStatement(session2.SQL("START TRANSACTION")); + // Should return immediately since document isn't locked. + docResult = ExecuteFindStatement(coll2.Find("_id = 2").LockExclusive()); + Assert.That(docResult.FetchAll(), Has.One.Items); + // Session2 blocks due to to LockExclusive() not allowing to read locked documents. + ExecuteSQLStatement(session2.SQL("SET SESSION innodb_lock_wait_timeout=1")); + Exception ex = Assert.Throws(() => ExecuteFindStatement(coll2.Find("_id = 1").LockExclusive())); + Assert.That(ex.Message, Is.EqualTo("Lock wait timeout exceeded; try restarting transaction")); + + // Session unlocks documents. + ExecuteSQLStatement(session.SQL("ROLLBACK")); + docResult = ExecuteFindStatement(coll2.Find("_id = 1").LockExclusive()); + Assert.That(docResult.FetchAll(), Has.One.Items); + ExecuteSQLStatement(session2.SQL("ROLLBACK")); + } + } + + [Test] + public void InOperatorWithListOfValues() + { + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); + + // Validates the IN operator allows expressions of the type + // ( compExpr ["NOT"] "IN" "(" argsList ")" ) | ( compExpr ["NOT"] "IN" "[" argsList "]" ) + Collection coll = CreateCollection("test"); + ExecuteAddStatement(coll.Add(new DbDoc("{ \"a\": 1, \"b\": [ 1, \"value\" ], \"d\":\"\" }"))); + + Assert.That(ExecuteFindStatement(coll.Find("a IN (1,2,3)")).FetchAll(), Has.One.Items); + Assert.That(ExecuteFindStatement(coll.Find("a not in (0,2,3)")).FetchAll(), Has.One.Items); + Assert.That(ExecuteFindStatement(coll.Find("b[0] in (1,2,3)")).FetchAll(), Has.One.Items); + Assert.That(ExecuteFindStatement(coll.Find("b[1] in (\"a\", \"b\", \"value\")")).FetchAll(), Has.One.Items); + Assert.That(ExecuteFindStatement(coll.Find("b[0] NOT IN (0,2,3)")).FetchAll(), Has.One.Items); + Assert.That(ExecuteFindStatement(coll.Find("b[1] not in (\"a\", \"b\", \"c\")")).FetchAll(), Has.One.Items); + Assert.That(ExecuteFindStatement(coll.Find("a in [1,2,3]")).FetchAll(), Has.One.Items); + Assert.That(ExecuteFindStatement(coll.Find("a in [2,3,4]")).FetchAll(), Is.Empty); + Assert.That(ExecuteFindStatement(coll.Find("a NOT in [0,2,3]")).FetchAll(), Has.One.Items); + Assert.That(ExecuteFindStatement(coll.Find("b not IN [1,2,3]")).FetchAll(), Has.One.Items); + Assert.That(ExecuteFindStatement(coll.Find("b[0] not IN [1,2,3]")).FetchAll(), Is.Empty); + Assert.That(ExecuteFindStatement(coll.Find("c NOT IN [1,2,3]")).FetchAll(), Is.Empty); + Assert.That(ExecuteFindStatement(coll.Find("a IN ('', ' ')")).FetchAll(), Is.Empty); + Assert.That(ExecuteFindStatement(coll.Find("'' IN (1,2,3)")).FetchAll(), Is.Empty); + Assert.That(ExecuteFindStatement(coll.Find("d IN ('')")).FetchAll(), Has.One.Items); + + Collection movies = CreateCollection("movies"); + var docString = "{ \"_id\" : \"a6f4b93e1a264a108393524f29546a8c\", \"title\" : \"AFRICAN EGG\", \"description\" : \"A Fast-Paced Documentary of a Pastry Chef And a Dentist who must Pursue a Forensic Psychologist in The Gulf of Mexico\", \"releaseyear\" : 2006, \"language\" : \"English\", \"duration\" : 130, \"rating\" : \"G\", \"genre\" : \"Science fiction\", \"actors\" : [{ \"name\" : \"MILLA PECK\", \"country\" : \"Mexico\", \"birthdate\": \"12 Jan 1984\"}, { \"name\" : \"VAL BOLGER\", \"country\" : \"Botswana\", \"birthdate\": \"26 Jul 1975\" }, { \"name\" : \"SCARLETT BENING\", \"country\" : \"Syria\", \"birthdate\": \"16 Mar 1978\" }], \"additionalinfo\" : { \"director\" : \"Sharice Legaspi\", \"writers\" : [\"Rusty Couturier\", \"Angelic Orduno\", \"Carin Postell\"], \"productioncompanies\" : [\"Qvodrill\", \"Indigoholdings\"] } }"; + ExecuteAddStatement(movies.Add(new DbDoc(docString))); + + Assert.That(ExecuteFindStatement(movies.Find("(1>5) in (true, false)")).FetchAll(), Has.One.Items); + Assert.That(ExecuteFindStatement(movies.Find("(1+5) in (1, 2, 3, 4, 5)")).FetchAll(), Is.Empty); + Assert.That(ExecuteFindStatement(movies.Find("('a'>'b') in (true, false)")).FetchAll(), Has.One.Items); + Assert.Throws(() => ExecuteFindStatement(movies.Find("(1>5) in [true, false]")).FetchAll()); + Assert.Throws(() => ExecuteFindStatement(movies.Find("(1+5) in [1, 2, 3, 4, 5]")).FetchAll()); + Assert.Throws(() => ExecuteFindStatement(movies.Find("('a'>'b') in [true, false]")).FetchAll()); + Assert.That(ExecuteFindStatement(movies.Find("true IN [(1>5), !(false), (true || false), (false && true)]")).FetchAll(), Has.One.Items); + Assert.That(ExecuteFindStatement(movies.Find("true IN ((1>5), !(false), (true || false), (false && true))")).FetchAll(), Has.One.Items); + Assert.That(ExecuteFindStatement(movies.Find("{\"field\":true} IN (\"mystring\", 124, myvar, othervar.jsonobj)")).FetchAll(), Is.Empty); + Assert.That(ExecuteFindStatement(movies.Find("actor.name IN ['a name', null, (1<5-4), myvar.jsonobj.name]")).FetchAll(), Is.Empty); + Assert.That(ExecuteFindStatement(movies.Find("!false && true IN [true]")).FetchAll(), Has.One.Items); + Assert.Throws(() => ExecuteFindStatement(movies.Find("1-5/2*2 > 3-2/1*2 IN [true, false]")).FetchAll()); + Assert.That(ExecuteFindStatement(movies.Find("true IN [1-5/2*2 > 3-2/1*2]")).FetchAll(), Is.Empty); + Assert.That(ExecuteFindStatement(movies.Find(" 'African Egg' IN ('African Egg', 1, true, NULL, [0,1,2], { 'title' : 'Atomic Firefighter' }) ")).FetchAll(), Has.One.Items); + Assert.That(ExecuteFindStatement(movies.Find(" 1 IN ('African Egg', 1, true, NULL, [0,1,2], { 'title' : 'Atomic Firefighter' }) ")).FetchAll(), Has.One.Items); + Assert.That(ExecuteFindStatement(movies.Find(" [0,1,2] IN ('African Egg', 1, true, NULL, [0,1,2], { 'title' : 'Atomic Firefighter' }) ")).FetchAll(), Has.One.Items); + Assert.That(ExecuteFindStatement(movies.Find(" { 'title' : 'Atomic Firefighter' } IN ('African Egg', 1, true, NULL, [0,1,2], { 'title' : 'Atomic Firefighter' }) ")).FetchAll(), Has.One.Items); + Assert.That(ExecuteFindStatement(movies.Find("title IN ('African Egg', 'The Witcher', 'Jurassic Perk')")).FetchAll(), Is.Empty); + Assert.That(ExecuteFindStatement(movies.Find("releaseyear IN (2006, 2010, 2017)")).FetchAll(), Has.One.Items); + Assert.That(ExecuteFindStatement(movies.Find("1 IN [1,2,3]")).FetchAll(), Has.One.Items); + Assert.That(ExecuteFindStatement(movies.Find("0 IN [1,2,3]")).FetchAll(), Is.Empty); + Assert.That(ExecuteFindStatement(movies.Find("0 NOT IN [1,2,3]")).FetchAll(), Has.One.Items); + Assert.That(ExecuteFindStatement(movies.Find("1 NOT IN [1,2,3]")).FetchAll(), Is.Empty); + Assert.That(ExecuteFindStatement(movies.Find("releaseyear IN [2006, 2007, 2008]")).FetchAll(), Has.One.Items); + } + + [Test] + public void InOperatorWithCompExpr() + { + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); + + // Validates the IN operator allows expressions of the type: compExpr ["NOT"] "IN" compExpr + Collection coll = CreateCollection("test"); + var docString = "{ \"a\": 1, \"b\": \"foo\", \"c\": { \"d\": true, \"e\": [1,2,3] }, \"f\": [ {\"x\":5}, {\"x\":7 } ] }"; + ExecuteAddStatement(coll.Add(new DbDoc(docString))); + + Assert.That(ExecuteFindStatement(coll.Find("a in [1,2,3]")).FetchAll(), Has.One.Items); + Assert.That(ExecuteFindStatement(coll.Find("c.e[0] in [1,2,3]")).FetchAll(), Has.One.Items); + Assert.That(ExecuteFindStatement(coll.Find("5 in f[*].x")).FetchAll(), Has.One.Items); + Assert.That(ExecuteFindStatement(coll.Find("3 in c.e")).FetchAll(), Has.One.Items); + Assert.That(ExecuteFindStatement(coll.Find("5 in c.e")).FetchAll(), Is.Empty); + Assert.That(ExecuteFindStatement(coll.Find("\"foo\" in " + docString)).FetchAll(), Is.Empty); + Assert.That(ExecuteFindStatement(coll.Find("\"a\" in " + docString)).FetchAll(), Is.Empty); + Assert.That(ExecuteFindStatement(coll.Find("a in " + docString)).FetchAll(), Is.Empty); + Assert.That(ExecuteFindStatement(coll.Find("{\"a\":1} in " + docString)).FetchAll(), Has.One.Items); + Assert.That(ExecuteFindStatement(coll.Find("\"foo\" in b")).FetchAll(), Has.One.Items); + + Collection movies = CreateCollection("movies"); + docString = "{ \"_id\" : \"a6f4b93e1a264a108393524f29546a8c\", \"title\" : \"AFRICAN EGG\", \"description\" : \"A Fast-Paced Documentary of a Pastry Chef And a Dentist who must Pursue a Forensic Psychologist in The Gulf of Mexico\", \"releaseyear\" : 2006, \"language\" : \"English\", \"duration\" : 130, \"rating\" : \"G\", \"genre\" : \"Science fiction\", \"actors\" : [{ \"name\" : \"MILLA PECK\", \"country\" : \"Mexico\", \"birthdate\": \"12 Jan 1984\"}, { \"name\" : \"VAL BOLGER\", \"country\" : \"Botswana\", \"birthdate\": \"26 Jul 1975\" }, { \"name\" : \"SCARLETT BENING\", \"country\" : \"Syria\", \"birthdate\": \"16 Mar 1978\" }], \"additionalinfo\" : { \"director\" : \"Sharice Legaspi\", \"writers\" : [\"Rusty Couturier\", \"Angelic Orduno\", \"Carin Postell\"], \"productioncompanies\" : [\"Qvodrill\", \"Indigoholdings\"] } }"; + ExecuteAddStatement(movies.Add(new DbDoc(docString))); + + Assert.That(ExecuteFindStatement(movies.Find("{ \"name\" : \"MILLA PECK\" } IN actors")).FetchAll(), Has.One.Items); + Assert.That(ExecuteFindStatement(movies.Find("'African Egg' in movietitle")).FetchAll(), Is.Empty); + Assert.Throws(() => ExecuteFindStatement(movies.Find("(1 = NULL) IN title")).FetchAll()); + Assert.Throws(() => ExecuteFindStatement(movies.Find("NOT NULL IN title")).FetchAll()); + Assert.That(ExecuteFindStatement(movies.Find("[\"Rusty Couturier\", \"Angelic Orduno\", \"Carin Postell\"] IN additionalinfo.writers")).FetchAll(), Has.One.Items); + Assert.That(ExecuteFindStatement(movies.Find("{ \"name\" : \"MILLA PECK\", \"country\" : \"Mexico\", \"birthdate\": \"12 Jan 1984\"} IN actors")).FetchAll(), Has.One.Items); + Assert.That(ExecuteFindStatement(movies.Find("true IN title")).FetchAll(), Is.Empty); + Assert.That(ExecuteFindStatement(movies.Find("false IN genre")).FetchAll(), Is.Empty); + Assert.That(ExecuteFindStatement(movies.Find("'Sharice Legaspi' IN additionalinfo.director")).FetchAll(), Has.One.Items); + Assert.That(ExecuteFindStatement(movies.Find("'Mexico' IN actors[*].country")).FetchAll(), Has.One.Items); + Assert.That(ExecuteFindStatement(movies.Find("'Angelic Orduno' IN additionalinfo.writers")).FetchAll(), Has.One.Items); + } + + [Test] + public void InOperatorWithJsonArrays() + { + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); + + Collection coll = CreateCollection("test"); + var docString = "{ \"_id\": \"1001\", \"ARR\":[1,2,3], \"ARR1\":[\"name\", \"name2\", \"name3\"]}"; + ExecuteAddStatement(coll.Add(new DbDoc(docString))); + + Assert.That(ExecuteFindStatement(coll.Find("\"1001\" in $._id")).FetchAll(), Has.One.Items); + Assert.That(ExecuteFindStatement(coll.Find("\"1002\" in $._id")).FetchAll(), Is.Empty); + Assert.That(ExecuteFindStatement(coll.Find("(1+2) in (1, 2, 3)")).FetchAll(), Has.One.Items); + Assert.Throws(() => ExecuteFindStatement(coll.Find("(1+2) in [1, 2, 3]")).FetchAll()); + Assert.Throws(() => ExecuteFindStatement(coll.Find("(1+2) in $.ARR")).FetchAll()); + } + + [Test] + public void GetOne() + { + Collection coll = CreateCollection("test"); + var docs = new[] + { + new { _id = 1, title = "Book 1", pages = 20 }, + new { _id = 2, title = "Book 2", pages = 30 }, + new { _id = 3, title = "Book 3", pages = 40 }, + new { _id = 4, title = "Book 4", pages = 50 }, + }; + Result r = ExecuteAddStatement(coll.Add(docs)); + Assert.That(r.AffectedItemsCount, Is.EqualTo(4)); + + // Expected exceptions. + Assert.Throws(() => coll.GetOne(null)); + Assert.Throws(() => coll.GetOne("")); + Assert.Throws(() => coll.GetOne(string.Empty)); + + // Get document using numeric parameter. + DbDoc document = coll.GetOne(1); + Assert.That(document.Id, Is.EqualTo(1)); + Assert.That(document["title"], Is.EqualTo("Book 1")); + Assert.That(Convert.ToInt32(document["pages"]), Is.EqualTo(20)); + + // Get document using string parameter. + document = coll.GetOne("3"); + Assert.That(document.Id, Is.EqualTo(3)); + Assert.That(document["title"], Is.EqualTo("Book 3")); + Assert.That(Convert.ToInt32(document["pages"]), Is.EqualTo(40)); + + // Get a non-existing document. + document = coll.GetOne(5); + Assert.That(document, Is.Null); + } + + public enum LockMode { Exclusive, Shared } + + [TestCase(LockContention.Default, LockMode.Exclusive)] + [TestCase(LockContention.NoWait, LockMode.Exclusive)] + [TestCase(LockContention.SkipLocked, LockMode.Exclusive)] + [TestCase(LockContention.Default, LockMode.Shared)] + [TestCase(LockContention.NoWait, LockMode.Shared)] + [TestCase(LockContention.SkipLocked, LockMode.Shared)] + public void LockExclusiveAndSharedWithWaitingOptions(LockContention lockOption, LockMode lockMode) + { + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); + + string collectionName = "test"; + var coll = CreateCollection(collectionName); + ExecuteAddStatement(coll.Add(new { _id = 1, name = "Jonh" })); + + // first session locks the row + using (Session s1 = MySQLX.GetSession(ConnectionString)) + { + var coll1 = s1.GetSchema(schemaName).GetCollection(collectionName); + s1.StartTransaction(); + var r1 = ExecuteFindStatement(coll1.Find("_id = :id").Bind("id", 1).LockExclusive()); + Assert.That(r1.FetchAll(), Has.One.Items); + + // second session tries to read the locked row + using (Session s2 = MySQLX.GetSession(ConnectionString)) + { + var coll2 = s2.GetSchema(schemaName).GetCollection(collectionName); + ExecuteSQLStatement(s2.SQL("SET innodb_lock_wait_timeout = 1")); + s2.StartTransaction(); + var stmt2 = coll2.Find("_id = :id").Bind("id", 1); + if (lockMode == LockMode.Exclusive) + stmt2.LockExclusive(lockOption); + else + stmt2.LockShared(lockOption); + + switch (lockOption) + { + case LockContention.Default: + // error 1205 Lock wait timeout exceeded; try restarting transaction + Assert.That(Assert.Throws(() => ExecuteFindStatement(stmt2).FetchAll()).Code, Is.EqualTo(1205u)); + break; + case LockContention.NoWait: + // error 1205 Lock wait timeout exceeded; try restarting transaction + uint expectedError = 1205; + if (session.XSession.GetServerVersion().isAtLeast(8, 0, 5)) + // error 3572 Statement aborted because lock(s) could not be acquired immediately and NOWAIT is set + expectedError = 3572; + Assert.That(Assert.Throws(() => ExecuteFindStatement(stmt2).FetchAll()).Code, Is.EqualTo(expectedError)); + break; + case LockContention.SkipLocked: + if (!session.XSession.GetServerVersion().isAtLeast(8, 0, 5)) + { + // error 1205 Lock wait timeout exceeded; try restarting transaction + Assert.That(Assert.Throws(() => ExecuteFindStatement(stmt2).FetchAll()).Code, Is.EqualTo(1205u)); + break; + } + Assert.That(ExecuteFindStatement(stmt2).FetchAll(), Is.Empty); + break; + default: + throw new NotImplementedException(lockOption.ToString()); + } + } + // first session frees the lock + s1.Commit(); + } + } + + [Test] + public void Grouping() + { + ExecuteSQLStatement(GetSession().SQL("SET GLOBAL sql_mode=(SELECT REPLACE(@@sql_mode, 'ONLY_FULL_GROUP_BY', '')); ")); + Collection collection = CreateCollection("test"); + var docs = new[] + { + new { _id = 1, name = "jonh doe", age = 38 }, + new { _id = 2, name = "milton green", age = 45 }, + new { _id = 3, name = "larry smith", age = 24}, + new { _id = 4, name = "mary weinstein", age = 24 }, + new { _id = 5, name = "jerry pratt", age = 45 }, + new { _id = 6, name = "hugh jackman", age = 20}, + new { _id = 7, name = "elizabeth olsen", age = 31} + }; + Result r = ExecuteAddStatement(collection.Add(docs)); + Assert.That(r.AffectedItemsCount, Is.EqualTo(7)); + + // GroupBy operation. + // GroupBy returns 5 rows since age 45 and 24 is repeated. + var result = ExecuteFindStatement(collection.Find().Fields("_id as ID", "name as Name", "age as Age").GroupBy("age")); + Assert.That(result.FetchAll().Count, Is.EqualTo(5)); + + // GroupBy with null. + result = ExecuteFindStatement(collection.Find().Fields("_id as ID", "name as Name", "age as Age").GroupBy(null)); + Assert.That(result.FetchAll().Count, Is.EqualTo(7)); + result = ExecuteFindStatement(collection.Find().Fields("_id as ID", "name as Name", "age as Age").GroupBy(null, null)); + Assert.That(result.FetchAll().Count, Is.EqualTo(7)); + result = ExecuteFindStatement(collection.Find().Fields("_id as ID", "name as Name", "age as Age").GroupBy(null, "age")); + Assert.That(result.FetchAll().Count, Is.EqualTo(5)); + + // Having operation. + // Having reduces the original 5 rows to 3 since 2 rows have a cnt=2, due to the repeated names. + result = ExecuteFindStatement(collection.Find().Fields("_id as ID", "count(name) as cnt", "age as Age").GroupBy("age").Having("cnt = 1")); + Assert.That(result.FetchAll().Count, Is.EqualTo(3)); + + // Having with null. + result = ExecuteFindStatement(collection.Find().Fields("_id as ID", "count(name) as cnt", "age as Age").GroupBy("age").Having(null)); + Assert.That(result.FetchAll().Count, Is.EqualTo(5)); + + // GroupBy with invalid field name. + var ex = Assert.Throws(() => ExecuteFindStatement(collection.Find().Fields("_id as ID", "name as Name", "age as Age").GroupBy("none"))); + Assert.That(ex.Message, Is.EqualTo("Unknown column 'none' in 'group statement'")); + + // GroupBy with empty strings. + var ex2 = Assert.Throws(() => ExecuteFindStatement(collection.Find().Fields("_id as ID", "name as Name", "age as Age").GroupBy(""))); + Assert.That(ex2.Message, Is.EqualTo("No more tokens when expecting one at token pos 0")); + ex2 = Assert.Throws(() => ExecuteFindStatement(collection.Find().Fields("_id as ID", "name as Name", "age as Age").GroupBy(" "))); + Assert.That(ex2.Message, Is.EqualTo("No more tokens when expecting one at token pos 0")); + ex2 = Assert.Throws(() => ExecuteFindStatement(collection.Find().Fields("_id as ID", "name as Name", "age as Age").GroupBy(string.Empty))); + Assert.That(ex2.Message, Is.EqualTo("No more tokens when expecting one at token pos 0")); + + // Having with invalid field name. + ex = Assert.Throws(() => ExecuteFindStatement(collection.Find().Fields("_id as ID", "count(name) as cnt", "age as Age").GroupBy("age").Having("none = 1"))); + Assert.That(ex.Message, Is.EqualTo("Invalid expression in grouping criteria")); + + // Having with empty strings. + ex2 = Assert.Throws(() => ExecuteFindStatement(collection.Find().Fields("_id as ID", "count(name) as cnt", "age as Age").GroupBy("age").Having(""))); + Assert.That(ex2.Message, Is.EqualTo("Unable to parse query ''")); + Assert.That(ex2.InnerException.Message, Is.EqualTo("No more tokens when expecting one at token pos 0")); + ex2 = Assert.Throws(() => ExecuteFindStatement(collection.Find().Fields("_id as ID", "count(name) as cnt", "age as Age").GroupBy("age").Having(" "))); + Assert.That(ex2.Message, Is.EqualTo("Unable to parse query ' '")); + Assert.That(ex2.InnerException.Message, Is.EqualTo("No more tokens when expecting one at token pos 0")); + ex2 = Assert.Throws(() => ExecuteFindStatement(collection.Find().Fields("_id as ID", "count(name) as cnt", "age as Age").GroupBy("age").Having(string.Empty))); + Assert.That(ex2.Message, Is.EqualTo("Unable to parse query ''")); + Assert.That(ex2.InnerException.Message, Is.EqualTo("No more tokens when expecting one at token pos 0")); + } + + [Test] + public void Fields() + { + Collection coll = CreateCollection("test"); + var docs = new[] + { + new { _id = 1, title = "Book 1", pages = 20 }, + new { _id = 2, title = "Book 2", pages = 30 }, + new { _id = 3, title = "Book 3", pages = 40 }, + new { _id = 4, title = "Book 4", pages = 50 }, + }; + Result r = ExecuteAddStatement(coll.Add(docs)); + Assert.That(r.AffectedItemsCount, Is.EqualTo(4ul)); + + // Single field. + var result = ExecuteFindStatement(coll.Find("pages = :Pages").Bind("pAges", 40).Fields("title")); + var document = result.FetchOne(); + Assert.That(document.values, Has.One.Items); + Assert.That(document["title"], Is.EqualTo("Book 3")); + + // Null values are ignored. + result = ExecuteFindStatement(coll.Find("pages = :Pages").Bind("pAges", 40).Fields(null)); + document = result.FetchOne(); + Assert.That(document.values.Count, Is.EqualTo(3)); + + // Null values are ignored. + result = ExecuteFindStatement(coll.Find("pages = :Pages").Bind("pAges", 40).Fields("title", null)); + document = result.FetchOne(); + Assert.That(document.values, Has.One.Items); + + // Single field in array. + result = ExecuteFindStatement(coll.Find("pages = :Pages").Bind("pAges", 40).Fields(new string[] { "title" })); + document = result.FetchOne(); + Assert.That(document.values, Has.One.Items); + Assert.That(document["title"], Is.EqualTo("Book 3")); + + // Single field with alias. + result = ExecuteFindStatement(coll.Find("pages = :Pages").Bind("pages", 20).Fields("title as title2")); + document = result.FetchOne(); + Assert.That(document.values, Has.One.Items); + Assert.That(document["title2"], Is.EqualTo("Book 1")); + Assert.That(document.values.ContainsKey("title"), Is.False); + + // Unexistent field returns null. + result = ExecuteFindStatement(coll.Find("pages = :Pages").Bind("pages", 20).Fields("book")); + document = result.FetchOne(); + Assert.That(document.values, Has.One.Items); + Assert.That(document["book"], Is.Null); + + // Unexistent field with alias returns null. + result = ExecuteFindStatement(coll.Find("pages = :Pages").Bind("pages", 20).Fields("book as book1")); + document = result.FetchOne(); + Assert.That(document.values, Has.One.Items); + Assert.That(document["book1"], Is.Null); + + // Multiple fields. + result = ExecuteFindStatement(coll.Find("pages = :Pages").Bind("pAges", 40).Fields("title", "pages", "other")); + document = result.FetchOne(); + Assert.That(document.values.Count, Is.EqualTo(3)); + Assert.That(document["title"], Is.EqualTo("Book 3")); + Assert.That(document["pages"], Is.EqualTo(40)); + Assert.That(document["other"], Is.Null); + + // Multiple fields in array. + result = ExecuteFindStatement(coll.Find("pages = :Pages").Bind("pAges", 40).Fields(new string[] { "title", "pages" })); + document = result.FetchOne(); + Assert.That(document.values.Count, Is.EqualTo(2)); + Assert.That(document["title"], Is.EqualTo("Book 3")); + Assert.That(document["pages"], Is.EqualTo(40)); + + // Sending a document doesn't generate an error. + result = ExecuteFindStatement(coll.Find("pages = :Pages").Bind("pages", 20).Fields("{\"_id\":\"1004\",\"F1\": 1234 }")); + document = result.FetchOne(); + + // Empty string and white space raises error. + var ex = Assert.Throws(() => ExecuteFindStatement(coll.Find("pages = :Pages").Bind("pAges", 40).Fields(""))); + Assert.That(ex.Message, Is.EqualTo("No more tokens when expecting one at token pos 0")); + ex = Assert.Throws(() => ExecuteFindStatement(coll.Find("pages = :Pages").Bind("pAges", 40).Fields(" "))); + Assert.That(ex.Message, Is.EqualTo("No more tokens when expecting one at token pos 0")); + ex = Assert.Throws(() => ExecuteFindStatement(coll.Find("pages = :Pages").Bind("pAges", 40).Fields(string.Empty))); + Assert.That(ex.Message, Is.EqualTo("No more tokens when expecting one at token pos 0")); + + // Multiple word field name raises error. + ex = Assert.Throws(() => result = ExecuteFindStatement(coll.Find("pages = :Pages").Bind("pAges", 40).Fields("Book 1"))); + Assert.That(ex.Message, Is.EqualTo("Expression has unexpected token '1' at position 1.")); + } + + [TestCase("", "")] + [TestCase("'", "'")] + [TestCase("", "'")] + [TestCase("'", "")] + public void FindIdAsString(string prefix, string suffix) + { + Collection coll = CreateCollection("test"); + Result r = null; + var docs = new[] + { + new { _id = $"{prefix}1{suffix}", title = $"{prefix}Book 1{suffix}", pages = 20 }, + new { _id = $"{prefix}2{suffix}", title = $"{prefix}Book 2{suffix}", pages = 30 }, + new { _id = $"{prefix}3{suffix}", title = $"{prefix}Book 3{suffix}", pages = 40 }, + new { _id = $"{prefix}4{suffix}", title = $"{prefix}Book 4{suffix}", pages = 50 }, + }; + r = coll.Add(docs).Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(4)); + + var findStmt = coll.Find("_id = :id and pages = :pages").Bind("id", $"{prefix}3{suffix}").Bind("pages", 40); + var doc = ExecuteFindStatement(findStmt); + var books = doc.FetchAll(); + Assert.That(books, Has.One.Items); + Assert.That(books[0]["_id"], Is.EqualTo($"{prefix}3{suffix}")); + + findStmt = coll.Find("_id = :id and pages = :pages").Bind("Id", $"{prefix}2{suffix}").Bind("Pages", 30); + doc = ExecuteFindStatement(findStmt); + books = doc.FetchAll(); + Assert.That(books, Has.One.Items); + Assert.That(books[0]["_id"], Is.EqualTo($"{prefix}2{suffix}")); + + findStmt = coll.Find("title = :title").Bind("Title", $"{prefix}Book 4{suffix}"); + doc = ExecuteFindStatement(findStmt); + books = doc.FetchAll(); + Assert.That(books, Has.One.Items); + Assert.That(books[0]["_id"], Is.EqualTo($"{prefix}4{suffix}")); + Assert.That(books[0]["pages"], Is.EqualTo(50)); + } + + [TestCase(":hobbies IN $.additionalinfo.hobbies", "hobbies", "painting", 4)] + [TestCase(":hobbies IN $.additionalinfo.hobbies", "hobbies", "[\"playing\", \"listening\"]", 0)] + [TestCase("[\"playing\", \"listening\"] IN $.additionalinfo.hobbies", null, null, 3)] + public void InOperatorBindingJson(string condition, string bind, string value, int id) + { + Collection coll = CreateCollection("test"); + Result r = null; + var docs = new[] + { + new { _id = 1, title = $"Book 1", pages = 20, additionalinfo = new DbDoc("{\"company\":\"xyz\",\"vehicle\":\"bike\",\"hobbies\":\"reading\"}") }, + new { _id = 2, title = $"Book 2", pages = 30, additionalinfo = new DbDoc("{\"company\":\"abc\",\"vehicle\":\"car\",\"hobbies\":\"boxing\"}") }, + new { _id = 3, title = $"Book 3", pages = 40, additionalinfo = new DbDoc("{\"company\":\"qwe\",\"vehicle\":\"airplane\",\"hobbies\":[\"playing\", \"listening\"]}") }, + new { _id = 4, title = $"Book 4", pages = 50, additionalinfo = new DbDoc("{\"company\":\"zxc\",\"vehicle\":\"boat\",\"hobbies\":\"painting\"}") }, + }; + r = coll.Add(docs).Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(4)); + + var findStmt = coll.Find(condition); + if (bind != null) findStmt.Bind(bind, value); + var result = findStmt.Execute().FetchAll(); + Assert.That(result.Count, Is.EqualTo(id == 0 ? 0 : 1)); + if (id > 0) + { + Assert.That(result[0]["_id"], Is.EqualTo(id)); + } + } + + [Test] + public void FindUsingOverlaps() + { + Collection coll = CreateCollection("test"); + + coll.Add("{ \"_id\":1, \"title\": \"Book 1\", \"list\":[1, 4]}").Execute(); + coll.Add("{ \"_id\":2, \"title\": \"Book 2\", \"list\":[5, 7]}").Execute(); + coll.Add("{ \"_id\":3, \"title\": \"Book 3\", \"list\":[4, 9]}").Execute(); + coll.Add("{ \"_id\":4, \"title\": \"Book 4\", \"list\":[2]}").Execute(); + coll.Add("{ \"_id\":5, \"title\": \"Book 5\",\"list\":[\"\"]}").Execute(); + coll.Add("{ \"_id\":6, \"title\": \"Book 6\",\"list\":[\" \"]}").Execute(); + + var result = ExecuteFindStatement(coll.Find("[7] OVERLAPS $.list")).FetchAll(); + Assert.That(result[0]["title"], Is.EqualTo("Book 2")); + result = ExecuteFindStatement(coll.Find("[8] overlaps $.list")).FetchAll(); + Assert.That(result, Is.Empty); + result = ExecuteFindStatement(coll.Find("[1, 4] OVERLAPS $.list")).FetchAll(); + Assert.That(result, Is.Not.Empty); + Assert.That(result[0]["title"], Is.EqualTo("Book 1")); + Assert.That(result[1]["title"], Is.EqualTo("Book 3")); + result = ExecuteFindStatement(coll.Find("$.list OVERLAPS [1, 2]")).FetchAll(); + Assert.That(result, Is.Not.Empty); + Assert.That(result[0]["title"], Is.EqualTo("Book 1")); + Assert.That(result[1]["title"], Is.EqualTo("Book 4")); + result = ExecuteFindStatement(coll.Find("'Book 1' NOT OVERLAPS $.title").Fields("_id")).FetchAll(); + Assert.That(result.Count, Is.EqualTo(5)); + Assert.That(result[1].Id, Is.EqualTo(3)); + result = ExecuteFindStatement(coll.Find(":title NOT OVERLAPS $.title").Bind("title", "Book 1").Fields("_id")).FetchAll(); + Assert.That(result.Count, Is.EqualTo(5)); + Assert.That(result[2].Id, Is.EqualTo(4)); + result = ExecuteFindStatement(coll.Find("$.list OVERLAPS :list").Bind("list", 9)).FetchAll(); + Assert.That(result[0]["title"], Is.EqualTo("Book 3")); + var jsonParams = new { list = 4 }; + result = ExecuteFindStatement(coll.Find("$.list OVERLAPS :list").Bind(jsonParams).Fields("count(_id) as ID", "title as Title", "list as List"). + GroupBy("title", "list").Having("ID > 0")).FetchAll(); + Assert.That(result.Count, Is.EqualTo(2)); + Assert.That(result[0]["Title"], Is.EqualTo("Book 1")); + result = ExecuteFindStatement(coll.Find("[''] OVERLAPS $.list")).FetchAll(); + Assert.That(result, Has.One.Items); + Assert.That(result[0].Id, Is.EqualTo(5)); + result = ExecuteFindStatement(coll.Find("[' '] OVERLAPS $.list")).FetchAll(); + Assert.That(result, Has.One.Items); + Assert.That(result[0].Id, Is.EqualTo(6)); + + Assert.Throws(() => ExecuteFindStatement(coll.Find("$.list OVERLAPS -")).FetchAll()); + Assert.Throws(() => ExecuteFindStatement(coll.Find("[2, 9] OVERLAPS")).FetchAll()); + Assert.Throws(() => ExecuteFindStatement(coll.Find("[2, 9] OVERPS $.list")).FetchAll()); + } + + #region WL14389 + + [Test, Description("Collection.Find(condition).GroupBy(SearchExprStr).Having(SearchConditionStr)")] + public void FindGroupByHaving() + { + ExecuteSQLStatement(GetSession().SQL("set sql_mode = 'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';")); + + Collection collection = CreateCollection("test"); + var docs1 = new[] + { + new { _id = 1, name = "jonh doe", age = 38,profit = 100,test = 1.92,date="21/11/2011" }, + new { _id = 2, name = "milton green", age = 45,profit = 200,test = 12.08,date="21/11/2012" }, + new { _id = 3, name = "larry smith", age = 24,profit = 300,test = 12.1,date="21/11/2013" }, + new { _id = 4, name = "mary weinstein", age = 24 ,profit = 100,test = 12.0,date="21/11/2014" }, + new { _id = 5, name = "jerry pratt", age = 45 ,profit = 400,test = 20.87,date="21/11/2015" }, + new { _id = 6, name = "hugh jackman", age = 20,profit = 500,test = 20.65,date="21/11/2016"}, + new { _id = 7, name = "elizabeth olsen", age = 31,profit = 300,test = 20.45,date="21/11/2017" }, + new { _id = 8, name = "tommy h", age = 31,profit = 3000,test = 0.0,date="21/11/2018"} + }; + + Result r = collection.Add(docs1).Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(8)); + + // GroupBy operation. + // GroupBy returns 5 rows since age 45 and 24 is repeated. + var result = collection.Find().Fields("_id as ID", "name as Name", "age as Age").GroupBy("age").Execute(); + Assert.That(result.FetchAll().Count, Is.EqualTo(5)); + result = collection.Find().Fields("_id as ID", "name as Name", "profit as Profit", "test as test").GroupBy("test").Having("test=1.92").Execute(); + Assert.That(result.FetchAll().Count, Is.EqualTo(1)); + result = collection.Find().Fields("max($.age) as age", "max($.profit) as Profit", "max($.test) as test").GroupBy("$.test").Having("max($.age)>=31"). + Sort("profit DESC").Execute(); + Assert.That(result.FetchAll().Count, Is.EqualTo(result.FetchAll().Count)); + result = collection.Find().Fields("max($.age) as age", "max($.profit) as Profit", "max($.test) as test").GroupBy("$.test").Having("max($.age)>30 && max($.age)<32") + .Execute(); + Assert.That(result.FetchAll().Count, Is.EqualTo(2)); + result = collection.Find().Fields("max($.age) as age", "max($.profit) as Profit", "max($.test) as test").GroupBy("$.test").Having("max($.age)>300000000") + .Execute(); + Assert.That(result.FetchAll().Count, Is.EqualTo(0)); + + result = collection.Find().Fields("max($.age) as age", "max($.profit) as Profit", "max($.test) as test").GroupBy("$.test").Having("max($.age)>30"). + Having("max($.age)<32") + .Execute(); + Assert.That(result.FetchAll().Count, Is.EqualTo(5)); + + result = collection.Find().Fields("max($.age) as age", "max($.profit) as Profit", "max($.test) as test").GroupBy("$.test").Having("max($.age)>30"). + Having("max($.age)<32").Limit(5) + .Execute(); + Assert.That(result.FetchAll().Count, Is.EqualTo(5)); + + result = collection.Find().Fields("max($.age) as age", "max($.profit) as Profit", "max($.test) as test").GroupBy("$.test").Having("max($.age)>30"). + Having("max($.age)<32").Limit(3) + .Execute(); + Assert.That(result.FetchAll().Count, Is.EqualTo(3)); + + result = collection.Find().Fields("max($.age) as age", "max($.profit) as Profit", "max($.test) as test").GroupBy("$.test").Having("max($.age)>30"). + Having("max($.age)<32").Limit(3).Offset(2) + .Execute(); + Assert.That(result.FetchAll().Count, Is.EqualTo(3)); + + Assert.Throws(() => collection.Find().Fields("max($.age) as age", "max($.profit) as Profit", "max($.test) as test").GroupBy("$.test").Having("date=21/11/2011").Execute()); + } + + [Test, Description("Collection.Find().Limit(x).Offset(y)")] + public void FindLimitOffset() + { + ExecuteSQLStatement(GetSession().SQL("set sql_mode = 'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';")); + + Collection collection = CreateCollection("test"); + var docs1 = new[] + { + new { _id = 1, name = "jonh doe", age = 38,profit = 100,test = 1.92,date="21/11/2011" }, + new { _id = 2, name = "milton green", age = 45,profit = 200,test = 12.08,date="21/11/2012" }, + new { _id = 3, name = "larry smith", age = 24,profit = 300,test = 12.1,date="21/11/2013" }, + new { _id = 4, name = "mary weinstein", age = 24 ,profit = 100,test = 12.0,date="21/11/2014" }, + new { _id = 5, name = "jerry pratt", age = 45 ,profit = 400,test = 20.87,date="21/11/2015" }, + new { _id = 6, name = "hugh jackman", age = 20,profit = 500,test = 20.65,date="21/11/2016"}, + new { _id = 7, name = "elizabeth olsen", age = 31,profit = 300,test = 20.45,date="21/11/2017" }, + new { _id = 8, name = "tommy h", age = 31,profit = 3000,test = 0.0,date="21/11/2018"} + }; + + Result r = collection.Add(docs1).Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(8)); + + // GroupBy operation. + // GroupBy returns 5 rows since age 45 and 24 is repeated. + var result1 = collection.Find().Limit(2).Offset(-2378723).Execute(); + int k = result1.FetchAll().Count; + result1 = collection.Find().Limit(2).Offset(-1).Execute(); + k = result1.FetchAll().Count; + result1 = collection.Find().Limit(2).Offset(0).Execute(); + k = result1.FetchAll().Count; + + var result = collection.Find().Fields("_id as ID", "name as Name", "age as Age").GroupBy("age").Execute(); + Assert.That(result.FetchAll().Count, Is.EqualTo(5)); + result = collection.Find().Fields("_id as ID", "name as Name", "profit as Profit", "test as test").GroupBy("test").Having("test=1.92").Execute(); + Assert.That(result.FetchAll().Count, Is.EqualTo(1)); + result = collection.Find().Fields("max($.age) as age", "max($.profit) as Profit", "max($.test) as test").GroupBy("$.test").Having("max($.age)>=31"). + Sort("profit DESC").Execute(); + Assert.That(result.FetchAll().Count, Is.EqualTo(result.FetchAll().Count)); + result = collection.Find().Fields("max($.age) as age", "max($.profit) as Profit", "max($.test) as test").GroupBy("$.test").Having("max($.age)>30 && max($.age)<32") + .Execute(); + Assert.That(result.FetchAll().Count, Is.EqualTo(2)); + result = collection.Find().Fields("max($.age) as age", "max($.profit) as Profit", "max($.test) as test").GroupBy("$.test").Having("max($.age)>300000000") + .Execute(); + Assert.That(result.FetchAll().Count, Is.EqualTo(0)); + + result = collection.Find().Fields("max($.age) as age", "max($.profit) as Profit", "max($.test) as test").GroupBy("$.test").Having("max($.age)>30"). + Having("max($.age)<32") + .Execute(); + Assert.That(result.FetchAll().Count, Is.EqualTo(5)); + + result = collection.Find().Fields("max($.age) as age", "max($.profit) as Profit", "max($.test) as test").GroupBy("$.test").Having("max($.age)>30"). + Having("max($.age)<32").Limit(5) + .Execute(); + Assert.That(result.FetchAll().Count, Is.EqualTo(5)); + + result = collection.Find().Fields("max($.age) as age", "max($.profit) as Profit", "max($.test) as test").GroupBy("$.test").Having("max($.age)>30"). + Having("max($.age)<32").Limit(3) + .Execute(); + Assert.That(result.FetchAll().Count, Is.EqualTo(3)); + + result = collection.Find().Fields("max($.age) as age", "max($.profit) as Profit", "max($.test) as test").GroupBy("$.test").Having("max($.age)>30"). + Having("max($.age)<32").Limit(3).Offset(2) + .Execute(); + Assert.That(result.FetchAll().Count, Is.EqualTo(3)); + + result = collection.Find().Fields("$._id as _id", "$.test as test").GroupBy("$.test").Limit(5).Offset(1).Execute(); + Assert.That(result.FetchAll().Count, Is.EqualTo(5)); + + result = collection.Find().Fields("$._id as _id", "$.test as test").GroupBy("$.test").Limit(5).Offset(-1).Execute(); + Assert.That(result.FetchAll().Count, Is.EqualTo(5)); + + result = collection.Find().Fields("$._id as _id", "$.test as test").GroupBy("$.test").Limit(8).Execute(); + Assert.That(result.FetchAll().Count, Is.EqualTo(8)); + + result = collection.Find().Fields("max($.age) as age", "max($.profit) as Profit", "max($.test) as test").GroupBy("$.test").Having("max($.age)>30"). + Having("max($.age)<32").Limit(3).Offset(-1) + .Execute(); + Assert.That(result.FetchAll().Count, Is.EqualTo(3)); + + Assert.Throws(() => collection.Find().Fields("max($.age) as age", "max($.profit) as Profit", "max($.test) as test").GroupBy("$.test").Having("max($.age)>30"). + Having("max($.age)<32").Limit(-1).Offset(0) + .Execute()); + + DbDoc[] jsonlist = new DbDoc[2000]; + for (int i = 0; i < 2000; i++) + { + DbDoc newDoc2 = new DbDoc(); + newDoc2.SetValue("_id", (i + 1000).ToString()); + newDoc2.SetValue("F1", ("Field-1-Data-" + i)); + newDoc2.SetValue("F2", ("Field-2-Data-" + i)); + newDoc2.SetValue("F3", (300 + i).ToString()); + jsonlist[i] = newDoc2; + newDoc2 = null; + } + var res = collection.Add(jsonlist).Execute(); + + result = collection.Find().Fields("$.F1 as F1", "$.F2 as F2").GroupBy("$.F1").Limit(3).Offset(1).Execute(); + Assert.That(result.FetchAll().Count, Is.EqualTo(3)); + + result = collection.Find().Fields("$.F1 as F1", "$.F2 as F2").GroupBy("$.F1").Limit(3).Offset(1844674407370955161).Execute(); + Assert.That(result.FetchAll().Count, Is.EqualTo(0)); + } + + [Test, Description("Collection.Find().Limit(x,y)")] + public void FindLimitOffsetDeprecated() + { + ExecuteSQLStatement(GetSession().SQL("set sql_mode = 'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';")); + Collection collection = CreateCollection("test"); + var docs1 = new[] + { + new { _id = 1, name = "jonh doe", age = 38,profit = 100,test = 1.92,date="21/11/2011" }, + new { _id = 2, name = "milton green", age = 45,profit = 200,test = 12.08,date="21/11/2012" }, + new { _id = 3, name = "larry smith", age = 24,profit = 300,test = 12.1,date="21/11/2013" }, + new { _id = 4, name = "mary weinstein", age = 24 ,profit = 100,test = 12.0,date="21/11/2014" }, + new { _id = 5, name = "jerry pratt", age = 45 ,profit = 400,test = 20.87,date="21/11/2015" }, + new { _id = 6, name = "hugh jackman", age = 20,profit = 500,test = 20.65,date="21/11/2016"}, + new { _id = 7, name = "elizabeth olsen", age = 31,profit = 300,test = 20.45,date="21/11/2017" }, + new { _id = 8, name = "tommy h", age = 31,profit = 3000,test = 0.0,date="21/11/2018"} + }; + + Result r = collection.Add(docs1).Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(8)); + + // GroupBy operation. + var result1 = collection.Find().Limit(2).Offset(-2378723).Execute(); + int k = result1.FetchAll().Count; + result1 = collection.Find().Limit(2).Offset(-1).Execute(); + k = result1.FetchAll().Count; + result1 = collection.Find().Limit(2).Offset(0).Execute(); + k = result1.FetchAll().Count; + result1 = collection.Find().Limit(2).Offset(1000000000).Execute(); + k = result1.FetchAll().Count; + collection.Remove("true").Limit(2).Execute(); + + docs1 = new[] + { + new { _id = 1, name = "jonh doe", age = 38,profit = 100,test = 1.92,date="21/11/2011" }, + new { _id = 2, name = "milton green", age = 45,profit = 200,test = 12.08,date="21/11/2012" }, + }; + + r = collection.Add(docs1).Execute(); + Assert.Throws(() => collection.Remove("true").Limit(2).Offset(1).Execute()); + + collection.Remove("true").Limit(2).Offset(0).Execute(); + docs1 = new[] + { + new { _id = 1, name = "jonh doe", age = 38,profit = 100,test = 1.92,date="21/11/2011" }, + new { _id = 2, name = "milton green", age = 45,profit = 200,test = 12.08,date="21/11/2012" }, + }; + + r = collection.Add(docs1).Execute(); + Assert.Throws(() => collection.Modify("_id = 1 || _id = 2").Set("age", 34).Limit(1).Offset(1).Execute()); + + collection.Modify("_id = 1 || _id = 2").Set("age", 34).Limit(2).Offset(0).Execute(); + collection.Modify("_id = 1").Set("age", 38).Limit(2).Offset(0).Execute(); + collection.Modify("_id = 2").Set("age", 45).Limit(2).Offset(0).Execute(); + + var result = collection.Find().Fields("max($.age) as age", "max($.profit) as Profit", "max($.test) as test").GroupBy("$.test").Having("max($.age)>30"). + Having("max($.age)<32").Limit(3).Offset(2) + .Execute(); + Assert.That(result.FetchAll().Count, Is.EqualTo(3)); + + result = collection.Find().Fields("$._id as _id", "$.test as test").GroupBy("$.test").Limit(5).Offset(1).Execute(); + Assert.That(result.FetchAll().Count, Is.EqualTo(5)); + result = collection.Find().Fields("$._id as _id", "$.test as test").GroupBy("$.test").Limit(5).Offset(-1).Execute(); + Assert.That(result.FetchAll().Count, Is.EqualTo(5)); + + result = collection.Find().Fields("max($.age) as age", "max($.profit) as Profit", "max($.test) as test").GroupBy("$.test").Having("max($.age)>30"). + Having("max($.age)<32").Limit(3).Offset(-1) + .Execute(); + Assert.That(result.FetchAll().Count, Is.EqualTo(3)); + + Assert.Throws(() => collection.Find().Fields("max($.age) as age", "max($.profit) as Profit", "max($.test) as test").GroupBy("$.test").Having("max($.age)>30"). + Having("max($.age)<32").Limit(-1).Offset(0) + .Execute()); + } + + [Test, Description("Test MySQLX plugin Collection Dbdoc Scenarios")] + public void CollectionDbdoc() + { + Collection col = CreateCollection("my_collection_1"); + Collection col1 = CreateCollection("my_collection_2"); + var d1 = new DbDoc(); + d1.SetValue("_id", 1); + var docs1 = new[] + { + new { _id = 1, title = "Book 1" }, + new { _id = 2, title = "Book 2" }, + }; + + d1.SetValue("books", docs1); + d1.SetValue("pages", 20); + + var d2 = new DbDoc(); + d2.SetValue("_id", 2); + var docs2 = new[] + { + new { _id = 1, title = "Book 3" }, + new { _id = 2, title = "Book 4" }, + }; + + d2.SetValue("books", docs2); + d2.SetValue("pages", 30); + + var d3 = new DbDoc(); + d3.SetValue("_id", 3); + var docs3 = new[] + { + new { _id = 1, title = "Book 3" }, + new { _id = 2, title = "Book 4" }, + }; + + d3.SetValue("books", docs3); + d3.SetValue("pages", 40); + col.Add(d1).Add(d2).Add(d3).Execute(); + string[] test1 = new string[] { "_id=1" }; + string[] test2 = new string[] { "_id=2" }; + var res = col.Find("$._id = 1").Execute().FetchAll(); + Assert.That(res.Count, Is.EqualTo(1), "Matching the find count"); + Assert.That(res[0].ToString(), Is.EqualTo(d1.ToString()), "Matching the string"); + res = col.Find("$._id = 2").Execute().FetchAll(); + Assert.That(res.Count, Is.EqualTo(1), "Matching the find count"); + Assert.That(res[0].ToString(), Is.EqualTo(d2.ToString()), "Matching the string"); + res = col.Find("$._id = 3").Execute().FetchAll(); + Assert.That(res.Count, Is.EqualTo(1), "Matching the find count"); + Assert.That(res[0].ToString(), Is.EqualTo(d3.ToString()), "Matching the string"); + + } + + [Test, Description("Test MySQLX plugin Collection Dbdoc Scenarios - ID Present DbDoc Blank")] + public void CollectionIDPresentDbdocBlank() + { + Collection col = CreateCollection("my_collection_1"); + Collection col1 = CreateCollection("my_collection_2"); + var d1 = new DbDoc(); + d1.SetValue("_id", 1); + string[] a = { String.Empty }; + d1.SetValue("books", a); + d1.SetValue("pages", 20); + + var d2 = new DbDoc(); + d2.SetValue("_id", 2); + d2.SetValue("books", a); + d2.SetValue("pages", 30); + + var d3 = new DbDoc(); + d3.SetValue("_id", 3); + d3.SetValue("books", a); + d3.SetValue("pages", 40); + + col.Add(d1).Add(d2).Add(d3).Execute(); + string[] test1 = new string[] { "_id=1" }; + string[] test2 = new string[] { "_id=2" }; + var res = col.Find("$._id = 1").Execute().FetchAll(); + Assert.That(res.Count, Is.EqualTo(1), "Matching the find count"); + Assert.That(res[0].ToString(), Is.EqualTo(d1.ToString()), "Matching the string"); + res = col.Find("$._id = 2").Execute().FetchAll(); + Assert.That(res.Count, Is.EqualTo(1), "Matching the find count"); + Assert.That(res[0].ToString(), Is.EqualTo(d2.ToString()), "Matching the string"); + res = col.Find("$._id = 3").Execute().FetchAll(); + Assert.That(res.Count, Is.EqualTo(1), "Matching the find count"); + Assert.That(res[0].ToString(), Is.EqualTo(d3.ToString()), "Matching the string"); + } + + /// + /// Bug 23542055 + /// + [Test, Description("Test MySQLX plugin Find with Many conditions")] + [Ignore("Uncomment to execute")] + public void FindWithManyConditions() + { + int i = 0; + int Condition = 49; + String query = ""; + var col = CreateCollection("my_collection_1"); + + col.Add("{\"_id\":\"1002\",\"TEST1\":1111}").Execute(); + for (i = 0; i < Condition; i++) + { + if (i > 0) + query = query + " OR "; + query = query + "$.TEST1 > " + i; + } + var docs = col.Find(query).Execute(); + } + + [TestCase(1)] + [TestCase(2)] + [TestCase(3)] + [TestCase(4)] + [Test, Description("Reading exclusively locked anonymous object array using LockShared without waiting option. ")] + public void ExclusiveLocksAndCommit(int scenario) + { + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); + + ExecuteSQLStatement(session.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); + using (var session2 = MySQLX.GetSession(ConnectionString)) + { + ExecuteSQLStatement(session2.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); + Collection coll = CreateCollection("test"); + ExecuteSQLStatement(session2.SQL("ALTER TABLE `test`.`test` ADD COLUMN `$ix_i_r_index` INT GENERATED ALWAYS AS (JSON_UNQUOTE(JSON_EXTRACT(doc, '$._id'))) VIRTUAL NOT NULL, ADD UNIQUE INDEX `myIndex`(`$ix_i_r_index`)")); + Result result1 = null; + switch (scenario) + { + case 1: // Anonymous Object + var docs = new[] + { + new {_id = 1, a = 1}, + new {_id = 2, a = 2}, + new {_id = 3, a = 3} + }; + coll.Add(docs).Execute(); + break; + case 2: // DbDoc + for (int i = 0; i < 3; i++) + { + DbDoc DbDocs = new DbDoc(); + DbDocs.SetValue("_id", i); + DbDocs.SetValue("a", i); + result1 = coll.Add(DbDocs).Execute(); + } + break; + case 3: // Chained Add + var docs1 = new { _id = 1, title = "Book 1", pages = 20, a = 1 }; + var docs2 = new { _id = 2, title = "Book 1", pages = 20, a = 2 }; + var docs3 = new { _id = 3, title = "Book 1", pages = 20, a = 3 }; + result1 = coll.Add(docs1).Add(docs2).Add(docs3).Execute(); + break; + case 4: //Json string + result1 = coll.Add(@"{ ""_id"": 1,""a"": 1 }", @"{""_id"": 2,""a"": 2 }", @"{""_id"": 3, ""a"": 3 }", @"{ ""_id"": 4,""a"": 4 }").Execute(); + break; + } + + var coll2 = session2.GetSchema("test").GetCollection("test"); + session.SQL("START TRANSACTION").Execute(); + var docResult = coll.Find("_id = 1").LockExclusive().Execute(); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + + session2.SQL("START TRANSACTION").Execute(); + // Should return immediately since document isn't locked. + docResult = coll2.Find("_id = 2").LockExclusive().Execute(); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + + // Session2 blocks due to to LockExclusive() not allowing to read locked documents. + session2.SQL("SET SESSION innodb_lock_wait_timeout=1").Execute(); + Exception ex = Assert.Throws(() => ExecuteFindStatement(coll2.Find("_id = :id").LockExclusive().Bind("id", 1))); + + Assert.Throws(() => ExecuteModifyStatement(coll2.Modify("a = 1").Change("a", 10))); + + session.Commit(); + var result = coll2.Modify("a = 1").Set("a", 12).Execute(); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1)); + session.SQL("ROLLBACK").Execute(); + session2.SQL("ROLLBACK").Execute(); + } + } + + [TestCase(null)] + [TestCase(LockMode.Shared)] + [TestCase(LockMode.Exclusive)] + [Test, Description("Reading a document which was locked using lock_shared without waiting option")] + public void SharedLockAndCommit(LockMode? lockMode) + { + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); + ExecuteSQLStatement(session.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); + using (var session2 = MySQLX.GetSession(ConnectionString)) + { + ExecuteSQLStatement(session2.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); + Collection coll = CreateCollection("test"); + session2.SQL("ALTER TABLE `test`.`test` ADD COLUMN `$ix_i_r_index` INT GENERATED ALWAYS AS (JSON_UNQUOTE(JSON_EXTRACT(doc, '$._id'))) VIRTUAL NOT NULL, ADD UNIQUE INDEX `myIndex`(`$ix_i_r_index`)").Execute(); + var docs = new[] + { + new {_id = 1, a = 1}, + new {_id = 2, a = 2}, + new {_id = 3, a = 3} + }; + + coll.Add(docs).Execute(); + var coll2 = session2.GetSchema("test").GetCollection("test"); + + session.SQL("START TRANSACTION").Execute(); + var docResult = coll.Find("_id = 1").LockShared().Execute(); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + + session2.SQL("START TRANSACTION").Execute(); + // Should return immediately since document isn't locked. + switch (lockMode) + { + case LockMode.Shared: + docResult = coll2.Find("_id = 2").LockShared().Execute(); + break; + case LockMode.Exclusive: + docResult = coll2.Find("_id = 2").LockExclusive().Execute(); + break; + default: + docResult = coll2.Find("_id = 2").Execute(); + break; + } + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + + // Session2 returns immediately. + session2.SQL("SET SESSION innodb_lock_wait_timeout=1").Execute(); + docResult = coll2.Find("_id = :id").Bind("id", 1).Execute(); + Assert.That(docResult.FetchAll(), Has.One.Items); + + // Session2 blocks due to to LockShared() not allowing to modify locked documents. + Exception ex = Assert.Throws(() => ExecuteModifyStatement(coll2.Modify("a = 1").Change("a", 10))); + + // Session2 returns immediately as session is committed. + session.Commit(); + var result = coll2.Modify("a = 1").Set("a", 12).Execute(); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1)); + + session.SQL("ROLLBACK").Execute(); + session2.SQL("ROLLBACK").Execute(); + } + } + + [TestCase(LockMode.Shared)] + [TestCase(LockMode.Exclusive)] + [Test, Description("Reading a document using lock_shared using SKIPLOCK and NOWAIT options with CRUD operations happening parallely.")] + public void SharedAndExclusiveLockWithSkipAndNoWait(LockMode lockMode) + { + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); + ExecuteSQLStatement(session.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); + using (var session2 = MySQLX.GetSession(ConnectionString)) + { + ExecuteSQLStatement(session2.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); + Collection coll = CreateCollection("test"); + session2.SQL("ALTER TABLE `test`.`test` ADD COLUMN `$ix_i_r_index` INT GENERATED ALWAYS AS (JSON_UNQUOTE(JSON_EXTRACT(doc, '$._id'))) VIRTUAL NOT NULL, ADD UNIQUE INDEX `myIndex`(`$ix_i_r_index`)").Execute(); + if (lockMode == LockMode.Shared) + session2.SQL("ALTER TABLE `test`.`test` ADD COLUMN `$ix_i_m_index` INT GENERATED ALWAYS AS (JSON_UNQUOTE(JSON_EXTRACT(doc, '$.a'))) VIRTUAL NOT NULL, ADD UNIQUE INDEX `myIndex1`(`$ix_i_m_index`)").Execute(); + + var docs = new[] + { + new {_id = 1, a = 1}, + new {_id = 2, a = 2}, + new {_id = 3, a = 3} + }; + + coll.Add(docs).Execute(); + var coll2 = session2.GetSchema("test").GetCollection("test"); + + session.SQL("START TRANSACTION").Execute(); + var result1 = coll.Modify("a = 1").Set("a", 10).Execute(); + + session2.SQL("START TRANSACTION").Execute(); + session2.SQL("SET SESSION innodb_lock_wait_timeout=1").Execute(); + DocResult docResult = null; + switch (lockMode) + { + case LockMode.Exclusive: + Assert.Throws(() => ExecuteFindStatement(coll2.Find("_id = :id").LockExclusive(LockContention.NoWait).Bind("id", 1))); + docResult = coll2.Find("_id = :id").LockExclusive(LockContention.SkipLocked).Bind("id", 1).Execute(); + break; + case LockMode.Shared: + Assert.Throws(() => ExecuteFindStatement(coll2.Find("_id = :id").LockShared(LockContention.NoWait).Bind("id", 1))); + docResult = coll2.Find("_id = :id").LockShared(LockContention.SkipLocked).Bind("id", 1).Execute(); + break; + } + Assert.That(docResult.FetchAll().Count, Is.EqualTo(0), "Matching the document ID"); + + session.SQL("ROLLBACK").Execute(); + session2.SQL("ROLLBACK").Execute(); + } + } + + [Test, Description("Multiple lock calls using NOWAIT and SKIPLOCK waiting option. ")] + public void MultipleLocksWithNowaitAndSkiplock() + { + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); + ExecuteSQLStatement(session.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); + using (var session2 = MySQLX.GetSession(ConnectionString)) + { + ExecuteSQLStatement(session2.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); + Collection coll = CreateCollection("test"); + session2.SQL("ALTER TABLE `test`.`test` ADD COLUMN `$ix_i_r_index` INT GENERATED ALWAYS AS (JSON_UNQUOTE(JSON_EXTRACT(doc, '$._id'))) VIRTUAL NOT NULL, ADD UNIQUE INDEX `myIndex`(`$ix_i_r_index`)").Execute(); + var docs = new[] + { + new {_id = 1, a = 1}, + new {_id = 2, a = 2}, + new {_id = 3, a = 3} + }; + + coll.Add(docs).Execute(); + var coll2 = session2.GetSchema("test").GetCollection("test"); + + session.SQL("START TRANSACTION").Execute(); + var docResult = coll.Find("_id = 1").LockShared().Execute(); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + + session2.SQL("START TRANSACTION").Execute(); + + session2.SQL("SET SESSION innodb_lock_wait_timeout=1").Execute(); + Assert.Throws(() => ExecuteFindStatement(coll2.Find("_id = :id").LockExclusive(LockContention.SkipLocked).LockExclusive(LockContention.NoWait).Bind("id", 1))); + + docResult = coll2.Find("_id = :id").LockExclusive(LockContention.SkipLocked).LockShared(LockContention.NoWait).Bind("id", 1).Execute(); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + + docResult = coll2.Find("_id = :id").LockExclusive(LockContention.SkipLocked).LockShared(LockContention.SkipLocked).Bind("id", 1).Execute(); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + + docResult = coll2.Find("_id = :id").LockShared(LockContention.SkipLocked).LockExclusive(LockContention.SkipLocked).Bind("id", 1).Execute(); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(0), "Matching the document ID"); + + session.SQL("ROLLBACK").Execute(); + session2.SQL("ROLLBACK").Execute(); + } + } + + [Test, Description("Reading multiple rows in a locked document(lock_shared) using SKIPLOCK and NOWAIT ")] + public void LockSharedMultipleReads() + { + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); + ExecuteSQLStatement(session.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); + using (var session2 = MySQLX.GetSession(ConnectionString)) + { + ExecuteSQLStatement(session2.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); + Collection coll = CreateCollection("test"); + session2.SQL("ALTER TABLE `test`.`test` ADD COLUMN `$ix_i_r_index` INT GENERATED ALWAYS AS (JSON_EXTRACT(doc, '$._id')) VIRTUAL NOT NULL, ADD UNIQUE INDEX `myIndex`(`$ix_i_r_index`)").Execute(); + var docs = new[] + { + new {_id = 1, a = 1}, + new {_id = 2, a = 2}, + new {_id = 3, a = 3} + }; + + coll.Add(docs).Execute(); + var coll2 = session2.GetSchema("test").GetCollection("test"); + + session.SQL("START TRANSACTION").Execute(); + var docResult = coll.Find("_id >1").LockShared().Execute(); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(2), "Matching the document ID"); + + session2.SQL("START TRANSACTION").Execute(); + session2.SQL("SET SESSION innodb_lock_wait_timeout=1").Execute(); + + docResult = coll2.Find("_id < 3").LockShared(LockContention.SkipLocked).Execute(); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(2), "Matching the document ID"); + + docResult = coll2.Find("_id < 3").LockShared(LockContention.NoWait).Execute(); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(2), "Matching the document ID"); + + docResult = coll2.Find("_id < 3").LockExclusive(LockContention.SkipLocked).Execute(); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + + session.SQL("ROLLBACK").Execute(); + session2.SQL("ROLLBACK").Execute(); + } + } + + [Test, Description("Reading multiple rows in an exclusively locked document using SKIPLOCK and NOWAIT ")] + public void LockExclusiveMultipleReads() + { + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); + ExecuteSQLStatement(session.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); + using (var session2 = MySQLX.GetSession(ConnectionString)) + { + ExecuteSQLStatement(session2.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); + Collection coll = CreateCollection("test"); + session2.SQL("ALTER TABLE `test`.`test` ADD COLUMN `$ix_i_r_index` INT GENERATED ALWAYS AS (JSON_EXTRACT(doc, '$._id')) VIRTUAL NOT NULL, ADD UNIQUE INDEX `myIndex`(`$ix_i_r_index`)").Execute(); + var docs = new[] + { + new {_id = 1, a = 1}, + new {_id = 2, a = 2}, + new {_id = 3, a = 3} + }; + + coll.Add(docs).Execute(); + var coll2 = session2.GetSchema("test").GetCollection("test"); + + session.SQL("START TRANSACTION").Execute(); + var docResult = coll.Find("_id >1").LockExclusive().Execute(); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(2), "Matching the document ID"); + + session2.SQL("START TRANSACTION").Execute(); + session2.SQL("SET SESSION innodb_lock_wait_timeout=1").Execute(); + + docResult = coll2.Find("_id < 3").LockShared(LockContention.SkipLocked).Execute(); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + + docResult = coll2.Find("_id < 3").LockExclusive(LockContention.SkipLocked).Execute(); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + + session.SQL("ROLLBACK").Execute(); + session2.SQL("ROLLBACK").Execute(); + } + } + + [Test, Description("Collection.Find() with shared lock and Collection.Modify() normal from two sessions. ")] + public void LockSharedAndModify() + { + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); + ExecuteSQLStatement(session.SQL("SET autocommit = 0")); + using (var session2 = MySQLX.GetSession(ConnectionString)) + { + session2.SQL("SET autocommit = 0").Execute(); + Collection coll = CreateCollection("test"); + session2.SQL("ALTER TABLE `test`.`test` ADD COLUMN `$ix_i_r_index` INT GENERATED ALWAYS AS (JSON_UNQUOTE(JSON_EXTRACT(doc, '$._id'))) VIRTUAL NOT NULL, ADD UNIQUE INDEX `myIndex`(`$ix_i_r_index`)").Execute(); + var docs = new[] + { + new {_id = 1, a = 1}, + new {_id = 2, a = 2}, + new {_id = 3, a = 3} + }; + + coll.Add(docs).Execute(); + var coll2 = session2.GetSchema("test").GetCollection("test"); + + session.SQL("START TRANSACTION").Execute(); + var docResult = coll.Find("_id = 1").LockShared().Execute(); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + session2.SQL("START TRANSACTION").Execute(); + // Should return immediately since document isn't locked. + docResult = coll2.Find("_id = 1").Execute(); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + session2.SQL("SET SESSION innodb_lock_wait_timeout=1").Execute(); + // Should allow to modify immediately since document isn't locked. + var result = coll2.Modify("_id = 2").Set("a", 10).Execute(); + Assert.That((int)result.AffectedItemsCount, Is.EqualTo(1), "Match being done"); + Assert.Throws(() => ExecuteModifyStatement(coll2.Modify("_id = 1").Change("a", 10))); + + session.SQL("ROLLBACK").Execute(); + session2.SQL("ROLLBACK").Execute(); + } + + ExecuteSQLStatement(session.SQL("SET autocommit = 1")); + } + + [Test, Description("Collection.Find() with shared lock from two sessions. ")] + public void LockSharedTwoSessions() + { + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); + ExecuteSQLStatement(session.SQL("SET autocommit = 0")); + using (var session2 = MySQLX.GetSession(ConnectionString)) + { + session2.SQL("SET autocommit = 0").Execute(); + Collection coll = CreateCollection("test"); + session2.SQL("ALTER TABLE `test`.`test` ADD COLUMN `$ix_i_r_index` INT GENERATED ALWAYS AS (JSON_EXTRACT(doc, '$._id')) VIRTUAL NOT NULL, ADD UNIQUE INDEX `myIndex`(`$ix_i_r_index`)").Execute(); + var docs = new[] + { + new {_id = 1, a = 1}, + new {_id = 2, a = 1}, + new {_id = 3, a = 1} + }; + + coll.Add(docs).Execute(); + var coll2 = session2.GetSchema("test").GetCollection("test"); + + session.SQL("START TRANSACTION").Execute(); + var docResult = coll.Find("_id = 1").LockShared().Execute(); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + session2.SQL("START TRANSACTION").Execute(); + // Should return immediately since document isn't locked. + docResult = coll2.Find("_id = 2").LockShared().Execute(); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + // Should return immediately due to LockShared() allows reading by other sessions. + docResult = coll2.Find("_id = 1").LockShared().Execute(); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + session.SQL("ROLLBACK").Execute(); + session2.SQL("ROLLBACK").Execute(); + } + + ExecuteSQLStatement(session.SQL("SET autocommit = 1")); + } + + [Test, Description("Collection.Find() with exclusive lock and Collection.Find() with shared lock from two sessions. ")] + public void LockExclusiveFindAndLockSharedFind() + { + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); + ExecuteSQLStatement(session.SQL("SET autocommit = 0")); + using (var session2 = MySQLX.GetSession(ConnectionString)) + { + session2.SQL("SET autocommit = 0").Execute(); + Collection coll = CreateCollection("test"); + session2.SQL("ALTER TABLE `test`.`test` ADD COLUMN `$ix_i_r_index` INT GENERATED ALWAYS AS (JSON_UNQUOTE(JSON_EXTRACT(doc, '$._id'))) VIRTUAL NOT NULL, ADD UNIQUE INDEX `myIndex`(`$ix_i_r_index`)").Execute(); + var docs = new[] + { + new {_id = 1, a = 1}, + new {_id = 2, a = 1}, + new {_id = 3, a = 1} + }; + + coll.Add(docs).Execute(); + var coll2 = session2.GetSchema("test").GetCollection("test"); + + session.SQL("START TRANSACTION").Execute(); + var docResult = coll.Find("_id = 1").LockExclusive().Execute(); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + session2.SQL("START TRANSACTION").Execute(); + // Should return immediately since document isn't locked. + docResult = coll2.Find("_id = 2").LockShared().Execute(); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + session2.SQL("SET SESSION innodb_lock_wait_timeout=1").Execute(); + // Session2 blocks due to LockExclusive() not allowing to read locked documents. + Assert.Throws(() => ExecuteFindStatement(coll2.Find("_id = 1").LockShared())); + // Session unlocks documents. + session.SQL("ROLLBACK").Execute(); + docResult = coll2.Find("_id = 1").LockShared().Execute(); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + docResult = coll.Find("_id = 1").LockShared().Execute(); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + session2.SQL("ROLLBACK").Execute(); + } + + ExecuteSQLStatement(session.SQL("SET autocommit = 1")); + } + + [Test, Description("Collection.Find() with shared lock and Collection.Find() with exclusive lock from two sessions. ")] + public void LockSharedFindAndExclusiveLocks() + { + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); + ExecuteSQLStatement(session.SQL("SET autocommit = 0")); + using (var session2 = MySQLX.GetSession(ConnectionString)) + { + session2.SQL("SET autocommit = 0").Execute(); + Collection coll = CreateCollection("test"); + session2.SQL("ALTER TABLE `test`.`test` ADD COLUMN `$ix_i_r_index` INT GENERATED ALWAYS AS (JSON_UNQUOTE(JSON_EXTRACT(doc, '$._id'))) VIRTUAL NOT NULL, ADD UNIQUE INDEX `myIndex`(`$ix_i_r_index`)").Execute(); + var docs = new[] + { + new {_id = 1, a = 1}, + new {_id = 2, a = 1}, + new {_id = 3, a = 1} + }; + + coll.Add(docs).Execute(); + var coll2 = session2.GetSchema("test").GetCollection("test"); + + session.SQL("START TRANSACTION").Execute(); + var docResult = coll.Find("_id = 1").LockShared().Execute(); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document IDs"); + docResult = coll.Find("_id = 3").LockShared().Execute(); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document IDs"); + session2.SQL("START TRANSACTION").Execute(); + + // Should return immediately since document isn't locked. + docResult = coll2.Find("_id = 2").LockExclusive().Execute(); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + // Should return immediately due to LockShared() allows reading by other sessions. + docResult = coll2.Find("_id = 2").LockShared().Execute(); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + session2.SQL("SET SESSION innodb_lock_wait_timeout=1").Execute(); + // Session1 blocks due to LockExclusive() not allowing to read locked documents. + coll2.Find("_id = 2").LockExclusive().Execute(); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + Assert.Throws(() => ExecuteFindStatement(coll2.Find("_id = 1").LockExclusive())); + Assert.Throws(() => ExecuteModifyStatement(coll2.Modify("_id = 1").Set("a", 100))); + // Session unlocks documents. + session2.SQL("ROLLBACK").Execute(); + session.SQL("ROLLBACK").Execute(); + } + + ExecuteSQLStatement(session.SQL("SET autocommit = 1")); + } + + [Test, Description("Collection.Find() with exclusive lock and Collection.Find() with exclusive lock from two sessions. ")] + public void LockExclusiveWithRollback() + { + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); + ExecuteSQLStatement(session.SQL("SET autocommit = 0")); + using (var session2 = MySQLX.GetSession(ConnectionString)) + { + session2.SQL("SET autocommit = 0").Execute(); + Collection coll = CreateCollection("test"); + session2.SQL("ALTER TABLE `test`.`test` ADD COLUMN `$ix_i_r_index` INT GENERATED ALWAYS AS (JSON_UNQUOTE(JSON_EXTRACT(doc, '$._id'))) VIRTUAL NOT NULL, ADD UNIQUE INDEX `myIndex`(`$ix_i_r_index`)").Execute(); + var docs = new[] + { + new {_id = 1, a = 1}, + new {_id = 2, a = 1}, + new {_id = 3, a = 1} + }; + + coll.Add(docs).Execute(); + var coll2 = session2.GetSchema("test").GetCollection("test"); + + session.SQL("START TRANSACTION").Execute(); + var docResult = coll.Find("_id = 1").LockExclusive().Execute(); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document IDs"); + session2.SQL("START TRANSACTION").Execute(); + // Should return immediately due to LockShared() allows reading by other sessions. + docResult = coll2.Find("_id = 2").LockExclusive().Execute(); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + session.SQL("SET SESSION innodb_lock_wait_timeout=1").Execute(); + Assert.Throws(() => ExecuteFindStatement(coll.Find("_id = 2").LockExclusive())); + session2.SQL("SET SESSION innodb_lock_wait_timeout=1").Execute(); + // Session1 blocks due to LockExclusive() not allowing to read locked documents. + Assert.Throws(() => ExecuteFindStatement(coll2.Find("_id = 1").LockExclusive())); + // Session unlocks documents. + session2.SQL("ROLLBACK").Execute(); + docResult = coll.Find("_id = 2").LockExclusive().Execute(); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + session.SQL("ROLLBACK").Execute(); + docResult = coll2.Find("_id = 1").LockExclusive().Execute(); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + } + + ExecuteSQLStatement(session.SQL("SET autocommit = 1")); + } + + [Test, Description("Collection.Find() with exclusive lock and Collection.Find() with exclusive lock from two sessions--Select multiple records ")] + public void LockExclusiveWithINSelection() + { + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); + ExecuteSQLStatement(session.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); + using (var session2 = MySQLX.GetSession(ConnectionString)) + { + ExecuteSQLStatement(session2.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); + Collection coll = CreateCollection("test"); + var docs = new[] + { + new {_id = 1, a = 1}, + new {_id = 2, a = 1}, + new {_id = 3, a = 1} + }; + + coll.Add(docs).Execute(); + session2.SQL("ALTER TABLE `test`.`test` ADD COLUMN `$ix_i_r_index` INT GENERATED ALWAYS AS (JSON_UNQUOTE(JSON_EXTRACT(doc, '$._id'))) VIRTUAL NOT NULL, ADD UNIQUE INDEX `myIndex`(`$ix_i_r_index`)").Execute(); + var coll2 = session2.GetSchema("test").GetCollection("test"); + session.SQL("START TRANSACTION").Execute(); + var docResult = coll.Find("_id in (1,3)").LockExclusive().Execute(); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(2), "Matching the document ID"); + session2.SQL("START TRANSACTION").Execute(); + // Should return immediately since document isn't locked. + docResult = coll2.Find("_id = 2").LockExclusive().Execute(); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + // Should return immediately due to LockShared() allows reading by other sessions. + docResult = coll2.Find("_id = 2").LockShared().Execute(); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + session2.SQL("SET SESSION innodb_lock_wait_timeout=1").Execute(); + // Session1 blocks due to LockExclusive() not allowing to read locked documents. + coll2.Find("_id = 2").LockExclusive().Execute(); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + Assert.Throws(() => ExecuteFindStatement(coll2.Find("_id = 1").LockExclusive())); + Assert.Throws(() => ExecuteModifyStatement(coll2.Modify("_id = 1").Set("a", 100))); + // Session unlocks documents. + session2.SQL("ROLLBACK").Execute(); + session.SQL("ROLLBACK").Execute(); + } + + ExecuteSQLStatement(session.SQL("SET autocommit = 1")); + } + + [Test, Description("Collection.Find() with shared lock twice ")] + public void LockSharedReadTwice() + { + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); + ExecuteSQLStatement(session.SQL("SET autocommit = 0")); + using (var session2 = MySQLX.GetSession(ConnectionString)) + { + session2.SQL("SET autocommit = 0").Execute(); + Collection coll = CreateCollection("test"); + session2.SQL("ALTER TABLE `test`.`test` ADD COLUMN `$ix_i_r_index` INT GENERATED ALWAYS AS (JSON_UNQUOTE(JSON_EXTRACT(doc, '$._id'))) VIRTUAL NOT NULL, ADD UNIQUE INDEX `myIndex`(`$ix_i_r_index`)").Execute(); + var docs = new[] + { + new {_id = 1, a = 1}, + new {_id = 2, a = 1}, + new {_id = 3, a = 1} + }; + coll.Add(docs).Execute(); + var coll2 = session2.GetSchema("test").GetCollection("test"); + + session.SQL("START TRANSACTION").Execute(); + var docResult = coll.Find("_id = 1").LockShared().Execute(); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + session2.SQL("START TRANSACTION").Execute(); + + // Should return immediately since document isn't locked. + docResult = coll2.Find("_id = 2").LockExclusive().Execute(); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + docResult = coll2.Find("_id = 2").LockExclusive().Execute(); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + docResult = coll2.Find("_id = 2").LockShared().Execute(); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + docResult = coll2.Find("_id = 2").LockShared().Execute(); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + // Session unlocks documents. + session2.SQL("ROLLBACK").Execute(); + session.SQL("ROLLBACK").Execute(); + } + ExecuteSQLStatement(session.SQL("SET autocommit = 1")); + } + + [Test, Description("Test MySQLX plugin Collection Array or Object contains operator Scenarios-1")] + public void FindInJsonObjects() + { + Assume.That(Platform.IsWindows(), "This test is for Windows OS only"); + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); + + var col = CreateCollection("my_collection_1"); + string json = @"{ ""_id"": 0, ""title"": ""Book 0"" ,""pages"": 10,""name"": ""Jeoff Archer""}"; + Result r = col.Add(json).Execute(); + Assert.That((int)r.AffectedItemsCount, Is.EqualTo(1), "Matching Affected Records Count"); + var foundDocs = col.Find("1 in (1,2,3,6)").Execute(); + Assert.That(foundDocs.FetchAll().Count, Is.EqualTo(1), "Matching Count"); + //var result = col.Find("0 in $._id").Fields("$.name as name, $.pages as pages, $.title as title").Execute(); + foundDocs = col.Find("'Book 0' in $.title").Execute(); + Assert.That(foundDocs.FetchAll().Count, Is.EqualTo(1), "Matching Count"); + foundDocs = col.Find("100 in _id").Execute(); + Assert.That(foundDocs.FetchAll().Count, Is.EqualTo(0), "Matching Count"); + foundDocs = col.Find("100 not in _id").Execute(); + Assert.That(foundDocs.FetchAll().Count, Is.EqualTo(1), "Matching Count"); + + json = @"{ ""_id"" : 99950, ""city"" : ""KETCHIKAN"", ""loc"" : ""[ -133.18479, 55.942471 ]"", ""pop"" : 422, ""state"" : ""AK"" }"; + r = col.Add(json).Execute(); + + + var d = new DbDoc(@"{ ""id"": 1, ""pages"": 20, + ""person"": { ""name"": ""Fred"", ""age"": 45 } + }"); + var d2 = new DbDoc(); + d2.SetValue("id", 1); + d2.SetValue("pages", 20); + d2.SetValue("person", new { name = "Fred", age = 45 }); + + Assert.That(true, Is.EqualTo(d.Equals(d2)), "Matching"); + col.Add(d).Execute(); + + + d = new DbDoc(@"{""id"":100,""FirstName"":""xyz"",""lastname"":""pqr"", + ""address"": + {""house"":44,""city"":""Delhi"",""country"":""india""}}"); + col.Add(d).Execute(); + + d = new DbDoc(@"{""customerId"":100,""FirstName"":""xyz"",""lastname"":""pqr"", + ""address"": + {""house"":44,""city"":""Delhi"",""country"":""india""}, + ""employer"": + {""cmpName"":""ABC"",""type"":""IT""}}"); + col.Add(d).Execute(); + + d = new DbDoc(@"{ ""id"": 1, ""pages"": 20, + ""books"": [ + {""_id"" : 1, ""title"" : ""Book 1""}, + { ""_id"" : 2, ""title"" : ""Book 2"" } + ] + }"); + col.Add(d).Execute(); + + var docs = new[] { new { _id = 1, title = "Book 1" }, new { _id = 2, title = "Book 2" } }; + d2 = new DbDoc(); + d2.SetValue("id", 100); + d2.SetValue("pages", 20); + d2.SetValue("books", docs); + col.Add(d2).Execute(); + + var result = col.Find("0 in $._id").Fields("$._id as _id,$.name as name, $.pages as pages, $.title as title").Execute(); + var res1 = result.FetchOne(); + Assert.That(res1["_id"], Is.EqualTo(0)); + Assert.That(res1["name"], Is.EqualTo("Jeoff Archer")); + Assert.That(res1["pages"], Is.EqualTo(10)); + Assert.That(res1["title"], Is.EqualTo("Book 0")); + + result = col.Find("0 in $._id OR 1 in $._id").Fields("$._id as _id,$.name as name, $.pages as pages, $.title as title").Execute(); + res1 = result.FetchOne(); + Assert.That(res1["_id"], Is.EqualTo(0)); + Assert.That(res1["name"], Is.EqualTo("Jeoff Archer")); + Assert.That(res1["pages"], Is.EqualTo(10)); + Assert.That(res1["title"], Is.EqualTo("Book 0")); + + result = col.Find("0 not in $._id").Fields("$._id as _id,$.name as name, $.pages as pages, $.title as title").Execute(); + var res2 = result.FetchAll(); + Assert.That(res2.Count, Is.EqualTo(6), "Matching the find count"); + + result = col.Find("'Jeoff Archer' in $.name").Execute(); + res1 = result.FetchOne(); + Assert.That(res1["_id"], Is.EqualTo(0)); + Assert.That(res1["name"], Is.EqualTo("Jeoff Archer")); + Assert.That(res1["pages"], Is.EqualTo(10)); + Assert.That(res1["title"], Is.EqualTo("Book 0")); + + result = col.Find("0 not in $._id").Fields().Execute(); + res2 = result.FetchAll(); + Assert.That(res2[0]["_id"], Is.Not.Null); + + var test = new DbDoc(); + test.SetValue("_id", 1); + test.SetValue("age", 3488888888.9); + test.SetValue("name", + "ABBBBBBBBBBBBBBXXXXXXXXXXXXXXXYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYTTTTTTYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYABBBBBBBBBBBBBBXXXXXXXXXXXXXXXYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYTTTTTTYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYABBBBBBBBBBBBBBXXXXXXXXXXXXXXXYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYTTTTTTYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYABBBBBBBBBBBBBBXXXXXXXXXXXXXXXYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYTTTTTTYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYABBBBBBBBBBBBBBXXXXXXXXXXXXXXXYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYTTTTTTYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY"); + + var coll = CreateCollection("my_collection_123456789"); + var res = coll.Add(test).Execute(); + var foundDocs2 = coll + .Find( + "'ABBBBBBBBBBBBBBXXXXXXXXXXXXXXXYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYTTTTTTYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYABBBBBBBBBBBBBBXXXXXXXXXXXXXXXYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYTTTTTTYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYABBBBBBBBBBBBBBXXXXXXXXXXXXXXXYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYTTTTTTYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYABBBBBBBBBBBBBBXXXXXXXXXXXXXXXYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYTTTTTTYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYABBBBBBBBBBBBBBXXXXXXXXXXXXXXXYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYTTTTTTYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY' in $.name") + .Execute(); + var docs1 = foundDocs2.FetchAll(); + Assert.That(docs1.Count, Is.EqualTo(1)); + foundDocs2 = coll.Find("3488888888.9 in $.age").Execute(); + docs1 = foundDocs2.FetchAll(); + Assert.That(docs1.Count, Is.EqualTo(1)); + } + + [Test, Description("Test MySQLX plugin Collection Array or Object contains operator Scenarios-3")] + public void FindAndCountJsonValues() + { + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); + + var col = CreateCollection("my_collection_1"); + Result add; + add = col.Add("{ \"name\": \"abcdefghijk\", \"age\": 1 , \"misc\": \"10-15-2017\"}") + .Add("{ \"name\": \"xyz\", \"age\": 6 , \"misc\": \"19.5\"}").Execute(); + add = col.Add("{ \"name\": \"qwerty@#$%^&\", \"age\": 4 , \"misc\": \"11.9\"}").Execute(); + add = col.Add("{ \"name\": [\"name1\", \"name2\", \"name3\"], \"age\": 1 , \"misc\": \"1.2\"}").Execute(); + add = col.Add( + "{ \"name\": {\"first\" : \"ABCDEF1\", \"middle\" : \"ABCDEF2\", \"last\" : \"ABCDEF3\"}, " + + "\"age\": 1 , \"misc\": \"1.2\"}") + .Execute(); + add = col.Add( + "{ \"name\": {\"first\" : \"ABCDEF1\", \"middle\" : \"ABCDEF2\", \"last\" : \"ABCDEF3\"}, " + + "\"age\": 2, \"misc\": \"1.2\"}") + .Execute(); + var docs = col.Find().Execute(); + var result1 = col.Find("\"10-15-2017\" in $.misc").Execute().FetchAll().Count; + Assert.That(result1, Is.EqualTo(1)); + result1 = col.Find("\"10-15-2019\" in $.misc").Execute().FetchAll().Count; + Assert.That(result1, Is.EqualTo(0)); + var doc = docs.FetchOne(); + var result = col.Find("1 in $.age").Fields("$.name as name, $.age as age, $.misc as misc").Sort("name DESC").Execute(); + Assert.That(result.FetchAll().Count, Is.EqualTo(3)); + var coll = CreateCollection("test"); + coll.Add(new DbDoc("{ \"a\": 1, \"b\": [ 1, \"value\" ], \"d\":\"\", \"ARR1\":[\"Field-1-Data-0\"] }")).Execute(); + result = coll.Find("JSON_TYPE($.ARR1) = 'ARRAY' AND \"Field-1-Data-0\" in $.ARR1").Execute(); + var count = result.FetchAll().Count; + Assert.That(count, Is.EqualTo(1)); + + } + + [Test, Description("Test MySQLX plugin Collection Array or Object contains operator Scenarios-4")] + public void CheckCountAfterSort() + { + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); + var coll = CreateCollection("test"); + coll.Add("{ \"name\": \"abcdefghijk\", \"age\": 1 , \"misc\": 1.2}") + .Add("{ \"name\": \"xyz\", \"age\": 6 , \"misc\": 19.59}").Execute(); + coll.Add("{ \"name\": \"qwerty@#$%^&\", \"age\": 4 , \"misc\": 11.9}").Execute(); + coll.Add("{ \"name\": \"name1\", \"age\": 4 , \"misc\": 11.9}").Execute(); + coll.Add("{ \"name\": [\"name1\", \"name2\", \"name3\"], \"age\": 1 , \"misc\": 1.2}").Execute(); + coll.Add("{ \"name\": {\"first\" : \"ABCDEF1\", \"middle\" : \"ABCDEF2\", \"last\" : \"ABCDEF3\"}, \"age\": 1 , \"misc\": 1.2}").Execute(); + var docs = coll.Find("4 in $.age").Execute().FetchAll().Count; + Assert.That(docs > 0); + var res3 = coll.Find("4 in $.age").Sort("name ASC").Execute().FetchAll(); + Assert.That(res3.Count, Is.EqualTo(docs)); + } + + [Test, Description("Test MySQLX plugin Find with overlap Bugs")] + public void FindUsingOverLapsBug() + { + Assume.That(session.Version.isAtLeast(8, 0, 17), "This test is for MySql 8.0.17 or higher"); + String json = ""; + String[] splName = { "+", "*", "/", "a+b", "#1", "%", "&", "@1", "!1", "~", "^", + "(", ")", "{", "}", "[", "]", "|", "JSON", "ADD", "JSON_EXTRACT", "JSON_OBJECT", + "?", "=", "+", ";", ",", ":", "<", ">", "-"}; + Collection coll = CreateCollection("test"); + for (int i = 0; i < splName.Length; i++) + { + coll.Add("{\"" + splName[i] + "\":\"data" + i + "\",\"ID\":" + i + "}").Execute(); + var docs2 = coll.Find("$.ID OVERLAPS " + i).Fields("$.`" + splName[i] + "` as col1,$.ID as Id").Execute(); + var res2 = docs2.FetchOne(); + Assert.That(res2["Id"].ToString(), Is.EqualTo(i.ToString()), "Matching the ID"); + if (i == 30) + Assert.That("data30", Is.EqualTo("data" + i), "Matching the String"); + else + Assert.That(res2["col1"].ToString(), Is.EqualTo("data" + i), "Matching the String"); + } + + coll = CreateCollection("test"); + json = "{\"_id\":\"1005\",\"F1\": 123,\"F2\":\"ABCD\" }"; + coll.Add(json).Execute(); + json = "{\"_id\":\"1006\",\"F1\": 123,\"F2\":\"1234\" }"; + coll.Add(json).Execute(); + json = "{\"_id\":\"1007\",\"F1\": 123,\"F2\":\"S()R%^\" }"; + coll.Add(json).Execute(); + + var docs1 = coll.Find().Fields("$._id as _id", "1 << 4 as tmp").Execute(); + var res = docs1.FetchAll(); + docs1 = coll.Find().Fields("$._id as _id", "$.F2 ^ 1 as tmp").Execute(); + res = docs1.FetchAll(); + coll.Add("{\"_id\":\"100001\",\"x1\":\"31\", \"x2\":\"13\", \"x3\":\"8\", \"x4\":\"18446744073709551614\"}").Execute(); + + docs1 = coll.Find("CAST($.x1 as SIGNED) | pow(2,$.x1) = $.x1").Fields("$._id as _id, $.x1 as x1, $.x2 as x2, $.x3 as x3 , $.x2 | pow(2,$.x1) as tmp").Execute(); + res = docs1.FetchAll(); + + docs1 = coll.Find("~16 = ~CAST($.F2 as SIGNED)").Fields("$._id as _id,$.F2 as f2, ~1 as tmp").Execute(); + res = docs1.FetchAll(); + int maxrec = 100; + DbDoc newDoc = new DbDoc(); + newDoc.SetValue("_id", maxrec + 1000); + newDoc.SetValue("F1", "Field-1-Data-" + maxrec); + newDoc.SetValue("F2", "Field-2-Data-" + maxrec); + newDoc.SetValue("F3", 300 + maxrec); + coll.Add(newDoc).Execute(); + + json = "{'_id':'" + (maxrec + 1000 + 1) + "','F1':'Field-1-Data-" + (maxrec + 1) + "','F2':'Field-2-Data-" + (maxrec + 1) + "','F3':" + (300 + maxrec + 1) + "}"; + json = json.Replace("'", "\""); + coll.Add(json).Execute(); + json = "{'F1': 'Field-1-Data-9999','F2': 'Field-2-Data-9999','F3': 'Field-3-Data-9999'}".Replace("'", "\""); + coll.Add(json).Add(json.Replace("9", "8")).Execute(); + + var docs = coll.Find("$._id OVERLAPS 1100").Fields("$_id as _id,$.F1 as f1, $.F2 as f2, $.F3 as f3").Execute(); + var res1 = docs.FetchOne(); + Assert.That(res1["_id"].ToString(), Is.EqualTo("1100")); + Assert.That(res1["f1"].ToString(), Is.EqualTo("Field-1-Data-100")); + Assert.That(res1["f2"].ToString(), Is.EqualTo("Field-2-Data-100")); + Assert.That(res1["f3"].ToString(), Is.EqualTo("400")); + Assert.Throws(() => ExecuteFindStatement(coll.Find("$.F2 OVERLAPS #").Fields("$_id as _id,$.F1 as f1, $.F2 as f2, $.F3 as f3"))); + + docs = coll.Find("$.F2 OVERLAPS 'ABCD'").Fields("$_id as _id,$.F1 as f1, $.F2 as f2, $.F3 as f3").Execute(); + res1 = docs.FetchOne(); + Assert.That(res1["_id"], Is.EqualTo("1005")); + Assert.That(res1["f1"], Is.EqualTo(123)); + Assert.That(res1["f2"], Is.EqualTo("ABCD")); + Assert.Throws(() => ExecuteFindStatement(coll.Find("$.F2 OVERLAPS [1234").Fields("$_id as _id,$.F1 as f1, $.F2 as f2, $.F3 as f3"))); + Assert.Throws(() => ExecuteFindStatement(coll.Find("$.F2 OVERLAPS S()R%^").Fields("$_id as _id,$.F1 as f1, $.F2 as f2, $.F3 as f3"))); + + docs = coll.Find("$.F2 OVERLAPS 'S()R%^'").Fields("$_id as _id,$.F1 as f1, $.F2 as f2, $.F3 as f3").Execute(); + res1 = docs.FetchOne(); + Assert.That(res1["_id"], Is.EqualTo("1007")); + Assert.That(res1["f1"], Is.EqualTo(123)); + Assert.That(res1["f2"], Is.EqualTo("S()R%^")); + } + + [Test, Description("Test MySQLX plugin Find with overlap and Many conditions")] + public void FindUsingOverLapsManyConditions() + { + Assume.That(session.Version.isAtLeast(8, 0, 17), "This test is for MySql 8.0.17 or higher"); + int Condition = 45; + int i, j = 0; + String query = ""; + Collection coll = CreateCollection("test"); + for (i = 0; i < 50; i++) + { + coll.Add("{\"_id\":\"" + i + "\",\"TEST1\":" + (1000 + j) + "}").Execute(); + j++; + } + j = 0; + for (i = 0; i < Condition; i++) + { + if (i > 0) + query = query + " OR "; + query = query + "$.TEST1 OVERLAPS " + (1000 + j); + j++; + } + var docs = coll.Find(query).Execute(); + Assert.That(docs.FetchAll().Count > 0); + } + + [Test, Description("Deprecated Find Where")] + public void FindWhere() + { + Collection collection = CreateCollection("test"); + var docs = new[] + { + new { _id = 1, title = "Book 1", pages = 20 }, + new { _id = 2, title = "Book 2", pages = 30 }, + new { _id = 3, title = "Book 3", pages = 40 }, + new { _id = 4, title = "Book 4", pages = 50 }, + }; + var result1 = collection.Add(docs).Execute(); + Assert.That(result1.AffectedItemsCount, Is.EqualTo(4)); + + //Deprecated Find().Where() in 8.0.17 + var result2 = collection.Find("$._id = 1").Where("true").Execute().FetchAll(); + Assert.That(result2.Count, Is.EqualTo(4)); + } + + [Test, Description("Test MySQLX plugin Collection match count")] + public void CollectionFindFieldMatchingCount() + { + Collection col = CreateCollection("my_collection_1"); + Collection col1 = CreateCollection("my_collection_2"); + + var d1 = new DbDoc(); + d1.SetValue("_id", 1); + d1.SetValue("books", "test1"); + d1.SetValue("count", 10); + + var d2 = new DbDoc(); + d2.SetValue("_id", 2); + d2.SetValue("books", "test2"); + d2.SetValue("count", 20); + + var d3 = new DbDoc(); + d3.SetValue("_id", 3); + d3.SetValue("books", "test3"); + d3.SetValue("count", 30); + + var d4 = new DbDoc(); + d4.SetValue("_id", 4); + d4.SetValue("books", "test4"); + d4.SetValue("count", 40); + + var d5 = new DbDoc(); + d5.SetValue("_id", 5); + d5.SetValue("books", "test5"); + d5.SetValue("count", 50); + + var d6 = new DbDoc(); + d6.SetValue("_id", 6); + d6.SetValue("books", "test6"); + d6.SetValue("count", 0); + + var d7 = new DbDoc(); + d7.SetValue("_id", 0); + d7.SetValue("books", "test7"); + d7.SetValue("count", 60); + + var final = col.Add(d1, d2).Add(d3).Execute(); + var res1 = col.Find().Fields("{\"_id\":\"1\",\"books\": \"test1\" }").Fields("{\"_id\":\"2\",\"books\": \"test2\" }").Fields("{\"_id\":\"3\",\"books\": \"test3\" }").Execute().FetchAll(); + res1 = col.Find().Fields(new string[] { "_id", "books", "count" }).Execute().FetchAll(); + Assert.That(res1.Count, Is.EqualTo(3), "Matching the find count"); + Assert.That(res1[0].ToString(), Is.EqualTo(d1.ToString()), "Matching the doc string 1"); + Assert.That(res1[1].ToString(), Is.EqualTo(d2.ToString()), "Matching the doc string 2"); + Assert.That(res1[2].ToString(), Is.EqualTo(d3.ToString()), "Matching the doc string 3"); + final = col.Add(new DbDoc[] { d4, d5 }).Execute(); + var res2 = col.Find().Fields("$._id as _id,$.books as books, $.count as count").Execute().FetchAll(); + Assert.That(res2.Count, Is.EqualTo(5), "Matching the find count"); + Assert.That(res2[0].ToString(), Is.EqualTo(d1.ToString()), "Matching the doc string 1"); + Assert.That(res2[1].ToString(), Is.EqualTo(d2.ToString()), "Matching the doc string 2"); + Assert.That(res2[2].ToString(), Is.EqualTo(d3.ToString()), "Matching the doc string 3"); + Assert.That(res2[3].ToString(), Is.EqualTo(d4.ToString()), "Matching the doc string 4"); + Assert.That(res2[4].ToString(), Is.EqualTo(d5.ToString()), "Matching the doc string 5"); + final = col.Add(d6, d7).Execute(); + var res3 = col.Find().Sort("count ASC").Execute().FetchAll(); + Assert.That(res3[0].ToString(), Is.EqualTo(d6.ToString()), "Matching the doc string 7"); + Assert.That(res3[1].ToString(), Is.EqualTo(d1.ToString()), "Matching the doc string 1"); + Assert.That(res3[2].ToString(), Is.EqualTo(d2.ToString()), "Matching the doc string 2"); + Assert.That(res3[3].ToString(), Is.EqualTo(d3.ToString()), "Matching the doc string 3"); + Assert.That(res3[4].ToString(), Is.EqualTo(d4.ToString()), "Matching the doc string 4"); + Assert.That(res3[5].ToString(), Is.EqualTo(d5.ToString()), "Matching the doc string 5"); + Assert.That(res3[6].ToString(), Is.EqualTo(d7.ToString()), "Matching the doc string 6"); + var res4 = col.Find().Sort("count DESC").Execute().FetchAll(); + Assert.That(res4[0].ToString(), Is.EqualTo(d7.ToString()), "Matching the doc string 6"); + Assert.That(res4[1].ToString(), Is.EqualTo(d5.ToString()), "Matching the doc string 1"); + Assert.That(res4[2].ToString(), Is.EqualTo(d4.ToString()), "Matching the doc string 2"); + Assert.That(res4[3].ToString(), Is.EqualTo(d3.ToString()), "Matching the doc string 3"); + Assert.That(res4[4].ToString(), Is.EqualTo(d2.ToString()), "Matching the doc string 4"); + Assert.That(res4[5].ToString(), Is.EqualTo(d1.ToString()), "Matching the doc string 5"); + Assert.That(res4[6].ToString(), Is.EqualTo(d6.ToString()), "Matching the doc string 7"); + col.Modify("_id = 1").Unset("count").Unset("books").Execute(); + col.Modify("_id = 1").Set("count", 10).Set("books", "test1").Execute(); + + } + + [Test, Description("GetName,Schema and Count")] + public void CollectionGetNameSchemaCount() + { + Assume.That(session.Version.isAtLeast(5, 7, 0), "This test is for MySql 5.7 or higher"); + var col = CreateCollection("my_collection_123456789"); + + Result r = col.Add(@"{ ""_id"": 1, ""foo"": 1 }").Execute(); + long count = col.Count(); + Assert.That(1, Is.EqualTo(count), "Matching the Collection Count"); + + var collectionName = col.Name; + Assert.That("my_collection_123456789", Is.EqualTo(collectionName), "Matching the collection Name"); + + var schema = col.Schema.Name; + Assert.That(schemaName, Is.EqualTo(schema), "Matching the Schema Name"); + + r = col.Add(@"{ ""_id"": 2, ""foo"": 2 }").Execute(); + count = col.Count(); + Assert.That(2, Is.EqualTo(count), "Matching the Collection Count"); + + r = col.Remove("_id=2").Execute(); + count = col.Count(); + Assert.That(1, Is.EqualTo(count), "Matching the Collection Count"); + session.Schema.DropCollection("my_collection_123456789"); + } + + #endregion WL14389 + + } +} + diff --git a/MySQL.Data/tests/MySqlX.Data.Tests/BasicSelectTests.cs b/MySQL.Data/tests/MySqlX.Data.Tests/BasicSelectTests.cs index d0e451116..60709a8b8 100644 --- a/MySQL.Data/tests/MySqlX.Data.Tests/BasicSelectTests.cs +++ b/MySQL.Data/tests/MySqlX.Data.Tests/BasicSelectTests.cs @@ -1,147 +1,148 @@ -// Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data.MySqlClient; -using MySqlX.XDevAPI; -using MySqlX.XDevAPI.Relational; -using System; -using NUnit.Framework; - -namespace MySqlX.Data.Tests -{ - public class BasicSelectTests : BaseTest - { - [Test] - public void SimpleSelect() - { - CreateBooksTable(); - Table books = GetTable("test", "books"); - - RowResult result = ExecuteSelectStatement(books.Select("name", "pages")); - var rows = result.FetchAll(); - Assert.True(result.Columns.Count == 2); - Assert.True(rows.Count == 2); - - var result2 = session.SQL("Select* from test.books").Execute(); - var row2 = result2.FetchOne(); - Assert.True(result2.Columns.Count == 3); - } - - [Test] - public void SimpleSelectWithWhere() - { - CreateBooksTable(); - Table books = GetTable("test", "books"); - - RowResult result = ExecuteSelectStatement(books.Select("name", "pages").Where("pages > 250")); - var rows = result.FetchAll(); - Assert.True(result.Columns.Count == 2); - Assert.That(rows, Has.One.Items); - } - - private void CreateBooksTable() - { - ExecuteSQL("DROP TABLE IF EXISTS test.books"); - ExecuteSQL("CREATE TABLE test.books(id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100), pages INT)"); - ExecuteSQL("INSERT INTO test.books VALUES (NULL, 'Moby Dick', 500)"); - ExecuteSQL("INSERT INTO test.books VALUES (NULL, 'A Tale of Two Cities', 250)"); - } - - public enum LockMode { Exclusive, Shared } - - [TestCase(LockContention.Default, LockMode.Exclusive)] - [TestCase(LockContention.NoWait, LockMode.Exclusive)] - [TestCase(LockContention.SkipLocked, LockMode.Exclusive)] - [TestCase(LockContention.Default, LockMode.Shared)] - [TestCase(LockContention.NoWait, LockMode.Shared)] - [TestCase(LockContention.SkipLocked, LockMode.Shared)] - public void LockExclusiveAndSharedWithWaitingOptions(LockContention lockOption, LockMode lockMode) - { - if (!session.XSession.GetServerVersion().isAtLeast(8, 0, 3)) return; - - CreateBooksTable(); - string tableName = "books"; - string schemaName = "test"; - - // first session locks the row - using (Session s1 = MySQLX.GetSession(ConnectionString)) - { - var t1 = s1.GetSchema(schemaName).GetTable(tableName); - s1.StartTransaction(); - RowResult r1 = ExecuteSelectStatement(t1.Select().Where("id = :id").Bind("id", 1).LockExclusive()); - var rows1 = r1.FetchAll(); - Assert.That(rows1, Has.One.Items); - Assert.AreEqual(1, rows1[0]["id"]); - - // second session tries to read the locked row - using (Session s2 = MySQLX.GetSession(ConnectionString)) - { - var t2 = s2.GetSchema(schemaName).GetTable(tableName); - ExecuteSQLStatement(s2.SQL("SET innodb_lock_wait_timeout = 1")); - s2.StartTransaction(); - var stmt2 = t2.Select(); - if (lockMode == LockMode.Exclusive) - stmt2.LockExclusive(lockOption); - else - stmt2.LockShared(lockOption); - - switch (lockOption) - { - case LockContention.Default: - // error 1205 Lock wait timeout exceeded; try restarting transaction - Assert.AreEqual(1205u, Assert.Throws(() => ExecuteSelectStatement(stmt2).FetchAll()).Code); - break; - case LockContention.NoWait: - // error 1205 Lock wait timeout exceeded; try restarting transaction - uint expectedError = 1205; - if (session.XSession.GetServerVersion().isAtLeast(8, 0, 5)) - // error 3572 Statement aborted because lock(s) could not be acquired immediately and NOWAIT is set - expectedError = 3572; - Assert.AreEqual(expectedError, Assert.Throws(() => ExecuteSelectStatement(stmt2).FetchAll()).Code); - break; - case LockContention.SkipLocked: - if (!session.XSession.GetServerVersion().isAtLeast(8, 0, 5)) - { - // error 1205 Lock wait timeout exceeded; try restarting transaction - Assert.AreEqual(1205u, Assert.Throws(() => ExecuteSelectStatement(stmt2).FetchAll()).Code); - break; - } - var rows2 = ExecuteSelectStatement(stmt2).FetchAll(); - Assert.That(rows2, Has.One.Items); - Assert.AreEqual(2, rows2[0]["id"]); - break; - default: - throw new NotImplementedException(lockOption.ToString()); - } - } - // first session frees the lock - s1.Commit(); - } - } - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data.MySqlClient; +using MySqlX.XDevAPI; +using MySqlX.XDevAPI.Relational; +using System; +using NUnit.Framework; +using NUnit.Framework.Legacy; + +namespace MySqlX.Data.Tests +{ + public class BasicSelectTests : BaseTest + { + [Test] + public void SimpleSelect() + { + CreateBooksTable(); + Table books = GetTable("test", "books"); + + RowResult result = ExecuteSelectStatement(books.Select("name", "pages")); + var rows = result.FetchAll(); + Assert.That(result.Columns.Count == 2); + Assert.That(rows.Count == 2); + + var result2 = session.SQL("Select* from test.books").Execute(); + var row2 = result2.FetchOne(); + Assert.That(result2.Columns.Count == 3); + } + + [Test] + public void SimpleSelectWithWhere() + { + CreateBooksTable(); + Table books = GetTable("test", "books"); + + RowResult result = ExecuteSelectStatement(books.Select("name", "pages").Where("pages > 250")); + var rows = result.FetchAll(); + Assert.That(result.Columns.Count == 2); + Assert.That(rows, Has.One.Items); + } + + private void CreateBooksTable() + { + ExecuteSQL("DROP TABLE IF EXISTS test.books"); + ExecuteSQL("CREATE TABLE test.books(id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100), pages INT)"); + ExecuteSQL("INSERT INTO test.books VALUES (NULL, 'Moby Dick', 500)"); + ExecuteSQL("INSERT INTO test.books VALUES (NULL, 'A Tale of Two Cities', 250)"); + } + + public enum LockMode { Exclusive, Shared } + + [TestCase(LockContention.Default, LockMode.Exclusive)] + [TestCase(LockContention.NoWait, LockMode.Exclusive)] + [TestCase(LockContention.SkipLocked, LockMode.Exclusive)] + [TestCase(LockContention.Default, LockMode.Shared)] + [TestCase(LockContention.NoWait, LockMode.Shared)] + [TestCase(LockContention.SkipLocked, LockMode.Shared)] + public void LockExclusiveAndSharedWithWaitingOptions(LockContention lockOption, LockMode lockMode) + { + if (!session.XSession.GetServerVersion().isAtLeast(8, 0, 3)) return; + + CreateBooksTable(); + string tableName = "books"; + string schemaName = "test"; + + // first session locks the row + using (Session s1 = MySQLX.GetSession(ConnectionString)) + { + var t1 = s1.GetSchema(schemaName).GetTable(tableName); + s1.StartTransaction(); + RowResult r1 = ExecuteSelectStatement(t1.Select().Where("id = :id").Bind("id", 1).LockExclusive()); + var rows1 = r1.FetchAll(); + Assert.That(rows1, Has.One.Items); + Assert.That(rows1[0]["id"], Is.EqualTo(1)); + + // second session tries to read the locked row + using (Session s2 = MySQLX.GetSession(ConnectionString)) + { + var t2 = s2.GetSchema(schemaName).GetTable(tableName); + ExecuteSQLStatement(s2.SQL("SET innodb_lock_wait_timeout = 1")); + s2.StartTransaction(); + var stmt2 = t2.Select(); + if (lockMode == LockMode.Exclusive) + stmt2.LockExclusive(lockOption); + else + stmt2.LockShared(lockOption); + + switch (lockOption) + { + case LockContention.Default: + // error 1205 Lock wait timeout exceeded; try restarting transaction + Assert.That(Assert.Throws(() => ExecuteSelectStatement(stmt2).FetchAll()).Code, Is.EqualTo(1205u)); + break; + case LockContention.NoWait: + // error 1205 Lock wait timeout exceeded; try restarting transaction + uint expectedError = 1205; + if (session.XSession.GetServerVersion().isAtLeast(8, 0, 5)) + // error 3572 Statement aborted because lock(s) could not be acquired immediately and NOWAIT is set + expectedError = 3572; + Assert.That(Assert.Throws(() => ExecuteSelectStatement(stmt2).FetchAll()).Code, Is.EqualTo(expectedError)); + break; + case LockContention.SkipLocked: + if (!session.XSession.GetServerVersion().isAtLeast(8, 0, 5)) + { + // error 1205 Lock wait timeout exceeded; try restarting transaction + Assert.That(Assert.Throws(() => ExecuteSelectStatement(stmt2).FetchAll()).Code, Is.EqualTo(1205u)); + break; + } + var rows2 = ExecuteSelectStatement(stmt2).FetchAll(); + Assert.That(rows2, Has.One.Items); + Assert.That(rows2[0]["id"], Is.EqualTo(2)); + break; + default: + throw new NotImplementedException(lockOption.ToString()); + } + } + // first session frees the lock + s1.Commit(); + } + } + } +} diff --git a/MySQL.Data/tests/MySqlX.Data.Tests/CharsetAndCollationTests.cs b/MySQL.Data/tests/MySqlX.Data.Tests/CharsetAndCollationTests.cs index 47571507a..226d722f5 100644 --- a/MySQL.Data/tests/MySqlX.Data.Tests/CharsetAndCollationTests.cs +++ b/MySQL.Data/tests/MySqlX.Data.Tests/CharsetAndCollationTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2017, 2022, Oracle and/or its affiliates. +// Copyright © 2017, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -31,6 +31,7 @@ using MySqlX.XDevAPI; using MySqlX.XDevAPI.Relational; using NUnit.Framework; +using NUnit.Framework.Legacy; using System; using System.Collections.Generic; using System.Linq; @@ -60,7 +61,7 @@ public void DefaultCharSet() using (var session = MySQLX.GetSession(ConnectionString)) { - Assert.AreEqual("utf8mb4", session.Settings.CharacterSet); + Assert.That(session.Settings.CharacterSet, Is.EqualTo("utf8mb4")); } using (var connection = new MySqlConnection(ConnectionStringRoot)) @@ -69,26 +70,26 @@ public void DefaultCharSet() MySqlCommand cmd = new MySqlCommand("SHOW VARIABLES LIKE 'character_set_connection'", connection); MySqlDataReader reader = cmd.ExecuteReader(); reader.Read(); - Assert.AreEqual("utf8mb4", reader.GetString("Value")); + Assert.That(reader.GetString("Value"), Is.EqualTo("utf8mb4")); reader.Close(); cmd.CommandText = "SHOW VARIABLES LIKE 'character_set_database'"; reader = cmd.ExecuteReader(); reader.Read(); - Assert.AreEqual("utf8mb4", reader.GetString("Value")); + Assert.That(reader.GetString("Value"), Is.EqualTo("utf8mb4")); reader.Close(); cmd.CommandText = "SHOW VARIABLES LIKE 'character_set_server'"; reader = cmd.ExecuteReader(); reader.Read(); - Assert.AreEqual("utf8mb4", reader.GetString("Value")); + Assert.That(reader.GetString("Value"), Is.EqualTo("utf8mb4")); reader.Close(); cmd.CommandText = "SHOW VARIABLES LIKE 'collation_%'"; reader = cmd.ExecuteReader(); while (reader.Read()) { - Assert.AreEqual("utf8mb4_0900_ai_ci", reader.GetString("Value")); + Assert.That(reader.GetString("Value"), Is.EqualTo("utf8mb4_0900_ai_ci")); } reader.Close(); } @@ -104,7 +105,7 @@ public void ValidateCollationMapList() connection.Open(); var command = new MySqlCommand("SELECT id, collation_name FROM INFORMATION_SCHEMA.COLLATIONS", connection); var reader = command.ExecuteReader(); - Assert.True(reader.HasRows); + Assert.That(reader.HasRows); while (reader.Read()) { @@ -114,7 +115,7 @@ public void ValidateCollationMapList() if (!_serverVersion.isAtLeast(8, 0, 30) && collationName.Contains("utf8_")) collationName = collationName.Replace("utf8_", "utf8mb3_"); - Assert.AreEqual(CollationMap.GetCollationName(id), collationName); + Assert.That(collationName, Is.EqualTo(CollationMap.GetCollationName(id))); } } } @@ -131,12 +132,12 @@ public void Utf8mb4CharsetExists() { // Search utf8mb4 database. var result = ExecuteSQLStatement(session.SQL("SHOW COLLATION WHERE id = 255")); - Assert.True(result.HasData); + Assert.That(result.HasData); var data = result.FetchOne(); - Assert.AreEqual("utf8mb4_0900_ai_ci", data.GetString("Collation")); + Assert.That(data.GetString("Collation"), Is.EqualTo("utf8mb4_0900_ai_ci")); // Check in CollationMap. - Assert.AreEqual("utf8mb4_0900_ai_ci", CollationMap.GetCollationName(255)); + Assert.That(CollationMap.GetCollationName(255), Is.EqualTo("utf8mb4_0900_ai_ci")); } } @@ -149,25 +150,25 @@ public void IllegalMixCollations() using (Session session = MySQLX.GetSession(ConnectionString)) { var result = ExecuteSQLStatement(session.SQL("SHOW COLLATION WHERE `Default` ='Yes';")); - Assert.True(result.HasData); + Assert.That(result.HasData); } using (Session session = MySQLX.GetSession(ConnectionString + ";charset=latin1")) { var result = ExecuteSQLStatement(session.SQL("SHOW COLLATION WHERE `Default` ='Yes';")); - Assert.True(result.HasData); + Assert.That(result.HasData); } using (Session session = MySQLX.GetSession(ConnectionString + ";charset=utf8mb4")) { var result = ExecuteSQLStatement(session.SQL("SHOW COLLATION WHERE `Default` ='Yes';")); - Assert.True(result.HasData); + Assert.That(result.HasData); } using (Session session = MySQLX.GetSession(ConnectionString + ";charset=utf-8")) { var result = ExecuteSQLStatement(session.SQL("SHOW COLLATION WHERE `Default` ='Yes';")); - Assert.True(result.HasData); + Assert.That(result.HasData); } } @@ -195,29 +196,29 @@ public void NamesAreReturnedAsStrings() ExecuteSQL("SELECT * FROM view2"); List
tables = test.GetTables(); - Assert.AreEqual(4, tables.Count); - Assert.AreEqual(2, tables.FindAll(i => !i.IsView).Count); - Assert.AreEqual(2, tables.FindAll(i => i.IsView).Count); + Assert.That(tables.Count, Is.EqualTo(4)); + Assert.That(tables.FindAll(i => !i.IsView).Count, Is.EqualTo(2)); + Assert.That(tables.FindAll(i => i.IsView).Count, Is.EqualTo(2)); ExecuteSelectStatement(tables[0].Select()); ExecuteSelectStatement(tables[1].Select()); ExecuteSelectStatement(tables[2].Select()); ExecuteSelectStatement(tables[3].Select()); - Assert.AreEqual("test1", tables[0].Name); - Assert.AreEqual("test2", tables[1].Name); - Assert.AreEqual("view1", tables[2].Name); - Assert.AreEqual("view2", tables[3].Name); + Assert.That(tables[0].Name, Is.EqualTo("test1")); + Assert.That(tables[1].Name, Is.EqualTo("test2")); + Assert.That(tables[2].Name, Is.EqualTo("view1")); + Assert.That(tables[3].Name, Is.EqualTo("view2")); Table table = test.GetTable("test2"); - Assert.AreEqual("test2", table.Name); + Assert.That(table.Name, Is.EqualTo("test2")); Collection c = test.CreateCollection("coll"); List collections = test.GetCollections(); Assert.That(collections, Has.One.Items); - Assert.AreEqual("coll", collections[0].Name); + Assert.That(collections[0].Name, Is.EqualTo("coll")); Collection collection = test.GetCollection("coll"); - Assert.AreEqual("coll", collection.Name); + Assert.That(collection.Name, Is.EqualTo("coll")); } } @@ -226,7 +227,7 @@ public void NamesAreReturnedAsStrings() [Test, Description("Column Default Datatypes")] public void ColumnDefaultDatatypes() { - if (!session.Version.isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher"); + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); session.SQL($"USE {schemaName}").Execute(); session.SQL("Drop table if exists address").Execute(); session.SQL("CREATE TABLE address" + @@ -287,46 +288,46 @@ public void ColumnDefaultDatatypes() for (int i = 0; i < columns.Length; i++) { var tableType = result.Columns[i].Type; - Assert.AreEqual(columnTypeMatch[i], tableType.ToString(), "Matching the table Type"); + Assert.That(tableType.ToString(), Is.EqualTo(columnTypeMatch[i]), "Matching the table Type"); string tableLabel = result.Columns[i].TableLabel; - Assert.AreEqual("address", tableLabel, "Matching the table label"); + Assert.That(tableLabel, Is.EqualTo("address"), "Matching the table label"); string columnName = result.Columns[i].ColumnName; - Assert.AreEqual(columns[i].ToString(), columnName, "Matching the Column Name"); + Assert.That(columnName, Is.EqualTo(columns[i].ToString()), "Matching the Column Name"); string columnLabel = result.Columns[i].ColumnLabel; - Assert.AreEqual(columns[i].ToString(), columnLabel, "Matching the Column Label"); + Assert.That(columnLabel, Is.EqualTo(columns[i].ToString()), "Matching the Column Label"); uint columnLength = result.Columns[i].Length; - Assert.AreEqual(columnLength, columnLength, "Matching the Column Length"); + Assert.That(columnLength, Is.EqualTo(columnLength), "Matching the Column Length"); var columnType = result.Columns[i].Type; - Assert.AreEqual(columnTypeMatch[i], columnType.ToString(), "Matching the Column Type"); + Assert.That(columnType.ToString(), Is.EqualTo(columnTypeMatch[i]), "Matching the Column Type"); var columnFD = result.Columns[i].FractionalDigits; - Assert.AreEqual(FDLength[i], columnFD, "Matching the Column FD"); + Assert.That(columnFD, Is.EqualTo(FDLength[i]), "Matching the Column FD"); var columnIsSigned = result.Columns[i].IsNumberSigned; - Assert.AreEqual(columnIsSignedMatch[i], columnIsSigned.ToString(), "Matching whether column is signed or not"); + Assert.That(columnIsSigned.ToString(), Is.EqualTo(columnIsSignedMatch[i]), "Matching whether column is signed or not"); string columnCollation = result.Columns[i].CollationName; if (i == 10 || i == 11 || i == 12 || i == 13 || i == 14 || i == 20 || i == 21) - Assert.AreEqual(columnCollation, columnCollation, "Matching the Collation Name for default characters"); + Assert.That(columnCollation, Is.EqualTo(columnCollation), "Matching the Collation Name for default characters"); else if (i == 15 || i == 16 || i == 17 || i == 18 || i == 19) - Assert.AreEqual("binary", columnCollation, "Matching the Collation Name for default characters"); + Assert.That(columnCollation, Is.EqualTo("binary"), "Matching the Collation Name for default characters"); else - Assert.AreEqual(null, columnCollation, "Matching the Collation Name as null for data types other than characters"); + Assert.That(columnCollation, Is.EqualTo(null), "Matching the Collation Name as null for data types other than characters"); string columnCharacterSet = result.Columns[i].CharacterSetName; if (i == 10 || i == 11 || i == 12 || i == 13 || i == 14 || i == 20 || i == 21) - Assert.AreEqual(columnCharacterSet, columnCharacterSet, "Matching the CharacterSet Name for default characters"); + Assert.That(columnCharacterSet, Is.EqualTo(columnCharacterSet), "Matching the CharacterSet Name for default characters"); else if (i == 15 || i == 16 || i == 17 || i == 18 || i == 19) - Assert.AreEqual("binary", columnCharacterSet, "Matching the Collation Name for default characters"); + Assert.That(columnCharacterSet, Is.EqualTo("binary"), "Matching the Collation Name for default characters"); else - Assert.AreEqual(null, columnCharacterSet, "Matching the Collation Name as null for data types other than characters"); + Assert.That(columnCharacterSet, Is.EqualTo(null), "Matching the Collation Name as null for data types other than characters"); var columnIsPadded = result.Columns[i].IsPadded; - Assert.AreEqual(columnIsPaddedMatch[i], columnIsPadded.ToString(), "Matching whether column is padded or not"); + Assert.That(columnIsPadded.ToString(), Is.EqualTo(columnIsPaddedMatch[i]), "Matching whether column is padded or not"); var columnClrType = result.Columns[i].ClrType; - Assert.AreEqual(clrTypeMatch[i], columnClrType.ToString(), "Matching whether column CLR Type"); + Assert.That(columnClrType.ToString(), Is.EqualTo(clrTypeMatch[i]), "Matching whether column CLR Type"); } } [Test, Description("Column Custom Datatypes(Unsigned,Padded,CharacterSet,Collation)")] public void ColumnCustomDatatypes() { - if (!session.Version.isAtLeast(8, 0, 14)) Assert.Ignore("This test is for MySql 8.0.14 or higher"); + Assume.That(session.Version.isAtLeast(8, 0, 14), "This test is for MySql 8.0.14 or higher"); var defaultCharset = "utf8mb4"; session.SQL($"USE {schemaName}").Execute(); session.SQL("CREATE TABLE IF NOT EXISTS address" + @@ -387,37 +388,37 @@ public void ColumnCustomDatatypes() for (int i = 0; i < columns.Length; i++) { string tableLabel = result.Columns[i].TableLabel; - Assert.AreEqual("address", tableLabel, "Matching the table label"); + Assert.That(tableLabel, Is.EqualTo("address"), "Matching the table label"); string columnName = result.Columns[i].ColumnName; - Assert.AreEqual(columns[i].ToString(), columnName, "Matching the Column Name"); + Assert.That(columnName, Is.EqualTo(columns[i].ToString()), "Matching the Column Name"); string columnLabel = result.Columns[i].ColumnLabel; - Assert.AreEqual(columns[i].ToString(), columnLabel, "Matching the Column Label"); + Assert.That(columnLabel, Is.EqualTo(columns[i].ToString()), "Matching the Column Label"); uint columnLength = result.Columns[i].Length; - Assert.AreEqual(Length[i], columnLength, "Matching the Column Length"); + Assert.That(columnLength, Is.EqualTo(Length[i]), "Matching the Column Length"); var columnType = result.Columns[i].Type; - Assert.AreEqual(columnTypeMatch[i], columnType.ToString(), "Matching the Column Type"); + Assert.That(columnType.ToString(), Is.EqualTo(columnTypeMatch[i]), "Matching the Column Type"); var columnFD = result.Columns[i].FractionalDigits; - Assert.AreEqual(FDLength[i], columnFD, "Matching the Column FD"); + Assert.That(columnFD, Is.EqualTo(FDLength[i]), "Matching the Column FD"); var columnIsSigned = result.Columns[i].IsNumberSigned; - Assert.AreEqual(columnIsSignedMatch[i], columnIsSigned.ToString(), "Matching whether column is signed or not"); + Assert.That(columnIsSigned.ToString(), Is.EqualTo(columnIsSignedMatch[i]), "Matching whether column is signed or not"); string columnCollation = result.Columns[i].CollationName; if (i == 10 || i == 11 || i == 12 || i == 13 || i == 14 || i == 20 || i == 21) - Assert.AreEqual(columnCollation, columnCollation, "Matching the Collation Name for default characters"); + Assert.That(columnCollation, Is.EqualTo(columnCollation), "Matching the Collation Name for default characters"); else if (i == 15 || i == 16 || i == 17 || i == 18 || i == 19) - Assert.AreEqual("binary", columnCollation, "Matching the Collation Name for default characters"); + Assert.That(columnCollation, Is.EqualTo("binary"), "Matching the Collation Name for default characters"); else - Assert.AreEqual(null, columnCollation, "Matching the Collation Name as null for data types other than characters"); + Assert.That(columnCollation, Is.EqualTo(null), "Matching the Collation Name as null for data types other than characters"); string columnCharacterSet = result.Columns[i].CharacterSetName; if (i == 10 || i == 11 || i == 12 || i == 13 || i == 14 || i == 20 || i == 21) - StringAssert.AreEqualIgnoringCase(defaultCharset, columnCharacterSet, "Matching the CharacterSet Name for default characters"); + Assert.That(columnCharacterSet, Is.EqualTo(defaultCharset).IgnoreCase, "Matching the CharacterSet Name for default characters"); else if (i == 15 || i == 16 || i == 17 || i == 18 || i == 19) - Assert.AreEqual("binary", columnCharacterSet, "Matching the Collation Name for default characters"); + Assert.That(columnCharacterSet, Is.EqualTo("binary"), "Matching the Collation Name for default characters"); else - Assert.AreEqual(null, columnCharacterSet, "Matching the Collation Name as null for data types other than characters"); + Assert.That(columnCharacterSet, Is.EqualTo(null), "Matching the Collation Name as null for data types other than characters"); var columnIsPadded = result.Columns[i].IsPadded; - Assert.AreEqual(columnIsPaddedMatch[i], columnIsPadded.ToString(), "Matching whether column is padded or not"); + Assert.That(columnIsPadded.ToString(), Is.EqualTo(columnIsPaddedMatch[i]), "Matching whether column is padded or not"); var columnClrType = result.Columns[i].ClrType; - Assert.AreEqual(clrTypeMatch[i], columnClrType.ToString(), "Matching whether column CLR Type"); + Assert.That(columnClrType.ToString(), Is.EqualTo(clrTypeMatch[i]), "Matching whether column CLR Type"); } session.SQL($"drop table if exists address").Execute(); } @@ -425,7 +426,7 @@ public void ColumnCustomDatatypes() [Test, Description("Column Join Two tables")] public void ColumnJoin() { - if (!session.Version.isAtLeast(8, 0, 14)) Assert.Ignore("This test is for MySql 8.0.14 or higher"); + Assume.That(session.Version.isAtLeast(8, 0, 14), "This test is for MySql 8.0.14 or higher"); var defaultCharset = "utf8mb4"; session.SQL($"USE {schemaName}").Execute(); session.SQL("CREATE TABLE address1" + @@ -480,73 +481,73 @@ public void ColumnJoin() for (int i = 0; i < columns1.Length; i++) { string tableName = result1.Columns[i].TableName; - Assert.AreEqual("result1", tableName, "Matching the table name"); + Assert.That(tableName, Is.EqualTo("result1"), "Matching the table name"); string tableLabel = result1.Columns[i].TableLabel; - Assert.AreEqual("result1", tableLabel, "Matching the table label"); + Assert.That(tableLabel, Is.EqualTo("result1"), "Matching the table label"); string columnName = result1.Columns[i].ColumnName; - Assert.AreEqual(columns1[i].ToString(), columnName, "Matching the Column Name"); + Assert.That(columnName, Is.EqualTo(columns1[i].ToString()), "Matching the Column Name"); string columnLabel = result1.Columns[i].ColumnLabel; - Assert.AreEqual(columns1[i].ToString(), columnLabel, "Matching the Column Label"); + Assert.That(columnLabel, Is.EqualTo(columns1[i].ToString()), "Matching the Column Label"); uint columnLength = result1.Columns[i].Length; - Assert.AreEqual(Length1[i], Length1[i], "Matching the Column Length"); + Assert.That(Length1[i], Is.EqualTo(Length1[i]), "Matching the Column Length"); var columnType = result1.Columns[i].Type; - Assert.AreEqual(columnTypeMatch1[i], columnType.ToString(), "Matching the Column Type"); + Assert.That(columnType.ToString(), Is.EqualTo(columnTypeMatch1[i]), "Matching the Column Type"); var columnFD = result1.Columns[i].FractionalDigits; - Assert.AreEqual(FDLength1[i], columnFD, "Matching the Column FD"); + Assert.That(columnFD, Is.EqualTo(FDLength1[i]), "Matching the Column FD"); var columnIsSigned = result1.Columns[i].IsNumberSigned; - Assert.AreEqual(columnIsSignedMatch1[i], columnIsSigned.ToString(), "Matching whether column is signed or not"); + Assert.That(columnIsSigned.ToString(), Is.EqualTo(columnIsSignedMatch1[i]), "Matching whether column is signed or not"); string columnCollation = result1.Columns[i].CollationName; if (i == 2 || i == 5) { - StringAssert.Contains(defaultCharset, columnCollation, "Matching the Collation Name for default characters"); + Assert.That(columnCollation, Does.Contain(defaultCharset), "Matching the Collation Name for default characters"); } else { - Assert.AreEqual(null, columnCollation, "Matching the Collation Name as null for data types other than characters"); + Assert.That(columnCollation, Is.EqualTo(null), "Matching the Collation Name as null for data types other than characters"); } string columnCharacterSet = result1.Columns[i].CharacterSetName; if (i == 2 || i == 5) - StringAssert.AreEqualIgnoringCase(defaultCharset, columnCharacterSet, "Matching the CharacterSet Name for default characters"); + Assert.That(columnCharacterSet, Is.EqualTo(defaultCharset).IgnoreCase, "Matching the CharacterSet Name for default characters"); else - Assert.AreEqual(null, columnCharacterSet, "Matching the Collation Name as null for data types other than characters"); + Assert.That(columnCharacterSet, Is.EqualTo(null), "Matching the Collation Name as null for data types other than characters"); var columnIsPadded = result1.Columns[i].IsPadded; - Assert.AreEqual(columnIsPaddedMatch1[i], columnIsPadded.ToString(), "Matching whether column is padded or not"); + Assert.That(columnIsPadded.ToString(), Is.EqualTo(columnIsPaddedMatch1[i]), "Matching whether column is padded or not"); var columnClrType = result1.Columns[i].ClrType; - Assert.AreEqual(clrTypeMatch1[i], columnClrType.ToString(), "Matching whether column CLR Type"); + Assert.That(columnClrType.ToString(), Is.EqualTo(clrTypeMatch1[i]), "Matching whether column CLR Type"); } for (int i = 0; i < columns2.Length; i++) { string tableName = result2.Columns[i].TableName; - Assert.AreEqual("result2", tableName, "Matching the table name"); + Assert.That(tableName, Is.EqualTo("result2"), "Matching the table name"); string tableLabel = result2.Columns[i].TableLabel; - Assert.AreEqual("result2", tableLabel, "Matching the table label"); + Assert.That(tableLabel, Is.EqualTo("result2"), "Matching the table label"); string columnName = result2.Columns[i].ColumnName; - Assert.AreEqual(columns2[i].ToString(), columnName, "Matching the Column Name"); + Assert.That(columnName, Is.EqualTo(columns2[i].ToString()), "Matching the Column Name"); string columnLabel = result2.Columns[i].ColumnLabel; - Assert.AreEqual(columns2[i].ToString(), columnLabel, "Matching the Column Label"); + Assert.That(columnLabel, Is.EqualTo(columns2[i].ToString()), "Matching the Column Label"); uint columnLength = result2.Columns[i].Length; - Assert.AreEqual(Length2[i], columnLength, "Matching the Column Length"); + Assert.That(columnLength, Is.EqualTo(Length2[i]), "Matching the Column Length"); var columnType = result2.Columns[i].Type; - Assert.AreEqual(columnTypeMatch2[i], columnType.ToString(), "Matching the Column Type"); + Assert.That(columnType.ToString(), Is.EqualTo(columnTypeMatch2[i]), "Matching the Column Type"); var columnFD = result2.Columns[i].FractionalDigits; - Assert.AreEqual(FDLength2[i], columnFD, "Matching the Column FD"); + Assert.That(columnFD, Is.EqualTo(FDLength2[i]), "Matching the Column FD"); var columnIsSigned = result2.Columns[i].IsNumberSigned; - Assert.AreEqual(columnIsSignedMatch2[i], columnIsSigned.ToString(), "Matching whether column is signed or not"); + Assert.That(columnIsSigned.ToString(), Is.EqualTo(columnIsSignedMatch2[i]), "Matching whether column is signed or not"); string columnCollation = result2.Columns[i].CollationName; if (i == 2) - StringAssert.Contains(defaultCharset, columnCollation, "Matching the Collation Name for default characters"); + Assert.That(columnCollation, Does.Contain(defaultCharset), "Matching the Collation Name for default characters"); else - Assert.AreEqual(null, columnCollation, "Matching the Collation Name as null for data types other than characters"); + Assert.That(columnCollation, Is.EqualTo(null), "Matching the Collation Name as null for data types other than characters"); string columnCharacterSet = result2.Columns[i].CharacterSetName; if (i == 2) - StringAssert.AreEqualIgnoringCase(defaultCharset, columnCharacterSet, "Matching the CharacterSet Name for default characters"); + Assert.That(columnCharacterSet, Is.EqualTo(defaultCharset).IgnoreCase, "Matching the CharacterSet Name for default characters"); else - Assert.AreEqual(null, columnCharacterSet, "Matching the Collation Name as null for data types other than characters"); + Assert.That(columnCharacterSet, Is.EqualTo(null), "Matching the Collation Name as null for data types other than characters"); var columnIsPadded = result2.Columns[i].IsPadded; - Assert.AreEqual(columnIsPaddedMatch2[i], columnIsPadded.ToString(), "Matching whether column is padded or not"); + Assert.That(columnIsPadded.ToString(), Is.EqualTo(columnIsPaddedMatch2[i]), "Matching whether column is padded or not"); var columnClrType = result2.Columns[i].ClrType; - Assert.AreEqual(clrTypeMatch2[i], columnClrType.ToString(), "Matching whether column CLR Type"); + Assert.That(columnClrType.ToString(), Is.EqualTo(clrTypeMatch2[i]), "Matching whether column CLR Type"); } session.SQL("DROP TABLE if exists test").Execute(); @@ -554,95 +555,95 @@ public void ColumnJoin() session.SQL("INSERT INTO test VALUES('Bob')").Execute(); result2 = session.GetSchema(schemaName).GetTable("test").Select("1 + 1 as a", "b").Execute(); var rows = result2.FetchAll(); - Assert.AreEqual(2, result2.Columns.Count, "Matching Column Count"); - - Assert.AreEqual(null, result2.Columns[0].SchemaName, "Matching Column Schema Name"); - Assert.AreEqual(null, result2.Columns[0].TableName, "Matching Column Table Name"); - Assert.AreEqual(null, result2.Columns[0].TableLabel, "Matching Column Table Label"); - Assert.AreEqual(null, result2.Columns[0].ColumnName, "Matching Column Name"); - Assert.AreEqual("a", result2.Columns[0].ColumnLabel, "Matching Column Label"); - Assert.AreEqual("Tinyint", result2.Columns[0].Type.ToString(), "Matching Column Type"); - Assert.AreEqual(3u, result2.Columns[0].Length, "Matching Column Length"); - Assert.AreEqual(0u, result2.Columns[0].FractionalDigits, "Matching Column FD"); - Assert.AreEqual(true, result2.Columns[0].IsNumberSigned, "Matching Column Is Signed"); - Assert.AreEqual(null, result2.Columns[0].CharacterSetName, "Matching Character Set Name"); - Assert.AreEqual(null, result2.Columns[0].CollationName, "Matching Collation Name"); - Assert.AreEqual(false, result2.Columns[0].IsPadded, "Matching Column Padded"); - - Assert.AreEqual(schemaName, result2.Columns[1].SchemaName, "Matching Column Schema Name"); - Assert.AreEqual("test", result2.Columns[1].TableName, "Matching Column Table Name"); - Assert.AreEqual("test", result2.Columns[1].TableLabel, "Matching Column Table Label"); - Assert.AreEqual("b", result2.Columns[1].ColumnName, "Matching Column Name"); - Assert.AreEqual("b", result2.Columns[1].ColumnLabel, "Matching Column Label"); - Assert.AreEqual("String", result2.Columns[1].Type.ToString(), "Matching Column Type"); - Assert.AreEqual(1020u, result2.Columns[1].Length, "Matching Column Length"); - Assert.AreEqual(0u, result2.Columns[1].FractionalDigits, "Matching Column FD"); - Assert.AreEqual(false, result2.Columns[1].IsNumberSigned, "Matching Column Is Signed"); - Assert.AreEqual(defaultCharset, result2.Columns[1].CharacterSetName, "Matching Character Set Name"); - StringAssert.Contains(defaultCharset, result2.Columns[1].CollationName, "Matching Collation Name"); - Assert.AreEqual(false, result2.Columns[1].IsPadded, "Matching Column Padded"); + Assert.That(result2.Columns.Count, Is.EqualTo(2), "Matching Column Count"); + + Assert.That(result2.Columns[0].SchemaName, Is.EqualTo(null), "Matching Column Schema Name"); + Assert.That(result2.Columns[0].TableName, Is.EqualTo(null), "Matching Column Table Name"); + Assert.That(result2.Columns[0].TableLabel, Is.EqualTo(null), "Matching Column Table Label"); + Assert.That(result2.Columns[0].ColumnName, Is.EqualTo(null), "Matching Column Name"); + Assert.That(result2.Columns[0].ColumnLabel, Is.EqualTo("a"), "Matching Column Label"); + Assert.That(result2.Columns[0].Type.ToString(), Is.EqualTo("Tinyint"), "Matching Column Type"); + Assert.That(result2.Columns[0].Length, Is.EqualTo(3u), "Matching Column Length"); + Assert.That(result2.Columns[0].FractionalDigits, Is.EqualTo(0u), "Matching Column FD"); + Assert.That(result2.Columns[0].IsNumberSigned, Is.EqualTo(true), "Matching Column Is Signed"); + Assert.That(result2.Columns[0].CharacterSetName, Is.EqualTo(null), "Matching Character Set Name"); + Assert.That(result2.Columns[0].CollationName, Is.EqualTo(null), "Matching Collation Name"); + Assert.That(result2.Columns[0].IsPadded, Is.EqualTo(false), "Matching Column Padded"); + + Assert.That(result2.Columns[1].SchemaName, Is.EqualTo(schemaName), "Matching Column Schema Name"); + Assert.That(result2.Columns[1].TableName, Is.EqualTo("test"), "Matching Column Table Name"); + Assert.That(result2.Columns[1].TableLabel, Is.EqualTo("test"), "Matching Column Table Label"); + Assert.That(result2.Columns[1].ColumnName, Is.EqualTo("b"), "Matching Column Name"); + Assert.That(result2.Columns[1].ColumnLabel, Is.EqualTo("b"), "Matching Column Label"); + Assert.That(result2.Columns[1].Type.ToString(), Is.EqualTo("String"), "Matching Column Type"); + Assert.That(result2.Columns[1].Length, Is.EqualTo(1020u), "Matching Column Length"); + Assert.That(result2.Columns[1].FractionalDigits, Is.EqualTo(0u), "Matching Column FD"); + Assert.That(result2.Columns[1].IsNumberSigned, Is.EqualTo(false), "Matching Column Is Signed"); + Assert.That(result2.Columns[1].CharacterSetName, Is.EqualTo(defaultCharset), "Matching Character Set Name"); + Assert.That(result2.Columns[1].CollationName, Does.Contain(defaultCharset), "Matching Collation Name"); + Assert.That(result2.Columns[1].IsPadded, Is.EqualTo(false), "Matching Column Padded"); session.SQL("create table test1(c1 int,c2 double GENERATED ALWAYS AS (c1*101/102) Stored COMMENT 'First Gen Col',c3 Json GENERATED ALWAYS AS (concat('{\"F1\":',c1,'}')) VIRTUAL COMMENT 'Second Gen /**/Col', c4 bigint GENERATED ALWAYS as (c1*10000) VIRTUAL UNIQUE KEY Comment '3rd Col' NOT NULL)").Execute(); session.SQL("insert into test1(c1) values(1000)").Execute(); result2 = session.GetSchema(schemaName).GetTable("test1").Select("c1").Execute(); - Assert.AreEqual(schemaName, result2.Columns[0].SchemaName, "Matching Column Schema Name"); - Assert.AreEqual("test1", result2.Columns[0].TableName, "Matching Column Table Name"); - Assert.AreEqual("test1", result2.Columns[0].TableLabel, "Matching Column Table Label"); - Assert.AreEqual("c1", result2.Columns[0].ColumnName, "Matching Column Name"); - Assert.AreEqual("c1", result2.Columns[0].ColumnLabel, "Matching Column Label"); - Assert.AreEqual("Int", result2.Columns[0].Type.ToString(), "Matching Column Type"); - Assert.AreEqual(11, result2.Columns[0].Length, "Matching Column Length"); - Assert.AreEqual(0u, result2.Columns[0].FractionalDigits, "Matching Column FD"); - Assert.AreEqual(true, result2.Columns[0].IsNumberSigned, "Matching Column Is Signed"); - Assert.AreEqual(null, result2.Columns[0].CharacterSetName, "Matching Character Set Name"); - Assert.AreEqual(null, result2.Columns[0].CollationName, "Matching Collation Name"); - Assert.AreEqual(false, result2.Columns[0].IsPadded, "Matching Column Padded"); + Assert.That(result2.Columns[0].SchemaName, Is.EqualTo(schemaName), "Matching Column Schema Name"); + Assert.That(result2.Columns[0].TableName, Is.EqualTo("test1"), "Matching Column Table Name"); + Assert.That(result2.Columns[0].TableLabel, Is.EqualTo("test1"), "Matching Column Table Label"); + Assert.That(result2.Columns[0].ColumnName, Is.EqualTo("c1"), "Matching Column Name"); + Assert.That(result2.Columns[0].ColumnLabel, Is.EqualTo("c1"), "Matching Column Label"); + Assert.That(result2.Columns[0].Type.ToString(), Is.EqualTo("Int"), "Matching Column Type"); + Assert.That(result2.Columns[0].Length, Is.EqualTo(11), "Matching Column Length"); + Assert.That(result2.Columns[0].FractionalDigits, Is.EqualTo(0u), "Matching Column FD"); + Assert.That(result2.Columns[0].IsNumberSigned, Is.EqualTo(true), "Matching Column Is Signed"); + Assert.That(result2.Columns[0].CharacterSetName, Is.EqualTo(null), "Matching Character Set Name"); + Assert.That(result2.Columns[0].CollationName, Is.EqualTo(null), "Matching Collation Name"); + Assert.That(result2.Columns[0].IsPadded, Is.EqualTo(false), "Matching Column Padded"); result2 = session.GetSchema(schemaName).GetTable("test1").Select("c2").Execute(); - Assert.AreEqual(schemaName, result2.Columns[0].SchemaName, "Matching Column Schema Name"); - Assert.AreEqual("test1", result2.Columns[0].TableName, "Matching Column Table Name"); - Assert.AreEqual("test1", result2.Columns[0].TableLabel, "Matching Column Table Label"); - Assert.AreEqual("c2", result2.Columns[0].ColumnName, "Matching Column Name"); - Assert.AreEqual("c2", result2.Columns[0].ColumnLabel, "Matching Column Label"); - Assert.AreEqual("Double", result2.Columns[0].Type.ToString(), "Matching Column Type"); - Assert.AreEqual(22, result2.Columns[0].Length, "Matching Column Length"); - Assert.AreEqual(31, result2.Columns[0].FractionalDigits, "Matching Column FD"); - Assert.AreEqual(false, result2.Columns[0].IsNumberSigned, "Matching Column Is Signed"); - Assert.AreEqual(null, result2.Columns[0].CharacterSetName, "Matching Character Set Name"); - Assert.AreEqual(null, result2.Columns[0].CollationName, "Matching Collation Name"); - Assert.AreEqual(false, result2.Columns[0].IsPadded, "Matching Column Padded"); + Assert.That(result2.Columns[0].SchemaName, Is.EqualTo(schemaName), "Matching Column Schema Name"); + Assert.That(result2.Columns[0].TableName, Is.EqualTo("test1"), "Matching Column Table Name"); + Assert.That(result2.Columns[0].TableLabel, Is.EqualTo("test1"), "Matching Column Table Label"); + Assert.That(result2.Columns[0].ColumnName, Is.EqualTo("c2"), "Matching Column Name"); + Assert.That(result2.Columns[0].ColumnLabel, Is.EqualTo("c2"), "Matching Column Label"); + Assert.That(result2.Columns[0].Type.ToString(), Is.EqualTo("Double"), "Matching Column Type"); + Assert.That(result2.Columns[0].Length, Is.EqualTo(22), "Matching Column Length"); + Assert.That(result2.Columns[0].FractionalDigits, Is.EqualTo(31), "Matching Column FD"); + Assert.That(result2.Columns[0].IsNumberSigned, Is.EqualTo(false), "Matching Column Is Signed"); + Assert.That(result2.Columns[0].CharacterSetName, Is.EqualTo(null), "Matching Character Set Name"); + Assert.That(result2.Columns[0].CollationName, Is.EqualTo(null), "Matching Collation Name"); + Assert.That(result2.Columns[0].IsPadded, Is.EqualTo(false), "Matching Column Padded"); result2 = session.GetSchema(schemaName).GetTable("test1").Select("c3").Execute(); - Assert.AreEqual(schemaName, result2.Columns[0].SchemaName, "Matching Column Schema Name"); - Assert.AreEqual("test1", result2.Columns[0].TableName, "Matching Column Table Name"); - Assert.AreEqual("test1", result2.Columns[0].TableLabel, "Matching Column Table Label"); - Assert.AreEqual("c3", result2.Columns[0].ColumnName, "Matching Column Name"); - Assert.AreEqual("c3", result2.Columns[0].ColumnLabel, "Matching Column Label"); - Assert.AreEqual("Json", result2.Columns[0].Type.ToString(), "Matching Column Type"); - Assert.AreEqual(4294967295, result2.Columns[0].Length, "Matching Column Length"); - Assert.AreEqual(0u, result2.Columns[0].FractionalDigits, "Matching Column FD"); - Assert.AreEqual(false, result2.Columns[0].IsNumberSigned, "Matching Column Is Signed"); - Assert.AreEqual("binary", result2.Columns[0].CharacterSetName, "Matching Character Set Name"); - Assert.AreEqual("binary", result2.Columns[0].CollationName, "Matching Collation Name"); - Assert.AreEqual(false, result2.Columns[0].IsPadded, "Matching Column Padded"); + Assert.That(result2.Columns[0].SchemaName, Is.EqualTo(schemaName), "Matching Column Schema Name"); + Assert.That(result2.Columns[0].TableName, Is.EqualTo("test1"), "Matching Column Table Name"); + Assert.That(result2.Columns[0].TableLabel, Is.EqualTo("test1"), "Matching Column Table Label"); + Assert.That(result2.Columns[0].ColumnName, Is.EqualTo("c3"), "Matching Column Name"); + Assert.That(result2.Columns[0].ColumnLabel, Is.EqualTo("c3"), "Matching Column Label"); + Assert.That(result2.Columns[0].Type.ToString(), Is.EqualTo("Json"), "Matching Column Type"); + Assert.That(result2.Columns[0].Length, Is.EqualTo(4294967295), "Matching Column Length"); + Assert.That(result2.Columns[0].FractionalDigits, Is.EqualTo(0u), "Matching Column FD"); + Assert.That(result2.Columns[0].IsNumberSigned, Is.EqualTo(false), "Matching Column Is Signed"); + Assert.That(result2.Columns[0].CharacterSetName, Is.EqualTo("binary"), "Matching Character Set Name"); + Assert.That(result2.Columns[0].CollationName, Is.EqualTo("binary"), "Matching Collation Name"); + Assert.That(result2.Columns[0].IsPadded, Is.EqualTo(false), "Matching Column Padded"); result2 = session.GetSchema(schemaName).GetTable("test1").Select("c4").Execute(); - Assert.AreEqual(schemaName, result2.Columns[0].SchemaName, "Matching Column Schema Name"); - Assert.AreEqual("test1", result2.Columns[0].TableName, "Matching Column Table Name"); - Assert.AreEqual("test1", result2.Columns[0].TableLabel, "Matching Column Table Label"); - Assert.AreEqual("c4", result2.Columns[0].ColumnName, "Matching Column Name"); - Assert.AreEqual("c4", result2.Columns[0].ColumnLabel, "Matching Column Label"); - Assert.AreEqual("Bigint", result2.Columns[0].Type.ToString(), "Matching Column Type"); - Assert.AreEqual(20, result2.Columns[0].Length, "Matching Column Length"); - Assert.AreEqual(0u, result2.Columns[0].FractionalDigits, "Matching Column FD"); - Assert.AreEqual(true, result2.Columns[0].IsNumberSigned, "Matching Column Is Signed"); - Assert.AreEqual(null, result2.Columns[0].CharacterSetName, "Matching Character Set Name"); - Assert.AreEqual(null, result2.Columns[0].CollationName, "Matching Collation Name"); - Assert.AreEqual(false, result2.Columns[0].IsPadded, "Matching Column Padded"); + Assert.That(result2.Columns[0].SchemaName, Is.EqualTo(schemaName), "Matching Column Schema Name"); + Assert.That(result2.Columns[0].TableName, Is.EqualTo("test1"), "Matching Column Table Name"); + Assert.That(result2.Columns[0].TableLabel, Is.EqualTo("test1"), "Matching Column Table Label"); + Assert.That(result2.Columns[0].ColumnName, Is.EqualTo("c4"), "Matching Column Name"); + Assert.That(result2.Columns[0].ColumnLabel, Is.EqualTo("c4"), "Matching Column Label"); + Assert.That(result2.Columns[0].Type.ToString(), Is.EqualTo("Bigint"), "Matching Column Type"); + Assert.That(result2.Columns[0].Length, Is.EqualTo(20), "Matching Column Length"); + Assert.That(result2.Columns[0].FractionalDigits, Is.EqualTo(0u), "Matching Column FD"); + Assert.That(result2.Columns[0].IsNumberSigned, Is.EqualTo(true), "Matching Column Is Signed"); + Assert.That(result2.Columns[0].CharacterSetName, Is.EqualTo(null), "Matching Character Set Name"); + Assert.That(result2.Columns[0].CollationName, Is.EqualTo(null), "Matching Collation Name"); + Assert.That(result2.Columns[0].IsPadded, Is.EqualTo(false), "Matching Column Padded"); session.SQL("DROP TABLE if exists test").Execute(); session.SQL("DROP TABLE if exists test1").Execute(); @@ -683,33 +684,33 @@ public void ColumnCharacterDefaultDatatype() for (int i = 0; i < columns.Length; i++) { string tableLabel = result.Columns[i].TableLabel; - Assert.AreEqual("address", tableLabel, "Matching the table label"); + Assert.That(tableLabel, Is.EqualTo("address"), "Matching the table label"); string columnName = result.Columns[i].ColumnName; - Assert.AreEqual(columns[i].ToString(), columnName, "Matching the Column Name"); + Assert.That(columnName, Is.EqualTo(columns[i].ToString()), "Matching the Column Name"); string columnLabel = result.Columns[i].ColumnLabel; - Assert.AreEqual(columns[i].ToString(), columnLabel, "Matching the Column Label"); + Assert.That(columnLabel, Is.EqualTo(columns[i].ToString()), "Matching the Column Label"); uint columnLength = result.Columns[i].Length; - Assert.AreEqual(columnLength, columnLength, "Matching the Column Length"); + Assert.That(columnLength, Is.EqualTo(columnLength), "Matching the Column Length"); var columnType = result.Columns[i].Type; - Assert.AreEqual(columnTypeMatch[i], columnType.ToString(), "Matching the Column Type"); + Assert.That(columnType.ToString(), Is.EqualTo(columnTypeMatch[i]), "Matching the Column Type"); var columnFD = result.Columns[i].FractionalDigits; - Assert.AreEqual(FDLength[i], columnFD, "Matching the Column FD"); + Assert.That(columnFD, Is.EqualTo(FDLength[i]), "Matching the Column FD"); var columnIsSigned = result.Columns[i].IsNumberSigned; - Assert.AreEqual(columnIsSignedMatch[i], columnIsSigned.ToString(), "Matching whether column is signed or not"); + Assert.That(columnIsSigned.ToString(), Is.EqualTo(columnIsSignedMatch[i]), "Matching whether column is signed or not"); string columnCollation = result.Columns[i].CollationName; if (i == 1 || i == 2 || i == 3 || i == 4 || i == 5) - Assert.AreEqual(columnCollation, columnCollation, "Matching the Collation Name for default characters"); + Assert.That(columnCollation, Is.EqualTo(columnCollation), "Matching the Collation Name for default characters"); else - Assert.AreEqual(null, columnCollation, "Matching the Collation Name as null for data types other than characters"); + Assert.That(columnCollation, Is.EqualTo(null), "Matching the Collation Name as null for data types other than characters"); string columnCharacterSet = result.Columns[i].CharacterSetName; if (i == 1 || i == 2 || i == 3 || i == 4 || i == 5) - Assert.AreEqual(columnCharacterSet, columnCharacterSet, "Matching the CharacterSet Name for default characters"); + Assert.That(columnCharacterSet, Is.EqualTo(columnCharacterSet), "Matching the CharacterSet Name for default characters"); else - Assert.AreEqual(null, columnCharacterSet, "Matching the Collation Name as null for data types other than characters"); + Assert.That(columnCharacterSet, Is.EqualTo(null), "Matching the Collation Name as null for data types other than characters"); var columnIsPadded = result.Columns[i].IsPadded; - Assert.AreEqual(columnIsPaddedMatch[i], columnIsPadded.ToString(), "Matching whether column is padded or not"); + Assert.That(columnIsPadded.ToString(), Is.EqualTo(columnIsPaddedMatch[i]), "Matching whether column is padded or not"); var columnClrType = result.Columns[i].ClrType; - Assert.AreEqual(clrTypeMatch[i], columnClrType.ToString(), "Matching whether column CLR Type"); + Assert.That(columnClrType.ToString(), Is.EqualTo(clrTypeMatch[i]), "Matching whether column CLR Type"); } session.SQL("DROP TABLE if exists address").Execute(); } @@ -717,7 +718,7 @@ public void ColumnCharacterDefaultDatatype() [Test, Description("Column Character Custom Datatype")] public void ColumnCharacterCustomDatatype() { - if (!session.Version.isAtLeast(8, 0, 14)) Assert.Ignore("This test is for MySql 8.0.14 or higher"); + Assume.That(session.Version.isAtLeast(8, 0, 14), "This test is for MySql 8.0.14 or higher"); var defaultCharset = "utf8mb4"; session.SQL($"USE {schemaName}").Execute(); session.SQL("Drop table if exists address").Execute(); @@ -746,33 +747,33 @@ public void ColumnCharacterCustomDatatype() for (int i = 0; i < columns.Length; i++) { string tableLabel = result.Columns[i].TableLabel; - Assert.AreEqual("address", tableLabel, "Matching the table label"); + Assert.That(tableLabel, Is.EqualTo("address"), "Matching the table label"); string columnName = result.Columns[i].ColumnName; - Assert.AreEqual(columns[i].ToString(), columnName, "Matching the Column Name"); + Assert.That(columnName, Is.EqualTo(columns[i].ToString()), "Matching the Column Name"); string columnLabel = result.Columns[i].ColumnLabel; - Assert.AreEqual(columns[i].ToString(), columnLabel, "Matching the Column Label"); + Assert.That(columnLabel, Is.EqualTo(columns[i].ToString()), "Matching the Column Label"); uint columnLength = result.Columns[i].Length; - Assert.AreEqual(Length[i], columnLength, "Matching the Column Length"); + Assert.That(columnLength, Is.EqualTo(Length[i]), "Matching the Column Length"); var columnType = result.Columns[i].Type; - Assert.AreEqual(columnTypeMatch[i], columnType.ToString(), "Matching the Column Type"); + Assert.That(columnType.ToString(), Is.EqualTo(columnTypeMatch[i]), "Matching the Column Type"); var columnFD = result.Columns[i].FractionalDigits; - Assert.AreEqual(FDLength[i], columnFD, "Matching the Column FD"); + Assert.That(columnFD, Is.EqualTo(FDLength[i]), "Matching the Column FD"); var columnIsSigned = result.Columns[i].IsNumberSigned; - Assert.AreEqual(columnIsSignedMatch[i], columnIsSigned.ToString(), "Matching whether column is signed or not"); + Assert.That(columnIsSigned.ToString(), Is.EqualTo(columnIsSignedMatch[i]), "Matching whether column is signed or not"); string columnCollation = result.Columns[i].CollationName; if (i == 1 || i == 2 || i == 3 || i == 4 || i == 5) - StringAssert.Contains(defaultCharset, columnCollation, "Matching the Collation Name for big5_chinese_ci characters"); + Assert.That(columnCollation, Does.Contain(defaultCharset), "Matching the Collation Name for big5_chinese_ci characters"); else - Assert.AreEqual(null, columnCollation, "Matching the Collation Name as null for data types other than characters"); + Assert.That(columnCollation, Is.EqualTo(null), "Matching the Collation Name as null for data types other than characters"); string columnCharacterSet = result.Columns[i].CharacterSetName; if (i == 1 || i == 2 || i == 3 || i == 4 || i == 5) - StringAssert.AreEqualIgnoringCase(defaultCharset, columnCharacterSet, "Matching the CharacterSet Name for big5 characters"); + Assert.That(columnCharacterSet, Is.EqualTo(defaultCharset).IgnoreCase, "Matching the CharacterSet Name for big5 characters"); else - Assert.AreEqual(null, columnCharacterSet, "Matching the Collation Name as null for data types other than characters"); + Assert.That(columnCharacterSet, Is.EqualTo(null), "Matching the Collation Name as null for data types other than characters"); var columnIsPadded = result.Columns[i].IsPadded; - Assert.AreEqual(columnIsPaddedMatch[i], columnIsPadded.ToString(), "Matching whether column is padded or not"); + Assert.That(columnIsPadded.ToString(), Is.EqualTo(columnIsPaddedMatch[i]), "Matching whether column is padded or not"); var columnClrType = result.Columns[i].ClrType; - Assert.AreEqual(clrTypeMatch[i], columnClrType.ToString(), "Matching whether column CLR Type"); + Assert.That(columnClrType.ToString(), Is.EqualTo(clrTypeMatch[i]), "Matching whether column CLR Type"); } session.SQL("Drop table if exists address").Execute(); } @@ -780,7 +781,7 @@ public void ColumnCharacterCustomDatatype() [Test, Description("Column Geometric Datatypes")] public void ColumnCharacterGeometricDatatype() { - if (!session.Version.isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher"); + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); session.SQL($"USE {schemaName}").Execute(); session.SQL($"drop table if exists geotest").Execute(); session.SQL("CREATE TABLE geotest (g GEOMETRY,p POINT,l LINESTRING,po POLYGON,mp MULTIPOINT,ml MULTILINESTRING,mpo MULTIPOLYGON,gc GEOMETRYCOLLECTION);").Execute(); @@ -789,36 +790,36 @@ public void ColumnCharacterGeometricDatatype() for (int i = 0; i < columns.Length; i++) { string tableName = result.Columns[i].TableName; - Assert.AreEqual("geotest", tableName, "Matching the table name"); + Assert.That(tableName, Is.EqualTo("geotest"), "Matching the table name"); string tableLabel = result.Columns[i].TableLabel; - Assert.AreEqual("geotest", tableLabel, "Matching the table label"); + Assert.That(tableLabel, Is.EqualTo("geotest"), "Matching the table label"); string columnName = result.Columns[i].ColumnName; - Assert.AreEqual(columns[i].ToString(), columnName, "Matching the Column Name"); + Assert.That(columnName, Is.EqualTo(columns[i].ToString()), "Matching the Column Name"); string columnLabel = result.Columns[i].ColumnLabel; - Assert.AreEqual(columns[i].ToString(), columnLabel, "Matching the Column Label"); + Assert.That(columnLabel, Is.EqualTo(columns[i].ToString()), "Matching the Column Label"); uint columnLength = result.Columns[i].Length; - Assert.AreEqual(0, columnLength, "Matching the Column Length"); + Assert.That(columnLength, Is.EqualTo(0), "Matching the Column Length"); var columnType = result.Columns[i].Type; - Assert.AreEqual("Geometry", columnType.ToString(), "Matching the Column Type"); + Assert.That(columnType.ToString(), Is.EqualTo("Geometry"), "Matching the Column Type"); var columnFD = result.Columns[i].FractionalDigits; - Assert.AreEqual(0, columnFD, "Matching the Column FD"); + Assert.That(columnFD, Is.EqualTo(0), "Matching the Column FD"); var columnIsSigned = result.Columns[i].IsNumberSigned; - Assert.AreEqual(false, columnIsSigned, "Matching whether column is signed or not"); + Assert.That(columnIsSigned, Is.EqualTo(false), "Matching whether column is signed or not"); string columnCollation = result.Columns[i].CollationName; - Assert.AreEqual(null, columnCollation, "Matching the Collation Name for default characters"); + Assert.That(columnCollation, Is.EqualTo(null), "Matching the Collation Name for default characters"); string columnCharacterSet = result.Columns[i].CharacterSetName; - Assert.AreEqual(null, columnCharacterSet, "Matching the Collation Name as null for data types other than characters"); + Assert.That(columnCharacterSet, Is.EqualTo(null), "Matching the Collation Name as null for data types other than characters"); var columnIsPadded = result.Columns[i].IsPadded; - Assert.AreEqual(false, columnIsPadded, "Matching whether column is padded or not"); + Assert.That(columnIsPadded, Is.EqualTo(false), "Matching whether column is padded or not"); var columnClrType = result.Columns[i].ClrType; - Assert.AreEqual("System.Byte[]", columnClrType.ToString(), "Matching whether column CLR Type"); + Assert.That(columnClrType.ToString(), Is.EqualTo("System.Byte[]"), "Matching whether column CLR Type"); } } [Test, Description("Column Blob Datatype")] public void ColumnCharacterBlobDatatype() { - if (!session.Version.isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher"); + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); session.SQL($"USE {schemaName}").Execute(); session.SQL($"drop table if exists geotest").Execute(); @@ -831,37 +832,37 @@ public void ColumnCharacterBlobDatatype() for (int i = 0; i < columns.Length; i++) { string tableName = result.Columns[i].TableName; - Assert.AreEqual("geotest", tableName, "Matching the table name"); + Assert.That(tableName, Is.EqualTo("geotest"), "Matching the table name"); string tableLabel = result.Columns[i].TableLabel; - Assert.AreEqual("geotest", tableLabel, "Matching the table label"); + Assert.That(tableLabel, Is.EqualTo("geotest"), "Matching the table label"); string columnName = result.Columns[i].ColumnName; - Assert.AreEqual(columns[i].ToString(), columnName, "Matching the Column Name"); + Assert.That(columnName, Is.EqualTo(columns[i].ToString()), "Matching the Column Name"); string columnLabel = result.Columns[i].ColumnLabel; - Assert.AreEqual(columns[i].ToString(), columnLabel, "Matching the Column Label"); + Assert.That(columnLabel, Is.EqualTo(columns[i].ToString()), "Matching the Column Label"); uint columnLength = result.Columns[i].Length; - Assert.AreEqual(ColumnLength[i], columnLength, "Matching the Column Length"); + Assert.That(columnLength, Is.EqualTo(ColumnLength[i]), "Matching the Column Length"); var columnType = result.Columns[i].Type; - Assert.AreEqual(columnTypeMatch[i], columnType.ToString(), "Matching the Column Type"); + Assert.That(columnType.ToString(), Is.EqualTo(columnTypeMatch[i]), "Matching the Column Type"); var columnFD = result.Columns[i].FractionalDigits; - Assert.AreEqual(0, columnFD, "Matching the Column FD"); + Assert.That(columnFD, Is.EqualTo(0), "Matching the Column FD"); var columnIsSigned = result.Columns[i].IsNumberSigned; - Assert.AreEqual("False", columnIsSigned.ToString(), "Matching whether column is signed or not"); + Assert.That(columnIsSigned.ToString(), Is.EqualTo("False"), "Matching whether column is signed or not"); string columnCollation = result.Columns[i].CollationName; - Assert.AreEqual("binary", columnCollation, "Matching the Collation Name for default characters"); + Assert.That(columnCollation, Is.EqualTo("binary"), "Matching the Collation Name for default characters"); string columnCharacterSet = result.Columns[i].CharacterSetName; //Character name returns binary for blob - Assert.AreEqual("binary", columnCharacterSet, "Matching the Collation Name as null for data types other than characters"); + Assert.That(columnCharacterSet, Is.EqualTo("binary"), "Matching the Collation Name as null for data types other than characters"); var columnIsPadded = result.Columns[i].IsPadded; - Assert.AreEqual("False", columnIsPadded.ToString(), "Matching whether column is padded or not"); + Assert.That(columnIsPadded.ToString(), Is.EqualTo("False"), "Matching whether column is padded or not"); var columnClrType = result.Columns[i].ClrType; - Assert.AreEqual("System.Byte[]", columnClrType.ToString(), "Matching whether column CLR Type"); + Assert.That(columnClrType.ToString(), Is.EqualTo("System.Byte[]"), "Matching whether column CLR Type"); } } [Test, Description("Verify that different language specific collations are availabe for charset utf8mb4 when server version is 8.0 or greater")] public void LanguageSpecificCollations() { - if (!session.Version.isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher"); + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); var charset = "utf8mb4"; string[] collationname = { @@ -875,7 +876,7 @@ public void LanguageSpecificCollations() var database_name = "collation_test"; session.DropSchema(database_name); var CommandText1 = "SHOW VARIABLES LIKE 'collation_%';"; - Assert.AreEqual(charset, session.Settings.CharacterSet, "Matching the character set of the session"); + Assert.That(session.Settings.CharacterSet, Is.EqualTo(charset), "Matching the character set of the session"); for (var i = 0; i < collationname.Length; i++) { @@ -885,18 +886,18 @@ public void LanguageSpecificCollations() session.SQL("USE " + database_name).Execute(); session.SQL("create table x(id int,name char(25));").Execute(); var res = session.SQL("insert into x values(10,'AXTREF');").Execute(); - Assert.AreEqual(1, res.AffectedItemsCount); + Assert.That(res.AffectedItemsCount, Is.EqualTo(1)); session.SQL("insert into x values(20,'Trädgårdsvägen');").Execute(); - Assert.AreEqual(1, res.AffectedItemsCount); + Assert.That(res.AffectedItemsCount, Is.EqualTo(1)); session.SQL("insert into x values(30,'foo𝌆bar');").Execute(); - Assert.AreEqual(1, res.AffectedItemsCount); + Assert.That(res.AffectedItemsCount, Is.EqualTo(1)); session.SQL("insert into x values(40,'Dolphin:🐬');").Execute(); - Assert.AreEqual(1, res.AffectedItemsCount); + Assert.That(res.AffectedItemsCount, Is.EqualTo(1)); var dbCharset = session.SQL("select @@character_set_database;").Execute().FirstOrDefault(); var dbCollation = session.SQL("select @@collation_database").Execute().FirstOrDefault(); - Assert.AreEqual(dbCharset[0], charset); - Assert.AreEqual(dbCollation[0], collationname[i]); + Assert.That(charset, Is.EqualTo(dbCharset[0])); + Assert.That(collationname[i], Is.EqualTo(dbCollation[0])); session.DropSchema(database_name); } } @@ -907,7 +908,7 @@ public void LanguageSpecificCollations() [Test] public void VerifyRenamedCollations() { - if (!session.Version.isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher"); + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); var charset = "utf8mb3"; var collation = session.Version.isAtLeast(8, 0, 30) ? "utf8mb3" : "utf8"; @@ -925,7 +926,7 @@ public void VerifyRenamedCollations() var database_name = "collation_test"; session.DropSchema(database_name); - Assert.AreEqual(charset, sessionX.Settings.CharacterSet, "Matching the character set of the session"); + Assert.That(sessionX.Settings.CharacterSet, Is.EqualTo(charset), "Matching the character set of the session"); for (var i = 0; i < collationname.Length; i++) { @@ -934,18 +935,18 @@ public void VerifyRenamedCollations() sessionX.SQL("USE " + database_name).Execute(); sessionX.SQL("CREATE TABLE x(id int,name char(25));").Execute(); var res = sessionX.SQL("insert into x values(10,'AXTREF');").Execute(); - Assert.AreEqual(1, res.AffectedItemsCount); + Assert.That(res.AffectedItemsCount, Is.EqualTo(1)); sessionX.SQL("insert into x values(20,'Trädgårdsvägen');").Execute(); - Assert.AreEqual(1, res.AffectedItemsCount); + Assert.That(res.AffectedItemsCount, Is.EqualTo(1)); sessionX.SQL("insert into x values(30,'foo𝌆bar');").Execute(); - Assert.AreEqual(1, res.AffectedItemsCount); + Assert.That(res.AffectedItemsCount, Is.EqualTo(1)); sessionX.SQL("insert into x values(40,'Dolphin:🐬');").Execute(); - Assert.AreEqual(1, res.AffectedItemsCount); + Assert.That(res.AffectedItemsCount, Is.EqualTo(1)); var dbCharset = sessionX.SQL("select @@character_set_database;").Execute().FirstOrDefault(); var dbCollation = sessionX.SQL("select @@collation_database").Execute().FirstOrDefault(); - Assert.AreEqual(dbCharset[0], charset); - Assert.AreEqual(dbCollation[0], collationname[i]); + Assert.That(charset, Is.EqualTo(dbCharset[0])); + Assert.That(collationname[i], Is.EqualTo(dbCollation[0])); sessionX.DropSchema(database_name); } } @@ -956,12 +957,12 @@ public void VerifyRenamedCollations() [Test, Description("Verify default charset and collation")] public void VerifyLatinCharsetAndCollation() { - if (!session.Version.isAtLeast(8, 0, 14)) Assert.Ignore("This test is for MySql 8.0.14 or higher"); + Assume.That(session.Version.isAtLeast(8, 0, 14), "This test is for MySql 8.0.14 or higher"); var database_name = "collation_test"; var charset = "latin1"; var collationname = "latin1_danish_ci"; var defaultCharset = "utf8mb4"; - Assert.AreEqual(defaultCharset, session.Settings.CharacterSet, "Matching the character set of the session"); + Assert.That(session.Settings.CharacterSet, Is.EqualTo(defaultCharset), "Matching the character set of the session"); session.DropSchema(database_name); var CommandText1 = $"CREATE DATABASE {database_name} CHARACTER SET {charset} COLLATE {collationname}"; session.SQL(CommandText1).Execute(); @@ -969,19 +970,19 @@ public void VerifyLatinCharsetAndCollation() session.SQL("create table x(id int,name char(25));").Execute(); session.SQL("insert into x values(10,'AXTREF');").Execute(); RowResult result1 = session.GetSchema(database_name).GetTable("x").Select("id").Execute(); - Assert.AreEqual(null, result1.Columns[0].CharacterSetName, "id-charset"); - Assert.AreEqual(null, result1.Columns[0].CollationName, "id-collation"); + Assert.That(result1.Columns[0].CharacterSetName, Is.EqualTo(null), "id-charset"); + Assert.That(result1.Columns[0].CollationName, Is.EqualTo(null), "id-collation"); result1 = session.GetSchema(database_name).GetTable("x").Select("name").Execute(); - StringAssert.AreEqualIgnoringCase(defaultCharset, result1.Columns[0].CharacterSetName, "name-charset"); - StringAssert.Contains(defaultCharset, result1.Columns[0].CollationName, "name-collation"); + Assert.That(result1.Columns[0].CharacterSetName, Is.EqualTo(defaultCharset).IgnoreCase, "name-charset"); + Assert.That(result1.Columns[0].CollationName, Does.Contain(defaultCharset), "name-collation"); session.DropSchema(database_name); } [Test, Description("Create table/db with collation utf8mb4_0900_bin and insert non ascii characters and fetch data")] public void Utf8mb4BinaryNopadCollationTable() { - if (!Platform.IsWindows()) Assert.Ignore("This test is for Windows OS only."); - if (!_serverVersion.isAtLeast(8, 0, 17)) Assert.Ignore("This test is for MySql 8.0.17 or higher"); + Assume.That(Platform.IsWindows(), "This test is for Windows OS only."); + Assume.That(session.Version.isAtLeast(8, 0, 17), "This test is for MySql 8.0.17 or higher"); char t_char; var charset = "utf8mb4"; var collation = "utf8mb4_0900_ai_ci"; @@ -996,7 +997,7 @@ public void Utf8mb4BinaryNopadCollationTable() var database_name = "collation_test"; - Assert.AreEqual(charset, session.Settings.CharacterSet, "Matching the character set of the session"); + Assert.That(session.Settings.CharacterSet, Is.EqualTo(charset), "Matching the character set of the session"); session.DropSchema(database_name); CommandText1 = "CREATE DATABASE " + database_name; var sqlRes = session.SQL(CommandText1).Execute(); @@ -1005,13 +1006,13 @@ public void Utf8mb4BinaryNopadCollationTable() Table t = session.GetSchema(database_name).GetTable("t"); t.Insert().Values(foo).Execute(); Row r = t.Select().Limit(1).Execute().FetchOne(); - Assert.AreEqual(foo, r[0].ToString(), "Compare extracted string"); + Assert.That(r[0].ToString(), Is.EqualTo(foo), "Compare extracted string"); session.DropSchema(database_name); CommandText1 = "SHOW VARIABLES LIKE 'collation_%';"; sqlRes = session.SQL(CommandText1).Execute(); while (sqlRes.Next()) ; - Assert.AreEqual(collation, sqlRes.Rows.ToArray()[0][1].ToString(), "Matching the collation"); + Assert.That(sqlRes.Rows.ToArray()[0][1].ToString(), Is.EqualTo(collation), "Matching the collation"); for (var i = 0; i < collationname.Count; i++) { @@ -1025,15 +1026,15 @@ public void Utf8mb4BinaryNopadCollationTable() session.SQL("insert into x values(40,'Dolphin:🐬');").Execute(); t = session.GetSchema(database_name).GetTable("x"); var res = t.Select().Execute().FetchAll(); - Assert.AreEqual("AXTREF", res[0][1].ToString(), "Matching the data"); - Assert.AreEqual("Trädgårdsvägen", res[1][1].ToString(), "Matching the data"); - Assert.AreEqual("foo𝌆bar", res[2][1].ToString(), "Matching the data"); - Assert.AreEqual("Dolphin:🐬", res[3][1].ToString(), "Matching the data"); + Assert.That(res[0][1].ToString(), Is.EqualTo("AXTREF"), "Matching the data"); + Assert.That(res[1][1].ToString(), Is.EqualTo("Trädgårdsvägen"), "Matching the data"); + Assert.That(res[2][1].ToString(), Is.EqualTo("foo𝌆bar"), "Matching the data"); + Assert.That(res[3][1].ToString(), Is.EqualTo("Dolphin:🐬"), "Matching the data"); RowResult result_collation = t.Select("name").Execute(); var collationName = result_collation.Columns[0].CollationName; - Assert.AreEqual(collationname[i], collationName, "Matching the collation"); + Assert.That(collationName, Is.EqualTo(collationname[i]), "Matching the collation"); var characterName = result_collation.Columns[0].CharacterSetName; - Assert.AreEqual(charset, characterName, "Matching the charset"); + Assert.That(characterName, Is.EqualTo(charset), "Matching the charset"); session.DropSchema(database_name); } @@ -1049,15 +1050,15 @@ public void Utf8mb4BinaryNopadCollationTable() session.SQL("insert into x values(40,'Dolphin:🐬');").Execute(); t = session.GetSchema(database_name).GetTable("x"); var res = t.Select().Execute().FetchAll(); - Assert.AreEqual("AXTREF", res[0][1].ToString(), "Matching the data"); - Assert.AreEqual("Trädgårdsvägen", res[1][1].ToString(), "Matching the data"); - Assert.AreEqual("foo𝌆bar", res[2][1].ToString(), "Matching the data"); - Assert.AreEqual("Dolphin:🐬", res[3][1].ToString(), "Matching the data"); + Assert.That(res[0][1].ToString(), Is.EqualTo("AXTREF"), "Matching the data"); + Assert.That(res[1][1].ToString(), Is.EqualTo("Trädgårdsvägen"), "Matching the data"); + Assert.That(res[2][1].ToString(), Is.EqualTo("foo𝌆bar"), "Matching the data"); + Assert.That(res[3][1].ToString(), Is.EqualTo("Dolphin:🐬"), "Matching the data"); RowResult result_collation = t.Select("name").Execute(); var collationName = result_collation.Columns[0].CollationName; - Assert.AreEqual(collationname[i], collationName, "Matching the collation"); + Assert.That(collationName, Is.EqualTo(collationname[i]), "Matching the collation"); var characterName = result_collation.Columns[0].CharacterSetName; - Assert.AreEqual(charset, characterName, "Matching the charset"); + Assert.That(characterName, Is.EqualTo(charset), "Matching the charset"); session.DropSchema(database_name); //ALTER CommandText1 = "CREATE DATABASE " + database_name; @@ -1071,15 +1072,15 @@ public void Utf8mb4BinaryNopadCollationTable() session.SQL("insert into x values(40,'Dolphin:🐬');").Execute(); t = session.GetSchema(database_name).GetTable("x"); res = t.Select().Execute().FetchAll(); - Assert.AreEqual("AXTREF", res[0][1].ToString(), "Matching the data"); - Assert.AreEqual("Trädgårdsvägen", res[1][1].ToString(), "Matching the data"); - Assert.AreEqual("foo𝌆bar", res[2][1].ToString(), "Matching the data"); - Assert.AreEqual("Dolphin:🐬", res[3][1].ToString(), "Matching the data"); + Assert.That(res[0][1].ToString(), Is.EqualTo("AXTREF"), "Matching the data"); + Assert.That(res[1][1].ToString(), Is.EqualTo("Trädgårdsvägen"), "Matching the data"); + Assert.That(res[2][1].ToString(), Is.EqualTo("foo𝌆bar"), "Matching the data"); + Assert.That(res[3][1].ToString(), Is.EqualTo("Dolphin:🐬"), "Matching the data"); result_collation = t.Select("name").Execute(); collationName = result_collation.Columns[0].CollationName; - Assert.AreEqual(collationname[i], collationName, "Matching the collation"); + Assert.That(collationName, Is.EqualTo(collationname[i]), "Matching the collation"); characterName = result_collation.Columns[0].CharacterSetName; - Assert.AreEqual(charset, characterName, "Matching the charset"); + Assert.That(characterName, Is.EqualTo(charset), "Matching the charset"); session.DropSchema(database_name); } @@ -1097,7 +1098,7 @@ public void Utf8mb4BinaryNopadCollationTable() session.SQL($"insert into x values({k},'{t_char}')").Execute(); t = session.GetSchema(database_name).GetTable("x"); r = t.Select().Limit(1).Execute().FetchOne(); - Assert.AreEqual(t_char.ToString(), r[1].ToString(), "Compare extracted string"); + Assert.That(r[1].ToString(), Is.EqualTo(t_char.ToString()), "Compare extracted string"); } session.DropSchema(database_name); @@ -1111,7 +1112,7 @@ public void Utf8mb4BinaryNopadCollationTable() session.SQL($"insert into x values({k},'{t_char}')").Execute(); t = session.GetSchema(database_name).GetTable("x"); r = t.Select().Limit(1).Execute().FetchOne(); - Assert.AreEqual(t_char.ToString(), r[1].ToString(), "Compare extracted string"); + Assert.That(r[1].ToString(), Is.EqualTo(t_char.ToString()), "Compare extracted string"); } session.DropSchema(database_name); } @@ -1126,7 +1127,7 @@ public void Utf8mb4BinaryNopadCollationTable() mysqlx0.Password = session.Settings.Password; mysqlx0.CharacterSet = "utf8mb4"; mysqlx0.SslMode = MySqlSslMode.Required; - mysqlx0.ConnectTimeout = 10; + mysqlx0.ConnectTimeout = 1000; mysqlx0.Keepalive = 10; mysqlx0.CertificateFile = sslCa; mysqlx0.CertificatePassword = sslCertificatePassword; @@ -1135,7 +1136,7 @@ public void Utf8mb4BinaryNopadCollationTable() using (var sessiontest = MySQLX.GetSession(mysqlx0.ConnectionString)) { - Assert.AreEqual(charset, sessiontest.Settings.CharacterSet, "Matching the character set of the session"); + Assert.That(sessiontest.Settings.CharacterSet, Is.EqualTo(charset), "Matching the character set of the session"); sessiontest.DropSchema(database_name); CommandText1 = "CREATE DATABASE " + database_name; sqlRes = sessiontest.SQL(CommandText1).Execute(); @@ -1144,7 +1145,7 @@ public void Utf8mb4BinaryNopadCollationTable() t = sessiontest.GetSchema(database_name).GetTable("t"); t.Insert().Values(foo).Execute(); r = t.Select().Limit(1).Execute().FetchOne(); - Assert.AreEqual(foo, r[0].ToString(), "Compare extracted string"); + Assert.That(r[0].ToString(), Is.EqualTo(foo), "Compare extracted string"); sessiontest.DropSchema(database_name); } } diff --git a/MySQL.Data/tests/MySqlX.Data.Tests/ClientSideFailoverTests.cs b/MySQL.Data/tests/MySqlX.Data.Tests/ClientSideFailoverTests.cs index e36fdcd25..13fb2e74b 100644 --- a/MySQL.Data/tests/MySqlX.Data.Tests/ClientSideFailoverTests.cs +++ b/MySQL.Data/tests/MySqlX.Data.Tests/ClientSideFailoverTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2017, 2022, Oracle and/or its affiliates. +// Copyright © 2017, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -31,6 +31,7 @@ using MySql.Data.MySqlClient; using MySqlX.XDevAPI; using NUnit.Framework; +using NUnit.Framework.Legacy; using System; using System.Collections.Generic; @@ -55,13 +56,13 @@ public void RandomMethodWithBasicFormatConnectionString() // Single host. using (var session = MySQLX.GetSession(ConnectionString)) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } // Multiple hosts. using (var session = MySQLX.GetSession($"server=10.10.10.10, {Host}, 20.20.20.20, 30.30.30.30;port={XPort};uid=test;password=test;connecttimeout={connectionTimeout}")) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } // Multiple hosts with IPv6 @@ -69,23 +70,23 @@ public void RandomMethodWithBasicFormatConnectionString() { using (var session = MySQLX.GetSession($"server=10.10.10.10, {localServerIpv6}, 20.20.20.20, 30.30.30.30;port={XPort};uid=test;password=test;connecttimeout={connectionTimeout}")) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } } // Multiple hosts using synonyms for "server" connection option. using (var session = MySQLX.GetSession($"host=10.10.10.10, {Host};port={XPort};uid=test;password=test;connecttimeout=" + connectionTimeout)) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } // Multiple hosts. All attempts fail. Exception ex = Assert.Throws(() => MySQLX.GetSession($"server= 10.10.10.10, 20.20.20.20 ;port={XPort};uid=test;password=test;connecttimeout={connectionTimeout}")); - Assert.AreEqual("Unable to connect to any of the specified MySQL hosts.", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Unable to connect to any of the specified MySQL hosts")); // Providing port number as part of the host name. ex = Assert.Throws(() => MySQLX.GetSession($"server= 10.10.10.10:33050, 20.20.20.20:33060, {Host}:{XPort} ;port={XPort};uid=test;password=test;connecttimeout={connectionTimeout}")); - Assert.AreEqual("Providing a port number as part of the host address isn't supported when using connection strings in basic format or anonymous objects. Use URI format instead.", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Providing a port number as part of the host address isn't supported when using connection strings in basic format or anonymous objects. Use URI format instead")); } [Test] @@ -96,13 +97,13 @@ public void RandomMethodWithUriFormatConnectionString() // Single host. using (var session = MySQLX.GetSession($"mysqlx://test:test@{Host}:{XPort}?connecttimeout={connectionTimeout}")) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } // Single host and port as an array. Successful connection. using (var session = MySQLX.GetSession($"mysqlx://test:test@[{Host}:" + XPort + "]?connecttimeout=" + connectionTimeout)) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } // Single host as an array. Failed connection. @@ -111,13 +112,13 @@ public void RandomMethodWithUriFormatConnectionString() // Multiple hosts. using (var session = MySQLX.GetSession($"mysqlx://test:test@[192.1.10.10,{Host}:" + XPort + "]?connecttimeout=" + connectionTimeout)) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } // Multiple hosts and a schema. using (var session = MySQLX.GetSession($"mysqlx://test:test@[192.1.10.10,{Host}:" + XPort + "]/test?connecttimeout=" + connectionTimeout)) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } // Multiple hosts which may or may not contain a port number. @@ -125,7 +126,7 @@ public void RandomMethodWithUriFormatConnectionString() { using (var session = MySQLX.GetSession($"mysqlx://test:test@[192.1.10.10,120.0.0.2:22000,[{localServerIpv6}]:{XPort}]/test?connecttimeout={connectionTimeout}")) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } } } @@ -140,13 +141,13 @@ public void RandomMethodWithAnonymousTypes() // Single host. using (var session = MySQLX.GetSession(new { server = Host, port = XPort, uid = uid, password = password, connecttimeout = connectionTimeout })) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } // Multiple hosts. using (var session = MySQLX.GetSession(new { server = $"10.10.10.10, {Host}", port = XPort, uid = uid, password = password, connecttimeout = connectionTimeout })) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } // Multiple hosts with IPv6 @@ -154,23 +155,23 @@ public void RandomMethodWithAnonymousTypes() { using (var session = MySQLX.GetSession(new { server = $"10.10.10.10, {localServerIpv6}", port = XPort, uid = uid, password = password, connecttimeout = connectionTimeout })) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } } // Multiple hosts using synonyms for "server" connection option. First attempt fails, second is succesful. using (var session = MySQLX.GetSession(new { datasource = $"10.10.10.10, {Host}", port = XPort, uid = uid, password = password, connecttimeout = connectionTimeout })) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } // Multiple hosts. All attempts fail. Exception ex = Assert.Throws(() => MySQLX.GetSession(new { server = "10.10.10.10, 20.20.20.20", port = XPort, uid = uid, password = password, connecttimeout = connectionTimeout })); - Assert.AreEqual("Unable to connect to any of the specified MySQL hosts.", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Unable to connect to any of the specified MySQL hosts")); // Providing port number as part of the host name. ex = Assert.Throws(() => MySQLX.GetSession(new { server = "10.10.10.10:33060, 20.20.20.20:33060", port = XPort, uid = uid, password = password, connecttimeout = connectionTimeout })); - Assert.AreEqual("Providing a port number as part of the host address isn't supported when using connection strings in basic format or anonymous objects. Use URI format instead.", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Providing a port number as part of the host address isn't supported when using connection strings in basic format or anonymous objects. Use URI format instead")); } [Test] @@ -188,11 +189,11 @@ public void PriorityMethodWithBasicFormatConnectionString() Session newSession = MySQLX.GetSession($"server=(address={Host},priority=100);port=" + XPort + ";uid=test;password=test;"); sessions.Add(newSession); } - Assert.False(true, "MySqlException should be thrown"); + Assert.That(true, Is.False, "MySqlException should be thrown"); } catch (MySqlException exception) { - Assert.AreEqual(ResourcesX.UnableToOpenSession, exception.Message); + Assert.That(exception.Message, Is.EqualTo(ResourcesX.UnableToOpenSession)); } finally { @@ -201,20 +202,20 @@ public void PriorityMethodWithBasicFormatConnectionString() using (var session = MySQLX.GetSession($"server=(address={Host},priority=100);port=" + XPort + ";uid=test;password=test;connecttimeout=" + connectionTimeout)) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); - Assert.AreEqual(Host, session.Settings.Server); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + Assert.That(session.Settings.Server, Is.EqualTo(Host)); } using (var session = MySQLX.GetSession($"server=(address=server.example,priority=50),(address={Host},priority=100);port=" + XPort + ";uid=test;password=test;connecttimeout=" + connectionTimeout)) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); - Assert.AreEqual(Host, session.Settings.Server); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + Assert.That(session.Settings.Server, Is.EqualTo(Host)); } using (var session = MySQLX.GetSession($"server=(address=server.example,priority=100),(address={Host},priority=25),(address=192.0.10.56,priority=75);port=" + XPort + ";uid=test;password=test;connecttimeout=" + connectionTimeout)) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); - Assert.AreEqual(Host, session.Settings.Server); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + Assert.That(session.Settings.Server, Is.EqualTo(Host)); } using (var session = MySQLX.GetSession(new @@ -226,33 +227,33 @@ public void PriorityMethodWithBasicFormatConnectionString() sslmode = MySqlSslMode.Disabled })) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); - Assert.AreEqual(Host, session.Settings.Server); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + Assert.That(session.Settings.Server, Is.EqualTo(Host)); } using (var session = MySQLX.GetSession($"server=(address=server.example,priority=100),(address={Host},priority=25),(address=192.0.10.56,priority=75);port=" + XPort + ";uid=test;password=test;connecttimeout=" + connectionTimeout)) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); - Assert.AreEqual(Host, session.Settings.Server); - Assert.AreEqual("server.example", FailoverManager.FailoverGroup.Hosts[0].Host); - Assert.AreEqual("192.0.10.56", FailoverManager.FailoverGroup.Hosts[1].Host); - Assert.AreEqual(Host, FailoverManager.FailoverGroup.Hosts[2].Host); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + Assert.That(session.Settings.Server, Is.EqualTo(Host)); + Assert.That(FailoverManager.FailoverGroup.Hosts[0].Host, Is.EqualTo("server.example")); + Assert.That(FailoverManager.FailoverGroup.Hosts[1].Host, Is.EqualTo("192.0.10.56")); + Assert.That(FailoverManager.FailoverGroup.Hosts[2].Host, Is.EqualTo(Host)); } // Priority outside the 0-100 allowed range. Exception ex = Assert.Throws(() => MySQLX.GetSession($"server=(address=server.example,priority=-20),(address={Host},priority=100);port=" + XPort + ";uid=test;password=test;connecttimeout=" + connectionTimeout)); - Assert.AreEqual("The priority must be between 0 and 100.", ex.Message); + Assert.That(ex.Message, Is.EqualTo("The priority must be between 0 and 100")); ex = Assert.Throws(() => MySQLX.GetSession($"server=(address=server.example,priority=-50),(address={Host},priority=101);port=" + XPort + ";uid=test;password=test;connecttimeout=" + connectionTimeout)); - Assert.AreEqual("The priority must be between 0 and 100.", ex.Message); + Assert.That(ex.Message, Is.EqualTo("The priority must be between 0 and 100")); // Set priority for a subset of the hosts. ex = Assert.Throws(() => MySQLX.GetSession($"server=(address=server.example),(address={Host},priority=100);port=" + XPort + ";uid=test;password=test;connecttimeout=" + connectionTimeout)); - Assert.AreEqual("You must either assign no priority to any of the hosts or give a priority for every host.", ex.Message); + Assert.That(ex.Message, Is.EqualTo("You must either assign no priority to any of the hosts or give a priority for every host")); ex = Assert.Throws(() => MySQLX.GetSession($"server=(address=server.example,priority=50),(address={Host});port=" + XPort + ";uid=test;password=test;connecttimeout=" + connectionTimeout)); - Assert.AreEqual("You must either assign no priority to any of the hosts or give a priority for every host.", ex.Message); + Assert.That(ex.Message, Is.EqualTo("You must either assign no priority to any of the hosts or give a priority for every host")); ex = Assert.Throws(() => MySQLX.GetSession($"server=(address=server.example,priority=50),(address={Host},priority=100),(address=server.example);port=" + XPort + ";uid=test;password=test;connecttimeout=" + connectionTimeout)); - Assert.AreEqual("You must either assign no priority to any of the hosts or give a priority for every host.", ex.Message); + Assert.That(ex.Message, Is.EqualTo("You must either assign no priority to any of the hosts or give a priority for every host")); // Automatically set priority if no priority is given. string hostList = string.Empty; @@ -265,11 +266,11 @@ public void PriorityMethodWithBasicFormatConnectionString() using (var session = MySQLX.GetSession($"server={hostList};port={XPort};uid=test;password=test;connecttimeout={connectionTimeout}")) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); priority = 100; foreach (var host in FailoverManager.FailoverGroup.Hosts) { - Assert.AreEqual(priority != 0 ? priority-- : 0, host.Priority); + Assert.That(host.Priority, Is.EqualTo(priority != 0 ? priority-- : 0)); } } } @@ -289,11 +290,11 @@ public void PriorityMethodWithUriFormatConnectonString() Session newSession = MySQLX.GetSession($"mysqlx://test:test@[(address={Host}:" + XPort + ",priority=50)]?connecttimeout=" + connectionTimeout); sessions.Add(newSession); } - Assert.False(true, "MySqlException should be thrown"); + Assert.That(true, Is.False, "MySqlException should be thrown"); } catch (MySqlException exception) { - Assert.AreEqual(ResourcesX.UnableToOpenSession, exception.Message); + Assert.That(exception.Message, Is.EqualTo(ResourcesX.UnableToOpenSession)); } finally { @@ -302,39 +303,39 @@ public void PriorityMethodWithUriFormatConnectonString() using (var session = MySQLX.GetSession($"mysqlx://test:test@[(address=server.example,priority=50),(address={Host}:{XPort},priority=100)]?connecttimeout=" + connectionTimeout)) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); - Assert.AreEqual(Host, session.Settings.Server); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + Assert.That(session.Settings.Server, Is.EqualTo(Host)); } using (var session = MySQLX.GetSession($"mysqlx://test:test@[(address=server.example,priority=50),(address={Host}:{XPort},priority=100)]?connecttimeout=" + connectionTimeout)) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); - Assert.AreEqual(Host, session.Settings.Server); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + Assert.That(session.Settings.Server, Is.EqualTo(Host)); } using (var session = MySQLX.GetSession($"mysqlx://test:test@[(address=server.example,priority=100),(address={Host}:{XPort},priority=25),(address=192.0.10.56,priority=75)]?connecttimeout=" + connectionTimeout)) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); - Assert.AreEqual(Host, session.Settings.Server); - Assert.AreEqual("server.example", FailoverManager.FailoverGroup.Hosts[0].Host); - Assert.AreEqual("192.0.10.56", FailoverManager.FailoverGroup.Hosts[1].Host); - Assert.AreEqual(Host, FailoverManager.FailoverGroup.Hosts[2].Host); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + Assert.That(session.Settings.Server, Is.EqualTo(Host)); + Assert.That(FailoverManager.FailoverGroup.Hosts[0].Host, Is.EqualTo("server.example")); + Assert.That(FailoverManager.FailoverGroup.Hosts[1].Host, Is.EqualTo("192.0.10.56")); + Assert.That(FailoverManager.FailoverGroup.Hosts[2].Host, Is.EqualTo(Host)); } // Priority outside the 0-100 allowed range. Exception ex = Assert.Throws(() => MySQLX.GetSession($"mysqlx://test:test@[(address=server.example,priority=-20),(address={Host}:{XPort},priority=100)]?connecttimeout=" + connectionTimeout)); - Assert.AreEqual("The priority must be between 0 and 100.", ex.Message); + Assert.That(ex.Message, Is.EqualTo("The priority must be between 0 and 100")); ex = Assert.Throws(() => MySQLX.GetSession($"mysqlx://test:test@[(address=server.example,priority=50),(address={Host}:{XPort},priority=101)]?connecttimeout=" + connectionTimeout)); - Assert.AreEqual("The priority must be between 0 and 100.", ex.Message); + Assert.That(ex.Message, Is.EqualTo("The priority must be between 0 and 100")); // Set priority for a subset of the hosts. ex = Assert.Throws(() => MySQLX.GetSession($"mysqlx://test:test@[(address=server.example),(address={Host}:{XPort},priority=100)]?connecttimeout=" + connectionTimeout)); - Assert.AreEqual("You must either assign no priority to any of the hosts or give a priority for every host.", ex.Message); + Assert.That(ex.Message, Is.EqualTo("You must either assign no priority to any of the hosts or give a priority for every host")); ex = Assert.Throws(() => MySQLX.GetSession($"mysqlx://test:test@[(address=server.example,priority=100),(address={Host}:{XPort})]?connecttimeout=" + connectionTimeout)); - Assert.AreEqual("You must either assign no priority to any of the hosts or give a priority for every host.", ex.Message); + Assert.That(ex.Message, Is.EqualTo("You must either assign no priority to any of the hosts or give a priority for every host")); ex = Assert.Throws(() => MySQLX.GetSession($"mysqlx://test:test@[(address=server.example),(address={Host}:{XPort}),(address=server2.example,priority=100)]?connecttimeout=" + connectionTimeout)); - Assert.AreEqual("You must either assign no priority to any of the hosts or give a priority for every host.", ex.Message); + Assert.That(ex.Message, Is.EqualTo("You must either assign no priority to any of the hosts or give a priority for every host")); // Automatically set priority if no priority is given. string hostList = string.Empty; @@ -347,11 +348,11 @@ public void PriorityMethodWithUriFormatConnectonString() using (var session = MySQLX.GetSession($"mysqlx://test:test@[{hostList}]?connecttimeout=" + connectionTimeout)) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); priority = 100; foreach (var host in FailoverManager.FailoverGroup.Hosts) { - Assert.AreEqual(priority != 0 ? priority-- : 0, host.Priority); + Assert.That(host.Priority, Is.EqualTo(priority != 0 ? priority-- : 0)); } } } @@ -374,11 +375,11 @@ public void PriorityMethodWithAnonymousTypes() sessions.Add(newSession); } - Assert.False(true, "MySqlException should be thrown"); + Assert.That(true, Is.False, "MySqlException should be thrown"); } catch (MySqlException exception) { - Assert.AreEqual(ResourcesX.UnableToOpenSession, exception.Message); + Assert.That(exception.Message, Is.EqualTo(ResourcesX.UnableToOpenSession)); } finally { @@ -387,44 +388,44 @@ public void PriorityMethodWithAnonymousTypes() using (var session = MySQLX.GetSession(new { server = $"(address={Host},priority=100)", port = XPort, uid = uid, password = password, connecttimeout = connectionTimeout })) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); - Assert.AreEqual(Host, session.Settings.Server); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + Assert.That(session.Settings.Server, Is.EqualTo(Host)); } using (var session = MySQLX.GetSession(new { server = $"(address=server.example,priority=50),(address={Host},priority=100)", port = XPort, uid = uid, password = password, connecttimeout = connectionTimeout })) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); - Assert.AreEqual(Host, session.Settings.Server); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + Assert.That(session.Settings.Server, Is.EqualTo(Host)); } using (var session = MySQLX.GetSession(new { server = $"(address=server.example,priority=100),(address={Host},priority=25),(address=192.0.10.56,priority=75)", port = XPort, uid = uid, password = password, connecttimeout = connectionTimeout })) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); - Assert.AreEqual(Host, session.Settings.Server); - Assert.AreEqual("server.example", FailoverManager.FailoverGroup.Hosts[0].Host); - Assert.AreEqual("192.0.10.56", FailoverManager.FailoverGroup.Hosts[1].Host); - Assert.AreEqual(Host, FailoverManager.FailoverGroup.Hosts[2].Host); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + Assert.That(session.Settings.Server, Is.EqualTo(Host)); + Assert.That(FailoverManager.FailoverGroup.Hosts[0].Host, Is.EqualTo("server.example")); + Assert.That(FailoverManager.FailoverGroup.Hosts[1].Host, Is.EqualTo("192.0.10.56")); + Assert.That(FailoverManager.FailoverGroup.Hosts[2].Host, Is.EqualTo(Host)); } using (var session = MySQLX.GetSession(new { host = $"(address={Host},priority=2),(address={Host},priority=3)", port = XPort, uid = uid, password = password, connecttimeout = connectionTimeout })) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } // Priority outside the 0-100 allowed range. Exception ex = Assert.Throws(() => MySQLX.GetSession(new { server = $"(address=server.example,priority=-20),(address={Host},priority=100)", port = XPort, uid = uid, password = password, connecttimeout = connectionTimeout })); - Assert.AreEqual("The priority must be between 0 and 100.", ex.Message); + Assert.That(ex.Message, Is.EqualTo("The priority must be between 0 and 100")); ex = Assert.Throws(() => MySQLX.GetSession(new { server = $"(address=server.example,priority=-50),(address={Host},priority=101)", port = XPort, uid = uid, password = password, connecttimeout = connectionTimeout })); - Assert.AreEqual("The priority must be between 0 and 100.", ex.Message); + Assert.That(ex.Message, Is.EqualTo("The priority must be between 0 and 100")); // Set priority for a subset of the hosts. ex = Assert.Throws(() => MySQLX.GetSession(new { server = $"(address=server.example),(address={Host},priority=100)", port = XPort, uid = uid, password = password, connecttimeout = connectionTimeout })); - Assert.AreEqual("You must either assign no priority to any of the hosts or give a priority for every host.", ex.Message); + Assert.That(ex.Message, Is.EqualTo("You must either assign no priority to any of the hosts or give a priority for every host")); ex = Assert.Throws(() => MySQLX.GetSession(new { server = $"(address=server.example,priority=50),(address={Host})", port = XPort, uid = uid, password = password, connecttimeout = connectionTimeout })); - Assert.AreEqual("You must either assign no priority to any of the hosts or give a priority for every host.", ex.Message); + Assert.That(ex.Message, Is.EqualTo("You must either assign no priority to any of the hosts or give a priority for every host")); ex = Assert.Throws(() => MySQLX.GetSession(new { server = $"(address=server.example,priority=50),(address={Host},priority=100),(address=server.example)", port = XPort, uid = uid, password = password, connecttimeout = connectionTimeout })); - Assert.AreEqual("You must either assign no priority to any of the hosts or give a priority for every host.", ex.Message); + Assert.That(ex.Message, Is.EqualTo("You must either assign no priority to any of the hosts or give a priority for every host")); // Automatically set priority if no priority is given. string hostList = string.Empty; @@ -437,11 +438,11 @@ public void PriorityMethodWithAnonymousTypes() using (var session = MySQLX.GetSession(new { server = hostList, port = XPort, uid = uid, password = password, connecttimeout = connectionTimeout })) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); priority = 100; foreach (var host in FailoverManager.FailoverGroup.Hosts) { - Assert.AreEqual(priority != 0 ? priority-- : 0, host.Priority); + Assert.That(host.Priority, Is.EqualTo(priority != 0 ? priority-- : 0)); } } } @@ -453,7 +454,7 @@ public void PriorityMethodWithAnonymousTypes() [Test, Description("Test MySQLX Client Side Failover(Implicit Failover -Not supported)")] public void ImplicitFailover() { - if (!session.Version.isAtLeast(8, 0, 8)) Assert.Ignore("This test is for MySql 8.0.8 or higher"); + Assume.That(session.Version.isAtLeast(8, 0, 8), "This test is for MySql 8.0.8 or higher"); MySqlXConnectionStringBuilder sb = new MySqlXConnectionStringBuilder(ConnectionString); string ipV6Address = GetIPV6Address(); string connectionString = $"mysqlx://test:test@[{sb.Server},{Host},{ipV6Address}:{sb.Port}]?implicit-failover"; @@ -463,9 +464,8 @@ public void ImplicitFailover() [Test, Description("Provide 101 hosts to connection without priority where 1st 100 hosts are invalid ones(Internal priority is set from 100...0) and the last host is valid")] public void ManyInvalidHost() { - if (!session.Version.isAtLeast(5, 7, 0)) Assert.Ignore("This test is for MySql 5.7 or higher"); + Assume.That(session.Version.isAtLeast(5, 7, 0), "This test is for MySql 5.7 or higher"); - var connectionTimeout = 1; MySqlXConnectionStringBuilder sb = new MySqlXConnectionStringBuilder(ConnectionString); // Automatically set priority if no priority is given. @@ -478,15 +478,14 @@ public void ManyInvalidHost() } using (var session1 = MySQLX.GetSession("server=" + hostList + ";port=" + sb.Port + ";uid=" + - sb.UserID + ";password=" + sb.Password + ";connect-timeout=" + - connectionTimeout + ";ssl-mode=Required")) + sb.UserID + ";password=" + sb.Password + ";connect-timeout=1000;ssl-mode=Required")) { - Assert.AreEqual(SessionState.Open, session1.InternalSession.SessionState); + Assert.That(session1.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); var schema = session1.GetSchema("test"); - Assert.IsNotNull(schema); + Assert.That(schema, Is.Not.Null); schema.DropCollection("test123"); var testColl = schema.CreateCollection("test123"); - Assert.IsNotNull(testColl); + Assert.That(testColl, Is.Not.Null); schema.DropCollection("test123"); } @@ -500,12 +499,12 @@ public void ManyInvalidHost() var connStr = "mysqlx://test:test@[" + hostList + "]" + "?ssl-mode=Required"; using (var session1 = MySQLX.GetSession(connStr)) { - Assert.AreEqual(SessionState.Open, session1.InternalSession.SessionState); + Assert.That(session1.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); var schema = session1.GetSchema("test"); - Assert.IsNotNull(schema); + Assert.That(schema, Is.Not.Null); schema.DropCollection("test123"); var testColl = schema.CreateCollection("test123"); - Assert.IsNotNull(testColl); + Assert.That(testColl, Is.Not.Null); schema.DropCollection("test123"); } @@ -526,12 +525,12 @@ public void ManyInvalidHost() sslmode = MySqlSslMode.Disabled })) { - Assert.AreEqual(SessionState.Open, session1.InternalSession.SessionState); + Assert.That(session1.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); var schema = session.GetSchema("test"); - Assert.IsNotNull(schema); + Assert.That(schema, Is.Not.Null); schema.DropCollection("test123"); var testColl = schema.CreateCollection("test123"); - Assert.IsNotNull(testColl); + Assert.That(testColl, Is.Not.Null); schema.DropCollection("test123"); } } @@ -539,13 +538,13 @@ public void ManyInvalidHost() [Test, Description("Provide two hosts to connection with priority where both are valid")] public void TwoValidHost() { - if (!session.Version.isAtLeast(5, 7, 0)) Assert.Ignore("This test is for MySql 5.7 or higher"); + Assume.That(session.Version.isAtLeast(5, 7, 0), "This test is for MySql 5.7 or higher"); MySqlXConnectionStringBuilder sb = new MySqlXConnectionStringBuilder(ConnectionString); var connStr = $"mysqlx://test:test@[ (address={Host}:{XPort}, priority=0,address={Host}:{XPort}, priority=100)]?ssl-mode=Required"; using (var sessionTest = MySQLX.GetSession(connStr)) { - Assert.AreEqual(SessionState.Open, sessionTest.InternalSession.SessionState); + Assert.That(sessionTest.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } var address_priority = $"(address = {Host}, priority = 0),(address={Host}, priority=100)"; @@ -554,7 +553,7 @@ public void TwoValidHost() ";password=" + sb.Password + ";ssl-mode=Required"; using (var sessionTest = MySQLX.GetSession(connStr)) { - Assert.AreEqual(SessionState.Open, sessionTest.InternalSession.SessionState); + Assert.That(sessionTest.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } using (var sessionTest = MySQLX.GetSession(new @@ -566,7 +565,7 @@ public void TwoValidHost() sslmode = MySqlSslMode.Disabled })) { - Assert.AreEqual(SessionState.Open, sessionTest.InternalSession.SessionState); + Assert.That(sessionTest.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } } @@ -574,7 +573,7 @@ public void TwoValidHost() [Test, Description("Provide two hosts to connection with priority where both are valid-with default port")] public void TwoValidHostWithDefaultPort() { - if (!session.Version.isAtLeast(5, 7, 0)) Assert.Ignore("This test is for MySql 5.7 or higher"); + Assume.That(session.Version.isAtLeast(5, 7, 0), "This test is for MySql 5.7 or higher"); MySqlXConnectionStringBuilder sb = new MySqlXConnectionStringBuilder(ConnectionString); var connStr = "mysqlx://test:test" + @@ -582,7 +581,7 @@ public void TwoValidHostWithDefaultPort() using (var sessionTest = MySQLX.GetSession(connStr)) { - Assert.AreEqual(SessionState.Open, sessionTest.InternalSession.SessionState); + Assert.That(sessionTest.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } var address_priority = $"(address={Host}, priority=0),(address={Host}, priority=100)"; @@ -590,7 +589,7 @@ public void TwoValidHostWithDefaultPort() ";ssl-mode=Required;" + "port=" + sb.Port; using (var sessionTest = MySQLX.GetSession(connStr)) { - Assert.AreEqual(SessionState.Open, sessionTest.InternalSession.SessionState); + Assert.That(sessionTest.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } using (var sessionTest = MySQLX.GetSession(new { @@ -601,14 +600,14 @@ public void TwoValidHostWithDefaultPort() port = sb.Port })) { - Assert.AreEqual(SessionState.Open, sessionTest.InternalSession.SessionState); + Assert.That(sessionTest.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } } [Test, Description("Provide a single host to connection with priority and disconnect and connect again(iterate priority from 0 - 100) ")] public void IteratedPriority() { - if (!session.Version.isAtLeast(5, 7, 0)) Assert.Ignore("This test is for MySql 5.7 or higher"); + Assume.That(session.Version.isAtLeast(5, 7, 0), "This test is for MySql 5.7 or higher"); var connectionTimeout = 900; // Automatically set priority if no priority is given. @@ -621,26 +620,26 @@ public void IteratedPriority() var test = "server=" + hostList[i] + ";uid=test;password=test;connect-timeout=" + connectionTimeout + ";ssl-mode=required;" + "port=" + XPort; using (var session1 = MySQLX.GetSession(test)) { - Assert.AreEqual(SessionState.Open, session1.InternalSession.SessionState); + Assert.That(session1.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } using (var session1 = MySQLX.GetSession("server=" + hostList[i] + ";port=" + XPort + ";uid=test;password=test;connect-timeout=" + connectionTimeout + ";ssl-mode=Required")) { - Assert.AreEqual(SessionState.Open, session1.InternalSession.SessionState); + Assert.That(session1.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } hostList[i] = "(address=" + Host + ":" + XPort + ",priority=" + (priority != 0 ? priority-- : 0) + ")"; var connStr = "mysqlx://test:test@[" + hostList[i] + "]?ssl-mode=Required"; using (var session1 = MySQLX.GetSession(connStr)) { - Assert.AreEqual(SessionState.Open, session1.InternalSession.SessionState); + Assert.That(session1.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } hostListPort[i] = $"(address={Host}:{XPort},priority={(priority != 0 ? priority-- : 0)})"; connStr = "mysqlx://test:test@[" + hostList[i] + "]?ssl-mode=Required"; using (var session1 = MySQLX.GetSession(connStr)) { - Assert.AreEqual(SessionState.Open, session1.InternalSession.SessionState); + Assert.That(session1.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } hostList[i] = "(address=" + Host + ",priority=" + (priority != 0 ? priority-- : 0) + ")"; @@ -653,7 +652,7 @@ public void IteratedPriority() sslmode = MySqlSslMode.Required })) { - Assert.AreEqual(SessionState.Open, session1.InternalSession.SessionState); + Assert.That(session1.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } } } @@ -661,7 +660,7 @@ public void IteratedPriority() [Test, Description("Provide a single host to connection with priority with SSL")] public void PriorityWithSsl() { - if (!session.Version.isAtLeast(5, 7, 0)) Assert.Ignore("This test is for MySql 5.7 or higher"); + Assume.That(session.Version.isAtLeast(5, 7, 0), "This test is for MySql 5.7 or higher"); var certificatePassword = "pass"; var certificatewrongPassword = "wrongpass"; @@ -670,14 +669,14 @@ public void PriorityWithSsl() using (var session1 = MySQLX.GetSession(connStr)) { - Assert.AreEqual(SessionState.Open, session1.InternalSession.SessionState); + Assert.That(session1.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } connStr = $"mysqlx://test:test@[ (address={Host}:{XPort}, priority=100)]" + $"/?ssl-mode=Required&ssl-ca-pwd={certificatePassword}&ssl-ca={sslCa}"; using (var session1 = MySQLX.GetSession(connStr)) { - Assert.AreEqual(SessionState.Open, session1.InternalSession.SessionState); + Assert.That(session1.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } connStr = $"mysqlx://test:test@[ (address={Host}" + ":" + XPort + ", priority=100)]" + @@ -688,14 +687,14 @@ public void PriorityWithSsl() connStr = "server=" + address_priority + ";port=" + XPort + ";uid=test;password=test;ssl-mode=VerifyCA;ssl-ca-pwd=pass;ssl-ca=" + sslCa; using (var session1 = MySQLX.GetSession(connStr)) { - Assert.AreEqual(SessionState.Open, session1.InternalSession.SessionState); + Assert.That(session1.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } address_priority = $"(address = {Host}, priority = 25)"; connStr = "server=" + address_priority + ";port=" + XPort + ";uid=test;password=test;ssl-mode=Required;ssl-ca-pwd=" + certificatePassword + ";ssl-ca=" + sslCa; using (var session1 = MySQLX.GetSession(connStr)) { - Assert.AreEqual(SessionState.Open, session1.InternalSession.SessionState); + Assert.That(session1.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } connStr = "server=" + address_priority + ";port=" + XPort + ";uid=test;password=test;ssl-mode=VerifyFull;ssl-ca-pwd=" + @@ -713,7 +712,7 @@ public void PriorityWithSsl() CertificatePassword = certificatePassword })) { - Assert.AreEqual(SessionState.Open, session1.InternalSession.SessionState); + Assert.That(session1.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } using (var session1 = MySQLX.GetSession(new @@ -727,7 +726,7 @@ public void PriorityWithSsl() CertificatePassword = certificatePassword })) { - Assert.AreEqual(SessionState.Open, session1.InternalSession.SessionState); + Assert.That(session1.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } Assert.Catch(() => MySQLX.GetSession(new @@ -764,7 +763,7 @@ public void SingleHostWithPriorityVerifyFull() CertificatePassword = certificatePassword })) { - Assert.AreEqual(SessionState.Open, session1.InternalSession.SessionState); + Assert.That(session1.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } } #endregion diff --git a/MySQL.Data/tests/MySqlX.Data.Tests/ClientTests.cs b/MySQL.Data/tests/MySqlX.Data.Tests/ClientTests.cs index b1bd83d3b..f50aa09fe 100644 --- a/MySQL.Data/tests/MySqlX.Data.Tests/ClientTests.cs +++ b/MySQL.Data/tests/MySqlX.Data.Tests/ClientTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2018, 2022, Oracle and/or its affiliates. +// Copyright © 2018, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -33,6 +33,7 @@ using MySqlX.XDevAPI.Common; using MySqlX.XDevAPI.Relational; using NUnit.Framework; +using NUnit.Framework.Legacy; using System; using System.Collections.Generic; using System.Diagnostics; @@ -83,7 +84,7 @@ public void ParseConnectionOptionsTest(ClientOptions clientOptions) { Client.ConnectionOptions poolingOptions = (Client.ConnectionOptions)clientOptions.Options; Client.ConnectionOptions connectionOptionsResult = Client.ParseConnectionOptions(clientOptions.ConnectionOptions); - Assert.True(poolingOptions.Equals(connectionOptionsResult)); + Assert.That(poolingOptions.Equals(connectionOptionsResult)); } public struct InvalidOptions @@ -252,7 +253,7 @@ public void PoolingTest(PoolingTestData poolingTestData) Session session = client.GetSession(); string host = session.SQL("SELECT host FROM information_schema.PROCESSLIST where id=CONNECTION_ID()").Execute().FetchOne().GetString("host"); sessions.Add(session); - Assert.Contains(host, hosts); + Assert.That(hosts, Does.Contain(host)); } closeSessions.Invoke(); } @@ -263,7 +264,7 @@ public void PoolingTest(PoolingTestData poolingTestData) [Property("Category", "Security")] public void QueueTimeoutTest() { - if (Platform.IsWindows()) Assert.Ignore("Fix this for Windows OS"); + Assume.That(!Platform.IsWindows(), "Fix this for Windows OS"); int timeout = 3000; using (Client client = MySQLX.GetClient(ConnectionString, new { pooling = new { maxSize = 1, queueTimeout = timeout } })) { @@ -272,8 +273,8 @@ public void QueueTimeoutTest() Stopwatch stopwatch = Stopwatch.StartNew(); TimeoutException ex = Assert.Throws(() => { Session session2 = client.GetSession(); }); stopwatch.Stop(); - Assert.AreEqual(ResourcesX.PoolingQueueTimeout, ex.Message); - Assert.True(stopwatch.ElapsedMilliseconds >= timeout); + Assert.That(ex.Message, Is.EqualTo(ResourcesX.PoolingQueueTimeout)); + Assert.That(stopwatch.ElapsedMilliseconds >= timeout); } } } @@ -287,10 +288,10 @@ public void ReuseSessions() using (Client client = MySQLX.GetClient(ConnectionString, new { pooling = new { maxSize = size, queueTimeout = timeout } })) { Session session = client.GetSession(); - Assert.AreEqual((sbyte)5, session.SQL("SELECT 5").Execute().FetchOne()[0]); + Assert.That(session.SQL("SELECT 5").Execute().FetchOne()[0], Is.EqualTo((sbyte)5)); session.Close(); MySqlException ex = Assert.Throws(() => { session.SQL("SELECT 5").Execute(); }); - Assert.AreEqual(ResourcesX.InvalidSession, ex.Message); + Assert.That(ex.Message, Is.EqualTo(ResourcesX.InvalidSession)); } } @@ -322,7 +323,7 @@ public void MultiHostTest(MultiHostData multiHostData) { using (Session session = client.GetSession()) { - Assert.AreEqual((sbyte)8, session.SQL("SELECT 8").Execute().FetchOne()[0]); + Assert.That(session.SQL("SELECT 8").Execute().FetchOne()[0], Is.EqualTo((sbyte)8)); } } } @@ -353,9 +354,9 @@ public void CloseTests(CloseData closeData) session.DropSchema(schemaName); session.CreateSchema(schemaName); client.Close(); - Assert.AreEqual(SessionState.Closed, session.XSession.SessionState); + Assert.That(session.XSession.SessionState, Is.EqualTo(SessionState.Closed)); MySqlException ex = Assert.Throws(() => { closeData.Action.Invoke(session); }); - Assert.AreEqual(ResourcesX.InvalidSession, ex.Message); + Assert.That(ex.Message, Is.EqualTo(ResourcesX.InvalidSession)); } } } @@ -401,22 +402,22 @@ private void ResetTestBeforeClose(Session session, int id) session.SQL(string.Format("SET @a='session{0}'", id)).Execute(); SqlResult res = session.SQL("SELECT @a AS a").Execute(); - Assert.AreEqual("session" + id, res.FetchAll()[0][0]); + Assert.That(res.FetchAll()[0][0], Is.EqualTo("session" + id)); res = session.SQL("SHOW CREATE TABLE testResetSession" + id).Execute(); - Assert.AreEqual("testResetSession" + id, res.FetchAll()[0][0]); + Assert.That(res.FetchAll()[0][0], Is.EqualTo("testResetSession" + id)); } private void ResetTestAfterClose(Session session, int threadId, int id) { - Assert.AreEqual(threadId, session.ThreadId); + Assert.That(session.ThreadId, Is.EqualTo(threadId)); SqlResult res = session.SQL("SELECT @a IS NULL").Execute(); - Assert.AreEqual((sbyte)1, res.FetchOne()[0]); + Assert.That(res.FetchOne()[0], Is.EqualTo((sbyte)1)); var ex = Assert.Throws(() => session.SQL("SHOW CREATE TABLE testResetSession" + id).Execute()); - StringAssert.AreEqualIgnoringCase(string.Format("Table 'test.testresetsession{0}' doesn't exist", id), ex.Message); + Assert.That(ex.Message, Is.EqualTo(string.Format("Table 'test.testresetsession{0}' doesn't exist", id)).IgnoreCase); session.SQL(string.Format("SET @a='session{0}'", id)).Execute(); res = session.SQL("SELECT @a AS a").Execute(); - Assert.AreEqual("session" + id, res.FetchAll()[0][0]); + Assert.That(res.FetchAll()[0][0], Is.EqualTo("session" + id)); } /// @@ -426,7 +427,7 @@ private void ResetTestAfterClose(Session session, int threadId, int id) [Property("Category", "Security")] public void ConnectionAttributes() { - if (!(session.Version.isAtLeast(8, 0, 16))) Assert.Ignore("This test is for MySql 8.0.16 or higher"); + Assume.That(session.Version.isAtLeast(8, 0, 16), "This test is for MySql 8.0.16 or higher"); // Validate that MySQLX.GetSession() supports a new 'connection-attributes' query parameter // with default values and all the client attributes starts with a '_'. @@ -452,13 +453,13 @@ public void ConnectionAttributes() // Errors var ex = Assert.Throws(() => MySQLX.GetSession(ConnectionString + ";connection-attributes=[_key=value]")); - Assert.AreEqual(ResourcesX.InvalidUserDefinedAttribute, ex.Message); + Assert.That(ex.Message, Is.EqualTo(ResourcesX.InvalidUserDefinedAttribute)); ex = Assert.Throws(() => MySQLX.GetSession(ConnectionString + ";connection-attributes=123")); - Assert.AreEqual(ResourcesX.InvalidConnectionAttributes, ex.Message); + Assert.That(ex.Message, Is.EqualTo(ResourcesX.InvalidConnectionAttributes)); ex = Assert.Throws(() => MySQLX.GetSession(ConnectionString + ";connection-attributes=[key=value,key=value2]")); - Assert.AreEqual(string.Format(ResourcesX.DuplicateUserDefinedAttribute, "key"), ex.Message); + Assert.That(ex.Message, Is.EqualTo(string.Format(ResourcesX.DuplicateUserDefinedAttribute, "key"))); MySqlXConnectionStringBuilder builder = new MySqlXConnectionStringBuilder(); builder.Server = Host; @@ -466,7 +467,7 @@ public void ConnectionAttributes() builder.UserID = RootUser; builder.ConnectionAttributes = ";"; ex = Assert.Throws(() => MySQLX.GetClient(builder.ConnectionString, "{ \"pooling\": { \"enabled\": true } }")); - Assert.AreEqual("The requested value ';' is invalid for the given keyword 'connection-attributes'.", ex.Message); + Assert.That(ex.Message, Is.EqualTo("The requested value ';' is invalid for the given keyword 'connection-attributes'")); } private void TestConnectionAttributes(string connString, Dictionary userAttrs = null) @@ -476,31 +477,31 @@ private void TestConnectionAttributes(string connString, Dictionary client2.GetSession()); @@ -742,31 +743,31 @@ public void MaxSizeOptionTests(string inputType) using (var client1 = MySQLX.GetClient(ConnectionString, (inputType == "string" ? connectionpooling : connectionpoolingObject)[i])) { var session1 = client1.GetSession(); - Assert.AreEqual(SessionState.Open, session1.InternalSession.SessionState); + Assert.That(session1.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } //Uri using (var client1 = MySQLX.GetClient(ConnectionStringUri, (inputType == "string" ? connectionpooling : connectionpoolingObject)[i])) { var session1 = client1.GetSession(); - Assert.AreEqual(SessionState.Open, session1.InternalSession.SessionState); + Assert.That(session1.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } //Connectin Object using (var client1 = MySQLX.GetClient(connObject, (inputType == "string" ? connectionpooling : connectionpoolingObject)[i])) { var session1 = client1.GetSession(); - Assert.AreEqual(SessionState.Open, session1.InternalSession.SessionState); + Assert.That(session1.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } } else { Exception ex = Assert.Catch(() => MySQLX.GetClient(ConnectionString, (inputType == "string" ? connectionpooling : connectionpoolingObject)[i])); - Assert.True(ex.Message.Contains("'pooling.maxSize' does not support value"), "Expected Exception"); + Assert.That(ex.Message.Contains("'pooling.maxSize' does not support value"), "Expected Exception"); ex = Assert.Catch(() => MySQLX.GetClient(ConnectionStringUri, (inputType == "string" ? connectionpooling : connectionpoolingObject)[i])); - Assert.True(ex.Message.Contains("'pooling.maxSize' does not support value"), "Expected Exception"); + Assert.That(ex.Message.Contains("'pooling.maxSize' does not support value"), "Expected Exception"); ex = Assert.Catch(() => MySQLX.GetClient(connObject, (inputType == "string" ? connectionpooling : connectionpoolingObject)[i])); - Assert.True(ex.Message.Contains("'pooling.maxSize' does not support value"), "Expected Exception"); + Assert.That(ex.Message.Contains("'pooling.maxSize' does not support value"), "Expected Exception"); } } } @@ -816,7 +817,7 @@ public void maxIdleTimeOptionTests(string inputType) [Test, Description("Test queueTimeout with different values")] public void QueueTimeoutOptionTests(string inputType) { - if (Platform.IsWindows()) Assert.Ignore("Fix this for Windows OS"); + Assume.That(!Platform.IsWindows(), "Fix this for Windows OS"); int timeoutMS = 3000; string[] connectionpooling = { "{ \"pooling\": { \"maxSize\": 2,\"queueTimeout\": " + timeoutMS + " } }", "{ \"pooling\": { \"queueTimeout\": true} }", "{ \"pooling\": { \"queueTimeout\": 'true'} }", "{ \"pooling\": { \"queueTimeout\": -1} }", "{ \"pooling\": { \"queueTimeout\": 84584759345 } }", "{ \"pooling\": { \"queueTimeout\": } }" }; @@ -833,7 +834,7 @@ public void QueueTimeoutOptionTests(string inputType) Stopwatch stopwatch = Stopwatch.StartNew(); Assert.Catch(() => client1.GetSession()); stopwatch.Stop(); - Assert.True(stopwatch.ElapsedMilliseconds >= timeoutMS); + Assert.That(stopwatch.ElapsedMilliseconds >= timeoutMS); } //Uri @@ -844,7 +845,7 @@ public void QueueTimeoutOptionTests(string inputType) Stopwatch stopwatch = Stopwatch.StartNew(); Assert.Catch(() => client1.GetSession()); stopwatch.Stop(); - Assert.True(stopwatch.ElapsedMilliseconds >= timeoutMS); + Assert.That(stopwatch.ElapsedMilliseconds >= timeoutMS); } //Anonymous Object @@ -855,7 +856,7 @@ public void QueueTimeoutOptionTests(string inputType) Stopwatch stopwatch = Stopwatch.StartNew(); Assert.Catch(() => client1.GetSession()); stopwatch.Stop(); - Assert.True(stopwatch.ElapsedMilliseconds >= timeoutMS); + Assert.That(stopwatch.ElapsedMilliseconds >= timeoutMS); } } else @@ -898,13 +899,13 @@ public void InvalidConnectionOptions(string inputType) { //Connection string Exception ex = Assert.Catch(() => MySQLX.GetClient(ConnectionString, (inputType == "string" ? connectionpooling : connectionpoolingObject)[i])); - Assert.True(ex is ArgumentNullException || ex is ArgumentException); + Assert.That(ex is ArgumentNullException || ex is ArgumentException); //Uri ex = Assert.Catch(() => MySQLX.GetClient(ConnectionStringUri, (inputType == "string" ? connectionpooling : connectionpoolingObject)[i])); - Assert.True(ex is ArgumentNullException || ex is ArgumentException); + Assert.That(ex is ArgumentNullException || ex is ArgumentException); //Anonymous object ex = Assert.Catch(() => MySQLX.GetClient(connObject, (inputType == "string" ? connectionpooling : connectionpoolingObject)[i])); - Assert.True(ex is ArgumentNullException || ex is ArgumentException); + Assert.That(ex is ArgumentNullException || ex is ArgumentException); } } @@ -941,10 +942,10 @@ public void MultipleHostsAndPriorityTests(string inputType, int hostNameOrIP) using (var localSession = client1.GetSession()) { var schema = localSession.GetSchema("test"); - Assert.IsNotNull(schema); + Assert.That(schema, Is.Not.Null); schema.DropCollection("test123"); var testColl = schema.CreateCollection("test123"); - Assert.IsNotNull(testColl); + Assert.That(testColl, Is.Not.Null); schema.DropCollection("test123"); } } @@ -972,10 +973,10 @@ public void MultipleHostsAndPriorityTests(string inputType, int hostNameOrIP) using (var localSession = client1.GetSession()) { var schema = localSession.GetSchema("test"); - Assert.IsNotNull(schema); + Assert.That(schema, Is.Not.Null); schema.DropCollection("test123"); var testColl = schema.CreateCollection("test123"); - Assert.IsNotNull(testColl); + Assert.That(testColl, Is.Not.Null); schema.DropCollection("test123"); } } @@ -997,10 +998,10 @@ public void MultipleHostsAndPriorityTests(string inputType, int hostNameOrIP) using (var localSession = client1.GetSession()) { var schema = localSession.GetSchema("test"); - Assert.IsNotNull(schema); + Assert.That(schema, Is.Not.Null); schema.DropCollection("test123"); var testColl = schema.CreateCollection("test123"); - Assert.IsNotNull(testColl); + Assert.That(testColl, Is.Not.Null); schema.DropCollection("test123"); } } @@ -1035,41 +1036,41 @@ public void SessionCreatedByClient() using (var client1 = MySQLX.GetClient(ConnectionString, connectionpoolingObject)) { var rs1 = client1.GetSession(); - Assert.AreEqual(SessionState.Open, rs1.InternalSession.SessionState); + Assert.That(rs1.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } using (var client1 = MySQLX.GetClient(ConnectionStringUri, connectionpoolingObject)) { client1.GetSession(); var rs1 = client1.GetSession(); - Assert.AreEqual(SessionState.Open, rs1.InternalSession.SessionState); + Assert.That(rs1.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } using (var client1 = MySQLX.GetClient(connObject, connectionpoolingObject)) { client1.GetSession(); var rs1 = client1.GetSession(); - Assert.AreEqual(SessionState.Open, rs1.InternalSession.SessionState); + Assert.That(rs1.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } using (var client1 = MySQLX.GetClient(ConnectionString, connectionpooling)) { var rs1 = client1.GetSession(); - Assert.AreEqual(SessionState.Open, rs1.InternalSession.SessionState); + Assert.That(rs1.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } using (var client1 = MySQLX.GetClient(ConnectionStringUri, connectionpooling)) { client1.GetSession(); var rs1 = client1.GetSession(); - Assert.AreEqual(SessionState.Open, rs1.InternalSession.SessionState); + Assert.That(rs1.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } using (var client1 = MySQLX.GetClient(connObject, connectionpooling)) { client1.GetSession(); var rs1 = client1.GetSession(); - Assert.AreEqual(SessionState.Open, rs1.InternalSession.SessionState); + Assert.That(rs1.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } } @@ -1371,7 +1372,7 @@ public void SessionResetConnectionState() } else { col1 = db1.CreateCollection("my_collection1"); } col1 = db1.GetCollection("my_collection1", true); - Assert.IsNotNull(col1); + Assert.That(col1, Is.Not.Null); var db2 = session2.GetSchema("test2"); if (db2.ExistsInDatabase()) @@ -1388,7 +1389,7 @@ public void SessionResetConnectionState() } else { col2 = db2.CreateCollection("my_collection2"); } col2 = db2.GetCollection("my_collection2", true); - Assert.IsNotNull(col2); + Assert.That(col2, Is.Not.Null); session1.Close(); DbDoc DbDocs1 = new DbDoc(); @@ -1397,21 +1398,21 @@ public void SessionResetConnectionState() db1 = session1.GetSchema("test1"); Exception ex = Assert.Throws(() => db1.ExistsInDatabase()); - StringAssert.Contains("Session state is not valid", ex.Message); + Assert.That(ex.Message, Does.Contain("Session state is not valid")); var result = col2.Add(DbDocs1).Execute(); - Assert.IsNotNull(result); + Assert.That(result, Is.Not.Null); session1 = client1.GetSession(); db1 = session1.GetSchema("test1"); col1 = db1.GetCollection("my_collection1", true); result = col1.Add(DbDocs1).Execute(); - Assert.IsNotNull(result); + Assert.That(result, Is.Not.Null); session1.Close(); db1 = session1.GetSchema("test1"); ex = Assert.Throws(() => db1.ExistsInDatabase()); - StringAssert.Contains("Session state is not valid", ex.Message); + Assert.That(ex.Message, Does.Contain("Session state is not valid")); session2.DropSchema("test1"); session2.DropSchema("test2"); @@ -1423,7 +1424,7 @@ public void SessionResetConnectionState() [Test, Description("MAX LENGTH OF KEY VALUE PAIR OF USER DEFINED CONNECTION ATTRIBUTES")] public void ConnectionAttributesLongValue() { - if (!(session.Version.isAtLeast(8, 0, 16))) Assert.Ignore("This test is for MySql 8.0.16 or higher"); + Assume.That(session.Version.isAtLeast(8, 0, 16), "This test is for MySql 8.0.16 or higher"); var serverSupportedSize = Convert.ToInt32(session.SQL("select @@Global.performance_schema_session_connect_attrs_size;").Execute().First()[0]); var connectAttributesLost = Convert.ToInt32(session.SQL("SHOW STATUS LIKE 'Performance_schema_session_connect_attrs_lost'").Execute().FirstOrDefault()[1]); @@ -1441,16 +1442,16 @@ public void ConnectionAttributesLongValue() //Connection String using (var s1 = MySQLX.GetSession($"{ConnectionString};connectionattributes={maxCombi}")) { - Assert.AreEqual(SessionState.Open, s1.InternalSession.SessionState); + Assert.That(s1.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); var truncatedValues = (int)session.SQL("SHOW STATUS LIKE 'Performance_schema_session_connect_attrs_lost'").Execute().First()[0]; - Assert.True(truncatedValues > connectAttributesLost); + Assert.That(truncatedValues > connectAttributesLost); } //Uri using (var s1 = MySQLX.GetSession($"{ConnectionStringUri}?connectionattributes={maxCombi}")) { - Assert.AreEqual(SessionState.Open, s1.InternalSession.SessionState); + Assert.That(s1.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); var truncatedValues = (int)session.SQL("SHOW STATUS LIKE 'Performance_schema_session_connect_attrs_lost'").Execute().First()[0]; - Assert.True(truncatedValues > connectAttributesLost); + Assert.That(truncatedValues > connectAttributesLost); } //Anonymous Object using (var s1 = MySQLX.GetSession(new @@ -1462,9 +1463,9 @@ public void ConnectionAttributesLongValue() ConnectionAttributes = maxCombi })) { - Assert.AreEqual(SessionState.Open, s1.InternalSession.SessionState); + Assert.That(s1.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); var truncatedValues = (int)session.SQL("SHOW STATUS LIKE 'Performance_schema_session_connect_attrs_lost'").Execute().First()[0]; - Assert.True(truncatedValues > connectAttributesLost); + Assert.That(truncatedValues > connectAttributesLost); } } } @@ -1472,21 +1473,21 @@ public void ConnectionAttributesLongValue() [Test, Description("GETSESSION THROWS EXCEPTION WHEN EQUAL IS USED AS PARAM FOR CONN ATTRIBUTE IN CONN ANONYMOUS OBJECT-WL#12514")] public void GetSessionExceptionWithConnetionAttribute() { - if (!(session.Version.isAtLeast(8, 0, 16))) Assert.Ignore("This test is for MySql 8.0.16 or higher"); + Assume.That(session.Version.isAtLeast(8, 0, 16), "This test is for MySql 8.0.16 or higher"); MySqlXConnectionStringBuilder sb = new MySqlXConnectionStringBuilder(ConnectionString); using (Client client = MySQLX.GetClient(new { server = sb.Server, port = XPort, user = sb.UserID, password = sb.Password, ConnectionAttributes = "=" } , "{ \"pooling\": { \"enabled\": true } }")) { Exception ex = Assert.Throws(() => client.GetSession()); - Assert.AreEqual("The requested value '=' is invalid for the given keyword 'connection-attributes'.", ex.Message); + Assert.That(ex.Message, Is.EqualTo("The requested value '=' is invalid for the given keyword 'connection-attributes'")); } } [Test, Description("Connection Attributes with arrays")] public void ConnectionAttributesWithArrays() { - if (!Platform.IsWindows()) Assert.Ignore("This test is for Windows OS only"); - if (!(session.Version.isAtLeast(8, 0, 16))) Assert.Ignore("This test is for MySql 8.0.16 or higher"); + Assume.That(Platform.IsWindows(), "This test is for Windows OS only."); + Assume.That(session.Version.isAtLeast(8, 0, 16), "This test is for MySql 8.0.16 or higher"); object[] arrayCases = new object[] { "[var1 = 1, 2, 3]", "[var1 = { 1, 2, 3}]" }; for (int i = 0; i < arrayCases.Length; i++) @@ -1496,7 +1497,7 @@ public void ConnectionAttributesWithArrays() { using (Session session1 = client.GetSession()) { - Assert.AreEqual(SessionState.Open, session1.InternalSession.SessionState); + Assert.That(session1.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } } //Uri @@ -1504,7 +1505,7 @@ public void ConnectionAttributesWithArrays() { using (Session session1 = client.GetSession()) { - Assert.AreEqual(SessionState.Open, session1.InternalSession.SessionState); + Assert.That(session1.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } } //Anonymous Object @@ -1513,7 +1514,7 @@ public void ConnectionAttributesWithArrays() { using (Session session1 = client.GetSession()) { - Assert.AreEqual(SessionState.Open, session1.InternalSession.SessionState); + Assert.That(session1.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } } //MySqlXConnectionStringBuilder @@ -1533,24 +1534,24 @@ public void ConnectionAttributesWithArrays() { using (Session session1 = client.GetSession()) { - Assert.AreEqual(SessionState.Open, session1.InternalSession.SessionState); + Assert.That(session1.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } } //Connection string using (Session session1 = MySQLX.GetSession(ConnectionString + ";connection-attributes=" + arrayCases[i])) { - Assert.AreEqual(SessionState.Open, session1.InternalSession.SessionState); + Assert.That(session1.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } //Uri using (Session session1 = MySQLX.GetSession(ConnectionStringUri + "?connection-attributes=" + arrayCases[i])) { - Assert.AreEqual(SessionState.Open, session1.InternalSession.SessionState); + Assert.That(session1.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } //Anonymous Object sb = new MySqlXConnectionStringBuilder(ConnectionString); using (Session session1 = MySQLX.GetSession(new { server = sb.Server, port = XPort, user = sb.UserID, password = sb.Password, ConnectionAttributes = arrayCases[i] })) { - Assert.AreEqual(SessionState.Open, session1.InternalSession.SessionState); + Assert.That(session1.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } //MySqlXConnectionStringBuilder mysqlx0 = new MySqlXConnectionStringBuilder(ConnectionString); @@ -1567,7 +1568,7 @@ public void ConnectionAttributesWithArrays() mysqlx0.ConnectionAttributes = arrayCases[i].ToString(); using (Session session1 = MySQLX.GetSession(mysqlx0.ConnectionString)) { - Assert.AreEqual(SessionState.Open, session1.InternalSession.SessionState); + Assert.That(session1.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } } } @@ -1575,13 +1576,13 @@ public void ConnectionAttributesWithArrays() [Test] public void NormalConnectionWithUri() { - if (!(session.Version.isAtLeast(8, 0, 16))) Assert.Ignore("This test is for MySql 8.0.16 or higher"); + Assume.That(session.Version.isAtLeast(8, 0, 16), "This test is for MySql 8.0.16 or higher"); //Normal connection with URI using (Client client = MySQLX.GetClient(ConnectionStringUri, "{ \"pooling\": { \"enabled\": true } }")) { using (Session session1 = client.GetSession()) { - Assert.AreEqual(SessionState.Open, session1.InternalSession.SessionState); + Assert.That(session1.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } } } @@ -1590,7 +1591,7 @@ public void NormalConnectionWithUri() [Ignore("Bug #33234243 need to fix Uri scenario")] public void ConnectionAttributesRepeated() { - if (!(session.Version.isAtLeast(8, 0, 16))) Assert.Ignore("This test is for MySql 8.0.16 or higher"); + Assume.That(session.Version.isAtLeast(8, 0, 16), "This test is for MySql 8.0.16 or higher"); //Connection String Assert.Catch(() => MySQLX.GetClient(ConnectionString + ";connection-attributes=true;connection-attributes=true;", "{ \"pooling\": { \"enabled\": true } }")); Assert.Catch(() => MySQLX.GetSession(ConnectionString + ";connection-attributes=true;connection-attributes=true;")); @@ -1602,26 +1603,26 @@ public void ConnectionAttributesRepeated() [Test, Description("Connection Attributes with key Repeated - Extending scenarios in ConnectionAttributes()")] public void ConnectionAttributesKeyRepeatedChars() { - if (!(session.Version.isAtLeast(8, 0, 16))) Assert.Ignore("This test is for MySql 8.0.16 or higher"); + Assume.That(session.Version.isAtLeast(8, 0, 16), "This test is for MySql 8.0.16 or higher"); var expectedMsg = string.Format(ResourcesX.DuplicateUserDefinedAttribute, "quua"); //Connection String using (Client client = MySQLX.GetClient(ConnectionString + ";connection-attributes=[quua=bar,quua=qux,key]", "{ \"pooling\": { \"enabled\": true } }")) { Exception ex = Assert.Throws(() => client.GetSession()); - Assert.AreEqual(expectedMsg, ex.Message); + Assert.That(ex.Message, Is.EqualTo(expectedMsg)); } //Uri using (Client client = MySQLX.GetClient(ConnectionStringUri + "?connection-attributes=[quua=bar,quua=qux,key];", "{ \"pooling\": { \"enabled\": true } }")) { Exception ex = Assert.Throws(() => client.GetSession()); - Assert.AreEqual(expectedMsg, ex.Message); + Assert.That(ex.Message, Is.EqualTo(expectedMsg)); } //Anonymous Object MySqlXConnectionStringBuilder sb = new MySqlXConnectionStringBuilder(ConnectionString); using (Client client = MySQLX.GetClient(new { server = sb.Server, port = XPort, user = sb.UserID, password = sb.Password, ConnectionAttributes = "[quua=bar,quua=qux,key=]" }, "{ \"pooling\": { \"enabled\": true } }")) { Exception ex = Assert.Throws(() => client.GetSession()); - Assert.AreEqual(expectedMsg, ex.Message); + Assert.That(ex.Message, Is.EqualTo(expectedMsg)); } if (Platform.IsWindows()) @@ -1641,18 +1642,18 @@ public void ConnectionAttributesKeyRepeatedChars() using (Client client = MySQLX.GetClient(mysqlx0.ConnectionString, "{ \"pooling\": { \"enabled\": true } }")) { Exception ex = Assert.Throws(() => client.GetSession()); - Assert.AreEqual(expectedMsg, ex.Message); + Assert.That(ex.Message, Is.EqualTo(expectedMsg)); } //Connection String Exception ex1 = Assert.Throws(() => MySQLX.GetSession(ConnectionString + ";connection-attributes=[quua=bar,quua=qux,key]")); - Assert.AreEqual(expectedMsg, ex1.Message); + Assert.That(ex1.Message, Is.EqualTo(expectedMsg)); //Uri ex1 = Assert.Throws(() => MySQLX.GetSession(ConnectionStringUri + "?connection-attributes=[quua=bar,quua=qux,key];")); - Assert.AreEqual(expectedMsg, ex1.Message); + Assert.That(ex1.Message, Is.EqualTo(expectedMsg)); //Anonymous Object sb = new MySqlXConnectionStringBuilder(ConnectionString); ex1 = Assert.Throws(() => MySQLX.GetSession(new { server = sb.Server, port = XPort, user = sb.UserID, password = sb.Password, ConnectionAttributes = "[quua=bar,quua=qux,key=]" })); - Assert.AreEqual(expectedMsg, ex1.Message); + Assert.That(ex1.Message, Is.EqualTo(expectedMsg)); //MySqlXConnectionStringBuilder mysqlx0 = new MySqlXConnectionStringBuilder(ConnectionString); mysqlx0.Database = schemaName; @@ -1666,32 +1667,32 @@ public void ConnectionAttributesKeyRepeatedChars() mysqlx0.CertificateThumbprint = ""; mysqlx0.ConnectionAttributes = "[quua=bar,quua=qux,key=]"; ex1 = Assert.Throws(() => MySQLX.GetSession(mysqlx0.ConnectionString)); - Assert.AreEqual(expectedMsg, ex1.Message); + Assert.That(ex1.Message, Is.EqualTo(expectedMsg)); } } [Test, Description("Connection Attributes with key 33 characters - Extending scenarios in ConnectionAttributes()")] public void ConnectionAttributesWithKey33Chars() { - if (!(session.Version.isAtLeast(8, 0, 16))) Assert.Ignore("This test is for MySql 8.0.16 or higher"); + Assume.That(session.Version.isAtLeast(8, 0, 16), "This test is for MySql 8.0.16 or higher"); var errorMsg = "Key name beginning with 'foo32foo32foo32foo32foo32foo3232'... is too long, currently limited to 32"; using (Client client = MySQLX.GetClient(ConnectionString + ";connection-attributes=[foo32foo32foo32foo32foo32foo32323=bar,quua=qux,key]", "{ \"pooling\": { \"enabled\": true } }")) { Exception ex = Assert.Throws(() => client.GetSession()); - Assert.AreEqual(errorMsg, ex.Message); + Assert.That(ex.Message, Is.EqualTo(errorMsg)); } using (Client client = MySQLX.GetClient(ConnectionStringUri + "?connection-attributes=[foo32foo32foo32foo32foo32foo32323=bar,quua=qux,key];", "{ \"pooling\": { \"enabled\": true } }")) { Exception ex = Assert.Throws(() => client.GetSession()); - Assert.AreEqual(errorMsg, ex.Message); + Assert.That(ex.Message, Is.EqualTo(errorMsg)); } MySqlXConnectionStringBuilder sb = new MySqlXConnectionStringBuilder(ConnectionString); using (Client client = MySQLX.GetClient(new { server = sb.Server, port = XPort, user = sb.UserID, password = sb.Password, ConnectionAttributes = "[foo32foo32foo32foo32foo32foo32323=bar,quua=qux,key=]" }, "{ \"pooling\": { \"enabled\": true } }")) { Exception ex = Assert.Throws(() => client.GetSession()); - Assert.AreEqual(errorMsg, ex.Message); + Assert.That(ex.Message, Is.EqualTo(errorMsg)); } if (Platform.IsWindows()) @@ -1709,18 +1710,18 @@ public void ConnectionAttributesWithKey33Chars() using (Client client = MySQLX.GetClient(mysqlx0.ConnectionString, "{ \"pooling\": { \"enabled\": true } }")) { Exception ex = Assert.Throws(() => client.GetSession()); - Assert.AreEqual(errorMsg, ex.Message); + Assert.That(ex.Message, Is.EqualTo(errorMsg)); } Exception ex1 = Assert.Throws(() => MySQLX.GetSession(ConnectionString + ";connection-attributes=[foo32foo32foo32foo32foo32foo32323=bar,quua=qux,key]")); - Assert.AreEqual(errorMsg, ex1.Message); + Assert.That(ex1.Message, Is.EqualTo(errorMsg)); ex1 = Assert.Throws(() => MySQLX.GetSession(ConnectionStringUri + "?connection-attributes=[foo32foo32foo32foo32foo32foo32323=bar,quua=qux,key];")); - Assert.AreEqual(errorMsg, ex1.Message); + Assert.That(ex1.Message, Is.EqualTo(errorMsg)); sb = new MySqlXConnectionStringBuilder(ConnectionString); ex1 = Assert.Throws(() => MySQLX.GetSession(new { server = sb.Server, port = XPort, user = sb.UserID, password = sb.Password, ConnectionAttributes = "[foo32foo32foo32foo32foo32foo32323=bar,quua=qux,key=]" })); - Assert.AreEqual(errorMsg, ex1.Message); + Assert.That(ex1.Message, Is.EqualTo(errorMsg)); mysqlx0 = new MySqlXConnectionStringBuilder(ConnectionString); mysqlx0.CharacterSet = "utf8mb4"; @@ -1733,36 +1734,36 @@ public void ConnectionAttributesWithKey33Chars() mysqlx0.CertificateThumbprint = ""; mysqlx0.ConnectionAttributes = "[foo32foo32foo32foo32foo32foo32323=bar,quua=qux,key=]"; ex1 = Assert.Throws(() => MySQLX.GetSession(mysqlx0.ConnectionString)); - Assert.AreEqual(errorMsg, ex1.Message); + Assert.That(ex1.Message, Is.EqualTo(errorMsg)); } } [Test, Description("Connection Attributes with invalid combinations - Extending scenarios in ConnectionAttributes()")] public void ConnectionAttributesInvalidCombinations() { - if (!(session.Version.isAtLeast(8, 0, 16))) Assert.Ignore("This test is for MySql 8.0.16 or higher"); + Assume.That(session.Version.isAtLeast(8, 0, 16), "This test is for MySql 8.0.16 or higher"); object[] invalid = new object[] { "var1", "1", "2", "(var1)", "{var1}", "[_testValue = test123, emptyValue]" }; - var errorMsgs = new string[] { @"The value of ""connection-attributes"" must be either a boolean or a list of key-value pairs.", @"Key names in ""connection-attributes"" cannot start with ""_""." }; + var errorMsgs = new string[] { @"The value of ""connection-attributes"" must be either a boolean or a list of key-value pairs", @"Key names in ""connection-attributes"" cannot start with ""_""" }; for (int i = 0; i < invalid.Length; i++) { //Connection String using (Client client = MySQLX.GetClient(ConnectionString + ";connection-attributes=" + invalid[i], "{ \"pooling\": { \"enabled\": true } }")) { Exception ex = Assert.Throws(() => client.GetSession()); - Assert.True(errorMsgs.Contains(ex.Message)); + Assert.That(errorMsgs.Contains(ex.Message)); } //Uri using (Client client = MySQLX.GetClient(ConnectionStringUri + "?connection-attributes=" + invalid[i], "{ \"pooling\": { \"enabled\": true } }")) { Exception ex = Assert.Throws(() => client.GetSession()); - Assert.True(errorMsgs.Contains(ex.Message)); + Assert.That(errorMsgs.Contains(ex.Message)); } //Anonymous object MySqlXConnectionStringBuilder sb = new MySqlXConnectionStringBuilder(ConnectionString); using (Client client = MySQLX.GetClient(new { server = sb.Server, port = XPort, user = sb.UserID, password = sb.Password, ConnectionAttributes = invalid[i] }, "{ \"pooling\": { \"enabled\": true } }")) { Exception ex = Assert.Throws(() => client.GetSession()); - Assert.True(errorMsgs.Contains(ex.Message)); + Assert.That(errorMsgs.Contains(ex.Message)); } if (Platform.IsWindows()) @@ -1772,7 +1773,7 @@ public void ConnectionAttributesInvalidCombinations() mysqlx0.Database = schemaName; mysqlx0.CharacterSet = "utf8mb4"; mysqlx0.SslMode = MySqlSslMode.Required; - mysqlx0.ConnectTimeout = 10; + mysqlx0.ConnectTimeout = 1000; mysqlx0.Keepalive = 10; mysqlx0.CertificateFile = sslCa; mysqlx0.CertificatePassword = sslCertificatePassword; @@ -1782,25 +1783,25 @@ public void ConnectionAttributesInvalidCombinations() using (Client client = MySQLX.GetClient(mysqlx0.ConnectionString, "{ \"pooling\": { \"enabled\": true } }")) { Exception ex = Assert.Throws(() => client.GetSession()); - Assert.True(errorMsgs.Contains(ex.Message)); + Assert.That(errorMsgs.Contains(ex.Message)); } //Connection String Exception ex1 = Assert.Throws(() => MySQLX.GetSession(ConnectionString + ";connection-attributes=" + invalid[i])); - Assert.True(errorMsgs.Contains(ex1.Message)); + Assert.That(errorMsgs.Contains(ex1.Message)); //Uri ex1 = Assert.Throws(() => MySQLX.GetSession(ConnectionStringUri + "?connection-attributes=" + invalid[i])); - Assert.True(errorMsgs.Contains(ex1.Message)); + Assert.That(errorMsgs.Contains(ex1.Message)); //Anonymous object sb = new MySqlXConnectionStringBuilder(ConnectionString); ex1 = Assert.Throws(() => MySQLX.GetSession(new { server = sb.Server, port = XPort, user = sb.UserID, password = sb.Password, ConnectionAttributes = invalid[i] })); - Assert.True(errorMsgs.Contains(ex1.Message)); + Assert.That(errorMsgs.Contains(ex1.Message)); //MySqlXConnectionStringBuilder mysqlx0 = new MySqlXConnectionStringBuilder(ConnectionString); mysqlx0.Database = schemaName; mysqlx0.CharacterSet = "utf8mb4"; mysqlx0.SslMode = MySqlSslMode.Required; - mysqlx0.ConnectTimeout = 10; + mysqlx0.ConnectTimeout = 1000; mysqlx0.Keepalive = 10; mysqlx0.CertificateFile = sslCa; mysqlx0.CertificatePassword = sslCertificatePassword; @@ -1808,7 +1809,7 @@ public void ConnectionAttributesInvalidCombinations() mysqlx0.CertificateThumbprint = ""; mysqlx0.ConnectionAttributes = invalid[i].ToString(); ex1 = Assert.Throws(() => MySQLX.GetSession(mysqlx0.ConnectionString)); - Assert.True(errorMsgs.Contains(ex1.Message)); + Assert.That(errorMsgs.Contains(ex1.Message)); } } } @@ -1816,8 +1817,8 @@ public void ConnectionAttributesInvalidCombinations() [Test, Description("Connection Attributes with valid combinations - Extending scenarios in ConnectionAttributes()")] public void ConnectionAttributesValidCombinations() { - if (!Platform.IsWindows()) Assert.Ignore("This test is for Windows OS only"); - if (!(session.Version.isAtLeast(8, 0, 16))) Assert.Ignore("This test is for MySql 8.0.16 or higher"); + Assume.That(Platform.IsWindows(), "This test is for Windows OS only."); + Assume.That(session.Version.isAtLeast(8, 0, 16), "This test is for MySql 8.0.16 or higher"); object[] invalid = new object[] { "[var1 = 1]" }; for (int i = 0; i < invalid.Length; i++) @@ -1826,7 +1827,7 @@ public void ConnectionAttributesValidCombinations() { using (Session session = client.GetSession()) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } } @@ -1834,7 +1835,7 @@ public void ConnectionAttributesValidCombinations() { using (Session session = client.GetSession()) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } } @@ -1843,7 +1844,7 @@ public void ConnectionAttributesValidCombinations() { using (Session session = client.GetSession()) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } } @@ -1851,7 +1852,7 @@ public void ConnectionAttributesValidCombinations() mysqlx0.Database = schemaName; mysqlx0.CharacterSet = "utf8mb4"; mysqlx0.SslMode = MySqlSslMode.Required; - mysqlx0.ConnectTimeout = 10; + mysqlx0.ConnectTimeout = 1000; mysqlx0.Keepalive = 10; mysqlx0.CertificateFile = sslCa; mysqlx0.CertificatePassword = sslCertificatePassword; @@ -1862,31 +1863,31 @@ public void ConnectionAttributesValidCombinations() { using (Session session = client.GetSession()) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } } using (Session session = MySQLX.GetSession(ConnectionString + ";connection-attributes=" + invalid[i])) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } using (Session session = MySQLX.GetSession(ConnectionStringUri + "?connection-attributes=" + invalid[i])) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } sb = new MySqlXConnectionStringBuilder(ConnectionString); using (Session session = MySQLX.GetSession(new { server = sb.Server, port = XPort, user = sb.UserID, password = sb.Password, ConnectionAttributes = invalid[i] })) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } mysqlx0 = new MySqlXConnectionStringBuilder(ConnectionString); mysqlx0.Database = schemaName; mysqlx0.CharacterSet = "utf8mb4"; mysqlx0.SslMode = MySqlSslMode.Required; - mysqlx0.ConnectTimeout = 10; + mysqlx0.ConnectTimeout = 1000; mysqlx0.Keepalive = 10; mysqlx0.CertificateFile = sslCa; mysqlx0.CertificatePassword = sslCertificatePassword; @@ -1896,7 +1897,7 @@ public void ConnectionAttributesValidCombinations() using (Session session = MySQLX.GetSession(mysqlx0.ConnectionString)) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } } } @@ -1904,14 +1905,14 @@ public void ConnectionAttributesValidCombinations() [Test, Description("Connection Attributes with key special characters - Extending scenarios in ConnectionAttributes()")] public void ConnectionAttributesKeySpecialChars() { + Assume.That(Platform.IsWindows(), "This test is for Windows OS only."); + Assume.That(session.Version.isAtLeast(8, 0, 16), "This test is for MySql 8.0.16 or higher"); MySqlXConnectionStringBuilder sb = new MySqlXConnectionStringBuilder(ConnectionString); - if (!Platform.IsWindows()) Assert.Ignore("This test is for Windows OS only"); - if (!(session.Version.isAtLeast(8, 0, 16))) Assert.Ignore("This test is for MySql 8.0.16 or higher"); using (Client client = MySQLX.GetClient(ConnectionString + ";connection-attributes=[@#$%^&* %^()=bar,quua=*(&^&#$%,key]", "{ \"pooling\": { \"enabled\": true } }")) { using (Session session = client.GetSession()) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } } @@ -1919,7 +1920,7 @@ public void ConnectionAttributesKeySpecialChars() { using (Session session = client.GetSession()) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } } @@ -1934,7 +1935,7 @@ public void ConnectionAttributesKeySpecialChars() { using (Session session = client.GetSession()) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } } @@ -1942,7 +1943,7 @@ public void ConnectionAttributesKeySpecialChars() mysqlx0.Database = schemaName; mysqlx0.CharacterSet = "utf8mb4"; mysqlx0.SslMode = MySqlSslMode.Required; - mysqlx0.ConnectTimeout = 10; + mysqlx0.ConnectTimeout = 1000; mysqlx0.Keepalive = 10; mysqlx0.CertificateFile = sslCa; mysqlx0.CertificatePassword = sslCertificatePassword; @@ -1953,25 +1954,25 @@ public void ConnectionAttributesKeySpecialChars() { using (Session session = client.GetSession()) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } } using (Session session = MySQLX.GetSession(ConnectionString + ";connection-attributes=[@#$%^&*()=bar,quua=*(&^&#$%,key]")) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } using (Session session = MySQLX.GetSession(new { server = sb.Server, port = XPort, user = sb.UserID, password = sb.Password, ConnectionAttributes = "[@#$%^&*()=bar,quua=*(&^&#$%,key=]" })) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } mysqlx0 = new MySqlXConnectionStringBuilder(ConnectionString); mysqlx0.Database = schemaName; mysqlx0.CharacterSet = "utf8mb4"; mysqlx0.SslMode = MySqlSslMode.Required; - mysqlx0.ConnectTimeout = 10; + mysqlx0.ConnectTimeout = 1000; mysqlx0.Keepalive = 10; mysqlx0.CertificateFile = sslCa; mysqlx0.CertificatePassword = sslCertificatePassword; @@ -1980,7 +1981,7 @@ public void ConnectionAttributesKeySpecialChars() mysqlx0.ConnectionAttributes = "[@#$%^&*()=bar,quua=*(&^&#$%,key=]"; using (Session session = MySQLX.GetSession(mysqlx0.ConnectionString)) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } } @@ -1988,34 +1989,34 @@ public void ConnectionAttributesKeySpecialChars() [Test, Description("Connection Attributes with key with underline characters - Extending scenarios in ConnectionAttributes()")] public void ConnectionAttributesKeyWithUnderLineChars() { - if (!Platform.IsWindows()) Assert.Ignore("This test is for Windows OS only"); - if (!(session.Version.isAtLeast(8, 0, 16))) Assert.Ignore("This test is for MySql 8.0.16 or higher"); + Assume.That(Platform.IsWindows(), "This test is for Windows OS only."); + Assume.That(session.Version.isAtLeast(8, 0, 16), "This test is for MySql 8.0.16 or higher"); MySqlXConnectionStringBuilder sb = new MySqlXConnectionStringBuilder(ConnectionString); - var expectedMsg = @"Key names in ""connection-attributes"" cannot start with ""_""."; + var expectedMsg = @"Key names in ""connection-attributes"" cannot start with ""_"""; //Connection string using (Client client = MySQLX.GetClient(ConnectionString + ";connection-attributes=[_foo32=bar,quua=qux,key]", "{ \"pooling\": { \"enabled\": true } }")) { Exception ex = Assert.Throws(() => client.GetSession()); - Assert.AreEqual(expectedMsg, ex.Message); + Assert.That(ex.Message, Is.EqualTo(expectedMsg)); } //Uri using (Client client = MySQLX.GetClient(ConnectionStringUri + "?connection-attributes=[_foo32=bar,quua=qux,key];", "{ \"pooling\": { \"enabled\": true } }")) { Exception ex = Assert.Throws(() => client.GetSession()); - Assert.AreEqual(expectedMsg, ex.Message); + Assert.That(ex.Message, Is.EqualTo(expectedMsg)); } //Anonymous object using (Client client = MySQLX.GetClient(new { server = sb.Server, port = XPort, user = sb.UserID, password = sb.Password, ConnectionAttributes = "[_foo32=bar,quua=qux,key=]" }, "{ \"pooling\": { \"enabled\": true } }")) { Exception ex = Assert.Throws(() => client.GetSession()); - Assert.AreEqual(expectedMsg, ex.Message); + Assert.That(ex.Message, Is.EqualTo(expectedMsg)); } MySqlXConnectionStringBuilder mysqlx0 = new MySqlXConnectionStringBuilder(ConnectionString); mysqlx0.Database = schemaName; mysqlx0.CharacterSet = "utf8mb4"; mysqlx0.SslMode = MySqlSslMode.Required; - mysqlx0.ConnectTimeout = 10; + mysqlx0.ConnectTimeout = 1000; mysqlx0.Keepalive = 10; mysqlx0.CertificateFile = sslCa; mysqlx0.CertificatePassword = sslCertificatePassword; @@ -2025,24 +2026,24 @@ public void ConnectionAttributesKeyWithUnderLineChars() using (Client client = MySQLX.GetClient(mysqlx0.ConnectionString, "{ \"pooling\": { \"enabled\": true } }")) { Exception ex = Assert.Throws(() => client.GetSession()); - Assert.AreEqual(expectedMsg, ex.Message); + Assert.That(ex.Message, Is.EqualTo(expectedMsg)); } //Connection string Exception ex1 = Assert.Throws(() => MySQLX.GetSession(ConnectionString + ";connection-attributes=[_foo32=bar,quua=qux,key]")); - Assert.AreEqual(expectedMsg, ex1.Message); + Assert.That(ex1.Message, Is.EqualTo(expectedMsg)); //Uri ex1 = Assert.Throws(() => MySQLX.GetSession(ConnectionStringUri + "?connection-attributes=[_foo32=bar,quua=qux,key];")); - Assert.AreEqual(expectedMsg, ex1.Message); + Assert.That(ex1.Message, Is.EqualTo(expectedMsg)); //Anonymous object ex1 = Assert.Throws(() => MySQLX.GetSession(new { server = sb.Server, port = XPort, user = sb.UserID, password = sb.Password, ConnectionAttributes = "[_foo32=bar,quua=qux,key=]" })); - Assert.AreEqual(expectedMsg, ex1.Message); + Assert.That(ex1.Message, Is.EqualTo(expectedMsg)); //MySqlXConnectionStringBuilder mysqlx0 = new MySqlXConnectionStringBuilder(ConnectionString); mysqlx0.Database = schemaName; mysqlx0.CharacterSet = "utf8mb4"; mysqlx0.SslMode = MySqlSslMode.Required; - mysqlx0.ConnectTimeout = 10; + mysqlx0.ConnectTimeout = 1000; mysqlx0.Keepalive = 10; mysqlx0.CertificateFile = sslCa; mysqlx0.CertificatePassword = sslCertificatePassword; @@ -2050,36 +2051,36 @@ public void ConnectionAttributesKeyWithUnderLineChars() mysqlx0.CertificateThumbprint = ""; mysqlx0.ConnectionAttributes = "[_foo32=bar,quua=qux,key=]"; ex1 = Assert.Throws(() => MySQLX.GetSession(mysqlx0.ConnectionString)); - Assert.AreEqual(expectedMsg, ex1.Message); + Assert.That(ex1.Message, Is.EqualTo(expectedMsg)); } [Test, Description("Connection Attributes with key blank characters - Extending scenarios in ConnectionAttributes()")] public void ConnectionAttributesKeyBlankChars() { - if (!Platform.IsWindows()) Assert.Ignore("This test is for Windows OS only"); - if (!(session.Version.isAtLeast(8, 0, 16))) Assert.Ignore("This test is for MySql 8.0.16 or higher"); + Assume.That(Platform.IsWindows(), "This test is for Windows OS only."); + Assume.That(session.Version.isAtLeast(8, 0, 16), "This test is for MySql 8.0.16 or higher"); MySqlXConnectionStringBuilder sb = new MySqlXConnectionStringBuilder(ConnectionString); - var expectedMsg = "Key name in connection attribute cannot be an empty string."; + var expectedMsg = "Key name in connection attribute cannot be an empty string"; //Connection String using (Client client = MySQLX.GetClient(ConnectionString + ";connection-attributes=[=bar,quua=qux,key]", "{ \"pooling\": { \"enabled\": true } }")) { Exception ex = Assert.Throws(() => client.GetSession()); - Assert.AreEqual(expectedMsg, ex.Message); + Assert.That(ex.Message, Is.EqualTo(expectedMsg)); } //Uri using (Client client = MySQLX.GetClient(ConnectionStringUri + "?connection-attributes=[=bar,quua=qux,key];", "{ \"pooling\": { \"enabled\": true } }")) { Exception ex = Assert.Throws(() => client.GetSession()); - Assert.AreEqual(expectedMsg, ex.Message); + Assert.That(ex.Message, Is.EqualTo(expectedMsg)); } //Anonymous object using (Client client = MySQLX.GetClient(new { server = sb.Server, port = XPort, user = sb.UserID, password = sb.Password, ConnectionAttributes = "[=bar,quua=qux,key=]" }, "{ \"pooling\": { \"enabled\": true } }")) { Exception ex = Assert.Throws(() => client.GetSession()); - Assert.AreEqual(expectedMsg, ex.Message); + Assert.That(ex.Message, Is.EqualTo(expectedMsg)); } //MySqlXConnectionStringBuilder @@ -2087,7 +2088,7 @@ public void ConnectionAttributesKeyBlankChars() mysqlx0.Database = schemaName; mysqlx0.CharacterSet = "utf8mb4"; mysqlx0.SslMode = MySqlSslMode.Required; - mysqlx0.ConnectTimeout = 10; + mysqlx0.ConnectTimeout = 1000; mysqlx0.Keepalive = 10; mysqlx0.CertificateFile = sslCa; mysqlx0.CertificatePassword = sslCertificatePassword; @@ -2097,24 +2098,24 @@ public void ConnectionAttributesKeyBlankChars() using (Client client = MySQLX.GetClient(mysqlx0.ConnectionString, "{ \"pooling\": { \"enabled\": true } }")) { Exception ex = Assert.Throws(() => client.GetSession()); - Assert.AreEqual(expectedMsg, ex.Message); + Assert.That(ex.Message, Is.EqualTo(expectedMsg)); } //Connection String Exception ex1 = Assert.Throws(() => MySQLX.GetSession(ConnectionString + ";connection-attributes=[=bar,quua=qux,key]")); - Assert.AreEqual(expectedMsg, ex1.Message); + Assert.That(ex1.Message, Is.EqualTo(expectedMsg)); //Uri ex1 = Assert.Throws(() => MySQLX.GetSession(ConnectionStringUri + "?connection-attributes=[=bar,quua=qux,key];")); - Assert.AreEqual(expectedMsg, ex1.Message); + Assert.That(ex1.Message, Is.EqualTo(expectedMsg)); //Anonymous object ex1 = Assert.Throws(() => MySQLX.GetSession(new { server = sb.Server, port = XPort, user = sb.UserID, password = sb.Password, ConnectionAttributes = "[=bar,quua=qux,key=]" })); - Assert.AreEqual(expectedMsg, ex1.Message); + Assert.That(ex1.Message, Is.EqualTo(expectedMsg)); //MySqlXConnectionStringBuilder mysqlx0 = new MySqlXConnectionStringBuilder(ConnectionString); mysqlx0.Database = schemaName; mysqlx0.CharacterSet = "utf8mb4"; mysqlx0.SslMode = MySqlSslMode.Required; - mysqlx0.ConnectTimeout = 10; + mysqlx0.ConnectTimeout = 1000; mysqlx0.Keepalive = 10; mysqlx0.CertificateFile = sslCa; mysqlx0.CertificatePassword = sslCertificatePassword; @@ -2122,15 +2123,15 @@ public void ConnectionAttributesKeyBlankChars() mysqlx0.CertificateThumbprint = ""; mysqlx0.ConnectionAttributes = "[=bar,quua=qux,key=]"; ex1 = Assert.Throws(() => MySQLX.GetSession(mysqlx0.ConnectionString)); - Assert.AreEqual(expectedMsg, ex1.Message); + Assert.That(ex1.Message, Is.EqualTo(expectedMsg)); } [Test, Description("Connection Attributes with value 1025characters - Extending scenarios in ConnectionAttributes()")] public void ConnectionAttributesValue1025Chars() { - if (!Platform.IsWindows()) Assert.Ignore("This test is for Windows OS only"); - if (!(session.Version.isAtLeast(8, 0, 16))) Assert.Ignore("This test is for MySql 8.0.16 or higher"); + Assume.That(Platform.IsWindows(), "This test is for Windows OS only."); + Assume.That(session.Version.isAtLeast(8, 0, 16), "This test is for MySql 8.0.16 or higher"); MySqlXConnectionStringBuilder sb = new MySqlXConnectionStringBuilder(ConnectionString); var expectedMsg = "Value is too long for 'foo' attribute, currently limited to 1024"; var strValue = "[foo=12345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781,quua=qux,key=]"; @@ -2138,19 +2139,19 @@ public void ConnectionAttributesValue1025Chars() using (Client client = MySQLX.GetClient(ConnectionString + $";connection-attributes={strValue}", "{ \"pooling\": { \"enabled\": true } }")) { Exception ex = Assert.Catch(() => client.GetSession()); - Assert.AreEqual(expectedMsg, ex.Message); + Assert.That(ex.Message, Is.EqualTo(expectedMsg)); } //Uri using (Client client = MySQLX.GetClient(ConnectionStringUri + $"?connection-attributes={strValue};", "{ \"pooling\": { \"enabled\": true } }")) { Exception ex = Assert.Catch(() => client.GetSession()); - Assert.AreEqual(expectedMsg, ex.Message); + Assert.That(ex.Message, Is.EqualTo(expectedMsg)); } //Anonymous object using (Client client = MySQLX.GetClient(new { server = sb.Server, port = XPort, user = sb.UserID, password = sb.Password, ConnectionAttributes = strValue }, "{ \"pooling\": { \"enabled\": true } }")) { Exception ex = Assert.Catch(() => client.GetSession()); - Assert.AreEqual(expectedMsg, ex.Message); + Assert.That(ex.Message, Is.EqualTo(expectedMsg)); } //MySqlXConnectionStringBuilder @@ -2158,7 +2159,7 @@ public void ConnectionAttributesValue1025Chars() mysqlx0.Database = schemaName; mysqlx0.CharacterSet = "utf8mb4"; mysqlx0.SslMode = MySqlSslMode.Required; - mysqlx0.ConnectTimeout = 10; + mysqlx0.ConnectTimeout = 1000; mysqlx0.Keepalive = 10; mysqlx0.CertificateFile = sslCa; mysqlx0.CertificatePassword = sslCertificatePassword; @@ -2168,23 +2169,23 @@ public void ConnectionAttributesValue1025Chars() using (Client client = MySQLX.GetClient(mysqlx0.ConnectionString, "{ \"pooling\": { \"enabled\": true } }")) { Exception ex = Assert.Catch(() => client.GetSession()); - Assert.AreEqual(expectedMsg, ex.Message); + Assert.That(ex.Message, Is.EqualTo(expectedMsg)); } //Connection String Exception ex2 = Assert.Catch(() => MySQLX.GetSession(ConnectionString + $";connection-attributes={strValue}")); - Assert.AreEqual(expectedMsg, ex2.Message); + Assert.That(ex2.Message, Is.EqualTo(expectedMsg)); //Uri ex2 = Assert.Catch(() => MySQLX.GetSession(ConnectionStringUri + $"?connection-attributes={strValue};")); - Assert.AreEqual(expectedMsg, ex2.Message); + Assert.That(ex2.Message, Is.EqualTo(expectedMsg)); //Anonymous object ex2 = Assert.Catch(() => MySQLX.GetSession(new { server = sb.Server, port = XPort, user = sb.UserID, password = sb.Password, ConnectionAttributes = strValue })); - Assert.AreEqual(expectedMsg, ex2.Message); + Assert.That(ex2.Message, Is.EqualTo(expectedMsg)); //MySqlXConnectionStringBuilder mysqlx0 = new MySqlXConnectionStringBuilder(ConnectionString); mysqlx0.Database = schemaName; mysqlx0.CharacterSet = "utf8mb4"; mysqlx0.SslMode = MySqlSslMode.Required; - mysqlx0.ConnectTimeout = 10; + mysqlx0.ConnectTimeout = 1000; mysqlx0.Keepalive = 10; mysqlx0.CertificateFile = sslCa; mysqlx0.CertificatePassword = sslCertificatePassword; @@ -2192,7 +2193,7 @@ public void ConnectionAttributesValue1025Chars() mysqlx0.CertificateThumbprint = ""; mysqlx0.ConnectionAttributes = strValue; ex2 = Assert.Catch(() => MySQLX.GetSession(mysqlx0.ConnectionString)); - Assert.AreEqual(expectedMsg, ex2.Message); + Assert.That(ex2.Message, Is.EqualTo(expectedMsg)); } @@ -2200,7 +2201,7 @@ public void ConnectionAttributesValue1025Chars() public void SessionRestore() { // This feature was implemented since MySQL Server 8.0.16 - if (!(session.Version.isAtLeast(8, 0, 16))) Assert.Ignore("This test is for MySql 8.0.16 or higher"); + Assume.That(session.Version.isAtLeast(8, 0, 16), "This test is for MySql 8.0.16 or higher"); int size = 2; using (Client client = MySQLX.GetClient(ConnectionString + ";database=test;", new { pooling = new { enabled = true, maxSize = size, queueTimeout = 1000, maxIdleTime = 1000 } })) { @@ -2211,12 +2212,12 @@ public void SessionRestore() if (res0.HasData) { var row = res0.FetchOne(); - Assert.AreEqual("big5", row[1].ToString()); + Assert.That(row[1].ToString(), Is.EqualTo("big5")); } session1.Close(); Session session2 = client.GetSession(); string threadId2 = session2.SQL("SELECT THREAD_ID FROM performance_schema.threads WHERE PROCESSLIST_ID=CONNECTION_ID()").Execute().FetchOne()[0].ToString(); - Assert.True(threadId1.Equals(threadId2)); + Assert.That(threadId1.Equals(threadId2)); session2.Close(); } } @@ -2225,7 +2226,7 @@ public void SessionRestore() public void SessionAuthentication() { // This feature was implemented since MySQL Server 8.0.16 - if (!(session.Version.isAtLeast(8, 0, 16))) Assert.Ignore("This test is for MySql 8.0.16 or higher"); + Assume.That(session.Version.isAtLeast(8, 0, 16), "This test is for MySql 8.0.16 or higher"); int size = 1; using (Client client = MySQLX.GetClient(ConnectionString + ";database=test;", new { pooling = new { enabled = true, maxSize = size, queueTimeout = 1000, maxIdleTime = 1000 } })) { @@ -2247,7 +2248,7 @@ public void SessionAuthentication() public void MultiSessionAuthentication() { // This feature was implemented since MySQL Server 8.0.16 - if (!(session.Version.isAtLeast(8, 0, 16))) Assert.Ignore("This test is for MySql 8.0.16 or higher"); + Assume.That(session.Version.isAtLeast(8, 0, 16), "This test is for MySql 8.0.16 or higher"); int size = 2; using (Client client = MySQLX.GetClient(ConnectionString + ";database=test;", new { pooling = new { enabled = true, maxSize = size, queueTimeout = 1000, maxIdleTime = 1000 } })) { @@ -2282,8 +2283,8 @@ public void MultiSessionAuthentication() Session session4_1 = client.GetSession(); string threadId5 = session3_1.SQL("SELECT THREAD_ID FROM performance_schema.threads WHERE PROCESSLIST_ID=CONNECTION_ID()").Execute().FetchOne()[0].ToString(); string threadId6 = session4_1.SQL("SELECT THREAD_ID FROM performance_schema.threads WHERE PROCESSLIST_ID=CONNECTION_ID()").Execute().FetchOne()[0].ToString(); - Assert.False(threadId3.Equals(threadId5)); - Assert.False(threadId4.Equals(threadId6)); + Assert.That(threadId3.Equals(threadId5), Is.False); + Assert.That(threadId4.Equals(threadId6), Is.False); } } @@ -2311,7 +2312,7 @@ public void VerifyDataCleanupAfterClientClose(Client _client1, int iteration, st if (res0.HasData) { var row = res0.FetchOne(); - Assert.AreEqual("big5", row[1].ToString()); + Assert.That(row[1].ToString(), Is.EqualTo("big5")); } _client1.Close(); _client1 = MySQLX.GetClient(connectionString, clientOptions); @@ -2320,7 +2321,7 @@ public void VerifyDataCleanupAfterClientClose(Client _client1, int iteration, st if (res0.HasData) { var row = res0.FetchOne(); - Assert.AreEqual("utf8mb4", row[1].ToString()); + Assert.That(row[1].ToString(), Is.EqualTo("utf8mb4")); } } @@ -2341,7 +2342,7 @@ public void VerifyDataCleanupOneSession(Client client1, int iteration) if (res0.HasData) { var row = res0.FetchOne(); - Assert.AreEqual("big5", row[1].ToString()); + Assert.That(row[1].ToString(), Is.EqualTo("big5")); } sess0.Close(); Session sess4 = client1.GetSession(); @@ -2349,7 +2350,7 @@ public void VerifyDataCleanupOneSession(Client client1, int iteration) if (res0.HasData) { var row = res0.FetchOne(); - Assert.AreEqual("utf8mb4", row[1].ToString()); + Assert.That(row[1].ToString(), Is.EqualTo("utf8mb4")); } } @@ -2369,7 +2370,7 @@ public void CompareConnectionIDs(Client client1, int maxTimeout, bool maxTimeout if (res0.HasData) { var row = res0.FetchOne(); - Assert.AreEqual("big5", row[1].ToString()); + Assert.That(row[1].ToString(), Is.EqualTo("big5")); } res0 = sess0.SQL("SELECT CONNECTION_ID()").Execute(); if (res0.HasData) @@ -2385,7 +2386,7 @@ public void CompareConnectionIDs(Client client1, int maxTimeout, bool maxTimeout if (res0.HasData) { var row = res0.FetchOne(); - Assert.AreEqual("utf8mb4", row[1].ToString()); + Assert.That(row[1].ToString(), Is.EqualTo("utf8mb4")); } res0 = sess0.SQL("SELECT CONNECTION_ID()").Execute(); if (res0.HasData) @@ -2402,7 +2403,7 @@ public void CompareConnectionIDs(Client client1, int maxTimeout, bool maxTimeout if (res0.HasData) { var row = res0.FetchOne(); - Assert.AreEqual("big5", row[1].ToString()); + Assert.That(row[1].ToString(), Is.EqualTo("big5")); } res0 = sess0.SQL("SELECT CONNECTION_ID()").Execute(); if (res0.HasData) @@ -2419,7 +2420,7 @@ public void CompareConnectionIDs(Client client1, int maxTimeout, bool maxTimeout if (res0.HasData) { var row = res0.FetchOne(); - Assert.AreEqual("utf8mb4", row[1].ToString()); + Assert.That(row[1].ToString(), Is.EqualTo("utf8mb4")); } res0 = sess0.SQL("SELECT CONNECTION_ID()").Execute(); if (res0.HasData) @@ -2431,15 +2432,15 @@ public void CompareConnectionIDs(Client client1, int maxTimeout, bool maxTimeout sess0.Close(); if (maxTimeoutGreater) { - Assert.False(connectionID1.Equals(connectionID2)); + Assert.That(connectionID1.Equals(connectionID2), Is.False); } if (maxTimeoutGreater) { - Assert.AreNotEqual(cID3, cID2); + Assert.That(cID2, Is.Not.EqualTo(cID3)); } else { - Assert.True(cID3 == cID2); + Assert.That(cID3 == cID2); } } @@ -2458,7 +2459,7 @@ public void CompareConnectionIDs(Client client1, Client client2, Client client3) if (res0.HasData) { var row = res0.FetchOne(); - Assert.AreEqual("big5", row[1].ToString()); + Assert.That(row[1].ToString(), Is.EqualTo("big5")); } res0 = sess0.SQL("SELECT CONNECTION_ID()").Execute(); if (res0.HasData) @@ -2472,7 +2473,7 @@ public void CompareConnectionIDs(Client client1, Client client2, Client client3) if (res0.HasData) { var row = res0.FetchOne(); - Assert.AreEqual("utf8mb4", row[1].ToString()); + Assert.That(row[1].ToString(), Is.EqualTo("utf8mb4")); } res0 = sess0.SQL("SELECT CONNECTION_ID()").Execute(); if (res0.HasData) @@ -2492,7 +2493,7 @@ public void CompareConnectionIDs(Client client1, Client client2, Client client3) if (res.HasData) { var row = res.FetchOne(); - Assert.AreEqual("big5", row[1].ToString()); + Assert.That(row[1].ToString(), Is.EqualTo("big5")); } res = sess.SQL("SELECT CONNECTION_ID()").Execute(); if (res.HasData) @@ -2506,7 +2507,7 @@ public void CompareConnectionIDs(Client client1, Client client2, Client client3) if (res.HasData) { var row = res.FetchOne(); - Assert.AreEqual("utf8mb4", row[1].ToString()); + Assert.That(row[1].ToString(), Is.EqualTo("utf8mb4")); } res = sess.SQL("SELECT CONNECTION_ID()").Execute(); if (res.HasData) @@ -2515,7 +2516,7 @@ public void CompareConnectionIDs(Client client1, Client client2, Client client3) connectionID2 = row[0].ToString(); } sess.Close(); - Assert.False(connectionID1.Equals(connectionID2)); + Assert.That(connectionID1.Equals(connectionID2), Is.False); } /// @@ -2533,7 +2534,7 @@ public void CompareConnectionIDs(Client client1, int maxTimeout, bool maxTimeout if (res0.HasData) { var row = res0.FetchOne(); - Assert.AreEqual("big5", row[1].ToString()); + Assert.That(row[1].ToString(), Is.EqualTo("big5")); } res0 = sess0.SQL("SELECT CONNECTION_ID()").Execute(); if (res0.HasData) @@ -2549,7 +2550,7 @@ public void CompareConnectionIDs(Client client1, int maxTimeout, bool maxTimeout if (res0.HasData) { var row = res0.FetchOne(); - Assert.AreEqual("utf8mb4", row[1].ToString()); + Assert.That(row[1].ToString(), Is.EqualTo("utf8mb4")); } res0 = sess0.SQL("SELECT CONNECTION_ID()").Execute(); if (res0.HasData) @@ -2566,7 +2567,7 @@ public void CompareConnectionIDs(Client client1, int maxTimeout, bool maxTimeout if (res0.HasData) { var row = res0.FetchOne(); - Assert.AreEqual("big5", row[1].ToString()); + Assert.That(row[1].ToString(), Is.EqualTo("big5")); } res0 = sess0.SQL("SELECT CONNECTION_ID()").Execute(); if (res0.HasData) @@ -2583,7 +2584,7 @@ public void CompareConnectionIDs(Client client1, int maxTimeout, bool maxTimeout if (res0.HasData) { var row = res0.FetchOne(); - Assert.AreEqual("utf8mb4", row[1].ToString()); + Assert.That(row[1].ToString(), Is.EqualTo("utf8mb4")); } res0 = sess0.SQL("SELECT CONNECTION_ID()").Execute(); if (res0.HasData) @@ -2595,19 +2596,19 @@ public void CompareConnectionIDs(Client client1, int maxTimeout, bool maxTimeout sess0.Close(); if (maxTimeoutGreater) { - Assert.False(connectionID1.Equals(connectionID2), "Connection ID Matches when a session is closed and opened again"); + Assert.That(connectionID1.Equals(connectionID2), Is.False, "Connection ID Matches when a session is closed and opened again"); } if (maxTimeout.CompareTo(sleepTimeout) > 0) { - Assert.True(cID3 != cID2); + Assert.That(cID3 != cID2); } else if (maxTimeout.CompareTo(sleepTimeout) == 0) { - Assert.True(cID1 == cID2); + Assert.That(cID1 == cID2); } else { - Assert.True(cID1 == cID2); + Assert.That(cID1 == cID2); } } @@ -2622,9 +2623,9 @@ public void TestClientQueueTimeout(Client client, int minTime, int maxTime) { Stopwatch stopwatch = Stopwatch.StartNew(); Exception ex = Assert.Throws(() => client.GetSession()); - StringAssert.Contains("timeout", ex.Message); + Assert.That(ex.Message, Does.Contain("timeout")); stopwatch.Stop(); - Assert.True(stopwatch.ElapsedMilliseconds > minTime && stopwatch.ElapsedMilliseconds < maxTime); + Assert.That(stopwatch.ElapsedMilliseconds > minTime && stopwatch.ElapsedMilliseconds < maxTime); } /// @@ -2663,4 +2664,4 @@ public async void VerifyClientAsync(Client client1) #endregion Methods } -} \ No newline at end of file +} diff --git a/MySQL.Data/tests/MySqlX.Data.Tests/CloseConnectionTests.cs b/MySQL.Data/tests/MySqlX.Data.Tests/CloseConnectionTests.cs index b9c3a51ea..7f906380c 100644 --- a/MySQL.Data/tests/MySqlX.Data.Tests/CloseConnectionTests.cs +++ b/MySQL.Data/tests/MySqlX.Data.Tests/CloseConnectionTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2020, 2021, Oracle and/or its affiliates. +// Copyright © 2020, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -30,6 +30,7 @@ using MySql.Data.MySqlClient; using MySqlX.XDevAPI; using NUnit.Framework; +using NUnit.Framework.Legacy; using System; using System.Diagnostics; using System.Threading; @@ -50,11 +51,11 @@ public class CloseConnectionTests : BaseTest [Test] public void NotificationKill() { - if (!(session.InternalSession.GetServerVersion().isAtLeast(8, 0, 23))) Assert.Ignore(); + Assume.That(session.Version.isAtLeast(8, 0, 23), "This test is for MySql 8.0.23 or higher"); using (Session session1 = MySQLX.GetSession(ConnectionString)) { Schema test = session1.GetSchema("test"); - Assert.AreEqual(SessionState.Open, session1.XSession.SessionState); + Assert.That(session1.XSession.SessionState, Is.EqualTo(SessionState.Open)); var threadId1 = (UInt64)session1.ThreadId; // Kill connection @@ -62,9 +63,9 @@ public void NotificationKill() Thread.Sleep(5000); Exception ex = Assert.Throws(() => session1.SQL("select 1").Execute()); - StringAssert.Contains(ResourcesX.NoticeKilledConnection, ex.Message); + Assert.That(ex.Message, Does.Contain(ResourcesX.NoticeKilledConnection)); - Assert.AreEqual(SessionState.Closed, session1.XSession.SessionState); + Assert.That(session1.XSession.SessionState, Is.EqualTo(SessionState.Closed)); } } @@ -72,20 +73,20 @@ public void NotificationKill() [Test] public void NotificationIdle() { - if (!(session.InternalSession.GetServerVersion().isAtLeast(8, 0, 23))) Assert.Ignore(); + Assume.That(session.Version.isAtLeast(8, 0, 23), "This test is for MySql 8.0.23 or higher"); ExecuteSqlAsRoot("SET GLOBAL mysqlx_read_timeout = 5"); ExecuteSqlAsRoot("SET GLOBAL mysqlx_wait_timeout = 5"); using (Session localsession = MySQLX.GetSession(ConnectionString)) { - Assert.AreEqual(SessionState.Open, localsession.XSession.SessionState); + Assert.That(localsession.XSession.SessionState, Is.EqualTo(SessionState.Open)); //wait for server to kill idle connection Thread.Sleep(7000); Exception ex = Assert.Throws(() => localsession.SQL("select 1").Execute()); - StringAssert.Contains(ResourcesX.NoticeIdleConnection, ex.Message); + Assert.That(ex.Message, Does.Contain(ResourcesX.NoticeIdleConnection)); - Assert.AreEqual(SessionState.Closed, localsession.XSession.SessionState); + Assert.That(localsession.XSession.SessionState, Is.EqualTo(SessionState.Closed)); } ExecuteSqlAsRoot("SET GLOBAL mysqlx_read_timeout = 28800"); ExecuteSqlAsRoot("SET GLOBAL mysqlx_wait_timeout = 28800"); @@ -108,7 +109,7 @@ public void NotificationIdle() [Theory] public void CloseWarningsWithCollections(CloseData closeData) { - if (!(session.InternalSession.GetServerVersion().isAtLeast(8, 0, 23))) Assert.Ignore(); + Assume.That(session.Version.isAtLeast(8, 0, 23), "This test is for MySql 8.0.23 or higher"); Session sessionCol = null; sessionCol = MySQLX.GetSession(ConnectionString); @@ -121,8 +122,8 @@ public void CloseWarningsWithCollections(CloseData closeData) Thread.Sleep(5000); MySqlException ex = Assert.Throws(() => { closeData.Action.Invoke(sessionCol); }); - Assert.AreEqual(ResourcesX.NoticeKilledConnection, ex.Message); - Assert.AreEqual(SessionState.Closed, sessionCol.XSession.SessionState); + Assert.That(ex.Message, Is.EqualTo(ResourcesX.NoticeKilledConnection)); + Assert.That(sessionCol.XSession.SessionState, Is.EqualTo(SessionState.Closed)); } //Shutdown server Notice, exception expected @@ -130,20 +131,20 @@ public void CloseWarningsWithCollections(CloseData closeData) [Ignore("This test is marked as Ignore because it shutdown the local MySQL Server, comment this line to run this test manually")] public void NotificationShutdown() { - if (!(session.InternalSession.GetServerVersion().isAtLeast(8, 0, 23))) Assert.Ignore(); + Assume.That(session.Version.isAtLeast(8, 0, 23), "This test is for MySql 8.0.23 or higher"); using (Session localsession = MySQLX.GetSession(BaseTest.ConnectionString)) { - Assert.AreEqual(SessionState.Open, localsession.XSession.SessionState); + Assert.That(localsession.XSession.SessionState, Is.EqualTo(SessionState.Open)); // Shutdown local MySQL Server ShutdownServer(); Thread.Sleep(2000); Exception ex = Assert.Throws(() => localsession.SQL("select 1").Execute()); - StringAssert.Contains(ResourcesX.NoticeServerShutdown, ex.Message); + Assert.That(ex.Message, Does.Contain(ResourcesX.NoticeServerShutdown)); - Assert.AreEqual(SessionState.Closed, localsession.XSession.SessionState); + Assert.That(localsession.XSession.SessionState, Is.EqualTo(SessionState.Closed)); } } @@ -154,7 +155,7 @@ public void NotificationShutdown() [Test] public void PoolTestCloseOneConnection() { - if (!(session.InternalSession.GetServerVersion().isAtLeast(8, 0, 23))) Assert.Ignore(); + Assume.That(session.Version.isAtLeast(8, 0, 23), "This test is for MySql 8.0.23 or higher"); int size = 3; int timeout = 3000; using (Client client = MySQLX.GetClient(ConnectionString + ";database=test;", new { pooling = new { maxSize = size, queueTimeout = timeout } })) @@ -175,24 +176,24 @@ public void PoolTestCloseOneConnection() //verify session 1 open var result1 = session1.SQL("select sqrt(9) as raiz;").Execute().FetchOne().GetString("raiz"); - StringAssert.Contains("3", result1); + Assert.That(result1, Does.Contain("3")); //try to use session 2 Exception ex1 = Assert.Throws(() => session2.SQL("select sqrt(9) as raiz;").Execute()); - StringAssert.Contains(ResourcesX.NoticeKilledConnection, ex1.Message); + Assert.That(ex1.Message, Does.Contain(ResourcesX.NoticeKilledConnection)); //verify session 3 open var result2 = session3.SQL("select sqrt(9) as raiz;").Execute().FetchOne().GetString("raiz"); - StringAssert.Contains("3", result2); + Assert.That(result2, Does.Contain("3")); //try to use session 2 once it is Invalid Exception ex2 = Assert.Throws(() => session2.SQL("SELECT 5").Execute()); - Assert.AreEqual(ResourcesX.InvalidSession, ex2.Message); + Assert.That(ex2.Message, Is.EqualTo(ResourcesX.InvalidSession)); //reuse session2 session2 = client.GetSession(); var result3 = session2.SQL("select sqrt(9) as raiz;").Execute().FetchOne().GetString("raiz"); - StringAssert.Contains("3", result3); + Assert.That(result3, Does.Contain("3")); } } @@ -201,7 +202,7 @@ public void PoolTestCloseOneConnection() [Ignore("This test is marked as Ignore because it shutdown the local MySQL Server, comment this line to run this test manually")] public void PoolTestShutdown() { - if (!(session.InternalSession.GetServerVersion().isAtLeast(8, 0, 23))) Assert.Ignore(); + Assume.That(session.Version.isAtLeast(8, 0, 23), "This test is for MySql 8.0.23 or higher"); int size = 3; using (Client client = MySQLX.GetClient(ConnectionString + ";database=test;", new { pooling = new { maxSize = size } })) { @@ -215,13 +216,13 @@ public void PoolTestShutdown() // All connections should receive a close notification and become closed and invalid Exception ex1 = Assert.Throws(() => session1.SQL("select sqrt(9) as raiz;").Execute()); - StringAssert.Contains(ResourcesX.NoticeServerShutdown, ex1.Message); + Assert.That(ex1.Message, Does.Contain(ResourcesX.NoticeServerShutdown)); Exception ex2 = Assert.Throws(() => session2.SQL("select sqrt(9) as raiz;").Execute()); - StringAssert.Contains(ResourcesX.NoticeServerShutdown, ex2.Message); + Assert.That(ex2.Message, Does.Contain(ResourcesX.NoticeServerShutdown)); Exception ex3 = Assert.Throws(() => session3.SQL("select sqrt(9) as raiz;").Execute()); - StringAssert.Contains(ResourcesX.NoticeServerShutdown, ex3.Message); + Assert.That(ex3.Message, Does.Contain(ResourcesX.NoticeServerShutdown)); } } @@ -229,7 +230,7 @@ public void PoolTestShutdown() [Test] public void PoolWithIdleConnections() { - if (!(session.InternalSession.GetServerVersion().isAtLeast(8, 0, 23))) Assert.Ignore(); + Assume.That(session.Version.isAtLeast(8, 0, 23), "This test is for MySql 8.0.23 or higher"); int size = 2; ExecuteSqlAsRoot("SET GLOBAL mysqlx_read_timeout = 5"); ExecuteSqlAsRoot("SET GLOBAL mysqlx_wait_timeout = 5"); @@ -242,10 +243,10 @@ public void PoolWithIdleConnections() Thread.Sleep(8000); Exception ex1 = Assert.Throws(() => session1.SQL("select sqrt(9) as raiz;").Execute()); - StringAssert.Contains(ResourcesX.NoticeIdleConnection, ex1.Message); + Assert.That(ex1.Message, Does.Contain(ResourcesX.NoticeIdleConnection)); Exception ex2 = Assert.Throws(() => session2.SQL("select sqrt(9) as raiz;").Execute()); - StringAssert.Contains(ResourcesX.NoticeIdleConnection, ex2.Message); + Assert.That(ex2.Message, Does.Contain(ResourcesX.NoticeIdleConnection)); } ExecuteSqlAsRoot("SET GLOBAL mysqlx_read_timeout = 28800"); diff --git a/MySQL.Data/tests/MySqlX.Data.Tests/CollectionAsyncTests.cs b/MySQL.Data/tests/MySqlX.Data.Tests/CollectionAsyncTests.cs index a74b331ec..47c992ffc 100644 --- a/MySQL.Data/tests/MySqlX.Data.Tests/CollectionAsyncTests.cs +++ b/MySQL.Data/tests/MySqlX.Data.Tests/CollectionAsyncTests.cs @@ -1,134 +1,135 @@ -// Copyright (c) 2015, 2023, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySqlX.XDevAPI; -using MySqlX.XDevAPI.Common; -using MySqlX.XDevAPI.CRUD; -using NUnit.Framework; -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; - -namespace MySqlX.Data.Tests -{ - public class CollectionAsyncTests : BaseTest - { - [Test] - public void CollectionInsert() - { - var coll = CreateCollection("test"); - List> tasksList = new List>(); - - for (int i = 1; i <= 200; i++) - { - tasksList.Add(coll.Add(string.Format(@"{{ ""_id"": {0}, ""foo"": {0} }}", i)).ExecuteAsync()); - } - - Task.WaitAll(tasksList.ToArray(), TimeSpan.FromMinutes(1)); - - var count = session.SQL("SELECT COUNT(*) FROM test.test").Execute().FetchOne()[0]; - Assert.AreEqual(count, coll.Count()); - } - - [Test] - public void MultipleFindAsync() - { - var coll = CreateCollection("test"); - int docs = 100; - HashSet validator = new HashSet(); - var addStatement = coll.Add(new { id = 1, age = 1 }); - - for (int i = 2; i <= docs; i++) - { - addStatement.Add(new { id = i, age = i }); - } - var result = ExecuteAddStatement(addStatement); - - List>> tasksList = new List>>(); - - for (int i = 1; i <= docs; i++) - { - tasksList.Add(coll.Find("age = :age").Bind("AgE", i).ExecuteAsync()); - } - - Assert.True(Task.WaitAll(tasksList.ToArray(), TimeSpan.FromMinutes(2)), "WaitAll timeout"); - foreach (Task> task in tasksList) - { - var doc = task.Result.FetchOne(); - string value = task.Result.Current["age"].ToString(); - Assert.False(validator.Contains(value), value + " value exists"); - validator.Add(value); - } - Assert.AreEqual(docs, validator.Count); - } - - [Test, Description("Create valid index using a document field type of array and setting array to true/with single key on all possible datatypes concurrently)")] - public async Task IndexArrayMultiThreading() - { - var coll = CreateCollection("test"); - // For server not supporting array indexes, array option will be ignored and and old-style index will be created. - if (!session.Version.isAtLeast(8, 0, 17)) - { - coll.CreateIndex("myIndex", "{\"fields\": [{\"field\": $.myField, \"type\":\"DATE\", \"array\": true}]}"); - return; - } - int v1 = await IndexArrayMultiThreading_T1(); - int v2 = await IndexArrayMultiThreading_T2(); - - Assert.AreEqual(2, v1 + v2); - } - - private async Task IndexArrayMultiThreading_T1() - { - Schema test = session.GetSchema(schemaName); - var coll = test.GetCollection("test"); - Thread.Sleep(100); - coll.CreateIndex("multiArrayIndex1", "{\"fields\": [{\"field\": \"$.intField\", \"type\": \"INT\", \"array\": false}," + - "{\"field\": \"$.charField\", \"type\": \"CHAR(255)\", \"array\": false}," + - "{\"field\": \"$.decimalField\", \"type\": \"DECIMAL\", \"array\": true}," + - "{\"field\": \"$.dateField\", \"type\": \"DATE\", \"array\": false}," + - "{\"field\": \"$.timeField\", \"type\": \"TIME\", \"array\": false}," + - "{\"field\": \"$.datetimeField\", \"type\": \"DATETIME\", \"array\": false}]}"); - return 1; - } - - private async Task IndexArrayMultiThreading_T2() - { - Schema test = session.GetSchema(schemaName); - var coll = test.GetCollection("test"); - coll.CreateIndex("multiArrayIndex2", "{\"fields\": [{\"field\": \"$.intField\", \"type\": \"INT\", \"array\": false}," + - "{\"field\": \"$.charField\", \"type\": \"CHAR(255)\", \"array\": false}," + - "{\"field\": \"$.decimalField\", \"type\": \"DECIMAL\", \"array\": true}," + - "{\"field\": \"$.dateField\", \"type\": \"DATE\", \"array\": false}," + - "{\"field\": \"$.timeField\", \"type\": \"TIME\", \"array\": false}," + - "{\"field\": \"$.datetimeField\", \"type\": \"DATETIME\", \"array\": false}]}"); - return 1; - } - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySqlX.XDevAPI; +using MySqlX.XDevAPI.Common; +using MySqlX.XDevAPI.CRUD; +using NUnit.Framework; +using NUnit.Framework.Legacy; +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace MySqlX.Data.Tests +{ + public class CollectionAsyncTests : BaseTest + { + [Test] + public void CollectionInsert() + { + var coll = CreateCollection("test"); + List> tasksList = new List>(); + + for (int i = 1; i <= 200; i++) + { + tasksList.Add(coll.Add(string.Format(@"{{ ""_id"": {0}, ""foo"": {0} }}", i)).ExecuteAsync()); + } + + Task.WaitAll(tasksList.ToArray(), TimeSpan.FromMinutes(1)); + + var count = session.SQL("SELECT COUNT(*) FROM test.test").Execute().FetchOne()[0]; + Assert.That(coll.Count(), Is.EqualTo(count)); + } + + [Test] + public void MultipleFindAsync() + { + var coll = CreateCollection("test"); + int docs = 100; + HashSet validator = new HashSet(); + var addStatement = coll.Add(new { id = 1, age = 1 }); + + for (int i = 2; i <= docs; i++) + { + addStatement.Add(new { id = i, age = i }); + } + var result = ExecuteAddStatement(addStatement); + + List>> tasksList = new List>>(); + + for (int i = 1; i <= docs; i++) + { + tasksList.Add(coll.Find("age = :age").Bind("AgE", i).ExecuteAsync()); + } + + Assert.That(Task.WaitAll(tasksList.ToArray(), TimeSpan.FromMinutes(2)), "WaitAll timeout"); + foreach (Task> task in tasksList) + { + var doc = task.Result.FetchOne(); + string value = task.Result.Current["age"].ToString(); + Assert.That(validator.Contains(value), Is.False, value + " value exists"); + validator.Add(value); + } + Assert.That(validator.Count, Is.EqualTo(docs)); + } + + [Test, Description("Create valid index using a document field type of array and setting array to true/with single key on all possible datatypes concurrently)")] + public async Task IndexArrayMultiThreading() + { + var coll = CreateCollection("test"); + // For server not supporting array indexes, array option will be ignored and and old-style index will be created. + if (!session.Version.isAtLeast(8, 0, 17)) + { + coll.CreateIndex("myIndex", "{\"fields\": [{\"field\": $.myField, \"type\":\"DATE\", \"array\": true}]}"); + return; + } + int v1 = await IndexArrayMultiThreading_T1(); + int v2 = await IndexArrayMultiThreading_T2(); + + Assert.That(v1 + v2, Is.EqualTo(2)); + } + + private async Task IndexArrayMultiThreading_T1() + { + Schema test = session.GetSchema(schemaName); + var coll = test.GetCollection("test"); + Thread.Sleep(100); + coll.CreateIndex("multiArrayIndex1", "{\"fields\": [{\"field\": \"$.intField\", \"type\": \"INT\", \"array\": false}," + + "{\"field\": \"$.charField\", \"type\": \"CHAR(255)\", \"array\": false}," + + "{\"field\": \"$.decimalField\", \"type\": \"DECIMAL\", \"array\": true}," + + "{\"field\": \"$.dateField\", \"type\": \"DATE\", \"array\": false}," + + "{\"field\": \"$.timeField\", \"type\": \"TIME\", \"array\": false}," + + "{\"field\": \"$.datetimeField\", \"type\": \"DATETIME\", \"array\": false}]}"); + return 1; + } + + private async Task IndexArrayMultiThreading_T2() + { + Schema test = session.GetSchema(schemaName); + var coll = test.GetCollection("test"); + coll.CreateIndex("multiArrayIndex2", "{\"fields\": [{\"field\": \"$.intField\", \"type\": \"INT\", \"array\": false}," + + "{\"field\": \"$.charField\", \"type\": \"CHAR(255)\", \"array\": false}," + + "{\"field\": \"$.decimalField\", \"type\": \"DECIMAL\", \"array\": true}," + + "{\"field\": \"$.dateField\", \"type\": \"DATE\", \"array\": false}," + + "{\"field\": \"$.timeField\", \"type\": \"TIME\", \"array\": false}," + + "{\"field\": \"$.datetimeField\", \"type\": \"DATETIME\", \"array\": false}]}"); + return 1; + } + } +} diff --git a/MySQL.Data/tests/MySqlX.Data.Tests/CollectionIndexTests.cs b/MySQL.Data/tests/MySqlX.Data.Tests/CollectionIndexTests.cs index 2ba762809..1994f681c 100644 --- a/MySQL.Data/tests/MySqlX.Data.Tests/CollectionIndexTests.cs +++ b/MySQL.Data/tests/MySqlX.Data.Tests/CollectionIndexTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2017, 2023, Oracle and/or its affiliates. +// Copyright © 2017, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -31,6 +31,7 @@ using MySqlX.XDevAPI.Common; using MySqlX.XDevAPI.CRUD; using NUnit.Framework; +using NUnit.Framework.Legacy; using System; using System.Threading; using System.Threading.Tasks; @@ -47,37 +48,37 @@ public void IncorrectlyFormatedIndexDefinition() var collection = CreateCollection("test"); Exception ex = Assert.Throws(() => collection.CreateIndex("myIndex", "{\"type\": \"INDEX\" }")); - Assert.AreEqual("Field 'fields' is mandatory.", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Field 'fields' is mandatory")); ex = Assert.Throws(() => collection.CreateIndex("myIndex", "{\"fields\": [ { \"field\":$.myField, \"type\":\"TEXT\" } ], \"unexpectedField\" : false }")); - Assert.AreEqual("Field name 'unexpectedField' is not allowed.", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Field name 'unexpectedField' is not allowed")); ex = Assert.Throws(() => collection.CreateIndex("myIndex", "{\"fields\": [ { \"fields\":$.myField, \"types\":\"TEXT\" } ] }")); - Assert.AreEqual("Field 'field' is mandatory.", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Field 'field' is mandatory")); ex = Assert.Throws(() => collection.CreateIndex("myIndex", "{\"fields\": [ { \"field\":$.myField, \"types\":\"TEXT\" } ] }")); - Assert.AreEqual("Field 'type' is mandatory.", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Field 'type' is mandatory")); ex = Assert.Throws(() => collection.CreateIndex("myIndex", "{\"fields\": [ { \"field\":$.myField, \"type\":\"TEXT\", \"unexpectedField\" : false } ] }")); - Assert.AreEqual("Field name 'unexpectedField' is not allowed.", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Field name 'unexpectedField' is not allowed")); - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher."); + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); collection = CreateCollection("test"); ex = Assert.Throws(() => collection.CreateIndex("myIndex", "{\"fields\": [ { \"field\":$.myField, \"type\":\"INT\" } ], \"type\":\"indexa\" }")); - Assert.AreEqual("Argument value 'indexa' for index type is invalid", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Argument value 'indexa' for index type is invalid")); ex = Assert.Throws(() => collection.CreateIndex("myIndex", "{\"fields\": [ { \"field\":$.myField, \"type\":\"INT\" } ], \"type\":\"OTheR\" }")); - Assert.AreEqual("Argument value 'OTheR' for index type is invalid", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Argument value 'OTheR' for index type is invalid")); ex = Assert.Throws(() => collection.CreateIndex("myIndex1", "{\"fields\": [ { \"field\":$.myGeoJsonField, \"type\":\"GEOJSON\" } ], \"type\":\"Spatial\" }")); - Assert.AreEqual("GEOJSON index requires 'constraint.required: TRUE", ex.Message); + Assert.That(ex.Message, Is.EqualTo("GEOJSON index requires 'constraint.required: TRUE")); ex = Assert.Throws(() => collection.CreateIndex("myIndex2", "{\"fields\": [ { \"field\":$.myGeoJsonField, \"type\":\"GEOJSON\" } ], \"type\":\"spatial\" }")); - Assert.AreEqual("GEOJSON index requires 'constraint.required: TRUE", ex.Message); + Assert.That(ex.Message, Is.EqualTo("GEOJSON index requires 'constraint.required: TRUE")); ex = Assert.Throws(() => collection.CreateIndex("myIndex3", "{\"fields\": [ { \"field\":$.myGeoJsonField, \"type\":\"GEOJSON\" } ], \"type\":\"sPaTiAl\" }")); - Assert.AreEqual("GEOJSON index requires 'constraint.required: TRUE", ex.Message); + Assert.That(ex.Message, Is.EqualTo("GEOJSON index requires 'constraint.required: TRUE")); } [Test] @@ -214,11 +215,11 @@ public void DropIndex() collection.DropIndex("myIndex"); Exception ex = Assert.Throws(() => ValidateIndex("myIndex", "test", "t10", false, false, false, 1, 10)); - Assert.AreEqual("Index not found.", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Index not found.")); ex = Assert.Throws(() => ValidateIndex("myIndex", "test", "t10", false, true, false, 2, 10)); - Assert.AreEqual("Index not found.", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Index not found.")); ex = Assert.Throws(() => ValidateIndex("myIndex", "test", "i_u", false, false, true, 3)); - Assert.AreEqual("Index not found.", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Index not found.")); } [Test] @@ -228,7 +229,7 @@ public void CreateIndexWithDuplicateName() collection.CreateIndex("myUniqueIndex", "{\"fields\": [ { \"field\":$.myField, \"type\":\"INT\" } ] }"); Exception ex = Assert.Throws(() => collection.CreateIndex("myUniqueIndex", "{\"fields\": [ { \"field\":$.myField, \"type\":\"INT\" } ] }")); - Assert.AreEqual("Duplicate key name 'myUniqueIndex'", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Duplicate key name 'myUniqueIndex'")); } [Test] @@ -237,11 +238,11 @@ public void CreateIndexWithInvalidJsonDocumentDefinition() var collection = CreateCollection("test"); Exception ex = Assert.Throws(() => collection.CreateIndex("myIndex", "{\"fields\": [ { \"field\" = $.myField, \"type\" = \"TEXT\" } ] }")); - Assert.AreEqual("The value provided is not a valid JSON document. Expected token ':'", ex.Message); + Assert.That(ex.Message, Is.EqualTo("The value provided is not a valid JSON document. Expected token ':'")); ex = Assert.Throws(() => collection.CreateIndex("myIndex", "{\"fields\": [ { \"field\":$.myField, \"type\":\"TEXT\" ] }")); - Assert.AreEqual("The value provided is not a valid JSON document. Expected token ','", ex.Message); + Assert.That(ex.Message, Is.EqualTo("The value provided is not a valid JSON document. Expected token ','")); ex = Assert.Throws(() => collection.CreateIndex("myIndex", "{\"fields\": [ { \"field\":$.myField, type:\"TEXT\" } }")); - Assert.AreEqual("The value provided is not a valid JSON document. Expected token '\"'", ex.Message); + Assert.That(ex.Message, Is.EqualTo("The value provided is not a valid JSON document. Expected token '\"'")); } [Test] @@ -250,15 +251,15 @@ public void CreateIndexWithInvalidJsonDocumentStructure() var collection = CreateCollection("test"); Exception ex = Assert.Throws(() => collection.CreateIndex("myIndex", "{\"fields\": [ { \"field\":$.myField, \"type\":\"INT\", \"myCustomField\":\"myCustomValue\" } ] }")); - Assert.AreEqual("Field name 'myCustomField' is not allowed.", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Field name 'myCustomField' is not allowed")); ex = Assert.Throws(() => collection.CreateIndex("myIndex", "{\"fields\": [ { \"field\":$.myField, \"mytype\":\"INT\" } ] }")); - Assert.AreEqual("Field 'type' is mandatory.", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Field 'type' is mandatory")); ex = Assert.Throws(() => collection.CreateIndex("myIndex", "{\"fields\": [ { \"myfield\":$.myField, \"type\":\"INT\" } ] }")); - Assert.AreEqual("Field 'field' is mandatory.", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Field 'field' is mandatory")); ex = Assert.Throws(() => collection.CreateIndex("myIndex", "{\"fields\": [ { \"field\":$.name, \"type\":\"TEXT\" , \"myCustomField\":\"myCustomValue\"} ] }")); - Assert.AreEqual("Field name 'myCustomField' is not allowed.", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Field name 'myCustomField' is not allowed")); ex = Assert.Throws(() => collection.CreateIndex("myIndex", "")); - Assert.AreEqual("The value provided is not a valid JSON document. Index was outside the bounds of the array.", ex.Message); + Assert.That(ex.Message, Is.EqualTo("The value provided is not a valid JSON document. Index was outside the bounds of the array.")); } [Test] @@ -267,9 +268,9 @@ public void CreateIndexWithTypeNotIndexOrSpatial() var collection = CreateCollection("test"); Exception ex = Assert.Throws(() => collection.CreateIndex("myIndex", "{\"fields\": [ { \"field\":$.myField, \"type\":\"INT\" } ], \"type\":\"indexa\" }")); - Assert.AreEqual("Argument value 'indexa' for index type is invalid", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Argument value 'indexa' for index type is invalid")); ex = Assert.Throws(() => collection.CreateIndex("myIndex", "{\"fields\": [ { \"field\":$.myField, \"type\":\"INT\" } ], \"type\":\"OTheR\" }")); - Assert.AreEqual("Argument value 'OTheR' for index type is invalid", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Argument value 'OTheR' for index type is invalid")); } [Test] @@ -278,7 +279,7 @@ public void CreateSpatialIndexWithRequiredSetToFalse() var collection = CreateCollection("test"); Exception ex = Assert.Throws(() => collection.CreateIndex("myIndex", "{\"fields\": [ { \"field\":$.myField, \"type\":\"GEOJSON\", \"required\":false, \"options\":2, \"srid\":4326 } ], \"type\":\"SPATIAL\" }")); - Assert.AreEqual("GEOJSON index requires 'constraint.required: TRUE", ex.Message); + Assert.That(ex.Message, Is.EqualTo("GEOJSON index requires 'constraint.required: TRUE")); } [Test] @@ -288,13 +289,13 @@ public void CreateIndexWithInvalidType() // Missing key length for text type. Exception ex = Assert.Throws(() => collection.CreateIndex("myIndex", "{ \"fields\": [ { \"field\":\"$.myField\", \"type\":\"Text\" } ] }")); - StringAssert.EndsWith("used in key specification without a key length", ex.Message); + Assert.That(ex.Message, Does.EndWith("used in key specification without a key length")); // Invalid index types. ex = Assert.Throws(() => collection.CreateIndex("myIndex", "{ \"fields\": [ { \"field\":\"$.myField\", \"type\":\"Texta\" } ] }")); - StringAssert.EndsWith("Invalid or unsupported type specification 'Texta'", ex.Message); + Assert.That(ex.Message, Does.EndWith("Invalid or unsupported type specification 'Texta'")); ex = Assert.Throws(() => collection.CreateIndex("myIndex", "{ \"fields\": [ { \"field\":\"$.myField\", \"type\":\"INTO\" } ] }")); - StringAssert.EndsWith("Invalid or unsupported type specification 'INTO'", ex.Message); + Assert.That(ex.Message, Does.EndWith("Invalid or unsupported type specification 'INTO'")); try { collection.CreateIndex("myIndex", "{\"fields\": [ { \"field\":$.name, \"type\":\"Datetime\"} ] }"); @@ -316,10 +317,10 @@ public void CreateIndexWithInvalidGeojsonOptions() var collection = CreateCollection("test"); Exception ex = Assert.Throws(() => collection.CreateIndex("myIndex", "{ \"fields\": [ { \"field\":\"$.myField\", \"type\":\"INT\", \"options\":2, \"srid\":4326 } ] }")); - Assert.AreEqual("Unsupported argument specification for '$.myField'", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Unsupported argument specification for '$.myField'")); ex = Assert.Throws(() => collection.CreateIndex("myIndex", "{\"fields\": [ { \"field\":$.myField, \"type\":\"GEOJSON\", \"options\":2, \"srid\":4326 } ], \"type\":\"SPATIAL\" }")); - Assert.AreEqual("GEOJSON index requires 'constraint.required: TRUE", ex.Message); + Assert.That(ex.Message, Is.EqualTo("GEOJSON index requires 'constraint.required: TRUE")); } [Test] @@ -340,16 +341,16 @@ public void ValidIndexNames() collection.DropIndex("-myIndex"); Exception ex = Assert.Throws(() => collection.CreateIndex(null, "{\"fields\": [ { \"field\":$.name, \"type\":\"TEXT(64)\" , \"required\":true} ] }")); - Assert.AreEqual("Invalid value for argument 'name'", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Invalid value for argument 'name'")); ex = Assert.Throws(() => collection.CreateIndex("myIndex1243536464r4urgfu4rgh43urvbnu4rgh4u3rive39irgf9r4fri3jgnfi", "{\"fields\": [ { \"field\":$.name, \"type\":\"TEXT(64)\" , \"required\":true} ] }")); - Assert.AreEqual("Identifier name 'myIndex1243536464r4urgfu4rgh43urvbnu4rgh4u3rive39irgf9r4fri3jgnfi' is too long", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Identifier name 'myIndex1243536464r4urgfu4rgh43urvbnu4rgh4u3rive39irgf9r4fri3jgnfi' is too long")); } [Test] public void CreateIndexWithArrayOption() { var collection = CreateCollection("test"); - if (!session.Version.isAtLeast(8, 0, 17)) Assert.Ignore("This test is for MySql 8.0.17 or higher."); + Assume.That(session.Version.isAtLeast(8, 0, 17), "This test is for MySql 8.0.17 or higher"); // Supported types var doc = new[] { new { _id = 1, name = "Char", myField = new[] { "foo@mail.com", "bar@mail.com", "qux@mail.com" } } }; @@ -392,36 +393,36 @@ public void CreateIndexWithArrayOption() [Test, Description("Add Collection index")] public void AddIndexAndInsertRecords() { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher."); + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); Collection testColl = CreateCollection("test1"); - Assert.IsTrue(testColl.ExistsInDatabase()); + Assert.That(testColl.ExistsInDatabase()); testColl.CreateIndex("testIndex", "{\"fields\": [ { \"field\":$.myId, \"type\":\"INTEGER UNSIGNED\" , \"required\":true} ] }"); testColl.CreateIndex("testIndex1", "{\"fields\": [ { \"field\":$.myAge, \"type\":\"FLOAT UNSIGNED\" , \"required\":true} ] }"); var result = testColl.Add(new { myId = 1, myAge = 35.1, _id = 1 }).Add(new { myId = 2, myAge = 41.9, _id = 2 }).Execute(); - Assert.True(result.AffectedItemsCount > 0); + Assert.That(result.AffectedItemsCount > 0); Collection testCol2 = CreateCollection("test2"); testCol2.CreateIndex("testIndex2", "{\"fields\": [ { \"field\":$.myId, \"type\":\"INT\" , \"required\":true} ] }"); result = testCol2.Add(new { myId = 1 }).Execute(); - Assert.True(result.AffectedItemsCount > 0); + Assert.That(result.AffectedItemsCount > 0); } [Test, Description("Create valid index on a single key with all options")] public void InsertWithValidIndexAndNoIndex() { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher."); + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); var col = CreateCollection("my_collection"); Result result = col.Add(new { name = "Sakila", age = 15 }).Execute(); col.CreateIndex("myIndex", "{\"fields\": [ { \"field\":$.name, \"type\":\"TEXT(64)\" , \"required\":true} ] }"); Assert.Throws(() => ExecuteAddStatement(col.Add(new { age = 10 }))); col.DropIndex("myIndex"); result = col.Add(new { age = 10 }).Execute(); - Assert.AreEqual(1, result.AffectedItemsCount); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1)); } [Test, Description("Create a valid index on a single key of all DATATYPES.Datatypes supported: INT [UNSIGNED] TINYINT [UNSIGNED] SMALLINT [UNSIGNED] MEDIUMINT [UNSIGNED] INTEGER [UNSIGNED] BIGINT [UNSIGNED] REAL [UNSIGNED] FLOAT [UNSIGNED] DOUBLE [UNSIGNED] DECIMAL [UNSIGNED] NUMERIC [UNSIGNED] DATE TIME TIMESTAMP DATETIME TEXT[(length)]")] public void IndexOfAllDatatypes() { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher."); + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); var col = CreateCollection("my_collection"); Result result = col.Add(new { name = "Sakila", age = 15, date_time = "2010-01-01 00:00:00", time_stamp = "2015-01-01 00:11:02", date_check = "2117-12-17", time_check = "12:14:07", real_check = 12E+4, decimal_check = 122.134, float_check = 11.223, double_check = 23.32343425, numeric_check = 1122.3434, tiny_int = 112, medium_int = 12345, big_int = 1234567, int_check = 174734 }).Execute(); @@ -476,18 +477,18 @@ public void IndexOfAllDatatypes() [Test, Description("Create an index with mismatched data types")] public void IndexWithMismatchedDatatypes() { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher."); + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); var col = CreateCollection("my_collection"); Result result = col.Add(new { name = "Sakila", age = 15 }).Execute(); Thread.Sleep(2000); Exception ex = Assert.Throws(() => col.CreateIndex("myIndex", "{\"fields\": [ { \"field\":$.name, \"type\":\"DATETIME\"} ] }")); - StringAssert.Contains("Incorrect datetime value", ex.Message); + Assert.That(ex.Message, Does.Contain("Incorrect datetime value")); } [Test, Description("Create an index specifiying SPATIAL as the index type for a non spatial data type and vice versa")] public void IndexSpatialForNonSpatialDatatype() { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher."); + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); var col = CreateCollection("my_collection"); Result result = col.Add(new { name = "Sakila", age = 15 }).Execute(); Assert.Throws(() => col.CreateIndex("myIndex", "{\"fields\": [ { \"field\":$.name, \"type\":\"TEXT\"} ] , \"type\":\"SPATIAL\" }")); @@ -501,7 +502,7 @@ public void IndexSpatialForNonSpatialDatatype() [Test, Description("Create valid index with index definition given as DbDoc")] public void CreateIndexGivenDbDoc() { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher."); + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); var col = CreateCollection("my_collection"); Result result = col.Add(new { name = "Sakila", age = 15 }).Execute(); @@ -517,7 +518,7 @@ public void CreateIndexGivenDbDoc() [Test, Description("Create valid index on member of Array type as key")] public void IndexOnArrayMember() { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher."); + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); var col = CreateCollection("my_collection"); @@ -558,7 +559,7 @@ public void IndexOnArrayMember() [Test, Description("Create valid index on member of DbDoc type as key")] public void IndexOnDbDocMember() { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher."); + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); var col = CreateCollection("my_collection"); DbDoc data2 = new DbDoc(); data2.SetValue("name", "Sakila"); @@ -574,7 +575,7 @@ public void IndexOnDbDocMember() [Test, Description("Create valid index perform CRUD operations")] public void CountRecordsInsertedWithValidIndex() { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher."); + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); var col = CreateCollection("my_collection"); Result result = col.Add(new { name = "Sakila", age = 15 }).Execute(); Assert.Throws(() => col.CreateIndex("myIndex", "{\"fields\": [ { \"field\":$.name, \"type\":\"TEXT\" , \"required\":true} ] }")); @@ -582,13 +583,13 @@ public void CountRecordsInsertedWithValidIndex() result = col.Add(new { name = "Maria", age = 20 }).Execute(); result = col.Add(new { name = "Maria", age = 21 }).Execute(); var Removing = col.Remove("name='Maria'").Execute(); - Assert.AreEqual(2, (int)Removing.AffectedItemsCount, "Matches"); + Assert.That((int)Removing.AffectedItemsCount, Is.EqualTo(2), "Matches"); } [Test, Description("Create invalid index with non-existent key")] public void InvalidIndexNonExistentKey() { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher."); + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); var col = CreateCollection("my_collection"); Result result = col.Add(new { age = 15 }).Execute(); Assert.Throws(() => col.CreateIndex("myIndex", "{\"fields\": [ { \"field\":$.name, \"type\":\"TEXT\" , \"required\":\"true\"} ]}")); @@ -597,7 +598,7 @@ public void InvalidIndexNonExistentKey() [Test, Description("Create a valid index in async way")] public async Task CreateIndexInAsync() { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher."); + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); var col = CreateCollection("my_collection"); await col.Add(new { name = "Sakila", age = 15 }).ExecuteAsync(); col.CreateIndex("myIndex", "{\"fields\": [ { \"field\":$.name, \"type\":\"TEXT(64)\" , \"required\":true} ] }"); @@ -609,7 +610,7 @@ public async Task CreateIndexInAsync() [Test, Description("Create valid index using a document field type of array and setting array to true with single key on all possible datatypes-data inserted and then index created")] public void IndexWithArrayOptionSingleKeyAfterInsertData() { - if (!session.Version.isAtLeast(8, 0, 17)) Assert.Ignore("This test is for MySql 8.0.17 or higher."); + Assume.That(session.Version.isAtLeast(8, 0, 17), "This test is for MySql 8.0.17 or higher"); var collection = CreateCollection("test"); // Supported types @@ -632,14 +633,14 @@ public void IndexWithArrayOptionSingleKeyAfterInsertData() collection.Add(doc11).Execute(); collection.CreateIndex("myIndex", "{\"fields\": [{\"field\": $.myField, \"type\":\"" + "Time" + "\", \"array\": true}]}"); var docResult = collection.Find("'23:59:59.15' in myField").Execute(); - Assert.AreEqual(2, docResult.FetchAll().Count, "Matching the document ID"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(2), "Matching the document ID"); docResult = collection.Find("'1' in $.myField").Execute(); - Assert.AreEqual(3, docResult.FetchAll().Count, "Matching the document ID"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(3), "Matching the document ID"); docResult = collection.Find("1 in $.myField").Execute(); - Assert.AreEqual(3, docResult.FetchAll().Count, "Matching the document ID"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(3), "Matching the document ID"); docResult = collection.Find(":myField IN $.myField").Bind("myField", "23:59:59.15").Execute(); docResult = collection.Find(":myField IN $._id").Bind("myField", true).Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); collection = CreateCollection("test"); collection.Add(doc).Execute(); @@ -825,7 +826,7 @@ public void IndexWithArrayOptionSingleKeyAfterInsertData() "inserted and then index created")] public void IndexWithArrayOptionSingleKeyBeforeInsertData() { - if (!session.Version.isAtLeast(8, 0, 17)) Assert.Ignore("This test is for MySql 8.0.17 or higher."); + Assume.That(session.Version.isAtLeast(8, 0, 17), "This test is for MySql 8.0.17 or higher"); var collection = CreateCollection("test"); @@ -838,13 +839,13 @@ public void IndexWithArrayOptionSingleKeyBeforeInsertData() doc = new[] { new { _id = 1, name = "Char", myField = new[] { "foo@mail.com" } } }; collection.CreateIndex("myIndex", "{\"fields\": [{\"field\": $.myField, \"type\":\"" + "CHAR(11)" + "\", \"array\": true}]}"); Exception ex = Assert.Throws(() => collection.Add(doc).Execute()); - Assert.AreEqual("Data too long for functional index 'myIndex'.", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Data too long for functional index 'myIndex'.")); collection = CreateCollection("test"); var doc1 = new[] { new { _id = 1, name = "Char", myField = "foo@mail.com" } }; collection.CreateIndex("myIndex", "{\"fields\": [{\"field\": $.myField, \"type\":\"" + "CHAR(11)" + "\", \"array\": true}]}"); ex = Assert.Throws(() => collection.Add(doc1).Execute()); - Assert.AreEqual("Data too long for functional index 'myIndex'.", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Data too long for functional index 'myIndex'.")); collection = CreateCollection("test"); doc = new[] { new { _id = 1, name = "Binary", myField = new[] { "foo@mail.com", "bar@mail.com", "qux@mail.com" } } }; @@ -980,7 +981,7 @@ public void IndexWithArrayOptionSingleKeyBeforeInsertData() [Test, Description("Create index with array set as null,NULL,multile vel arrays,blank arrays,empty arrays.Also test in multikey scenarios")] public void IndexArrayCombinations() { - if (!session.Version.isAtLeast(8, 0, 17)) Assert.Ignore("This test is for MySql 8.0.17 or higher."); + Assume.That(session.Version.isAtLeast(8, 0, 17), "This test is for MySql 8.0.17 or higher"); var expectedException = "Index field 'array' member must be boolean."; var coll = CreateCollection("test"); @@ -996,34 +997,34 @@ public void IndexArrayCombinations() Assert.Throws(() => coll.CreateIndex("charArrayIndex1", "{\"fields\": [{\"field\": \"$.charField1\", \"array\": true}]}")); Exception e = Assert.Throws(() => coll.CreateIndex("intArrayIndex1", "{\"fields\": [{\"field\": \"$.intField1\", \"type\": \"SIGNED INTEGER\", \"array\": null}]}")); - Assert.AreEqual(expectedException, e.Message, "Matching the expected exception"); + Assert.That(e.Message, Is.EqualTo(expectedException), "Matching the expected exception"); e = Assert.Throws(() => coll.CreateIndex("intArrayIndex1", "{\"fields\": [{\"field\": \"$.intField1\", \"type\": \"SIGNED INTEGER\", \"array\": NULL}]}")); - Assert.AreEqual(expectedException, e.Message, "Matching the expected exception"); + Assert.That(e.Message, Is.EqualTo(expectedException), "Matching the expected exception"); e = Assert.Throws(() => coll.CreateIndex("uintArrayIndex1", "{\"fields\": [{\"field\": \"$.uintField\", \"type\": \"UNSIGNED INTEGER\", \"array\": null}]}")); - Assert.AreEqual(expectedException, e.Message, "Matching the expected exception"); + Assert.That(e.Message, Is.EqualTo(expectedException), "Matching the expected exception"); e = Assert.Throws(() => coll.CreateIndex("floatArrayIndex1", "{\"fields\": [{\"field\": \"$.floatField\", \"type\": \"DECIMAL(10,2)\", \"array\": null}]}")); - Assert.AreEqual(expectedException, e.Message, "Matching the expected exception"); + Assert.That(e.Message, Is.EqualTo(expectedException), "Matching the expected exception"); e = Assert.Throws(() => coll.CreateIndex("floatArrayIndex1", "{\"fields\": [{\"field\": \"$.floatField\", \"type\": \"DECIMAL(10,2)\", \"array\": NULL}]}")); - Assert.AreEqual(expectedException, e.Message, "Matching the expected exception"); + Assert.That(e.Message, Is.EqualTo(expectedException), "Matching the expected exception"); e = Assert.Throws(() => coll.CreateIndex("dateArrayIndex1", "{\"fields\": [{\"field\": \"$.dateField\", \"type\": \"DATE\", \"array\": null}]}")); - Assert.AreEqual(expectedException, e.Message, "Matching the expected exception"); + Assert.That(e.Message, Is.EqualTo(expectedException), "Matching the expected exception"); e = Assert.Throws(() => coll.CreateIndex("datetimeArrayIndex1", "{\"fields\": [{\"field\": \"$.datetimeField\", \"type\": \"DATETIME\", \"array\": null}]}")); - Assert.AreEqual(expectedException, e.Message, "Matching the expected exception"); + Assert.That(e.Message, Is.EqualTo(expectedException), "Matching the expected exception"); e = Assert.Throws(() => coll.CreateIndex("timeArrayIndex1", "{\"fields\": [{\"field\": \"$.timeField\", \"type\": \"TIME\", \"array\": null}]}")); - Assert.AreEqual(expectedException, e.Message, "Matching the expected exception"); + Assert.That(e.Message, Is.EqualTo(expectedException), "Matching the expected exception"); e = Assert.Throws(() => coll.CreateIndex("charArrayIndex1", "{\"fields\": [{\"field\": \"$.charField\", \"type\": \"CHAR(256)\", \"array\": null}]}")); - Assert.AreEqual(expectedException, e.Message, "Matching the expected exception"); + Assert.That(e.Message, Is.EqualTo(expectedException), "Matching the expected exception"); e = Assert.Throws(() => coll.CreateIndex("binaryArrayIndex1", "{\"fields\": [{\"field\": \"$.binaryField\", \"type\": \"BINARY(256)\", \"array\": null}]}")); - Assert.AreEqual(expectedException, e.Message, "Matching the expected exception"); + Assert.That(e.Message, Is.EqualTo(expectedException), "Matching the expected exception"); Assert.Throws(() => ExecuteAddStatement(coll.Add("{\"intField\" : [1,[2, 3],4], \"uintField\" : [51,[52, 53],54], \"dateField\" : [\"2019-1-1\", [\"2019-2-1\", \"2019-3-1\"], \"2019-4-1\"], " + "\"datetimeField\" : [\"9999-12-30 23:59:59\", [\"9999-12-31 23:59:59\"], \"9999-12-31 23:59:59\"], \"charField\" : [\"abcd1\", \"abcd1\", \"abcd2\", \"abcd4\"], " + @@ -1040,7 +1041,7 @@ public void IndexArrayCombinations() for (int i = 0; i < fields.Length; i++) { var res = coll.Add(fields[i]).Execute(); - Assert.AreEqual(1, res.AffectedItemsCount); + Assert.That(res.AffectedItemsCount, Is.EqualTo(1)); } fields = new string[] {"{\"intField\" : []}", "{\"uintField\" : []}", "{\"charField\" : []}", @@ -1048,7 +1049,7 @@ public void IndexArrayCombinations() for (int i = 0; i < fields.Length; i++) { var res = coll.Add(fields[i]).Execute(); - Assert.AreEqual(1, res.AffectedItemsCount); + Assert.That(res.AffectedItemsCount, Is.EqualTo(1)); } fields = new string[] { "[]", "[]", "[]", "[]", "[]", "[]", "[]", "[]" }; @@ -1152,7 +1153,7 @@ public void IndexArrayCombinations() DbDoc doc = docs.FetchOne(); var findStatement = coll.Find("57.6"); var res1 = findStatement.Execute().FetchAll(); - Assert.AreEqual(5, res1.Count, "Matching the find count"); + Assert.That(res1.Count, Is.EqualTo(5), "Matching the find count"); coll = CreateCollection("test"); @@ -1235,7 +1236,7 @@ public void IndexArrayCombinations() [Test, Description("Index Array Date bug with workaround")] public void IndexArrayBugWorkAround() { - if (!session.Version.isAtLeast(8, 0, 17)) Assert.Ignore("This test is for MySql 8.0.17 or higher."); + Assume.That(session.Version.isAtLeast(8, 0, 17), "This test is for MySql 8.0.17 or higher"); var coll = CreateCollection("test"); var doc = new[] { new { _id = 1, name = "Time", myField = "9:00:00" } };//Bug29692534 var doc22 = new[] { new { _id = 2, name = "Time", myField = new[] { "01:01:01.001", "23:59:59.15", "12:00:00", "1" } } };//Bug29692534 @@ -1243,17 +1244,17 @@ public void IndexArrayBugWorkAround() coll.Add(doc22).Execute(); coll.CreateIndex("myIndex", "{\"fields\": [{\"field\": $.myField, \"type\":\"" + "Time" + "\", \"array\": true}]}"); var docResult = coll.Find("CAST(CAST('12:00:00' as TIME) as JSON) in $.myField").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Time"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Time"); docResult = coll.Find("CAST(CAST('9:00:00' as TIME) as JSON) in $.myField").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Time"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Time"); docResult = coll.Find("CAST(CAST(:dt as TIME) as JSON) in $.myField").Bind("dt", "9:00:00").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Time-With Bind"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Time-With Bind"); docResult = coll.Find("CAST(CAST(:dt as TIME) as JSON) in $.myField").Bind("dt", "12:00:00").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Time-With Bind"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Time-With Bind"); docResult = coll.Find(":dt IN $.myField").Bind("dt", "9:00:00").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Time-With Bind-Bug"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Time-With Bind-Bug"); docResult = coll.Find(":dt IN $.myField").Bind("dt", "01:01:01.001").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Time-With Bind-Bug"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Time-With Bind-Bug"); coll = CreateCollection("test"); doc = new[] { new { _id = 1, name = "Decimal", myField = "5" } }; @@ -1262,19 +1263,19 @@ public void IndexArrayBugWorkAround() coll.Add(doc22).Execute(); coll.CreateIndex("myIndex", "{\"fields\": [{\"field\": $.myField, \"type\":\"" + "Decimal" + "\", \"array\": true}]}"); docResult = coll.Find("CAST(CAST('3.0' as DECIMAL) as JSON) in $.myField").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Decimal"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Decimal"); docResult = coll.Find("CAST(CAST('5' as DECIMAL) as JSON) in $.myField").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Decimal"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Decimal"); docResult = coll.Find("CAST(CAST(:dt as DECIMAL) as JSON) in $.myField").Bind("dt", "5").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Decimal-With Bind"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Decimal-With Bind"); docResult = coll.Find("CAST(CAST(:dt as DECIMAL) as JSON) in $.myField").Bind("dt", "3.0").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Decimal-With Bind"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Decimal-With Bind"); docResult = coll.Find(":dt IN $.myField").Bind("dt", "5").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Decimal-With Bind-Bug"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Decimal-With Bind-Bug"); docResult = coll.Find(":dt IN $.myField").Bind("dt", 5).Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Decimal-With Bind-Bug"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Decimal-With Bind-Bug"); docResult = coll.Find(":dt IN $.myField").Bind("dt", 3.0).Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Decimal-With Bind-Bug"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Decimal-With Bind-Bug"); coll = CreateCollection("test"); doc = new[] { new { _id = 1, name = "Date", myField = "2019-01-04" } }; @@ -1283,19 +1284,19 @@ public void IndexArrayBugWorkAround() coll.Add(doc22).Execute(); coll.CreateIndex("myIndex", "{\"fields\": [{\"field\": $.myField, \"type\":\"" + "Date" + "\", \"array\": true}]}"); docResult = coll.Find("CAST(CAST('2019-01-04' as DATE) as JSON) in $.myField").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Date"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Date"); docResult = coll.Find("CAST(CAST('2019-01-01' as DATE) as JSON) in $.myField").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Date"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Date"); docResult = coll.Find("CAST(CAST(:dt as DATE) as JSON) in $.myField").Bind("dt", "2019-01-04").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Date-With Bind"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Date-With Bind"); docResult = coll.Find("CAST(CAST(:dt as DATE) as JSON) in $.myField").Bind("dt", "2019-01-01").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Date-With Bind"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Date-With Bind"); docResult = coll.Find(":dt IN $.myField").Bind("dt", 2019 - 01 - 04).Execute(); - Assert.AreEqual(0, docResult.FetchAll().Count, "Matching the document ID-Date-With Bind-Bug"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(0), "Matching the document ID-Date-With Bind-Bug"); docResult = coll.Find(":dt IN $.myField").Bind("dt", "2019-01-04").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Date-With Bind-Bug"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Date-With Bind-Bug"); docResult = coll.Find(":dt IN $.myField").Bind("dt", "2019-01-01").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Date-With Bind-Bug"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Date-With Bind-Bug"); coll = CreateCollection("test"); doc = new[] { new { _id = 1, name = "DateTime", myField = "9999-02-02 01:20:33" } }; @@ -1304,17 +1305,17 @@ public void IndexArrayBugWorkAround() coll.Add(doc22).Execute(); coll.CreateIndex("myIndex", "{\"fields\": [{\"field\": $.myField, \"type\":\"" + "DateTime" + "\", \"array\": true}]}"); docResult = coll.Find("CAST(CAST('1000-01-01 00:00:00' as DATETIME) as JSON) in $.myField").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-DateTime"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-DateTime"); docResult = coll.Find("CAST(CAST('9999-02-02 01:20:33' as DATETIME) as JSON) in $.myField").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-DateTime"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-DateTime"); docResult = coll.Find("CAST(CAST(:dt as DATETIME) as JSON) in $.myField").Bind("dt", "9999-02-02 01:20:33").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Date-With Bind"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Date-With Bind"); docResult = coll.Find("CAST(CAST(:dt as DATETIME) as JSON) in $.myField").Bind("dt", "9999-12-31 23:59:59").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Date-With Bind"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Date-With Bind"); docResult = coll.Find(":dt IN $.myField").Bind("dt", "9999-02-02 01:20:33").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-DateTime-With Bind-Bug"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-DateTime-With Bind-Bug"); docResult = coll.Find(":dt IN $.myField").Bind("dt", "1000-01-01 00:00:00").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-DateTime-With Bind-Bug"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-DateTime-With Bind-Bug"); coll = CreateCollection("test"); doc = new[] { new { _id = 1, name = "Signed", myField = "100" } }; @@ -1323,19 +1324,19 @@ public void IndexArrayBugWorkAround() coll.Add(doc22).Execute(); coll.CreateIndex("myIndex", "{\"fields\": [{\"field\": $.myField, \"type\":\"" + "Signed" + "\", \"array\": true}]}"); docResult = coll.Find("CAST(CAST('100' as SIGNED) as JSON) in $.myField").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-SIGNED"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-SIGNED"); docResult = coll.Find("CAST(CAST('3' as SIGNED) as JSON) in $.myField").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-SIGNED"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-SIGNED"); docResult = coll.Find("CAST(CAST(:dt as SIGNED) as JSON) in $.myField").Bind("dt", "100").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-SIGNED-With Bind"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-SIGNED-With Bind"); docResult = coll.Find("CAST(CAST(:dt as SIGNED) as JSON) in $.myField").Bind("dt", "19").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-SIGNED-With Bind"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-SIGNED-With Bind"); docResult = coll.Find(":dt IN $.myField").Bind("dt", 100).Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Signed-With Bind"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Signed-With Bind"); docResult = coll.Find(":dt IN $.myField").Bind("dt", "100").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Signed-With Bind"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Signed-With Bind"); docResult = coll.Find(":dt IN $.myField").Bind("dt", "3").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Signed-With Bind"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Signed-With Bind"); coll = CreateCollection("test"); doc = new[] { new { _id = 1, name = "SIGNED INTEGER", myField = "100" } }; @@ -1344,21 +1345,21 @@ public void IndexArrayBugWorkAround() coll.Add(doc22).Execute(); coll.CreateIndex("myIndex", "{\"fields\": [{\"field\": $.myField, \"type\":\"" + "SIGNED INTEGER" + "\", \"array\": true}]}"); docResult = coll.Find("CAST(CAST('100' as SIGNED INTEGER) as JSON) in $.myField").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-SIGNED INTEGER"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-SIGNED INTEGER"); docResult = coll.Find("CAST(CAST('3' as SIGNED INTEGER) as JSON) in $.myField").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-SIGNED INTEGER"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-SIGNED INTEGER"); docResult = coll.Find("CAST(CAST(:dt as SIGNED INTEGER) as JSON) in $.myField").Bind("dt", "100").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-SIGNED INTEGER-With Bind"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-SIGNED INTEGER-With Bind"); docResult = coll.Find("CAST(CAST(:dt as SIGNED INTEGER) as JSON) in $.myField").Bind("dt", "19").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-SIGNED INTEGER-With Bind"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-SIGNED INTEGER-With Bind"); docResult = coll.Find(":dt IN $.myField").Bind("dt", 100).Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-SIGNED INTEGER-With Bind-Bug"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-SIGNED INTEGER-With Bind-Bug"); docResult = coll.Find(":dt IN $.myField").Bind("dt", "100").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-SIGNED INTEGER-With Bind-Bug"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-SIGNED INTEGER-With Bind-Bug"); docResult = coll.Find(":dt IN $.myField").Bind("dt", 3).Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-SIGNED INTEGER-With Bind-Bug"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-SIGNED INTEGER-With Bind-Bug"); docResult = coll.Find(":dt IN $.myField").Bind("dt", "3").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-SIGNED INTEGER-With Bind-Bug"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-SIGNED INTEGER-With Bind-Bug"); coll = CreateCollection("test"); doc = new[] { new { _id = 1, name = "Unsigned", myField = "100" } }; @@ -1367,21 +1368,21 @@ public void IndexArrayBugWorkAround() coll.Add(doc22).Execute(); coll.CreateIndex("myIndex", "{\"fields\": [{\"field\": $.myField, \"type\":\"" + "Unsigned" + "\", \"array\": true}]}"); docResult = coll.Find("CAST(CAST('100' as UNSIGNED) as JSON) in $.myField").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Unsigned"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Unsigned"); docResult = coll.Find("CAST(CAST('3' as UNSIGNED) as JSON) in $.myField").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Unsigned"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Unsigned"); docResult = coll.Find("CAST(CAST(:dt as UNSIGNED) as JSON) in $.myField").Bind("dt", "100").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Unsigned-With Bind"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Unsigned-With Bind"); docResult = coll.Find("CAST(CAST(:dt as UNSIGNED) as JSON) in $.myField").Bind("dt", "19").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Unsigned-With Bind"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Unsigned-With Bind"); docResult = coll.Find(":dt IN $.myField").Bind("dt", 100).Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Unsigned-With Bind-Bug"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Unsigned-With Bind-Bug"); docResult = coll.Find(":dt IN $.myField").Bind("dt", "100").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Unsigned-With Bind-Bug"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Unsigned-With Bind-Bug"); docResult = coll.Find(":dt IN $.myField").Bind("dt", 3).Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Unsigned-With Bind-Bug"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Unsigned-With Bind-Bug"); docResult = coll.Find(":dt IN $.myField").Bind("dt", "3").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Unsigned-With Bind-Bug"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Unsigned-With Bind-Bug"); coll = CreateCollection("test"); doc = new[] { new { _id = 1, name = "Char", myField = "too@mail.com" } }; @@ -1390,9 +1391,9 @@ public void IndexArrayBugWorkAround() coll.Add(doc22).Execute(); coll.CreateIndex("myIndex", "{\"fields\": [{\"field\": $.myField, \"type\":\"" + "CHAR(128)" + "\", \"array\": true}]}"); docResult = coll.Find(":dt IN $.myField").Bind("dt", "too@mail.com").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-CHAR(128)-With Bind"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-CHAR(128)-With Bind"); docResult = coll.Find(":dt IN $.myField").Bind("dt", "foo@mail.com").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-CHAR(128)-With Bind"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-CHAR(128)-With Bind"); } /// @@ -1401,41 +1402,41 @@ public void IndexArrayBugWorkAround() [Test, Description("Index Array Date bug with workaround")] public void IndexArrayWorkAroundOverlaps() { - if (!session.Version.isAtLeast(8, 0, 17)) Assert.Ignore("This test is for MySql 8.0.17 or higher."); + Assume.That(session.Version.isAtLeast(8, 0, 17), "This test is for MySql 8.0.17 or higher"); var coll = CreateCollection("test"); var doc = new[] { new { _id = 1, name = "Time", myField = "9:00:00" } }; var doc22 = new[] { new { _id = 2, name = "Time", myField = new[] { "01:01:01.001", "23:59:59.15", "12:00:00", "1" } } }; coll.Add(doc).Execute(); coll.Add(doc22).Execute(); var docResult = coll.Find(":dt overlaps $.myField").Bind("dt", "9:00:00").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Time-With Bind-Bug before index creation"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Time-With Bind-Bug before index creation"); docResult = coll.Find(":dt not overlaps $.myField").Bind("dt", "9:00:00").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Time-With Bind-Bug before index creation"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Time-With Bind-Bug before index creation"); docResult = coll.Find("CAST(CAST('01:01:01.001' as TIME) as JSON) overlaps $.myField").Execute(); - Assert.AreEqual(0, docResult.FetchAll().Count, "Matching the document ID-Time before index creation"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(0), "Matching the document ID-Time before index creation"); docResult = coll.Find("CAST(CAST('01:01:01.001' as TIME) as JSON) not overlaps $.myField").Execute(); - Assert.AreEqual(2, docResult.FetchAll().Count, "Matching the document ID-Time before index creation"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(2), "Matching the document ID-Time before index creation"); coll.CreateIndex("myIndex", "{\"fields\": [{\"field\": $.myField, \"type\":\"" + "Time" + "\", \"array\": true}]}"); docResult = coll.Find("CAST(CAST('12:00:00' as TIME) as JSON) overlaps $.myField").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Time"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Time"); docResult = coll.Find("CAST(CAST('9:00:00' as TIME) as JSON) overlaps $.myField").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Time"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Time"); docResult = coll.Find("CAST(CAST(:dt as TIME) as JSON) overlaps $.myField").Bind("dt", "9:00:00").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Time-With Bind"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Time-With Bind"); docResult = coll.Find("CAST(CAST(:dt as TIME) as JSON) overlaps $.myField").Bind("dt", "12:00:00").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Time-With Bind"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Time-With Bind"); docResult = coll.Find(":dt overlaps $.myField").Bind("dt", "9:00:00").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Time-With Bind-Bug"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Time-With Bind-Bug"); docResult = coll.Find(":dt overlaps $.myField").Bind("dt", "01:01:01.001").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Time-With Bind-Bug"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Time-With Bind-Bug"); docResult = coll.Find(":dt not overlaps $.myField").Bind("dt", "01:01:01.001").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Time-With Bind-Bug"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Time-With Bind-Bug"); docResult = coll.Find(":dt not IN $.myField").Bind("dt", "01:01:01.001").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Time-With Bind-Bug"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Time-With Bind-Bug"); docResult = coll.Find("CAST(CAST(:dt as TIME) as JSON) not overlaps $.myField").Bind("dt", "12:00:00").Execute(); - Assert.AreEqual(2, docResult.FetchAll().Count, "Matching the document ID-Time-With Bind"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(2), "Matching the document ID-Time-With Bind"); coll = CreateCollection("test"); @@ -1444,35 +1445,35 @@ public void IndexArrayWorkAroundOverlaps() coll.Add(doc).Execute(); coll.Add(doc22).Execute(); docResult = coll.Find(":dt overlaps $.myField").Bind("dt", "5").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-DECIMAL-With Bind-Bug before index creation"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-DECIMAL-With Bind-Bug before index creation"); docResult = coll.Find(":dt not overlaps $.myField").Bind("dt", "5").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-DECIMAL-With Bind-Bug before index creation"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-DECIMAL-With Bind-Bug before index creation"); docResult = coll.Find("CAST(CAST('5' as DECIMAL) as JSON) overlaps $.myField").Execute(); - Assert.AreEqual(0, docResult.FetchAll().Count, "Matching the document ID-DECIMAL before index creation"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(0), "Matching the document ID-DECIMAL before index creation"); docResult = coll.Find("CAST(CAST('5' as DECIMAL) as JSON) not overlaps $.myField").Execute(); - Assert.AreEqual(2, docResult.FetchAll().Count, "Matching the document ID-DECIMAL before index creation"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(2), "Matching the document ID-DECIMAL before index creation"); coll.CreateIndex("myIndex", "{\"fields\": [{\"field\": $.myField, \"type\":\"" + "Decimal" + "\", \"array\": true}]}"); docResult = coll.Find("CAST(CAST('3.0' as DECIMAL) as JSON) overlaps $.myField").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Decimal"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Decimal"); docResult = coll.Find("CAST(CAST('5' as DECIMAL) as JSON) overlaps $.myField").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Decimal"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Decimal"); docResult = coll.Find("CAST(CAST(:dt as DECIMAL) as JSON) overlaps $.myField").Bind("dt", "5").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Decimal-With Bind"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Decimal-With Bind"); docResult = coll.Find("CAST(CAST(:dt as DECIMAL) as JSON) overlaps $.myField").Bind("dt", "3.0").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Decimal-With Bind"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Decimal-With Bind"); docResult = coll.Find(":dt overlaps $.myField").Bind("dt", "5").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Decimal-With Bind-Bug"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Decimal-With Bind-Bug"); docResult = coll.Find(":dt overlaps $.myField").Bind("dt", 5).Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Decimal-With Bind-Bug"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Decimal-With Bind-Bug"); docResult = coll.Find(":dt overlaps $.myField").Bind("dt", 3.0).Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Decimal-With Bind-Bug"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Decimal-With Bind-Bug"); docResult = coll.Find(":dt not overlaps $.myField").Bind("dt", "5").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Decimal-With Bind-Bug"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Decimal-With Bind-Bug"); docResult = coll.Find(":dt not overlaps $.myField").Bind("dt", 3.0).Execute(); - Assert.AreEqual(2, docResult.FetchAll().Count, "Matching the document ID-Decimal-With Bind-Bug"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(2), "Matching the document ID-Decimal-With Bind-Bug"); docResult = coll.Find("CAST(CAST(:dt as DECIMAL) as JSON) not overlaps $.myField").Bind("dt", "3.0").Execute(); - Assert.AreEqual(2, docResult.FetchAll().Count, "Matching the document ID-Decimal-With Bind"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(2), "Matching the document ID-Decimal-With Bind"); coll = CreateCollection("test"); @@ -1482,23 +1483,23 @@ public void IndexArrayWorkAroundOverlaps() coll.Add(doc22).Execute(); coll.CreateIndex("myIndex", "{\"fields\": [{\"field\": $.myField, \"type\":\"" + "Date" + "\", \"array\": true}]}"); docResult = coll.Find("CAST(CAST('2019-01-04' as DATE) as JSON) overlaps $.myField").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Date"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Date"); docResult = coll.Find("CAST(CAST('2019-01-01' as DATE) as JSON) overlaps $.myField").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Date"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Date"); docResult = coll.Find("CAST(CAST(:dt as DATE) as JSON) overlaps $.myField").Bind("dt", "2019-01-04").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Date-With Bind"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Date-With Bind"); docResult = coll.Find("CAST(CAST(:dt as DATE) as JSON) overlaps $.myField").Bind("dt", "2019-01-01").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Date-With Bind"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Date-With Bind"); docResult = coll.Find(":dt overlaps $.myField").Bind("dt", 2019 - 01 - 04).Execute(); - Assert.AreEqual(0, docResult.FetchAll().Count, "Matching the document ID-Date-With Bind-Bug"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(0), "Matching the document ID-Date-With Bind-Bug"); docResult = coll.Find(":dt overlaps $.myField").Bind("dt", "2019-01-04").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Date-With Bind-Bug"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Date-With Bind-Bug"); docResult = coll.Find(":dt overlaps $.myField").Bind("dt", "2019-01-01").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Date-With Bind-Bug"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Date-With Bind-Bug"); docResult = coll.Find(":dt not overlaps $.myField").Bind("dt", "2019-01-01").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Date-With Bind-Bug"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Date-With Bind-Bug"); docResult = coll.Find("CAST(CAST(:dt as DATE) as JSON) not overlaps $.myField").Bind("dt", "2019-01-04").Execute(); - Assert.AreEqual(2, docResult.FetchAll().Count, "Matching the document ID-Date-With Bind"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(2), "Matching the document ID-Date-With Bind"); coll = CreateCollection("test"); @@ -1508,21 +1509,21 @@ public void IndexArrayWorkAroundOverlaps() coll.Add(doc22).Execute(); coll.CreateIndex("myIndex", "{\"fields\": [{\"field\": $.myField, \"type\":\"" + "DateTime" + "\", \"array\": true}]}"); docResult = coll.Find("CAST(CAST('1000-01-01 00:00:00' as DATETIME) as JSON) overlaps $.myField").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-DateTime"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-DateTime"); docResult = coll.Find("CAST(CAST('9999-02-02 01:20:33' as DATETIME) as JSON) overlaps $.myField").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-DateTime"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-DateTime"); docResult = coll.Find("CAST(CAST(:dt as DATETIME) as JSON) overlaps $.myField").Bind("dt", "9999-02-02 01:20:33").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Date-With Bind"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Date-With Bind"); docResult = coll.Find("CAST(CAST(:dt as DATETIME) as JSON) overlaps $.myField").Bind("dt", "9999-12-31 23:59:59").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Date-With Bind"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Date-With Bind"); docResult = coll.Find(":dt overlaps $.myField").Bind("dt", "9999-02-02 01:20:33").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-DateTime-With Bind-Bug"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-DateTime-With Bind-Bug"); docResult = coll.Find(":dt overlaps $.myField").Bind("dt", "1000-01-01 00:00:00").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-DateTime-With Bind-Bug"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-DateTime-With Bind-Bug"); docResult = coll.Find(":dt not overlaps $.myField").Bind("dt", "1000-01-01 00:00:00").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-DateTime-With Bind-Bug"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-DateTime-With Bind-Bug"); docResult = coll.Find("CAST(CAST(:dt as DATETIME) as JSON) not overlaps $.myField").Bind("dt", "9999-12-31 23:59:59").Execute(); - Assert.AreEqual(2, docResult.FetchAll().Count, "Matching the document ID-Date-With Bind"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(2), "Matching the document ID-Date-With Bind"); coll = CreateCollection("test"); @@ -1532,23 +1533,23 @@ public void IndexArrayWorkAroundOverlaps() coll.Add(doc22).Execute(); coll.CreateIndex("myIndex", "{\"fields\": [{\"field\": $.myField, \"type\":\"" + "Signed" + "\", \"array\": true}]}"); docResult = coll.Find("CAST(CAST('100' as SIGNED) as JSON) overlaps $.myField").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-SIGNED"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-SIGNED"); docResult = coll.Find("CAST(CAST('3' as SIGNED) as JSON) overlaps $.myField").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-SIGNED"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-SIGNED"); docResult = coll.Find("CAST(CAST(:dt as SIGNED) as JSON) overlaps $.myField").Bind("dt", "100").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-SIGNED-With Bind"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-SIGNED-With Bind"); docResult = coll.Find("CAST(CAST(:dt as SIGNED) as JSON) overlaps $.myField").Bind("dt", "19").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-SIGNED-With Bind"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-SIGNED-With Bind"); docResult = coll.Find(":dt overlaps $.myField").Bind("dt", 100).Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Signed-With Bind"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Signed-With Bind"); docResult = coll.Find(":dt overlaps $.myField").Bind("dt", "100").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Signed-With Bind"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Signed-With Bind"); docResult = coll.Find(":dt overlaps $.myField").Bind("dt", "3").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Signed-With Bind"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Signed-With Bind"); docResult = coll.Find(":dt not overlaps $.myField").Bind("dt", "100").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Signed-With Bind"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Signed-With Bind"); docResult = coll.Find("CAST(CAST(:dt as SIGNED) as JSON) not overlaps $.myField").Bind("dt", "19").Execute(); - Assert.AreEqual(2, docResult.FetchAll().Count, "Matching the document ID-SIGNED-With Bind"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(2), "Matching the document ID-SIGNED-With Bind"); coll = CreateCollection("test"); doc = new[] { new { _id = 1, name = "SIGNED INTEGER", myField = "100" } }; @@ -1557,25 +1558,25 @@ public void IndexArrayWorkAroundOverlaps() coll.Add(doc22).Execute(); coll.CreateIndex("myIndex", "{\"fields\": [{\"field\": $.myField, \"type\":\"" + "SIGNED INTEGER" + "\", \"array\": true}]}"); docResult = coll.Find("CAST(CAST('100' as SIGNED INTEGER) as JSON) overlaps $.myField").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-SIGNED INTEGER"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-SIGNED INTEGER"); docResult = coll.Find("CAST(CAST('3' as SIGNED INTEGER) as JSON) overlaps $.myField").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-SIGNED INTEGER"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-SIGNED INTEGER"); docResult = coll.Find("CAST(CAST(:dt as SIGNED INTEGER) as JSON) overlaps $.myField").Bind("dt", "100").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-SIGNED INTEGER-With Bind"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-SIGNED INTEGER-With Bind"); docResult = coll.Find("CAST(CAST(:dt as SIGNED INTEGER) as JSON) overlaps $.myField").Bind("dt", "19").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-SIGNED INTEGER-With Bind"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-SIGNED INTEGER-With Bind"); docResult = coll.Find(":dt overlaps $.myField").Bind("dt", 100).Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-SIGNED INTEGER-With Bind-Bug"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-SIGNED INTEGER-With Bind-Bug"); docResult = coll.Find(":dt overlaps $.myField").Bind("dt", "100").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-SIGNED INTEGER-With Bind-Bug"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-SIGNED INTEGER-With Bind-Bug"); docResult = coll.Find(":dt overlaps $.myField").Bind("dt", 3).Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-SIGNED INTEGER-With Bind-Bug"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-SIGNED INTEGER-With Bind-Bug"); docResult = coll.Find(":dt overlaps $.myField").Bind("dt", "3").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-SIGNED INTEGER-With Bind-Bug"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-SIGNED INTEGER-With Bind-Bug"); docResult = coll.Find(":dt not overlaps $.myField").Bind("dt", "3").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-SIGNED INTEGER-With Bind-Bug"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-SIGNED INTEGER-With Bind-Bug"); docResult = coll.Find("CAST(CAST(:dt as SIGNED INTEGER) as JSON) overlaps $.myField").Bind("dt", "19").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-SIGNED INTEGER-With Bind"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-SIGNED INTEGER-With Bind"); coll = CreateCollection("test"); doc = new[] { new { _id = 1, name = "Unsigned", myField = "100" } }; @@ -1584,25 +1585,25 @@ public void IndexArrayWorkAroundOverlaps() coll.Add(doc22).Execute(); coll.CreateIndex("myIndex", "{\"fields\": [{\"field\": $.myField, \"type\":\"" + "Unsigned" + "\", \"array\": true}]}"); docResult = coll.Find("CAST(CAST('100' as UNSIGNED) as JSON) overlaps $.myField").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Unsigned"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Unsigned"); docResult = coll.Find("CAST(CAST('3' as UNSIGNED) as JSON) overlaps $.myField").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Unsigned"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Unsigned"); docResult = coll.Find("CAST(CAST(:dt as UNSIGNED) as JSON) overlaps $.myField").Bind("dt", "100").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Unsigned-With Bind"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Unsigned-With Bind"); docResult = coll.Find("CAST(CAST(:dt as UNSIGNED) as JSON) overlaps $.myField").Bind("dt", "19").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Unsigned-With Bind"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Unsigned-With Bind"); docResult = coll.Find(":dt overlaps $.myField").Bind("dt", 100).Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Unsigned-With Bind-Bug"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Unsigned-With Bind-Bug"); docResult = coll.Find(":dt overlaps $.myField").Bind("dt", "100").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Unsigned-With Bind-Bug"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Unsigned-With Bind-Bug"); docResult = coll.Find(":dt overlaps $.myField").Bind("dt", 3).Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Unsigned-With Bind-Bug"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Unsigned-With Bind-Bug"); docResult = coll.Find(":dt overlaps $.myField").Bind("dt", "3").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Unsigned-With Bind-Bug"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Unsigned-With Bind-Bug"); docResult = coll.Find(":dt not overlaps $.myField").Bind("dt", "3").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Unsigned-With Bind-Bug"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Unsigned-With Bind-Bug"); docResult = coll.Find("CAST(CAST(:dt as UNSIGNED) as JSON) overlaps $.myField").Bind("dt", "19").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Unsigned-With Bind"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Unsigned-With Bind"); coll = CreateCollection("test"); doc = new[] { new { _id = 1, name = "Char", myField = "too@mail.com" } }; @@ -1611,18 +1612,18 @@ public void IndexArrayWorkAroundOverlaps() coll.Add(doc22).Execute(); coll.CreateIndex("myIndex", "{\"fields\": [{\"field\": $.myField, \"type\":\"" + "CHAR(128)" + "\", \"array\": true}]}"); docResult = coll.Find(":dt overlaps $.myField").Bind("dt", "too@mail.com").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-CHAR(128)-With Bind"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-CHAR(128)-With Bind"); docResult = coll.Find(":dt overlaps $.myField").Bind("dt", "foo@mail.com").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-CHAR(128)-With Bind"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-CHAR(128)-With Bind"); docResult = coll.Find(":dt not overlaps $.myField").Bind("dt", "foo@mail.com").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-CHAR(128)-With Bind"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-CHAR(128)-With Bind"); } [Test, Description("Index using overlaps")] public void IndexArrayWithOverlaps() { var coll = CreateCollection("test"); - if (!session.Version.isAtLeast(8, 0, 17)) Assert.Ignore("This test is for MySql 8.0.17 or higher."); + Assume.That(session.Version.isAtLeast(8, 0, 17), "This test is for MySql 8.0.17 or higher"); var doc = new[] { new { _id = 1, name = "Time", myField1 = "9:00:00" } }; var doc22 = new[] { new { _id = 2, name = "Time", myField2 = new[] { "01:01:01.001", "23:59:59.15", "12:00:00", "1" }, myField4 = new[] { "01:01:01.001", "23:59:59.15", "12:00:00", "1" } } }; @@ -1634,41 +1635,41 @@ public void IndexArrayWithOverlaps() coll.Add(doc34).Execute(); var docResult = coll.Find(":dt overlaps $.myField1").Bind("dt", "9:00:00").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the document ID-Time-With Bind-Bug before index creation"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID-Time-With Bind-Bug before index creation"); coll.CreateIndex("myIndex1", "{\"fields\": [{\"field\": $.myField1, \"type\":\"" + "Time" + "\", \"array\": true}]}"); coll.CreateIndex("myIndex2", "{\"fields\": [{\"field\": $.myField2, \"type\":\"" + "Time" + "\", \"array\": true}]}"); coll.CreateIndex("myIndex3", "{\"fields\": [{\"field\": $.myField3, \"type\":\"" + "Time" + "\", \"array\": true}]}"); coll.CreateIndex("myIndex4", "{\"fields\": [{\"field\": $.myField1, \"type\":\"" + "Time" + "\", \"array\": true}]}"); coll.CreateIndex("myIndex5", "{\"fields\": [{\"field\": $.myField3, \"type\":\"" + "Time" + "\", \"array\": true}]}"); docResult = coll.Find("myIndex1 overlaps myIndex2").Execute(); - Assert.AreEqual(0, docResult.FetchAll().Count, "Matching the indexes using overlaps"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(0), "Matching the indexes using overlaps"); docResult = coll.Find("myIndex2 overlaps myIndex3").Execute(); - Assert.AreEqual(0, docResult.FetchAll().Count, "Matching the indexes using overlaps"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(0), "Matching the indexes using overlaps"); docResult = coll.Find("myIndex2 not overlaps myIndex3").Execute(); - Assert.AreEqual(0, docResult.FetchAll().Count, "Matching the indexes using not overlaps"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(0), "Matching the indexes using not overlaps"); docResult = coll.Find("myIndex1 overlaps myIndex4").Execute(); - Assert.AreEqual(0, docResult.FetchAll().Count, "Matching the indexes using overlaps"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(0), "Matching the indexes using overlaps"); docResult = coll.Find("'myIndex3' overlaps 'myIndex5'").Execute(); - Assert.AreEqual(0, docResult.FetchAll().Count, "Matching the indexes using overlaps"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(0), "Matching the indexes using overlaps"); docResult = coll.Find("$.myField3 overlaps $.myField2").Execute(); - Assert.AreEqual(0, docResult.FetchAll().Count, "Matching the indexes using overlaps"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(0), "Matching the indexes using overlaps"); docResult = coll.Find("$.myField1 overlaps $.myField3").Execute(); - Assert.AreEqual(0, docResult.FetchAll().Count, "Matching the indexes using overlaps"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(0), "Matching the indexes using overlaps"); docResult = coll.Find("$.myField2 overlaps $.myField4").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the indexes using overlaps"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the indexes using overlaps"); docResult = coll.Find("$.myField2 not overlaps $.myField4").Execute(); - Assert.AreEqual(0, docResult.FetchAll().Count, "Matching the indexes using not overlaps"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(0), "Matching the indexes using not overlaps"); docResult = coll.Find("$.myField5 overlaps $.myField3").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the indexes using overlaps"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the indexes using overlaps"); docResult = coll.Find("$.myField5 not overlaps $.myField3").Execute(); - Assert.AreEqual(1, docResult.FetchAll().Count, "Matching the indexes using not overlaps"); + Assert.That(docResult.FetchAll().Count, Is.EqualTo(1), "Matching the indexes using not overlaps"); } [Test, Description("multikey scenarios with observations")] public void IndexArrayMultiKey() { var coll = CreateCollection("test"); - if (!session.Version.isAtLeast(8, 0, 17)) Assert.Ignore("This test is for MySql 8.0.17 or higher."); + Assume.That(session.Version.isAtLeast(8, 0, 17), "This test is for MySql 8.0.17 or higher"); coll.CreateIndex("myIndex", "{\"fields\": [{\"field\": $.myField, \"type\":\"CHAR(255)\", \"array\": false}]}"); @@ -1730,9 +1731,9 @@ public void IndexArrayMultiKey() [Test, Description("Test MySQLX plugin Create Collection Multiple Index Type")] public void CreateCollectionMultipleIndexDataType() { - if (!session.Version.isAtLeast(5, 7, 0)) Assert.Ignore("This test is for MySql 5.7 or higher."); + Assume.That(session.Version.isAtLeast(5, 7, 0), "This test is for MySql 5.7 or higher"); Collection testColl = CreateCollection("test"); - Assert.AreEqual(true, testColl.ExistsInDatabase(), "ExistsInDatabase failed"); + Assert.That(testColl.ExistsInDatabase(), Is.EqualTo(true), "ExistsInDatabase failed"); testColl.CreateIndex("testIndex12", "{\"fields\": [ { \"field\":$.myId, \"type\":\"DOUBLE\" , \"required\":true} ] }"); testColl.CreateIndex("testIndex", "{\"fields\": [ { \"field\":$.myId, \"type\":\"DOUBLE UNSIGNED\" , \"required\":true} ] }"); @@ -1744,20 +1745,20 @@ public void CreateCollectionMultipleIndexDataType() testColl.Add(new { myId = 990.196078431, myAge = 10000000 }).Execute(); testColl.DropIndex("testIndex"); var result = testColl.Add(new { myId = 990.196078431, myAge = 10000000 }).Execute(); - Assert.AreEqual(1, result.AffectedItemsCount); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1)); testColl.DropIndex("testIndex1"); result = testColl.Add(new { myId = 990.196078431, myAge = 10000000 }).Execute(); - Assert.AreEqual(1, result.AffectedItemsCount); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1)); Assert.Throws(() => testColl.CreateIndex("testIndex2", "{\"fields\": [ { \"field\":$.myName, \"type\":\"TEXT\" , \"required\":true} ] }")); } [Test, Description("Test MySQLX plugin Create Collection Multiple Index Stress")] public void CreateCollectionMultipleIndexStress() { - if (!session.Version.isAtLeast(5, 7, 0)) Assert.Ignore("This test is for MySql 5.7 or higher."); + Assume.That(session.Version.isAtLeast(5, 7, 0), "This test is for MySql 5.7 or higher"); Collection testColl = CreateCollection("test"); - Assert.AreEqual(true, testColl.ExistsInDatabase(), "ExistsInDatabase failed"); + Assert.That(testColl.ExistsInDatabase(), Is.EqualTo(true), "ExistsInDatabase failed"); testColl.CreateIndex("testIndex", "{\"fields\": [ { \"field\":$.myId, \"type\":\"TINYINT UNSIGNED\" , \"required\":true} ] }"); testColl.CreateIndex("testIndex1", "{\"fields\": [ { \"field\":$.myAge, \"type\":\"SMALLINT UNSIGNED\" , \"required\":true} ] }"); @@ -1821,27 +1822,27 @@ private void ValidateIndex(string fieldName, string collectionName, string dataT continue; indexFound = true; - Assert.AreEqual(collectionName, reader["Table"]); - Assert.AreEqual(unique ? 0 : 1, Convert.ToInt16(reader["Non_unique"])); + Assert.That(reader["Table"], Is.EqualTo(collectionName)); + Assert.That(Convert.ToInt16(reader["Non_unique"]), Is.EqualTo(unique ? 0 : 1)); if (!array && !string.IsNullOrEmpty(reader["Column_name"].ToString())) { var columnNameTokens = reader["Column_name"].ToString().Split('_'); - Assert.AreEqual(dataType, isUnsigned ? string.Format("{0}_{1}", columnNameTokens[1], columnNameTokens[2]) : columnNameTokens[1]); + Assert.That(isUnsigned ? string.Format("{0}_{1}", columnNameTokens[1], columnNameTokens[2]) : columnNameTokens[1], Is.EqualTo(dataType)); } else if (array && !string.IsNullOrEmpty(reader["Expression"].ToString())) { string expression = reader["Expression"].ToString(); int pos = reader["Expression"].ToString().IndexOf(" as "); expression = expression.Substring(pos + 4); - StringAssert.Contains("array", expression); + Assert.That(expression, Does.Contain("array")); expression = expression.Substring(0, expression.IndexOf(" array")); Assert.That(dataType, Is.EqualTo(expression.Replace(" ", string.Empty)).IgnoreCase); } - Assert.AreEqual(required ? "" : "YES", reader["Null"]); + Assert.That(reader["Null"], Is.EqualTo(required ? "" : "YES")); if (length != null) - Assert.AreEqual(length, Convert.ToInt32(reader["Sub_part"])); + Assert.That(Convert.ToInt32(reader["Sub_part"]), Is.EqualTo(length)); break; } } @@ -1853,4 +1854,4 @@ private void ValidateIndex(string fieldName, string collectionName, string dataT #endregion Methods } -} \ No newline at end of file +} diff --git a/MySQL.Data/tests/MySqlX.Data.Tests/CollectionTests.cs b/MySQL.Data/tests/MySqlX.Data.Tests/CollectionTests.cs index 52baf0761..ba00db91f 100644 --- a/MySQL.Data/tests/MySqlX.Data.Tests/CollectionTests.cs +++ b/MySQL.Data/tests/MySqlX.Data.Tests/CollectionTests.cs @@ -1,1739 +1,1740 @@ -// Copyright (c) 2015, 2022, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data; -using MySql.Data.MySqlClient; -using MySqlX.XDevAPI; -using MySqlX.XDevAPI.Common; -using MySqlX.XDevAPI.Relational; -using NUnit.Framework; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; - -namespace MySqlX.Data.Tests -{ - public class CollectionTests : BaseTest - { - [TearDown] - public void tearDown() - { - session.Schema.DropCollection("test"); - session.Schema.DropCollection("test123"); - session.Schema.DropCollection("testcount"); - session.Schema.DropCollection("coll"); - session.Schema.DropCollection("col20"); - session.Schema.DropCollection("col21"); - session.Schema.DropCollection("col22"); - } - - [Test] - public void GetAllCollections() - { - session.DropSchema("test"); - session.CreateSchema("test"); - Collection book = CreateCollection("book"); - List collections = book.Schema.GetCollections(); - Assert.That(collections, Has.One.Items); - Assert.True(collections[0].Name == "book"); - book.Schema.DropCollection("book"); - } - - [Test] - public void CreateAndDropCollection() - { - Session s = GetSession(); - Schema test = s.GetSchema("test"); - Collection testColl = test.CreateCollection("test"); - Assert.True(CollectionExistsInDatabase(testColl)); - - // Drop existing collection. - test.DropCollection("test"); - Assert.False(CollectionExistsInDatabase(testColl)); - - // Drop non-existing collection. - test.DropCollection("test"); - Assert.False(CollectionExistsInDatabase(testColl)); - - //dropCollection when the object to drop contains invalid characters - test.DropCollection("%^&!@~*(&*(*&:>(() => test.DropCollection(string.Empty)); - Assert.Throws(() => test.DropCollection(" ")); - Assert.Throws(() => test.DropCollection(" ")); - Assert.Throws(() => test.DropCollection(null)); - } - - [Test] - public void CreateCollectionIndex() - { - Session session = GetSession(); - Schema test = session.GetSchema(schemaName); - Collection testColl = test.CreateCollection("test"); - Assert.True(CollectionExistsInDatabase(testColl), "ExistsInDatabase failed"); - testColl.CreateIndex("testIndex", "{ \"fields\": [ { \"field\":$.myId, \"type\":\"INT\", \"required\":true } ] }"); - var result = ExecuteAddStatement(testColl.Add(new { myId = 1 }).Add(new { myId = 2 })); - Assert.AreEqual(result.AffectedItemsCount, 2); - } - - [Test] - public void DropCollectionIndex() - { - Session session = GetSession(); - Schema test = session.GetSchema(schemaName); - Collection testColl = CreateCollection("test"); - testColl.CreateIndex("testIndex", "{ \"fields\": [ { \"field\":$.myId, \"type\":\"INT\", \"required\":true } ] }"); - - // Drop existing index. - testColl.DropIndex("testIndex"); - - // Drop non-existing index. - testColl.DropIndex("testIndex"); - - //dropIndex contains invalid characters - testColl.DropIndex("%^&!@~*(&*(*&:>(() => testColl.DropIndex(string.Empty)); - Assert.Throws(() => testColl.DropIndex(" ")); - Assert.Throws(() => testColl.DropIndex(" ")); - Assert.Throws(() => testColl.DropIndex(null)); - - } - - [Test] - public void DropSchemaTests() - { - session.DropSchema("validSchema"); - session.CreateSchema("validSchema"); - session.DropSchema("validSchema"); - session.DropSchema("%^&!@~*(&*(*&:>(() => session.DropSchema(string.Empty)); - Assert.Throws(() => session.DropSchema(" ")); - Assert.Throws(() => session.DropSchema(" ")); - Assert.Throws(() => session.DropSchema(null)); - } - - - [Test] - public void ValidateExistence() - { - Session session = GetSession(); - Schema schema = session.GetSchema(schemaName); - var ex = Assert.Throws(() => schema.GetCollection("nonExistentCollection", true)); - Assert.AreEqual("Collection 'nonExistentCollection' does not exist.", ex.Message); - } - - [Test] - public void CountCollection() - { - Session session = GetSession(); - Schema schema = session.GetSchema(schemaName); - CreateCollection("testCount"); - var count = session.SQL("SELECT COUNT(*) FROM test.testCount").Execute().FetchOne()[0]; - - // Zero records - var collection = schema.GetCollection("testCount"); - Assert.AreEqual(count, collection.Count()); - var table = schema.GetTable("testCount"); - Assert.AreEqual(count, table.Count()); - - // Insert some records - var stm = collection.Add(@"{ ""_id"": 1, ""foo"": 1 }") - .Add(@"{ ""_id"": 2, ""foo"": 2 }") - .Add(@"{ ""_id"": 3, ""foo"": 3 }"); - stm.Execute(); - count = session.SQL("SELECT COUNT(*) FROM test.testCount").Execute().FetchOne()[0]; - Assert.AreEqual(count, collection.Count()); - - table.Insert("doc").Values(@"{ ""_id"": 4, ""foo"": 4 }").Execute(); - count = session.SQL("SELECT COUNT(*) FROM test.testCount").Execute().FetchOne()[0]; - Assert.AreEqual(count, table.Count()); - - collection.RemoveOne(2); - count = session.SQL("SELECT COUNT(*) FROM test.testCount").Execute().FetchOne()[0]; - Assert.AreEqual(count, collection.Count()); - Assert.AreEqual(count, table.Count()); - - // Collection/Table does not exist - var ex = Assert.Throws(() => schema.GetCollection("testCount_").Count()); - Assert.AreEqual("Collection 'testCount_' does not exist in schema 'test'.", ex.Message); - ex = Assert.Throws(() => schema.GetTable("testCount_").Count()); - Assert.AreEqual("Table 'testCount_' does not exist in schema 'test'.", ex.Message); - } - - [Test] - public void ModifyCollectionNoLevelNorSchema() - { - Session s = GetSession(); - Schema test = s.GetSchema("test"); - - // Modify a Collection without passing schema and Level, (Bug#30660917) - test.CreateCollection("coll"); - ModifyCollectionOptions options1 = new ModifyCollectionOptions(); - options1.Validation = new Validation() { }; - Assert.Throws(() => test.ModifyCollection("coll", options1)); - } - - [Test] - public void CreateCollectionWithOptions() - { - Session s = GetSession(); - Schema test = s.GetSchema("test"); - - // CreateCollection Test Cases - - // Create a Collection passing a valid schema and Level - CreateCollectionOptions options = new CreateCollectionOptions(); - Validation val = new Validation(); - val.Level = ValidationLevel.STRICT; - string str = "{\"id\": \"http://json-schema.org/geo\"," - + "\"$schema\": \"http://json-schema.org/draft-06/schema#\"," - + "\"description\": \"A geographical coordinate\"," - + "\"type\": \"object\"," - + "\"properties\": {" - + "\"latitude\": {" - + "\"type\": \"number\"" - + " }," - + "\"longitude\": {" - + "\"type\": \"number\"" - + "}" - + "}," - + "\"required\": [\"latitude\", \"longitude\"]" - + "}"; - val.Schema = str; - options.ReuseExisting = false; - options.Validation = val; - Collection testColl = test.CreateCollection("testWithSchemaValidation", options); - Assert.True(CollectionExistsInDatabase(testColl)); - - //Bug #30830962 - options = new CreateCollectionOptions(); - val = new Validation() { }; - options.Validation = val; - var testbug1 = test.CreateCollection("bug_0962", options); //create collection with empty options - testbug1.Add(@"{ ""latitude"": 20, ""longitude"": 30 }").Execute(); - testbug1.Add(@"{ ""sexo"": 1, ""edad"": 20 }").Execute(); - int.TryParse(session.SQL("SELECT COUNT(*) FROM test.bug_0962").Execute().FetchOne()[0].ToString(), out int expected_count); - Assert.AreEqual(2, expected_count); //Collection is created as STRICT with empty json schema,both records were inserted - - options = new CreateCollectionOptions(); - val = new Validation() { Schema = str }; - options.Validation = val; - testbug1 = test.CreateCollection("bug_0962b", options);// adding an schema from - testbug1.Add(@"{ ""latitude"": 20, ""longitude"": 30 }").Execute(); - var invalidEx = Assert.Throws(() => testbug1.Add(@"{ ""sexo"": 1, ""edad"": 20 }").Execute()); - StringAssert.Contains("Document is not valid according to the schema assigned to collection", invalidEx.Message); - - // Create a Collection passing a reuse_existing parameter to server - CreateCollectionOptions options_reuse = new CreateCollectionOptions(); - options_reuse.ReuseExisting = false; - options_reuse.Validation = val; - Collection testCol2 = test.CreateCollection("testReuseExisting_1", options_reuse); - Assert.True(CollectionExistsInDatabase(testCol2)); - - //Insert Valid record with Level Strict - var insert_statement = testColl.Add(@"{ ""latitude"": 20, ""longitude"": 30 }"); - insert_statement.Execute(); - var count = session.SQL("SELECT COUNT(*) FROM test.testWithSchemaValidation").Execute().FetchOne()[0]; - Assert.AreEqual(count, testColl.Count()); - - //Insert invalid record with Level Strict - insert_statement = testColl.Add(@"{ ""OtherField"": ""value"", ""Age"": 30 }"); - var invalidInsertEx = Assert.Throws(() => insert_statement.Execute()); - StringAssert.Contains("Document is not valid according to the schema assigned to collection", invalidInsertEx.Message); - - //Test: Old MySQL Server Version exceptions - if (!(session.Version.isAtLeast(8, 0, 19))) - { - //FR6.2 - var ex1 = Assert.Throws(() => test.CreateCollection("testInvalid", options)); - StringAssert.Contains("Invalid number of arguments, expected 2 but got 3, " + - "The server doesn't support the requested operation. Please update the MySQL Server and/or Client library", ex1.Message); - - //FR6.3 - test.CreateCollection("testInvalid"); - ModifyCollectionOptions modifyOptions = new ModifyCollectionOptions(); - modifyOptions.Validation = val; - var ex2 = Assert.Throws(() => test.ModifyCollection("testInvalid", modifyOptions)); - StringAssert.Contains("Invalid mysqlx command modify_collection_options, " + - "The server doesn't support the requested operation. Please update the MySQL Server and/or Client library", ex2.Message); - } - - //Create collection with json schema and level OFF. Try to insert document matches this schema - options = new CreateCollectionOptions(); - options.Validation = new Validation() { Level = ValidationLevel.OFF, Schema = str }; - Collection col_test = test.CreateCollection("Test_2b_1", options); - Assert.True(CollectionExistsInDatabase(col_test)); - insert_statement = col_test.Add(@"{ ""latitude"": 120, ""longitude"": 78 }"); - insert_statement.Execute(); - count = session.SQL("SELECT COUNT(*) FROM test.Test_2b_1").Execute().FetchOne()[0]; - Assert.AreEqual(count, col_test.Count()); - - //Create collection with json schema and level OFF,ReuseExisting set to true, Try to insert - options = new CreateCollectionOptions(); - options.Validation = new Validation() { Level = ValidationLevel.OFF, Schema = str }; - options.ReuseExisting = true; - col_test = test.CreateCollection("Test_2b_2", options); - Assert.True(CollectionExistsInDatabase(col_test)); - insert_statement = col_test.Add(@"{ ""latitude"": 20, ""longitude"": 42 }"); - insert_statement.Execute(); - count = session.SQL("SELECT COUNT(*) FROM test.Test_2b_2").Execute().FetchOne()[0]; - Assert.AreEqual(count, col_test.Count()); - - //Create collection with only schema option, Try to insert - options = new CreateCollectionOptions(); - options.Validation = new Validation() { Schema = str }; - col_test = test.CreateCollection("Test_2b_3", options); - Assert.True(CollectionExistsInDatabase(col_test)); - insert_statement = col_test.Add(@"{ ""latitude"": 5, ""longitude"": 10 }"); - insert_statement.Execute(); - count = session.SQL("SELECT COUNT(*) FROM test.Test_2b_3").Execute().FetchOne()[0]; - Assert.AreEqual(count, col_test.Count()); - - //Create collection with only schema option,ReuseExisting set to true, Try to insert - options = new CreateCollectionOptions(); - options.Validation = new Validation() { Schema = str }; - options.ReuseExisting = true; - col_test = test.CreateCollection("Test_2b_4", options); - Assert.True(CollectionExistsInDatabase(col_test)); - insert_statement = col_test.Add(@"{ ""latitude"": 25, ""longitude"": 52 }"); - insert_statement.Execute(); - count = session.SQL("SELECT COUNT(*) FROM test.Test_2b_4").Execute().FetchOne()[0]; - Assert.AreEqual(count, col_test.Count()); - - //Create collection with only level option - options = new CreateCollectionOptions(); - options.Validation = new Validation() { Level = ValidationLevel.OFF }; - col_test = test.CreateCollection("Test_2b_5", options); - Assert.True(CollectionExistsInDatabase(col_test)); - - //ResuseExisting = false should throw exception for an existing collection - CreateCollectionOptions testReuseOptions = new CreateCollectionOptions(); - testReuseOptions.ReuseExisting = false; - testReuseOptions.Validation = new Validation() { Level = ValidationLevel.OFF }; - test.CreateCollection("testReuse"); - var exreuse = Assert.Throws(() => test.CreateCollection("testReuse", testReuseOptions)); - StringAssert.AreEqualIgnoringCase("Table 'testReuse' already exists", exreuse.Message); - - //Test: Resuse Existing = True should return existing collection - testReuseOptions.ReuseExisting = true; - var existing = test.CreateCollection("testReuse", testReuseOptions); - Assert.True(CollectionExistsInDatabase(existing)); - - //Create collection and prepare test data with json schema and level STRICT - CreateCollectionOptions prepareOptions = new CreateCollectionOptions(); - prepareOptions.Validation = new Validation() { Level = ValidationLevel.STRICT, Schema = str }; - var res_stm = test.CreateCollection("TestCreateInsert", prepareOptions).Add(@"{ ""latitude"": 25, ""longitude"": 52 }"); - res_stm.Execute(); - var num = session.SQL("SELECT COUNT(*) FROM test.TestCreateInsert").Execute().FetchOne()[0]; - var collection_test = test.GetCollection("TestCreateInsert"); - Assert.AreEqual(num, collection_test.Count()); - - //Passing invalid Schema - options = new CreateCollectionOptions(); - options.Validation = new Validation() { Level = ValidationLevel.STRICT, Schema = "Not Valid JSON Schema" }; - Exception ex_schema = Assert.Throws(() => test.CreateCollection("testInvalidSchema", options)); - StringAssert.Contains(@"The value provided is not a valid JSON document.", ex_schema.Message); - - //Testing an schema with different data types - str = "{\"id\": \"http://json-schema.org/geo\"," - + "\"$schema\": \"http://json-schema.org/draft-06/schema#\"," - + "\"description\": \"A Person example\"," - + "\"type\": \"object\"," - + "\"properties\": {" - + "\"name\": {" - + "\"type\": \"string\"" - + " }," - + "\"age\": {" - + "\"type\": \"number\"" - + "}" - + "}," - + "\"required\": [\"name\", \"age\"]" - + "}"; - - options = new CreateCollectionOptions(); - options.Validation = new Validation() { Level = ValidationLevel.STRICT, Schema = str }; - Collection person_col = test.CreateCollection("testWithPersonSchema", options); - Assert.True(CollectionExistsInDatabase(person_col)); - person_col.Add(@"{ ""name"": ""John"", ""age"": 52 }").Execute(); - var rows = session.SQL("SELECT COUNT(*) FROM test.testWithPersonSchema").Execute().FetchOne()[0]; - Assert.AreEqual(rows, person_col.Count()); - - // Create an existing collection with different schema - options = new CreateCollectionOptions(); - options.ReuseExisting = true; - options.Validation = new Validation() { Level = ValidationLevel.STRICT, Schema = str }; - Collection col_schema1 = test.CreateCollection("testSchema1", options); - Assert.True(CollectionExistsInDatabase(col_schema1)); - - col_schema1.Add(@"{ ""name"": ""John"", ""age"": 52 }").Execute(); - Assert.AreEqual(1, col_schema1.Count()); - var sqlDefinition1 = session.SQL("SHOW CREATE TABLE test.testSchema1").Execute().FetchOne()[1]; - - - var schema2 = "{\"id\": \"http://json-schema.org/geo\"," - + "\"$schema\": \"http://json-schema.org/draft-06/schema#\"," - + "\"description\": \"A Movies example\"," - + "\"type\": \"object\"," - + "\"properties\": {" - + "\"title\": {" - + "\"type\": \"string\"" - + " }," - + "\"movie\": {" - + "\"type\": \"string\"" - + "}" - + "}," - + "\"required\": [\"title\", \"movie\"]" - + "}"; - - options.Validation = new Validation() { Level = ValidationLevel.STRICT, Schema = schema2 }; - Collection col_schema2 = test.CreateCollection("testSchema1", options); - var sqlDefinition2 = session.SQL("SHOW CREATE TABLE test.testSchema1").Execute().FetchOne()[1]; - Assert.AreEqual(sqlDefinition1, sqlDefinition2); - - //Create a collection without sending reuseExisting parameter and insert record - Collection original_col1 = test.CreateCollection("testOriginal1"); - Assert.True(CollectionExistsInDatabase(original_col1)); - original_col1.Add(@"{ ""name"": ""John"", ""age"": 52 }").Execute(); - rows = session.SQL("SELECT COUNT(*) FROM test.testOriginal1").Execute().FetchOne()[0]; - Assert.AreEqual(rows, original_col1.Count()); - - //Create a new collection sending reuseExisting as true, insert record - Collection original_col2 = test.CreateCollection("testOriginal2", true); - Assert.True(CollectionExistsInDatabase(original_col2)); - original_col2.Add(@"{ ""name"": ""John"", ""age"": 52 }").Execute(); - rows = session.SQL("SELECT COUNT(*) FROM test.testOriginal2").Execute().FetchOne()[0]; - Assert.AreEqual(rows, original_col2.Count()); - - //Create an existing collection sending reuseExisting as true, insert record - Collection original_col3 = test.CreateCollection("testOriginal2", true); - Assert.True(CollectionExistsInDatabase(original_col3)); - original_col3.Add(@"{ ""name"": ""John2"", ""age"": 12 }").Execute(); - Assert.AreEqual(2, original_col3.Count()); - - //Create an existing collection sending reuseExisting as false,exception expected - var ex_existing = Assert.Throws(() => test.CreateCollection("testOriginal2", false)); - StringAssert.AreEqualIgnoringCase(@"Table 'testOriginal2' already exists", ex_existing.Message); - - //Modify collection with only level option - ModifyCollectionOptions Test_Options = new ModifyCollectionOptions(); - Test_Options.Validation = new Validation() { Level = ValidationLevel.OFF }; - Collection col_Test_2a_1 = test.ModifyCollection("testWithSchemaValidation", Test_Options); - - // Inser valid and invalid records with level set to Off - insert_statement = col_Test_2a_1.Add(@"{ ""latitude"": 20, ""longitude"": 30 }") - .Add(@"{ ""OtherField"": ""value"", ""Age"": 30 }"); - insert_statement.Execute(); - count = session.SQL("SELECT COUNT(*) FROM test.testWithSchemaValidation").Execute().FetchOne()[0]; - Assert.AreEqual(count, col_Test_2a_1.Count()); - - //Modify collection with only schema option - Test_Options.Validation = new Validation() { Schema = "{ }" }; - test.ModifyCollection("testWithSchemaValidation", Test_Options); - var sqlCreate = session.SQL("SHOW CREATE TABLE test.testWithSchemaValidation").Execute().FetchOne()[1]; - Assert.True(sqlCreate.ToString().Contains(@"'{\r\n}'") || sqlCreate.ToString().Contains("{}")); - - //Passing null as parameter to ModifyCollection - var emptyOptions = new ModifyCollectionOptions(); - emptyOptions.Validation = new Validation() { }; - test.CreateCollection("testnull"); - exreuse = Assert.Throws(() => test.ModifyCollection("testnull", null)); - Assert.AreEqual(@"Arguments value used under ""validation"" must be an object with at least one field", exreuse.Message); - - test.DropCollection("testWithSchemaValidation"); - test.DropCollection("bug_0962"); - test.DropCollection("bug_0962b"); - test.DropCollection("testReuseExisting_1"); - test.DropCollection("Test_2b_1"); - test.DropCollection("Test_2b_2"); - test.DropCollection("Test_2b_3"); - test.DropCollection("Test_2b_4"); - test.DropCollection("Test_2b_5"); - test.DropCollection("testReuse"); - test.DropCollection("TestCreateInsert"); - test.DropCollection("testWithPersonSchema"); - test.DropCollection("testSchema1"); - test.DropCollection("testOriginal1"); - test.DropCollection("testOriginal2"); - test.DropCollection("testnull"); - } - - /// - /// Server Bug - /// Bug #31667405 - INCORRECT PREPARED STATEMENT OUTCOME WITH NUMERIC STRINGS IN JSON - /// - [Test] - public void PreparedStatementWithNumericStrings() - { - Collection coll = CreateCollection("test"); - object[] _docs = new[] - { - new { _id = "1", title = "foo" }, - new { _id = "2", title = "bar" } - }; - - ExecuteAddStatement(coll.Add(_docs)); - - var stmt = coll.Find("_id=:v").Bind("v", "1"); - var res = stmt.Execute(); - var values = res.FetchOne(); - Assert.AreEqual(1, Convert.ToInt32(values.values["_id"])); - StringAssert.AreEqualIgnoringCase("foo", values.values["title"].ToString()); - - res = coll.Find("_id=:v").Bind("v", "2").Execute(); - values = res.FetchOne(); - Assert.AreEqual(2, Convert.ToInt32(values.values["_id"])); - StringAssert.AreEqualIgnoringCase("bar", values.values["title"].ToString()); - } - - [Test, Description("Verify Count method for Tables,Collections,Collection As Table,Views with different combinations")] - public void AdditionalCountTests() - { - Session session = GetSession(); - Schema schema = session.GetSchema(schemaName); - CreateCollection("testCount"); - var count = session.SQL("SELECT COUNT(*) FROM test.testCount").Execute().FetchOne()[0]; - var collection = schema.GetCollection("testCount"); - var collectionAsTable = schema.GetCollectionAsTable("testCount"); - Assert.AreEqual(count, collection.Count()); - Assert.AreEqual(count, collectionAsTable.Count()); - - session.SQL($"USE {schemaName}").Execute(); - session.SQL("create table test1(name VARCHAR(40), age INT)").Execute(); - count = session.SQL($"SELECT COUNT(*) FROM {schemaName}.test1").Execute().FetchOne()[0]; - Table table = session.GetSchema(schemaName).GetTable("test1"); - Assert.AreEqual(count, collectionAsTable.Count()); - - var result = table.Insert("name", "age") - .Values("MARK", "34") - .Values("richie", "16") - .Values("TEST", "50") - .Execute(); - - Assert.AreEqual((ulong)3, result.AffectedItemsCount); - var selectResult = table.Select().Execute(); - while (selectResult.Next()) ; - Assert.AreEqual(3, selectResult.Rows.Count); - Assert.AreEqual("MARK", selectResult.Rows.ToArray()[0][0].ToString()); - count = session.SQL($"SELECT COUNT(*) FROM {schemaName}.test1").Execute().FetchOne()[0]; - Assert.AreEqual(count, table.Count()); - - // Insert some records - var stm = collection.Add(@"{ ""_id"": 1, ""foo"": 1 }") - .Add(@"{ ""_id"": 2, ""foo"": 2 }") - .Add(@"{ ""_id"": 3, ""foo"": 3 }"); - stm.Execute(); - count = session.SQL("SELECT COUNT(*) FROM test.testCount").Execute().FetchOne()[0]; - Assert.AreEqual(count, collection.Count()); - collectionAsTable = schema.GetCollectionAsTable("testCount"); - Assert.AreEqual(count, collectionAsTable.Count()); - - table = schema.GetTable("testCount"); - table.Insert("doc").Values(@"{ ""_id"": 4, ""foo"": 4 }").Execute(); - count = session.SQL($"SELECT COUNT(*) FROM {schemaName}.testCount").Execute().FetchOne()[0]; - Assert.AreEqual(count, table.Count()); - - collection.RemoveOne(2); - count = session.SQL($"SELECT COUNT(*) FROM {schemaName}.testCount").Execute().FetchOne()[0]; - Assert.AreEqual(count, collection.Count()); - Assert.AreEqual(count, table.Count()); - - // Collection/Table does not exist - Assert.Throws(() => schema.GetCollection("testCount_").Count()); - Assert.Throws(() => schema.GetTable("testCount_").Count()); - - session.SQL("DROP TABLE IF EXISTS test1").Execute(); - session.SQL("CREATE TABLE test1(id1 int,firstname varchar(20))").Execute(); - session.SQL("INSERT INTO test1 values ('1','Rob')").Execute(); - session.SQL("INSERT INTO test1 values ('2','Steve')").Execute(); - session.SQL("CREATE TABLE test2(id2 int,lastname varchar(20))").Execute(); - session.SQL("INSERT INTO test2 values ('1','Williams')").Execute(); - session.SQL("INSERT INTO test2 values ('2','Waugh')").Execute(); - session.SQL("CREATE VIEW view1 AS select * from test1").Execute(); - session.SQL("SELECT * FROM view1").Execute(); - session.SQL("CREATE VIEW view2 AS select * from test2").Execute(); - session.SQL("SELECT * FROM view2").Execute(); - count = session.SQL("SELECT COUNT(*) FROM view1").Execute().FetchOne()[0]; - Assert.AreEqual(count, schema.GetTable("view1").Count()); - schema.DropCollection("testCount"); - session.SQL("DROP TABLE IF EXISTS test1").Execute(); - session.SQL("DROP TABLE IF EXISTS test2").Execute(); - } - - [Test, Description("Verify Expected exceptions in Count")] - public void ExceptionsInCount() - { - if (!session.Version.isAtLeast(8, 0, 0)) Assert.Ignore("This test is for MySql 8.0 or higher."); - var coll = CreateCollection("testCount"); - var docs = new[] - { - new {_id = 1, title = "Book 1", pages = 20}, - new {_id = 2, title = "Book 2", pages = 30}, - new {_id = 3, title = "Book 3", pages = 40}, - new {_id = 4, title = "Book 4", pages = 50} - }; - var r = coll.Add(docs).Execute(); - var count = session.SQL("SELECT COUNT(*) FROM test.testCount").Execute().FetchOne()[0]; - Schema schema = session.GetSchema(schemaName); - var collection = schema.GetCollection("testCount"); - Assert.AreEqual(4, collection.Count()); - - coll.Add(new { _id = 5, title = "Book 5", pages = 60 }).Execute(); - count = session.SQL("SELECT COUNT(*) FROM test.testCount").Execute().FetchOne()[0]; - schema = session.GetSchema(schemaName); - collection = schema.GetCollection("testCount"); - Assert.AreEqual(5, collection.Count()); - - Table table = session.GetSchema("test").GetTable("testCount"); - Assert.AreEqual(5, table.Count()); - - // Expected exceptions. - Assert.Throws(() => coll.RemoveOne(null)); - Assert.Throws(() => coll.RemoveOne("")); - Assert.Throws(() => coll.RemoveOne(string.Empty)); - Assert.Throws(() => coll.RemoveOne(" ")); - - // Remove sending numeric parameter. - Assert.AreEqual(1, coll.RemoveOne(1).AffectedItemsCount); - Assert.AreEqual(4, collection.Count()); - Assert.AreEqual(4, table.Count()); - - // Remove sending string parameter. - Assert.AreEqual(1, coll.RemoveOne("3").AffectedItemsCount); - Assert.AreEqual(3, collection.Count()); - Assert.AreEqual(3, table.Count()); - - // Remove an auto-generated id. - var document = coll.Find("pages = 60").Execute().FetchOne(); - Assert.AreEqual(1, coll.RemoveOne(document.Id).AffectedItemsCount); - Assert.AreEqual(2, collection.Count()); - Assert.AreEqual(2, table.Count()); - - // Remove a non-existing document. - Assert.AreEqual(0, coll.RemoveOne(5).AffectedItemsCount); - Assert.AreEqual(2, collection.Count()); - Assert.AreEqual(2, table.Count()); - - // Add or ReplaceOne - Assert.AreEqual(1, coll.AddOrReplaceOne(5, new { _id = 5, title = "Book 5", pages = 60 }). - AffectedItemsCount); - Assert.AreEqual(3, collection.Count()); - Assert.AreEqual(3, table.Count()); - - // Add or ReplaceOne - Assert.AreEqual(2, coll.AddOrReplaceOne(2, new { title = "Book 50", pages = 60 }). - AffectedItemsCount); - Assert.AreEqual(3, collection.Count()); - Assert.AreEqual(3, table.Count()); - - // Add or ReplaceOne - Assert.AreEqual(1, coll.AddOrReplaceOne(6, new { _id = 6, title = "Book 6", pages = 70 }). - AffectedItemsCount); - Assert.AreEqual(4, collection.Count()); - Assert.AreEqual(4, table.Count()); - - var result = coll.Modify("_id = 5").Set("title", "Book 5").Execute(); - Assert.AreEqual(4, collection.Count()); - Assert.AreEqual(4, table.Count()); - - coll = CreateCollection("testCount"); - - DbDoc[] jsonlist = new DbDoc[1000]; - DbDoc[] jsonlist1 = new DbDoc[1000]; - for (int i = 0; i < 1000; i++) - { - DbDoc newDoc2 = new DbDoc(); - newDoc2.SetValue("_id", (i + 1000)); - newDoc2.SetValue("F1", ("Field-1-Data-" + i)); - newDoc2.SetValue("F2", ("Field-2-Data-" + i)); - newDoc2.SetValue("F3", (300 + i).ToString()); - jsonlist[i] = newDoc2; - newDoc2 = null; - } - - for (int i = 0; i < 1000; i++) - { - DbDoc newDoc2 = new DbDoc(); - newDoc2.SetValue("_id", (i + 10000)); - newDoc2.SetValue("F1", ("Field-1-Data-" + i)); - newDoc2.SetValue("F2", ("Field-2-Data-" + i)); - newDoc2.SetValue("F3", (300 + i).ToString()); - jsonlist1[i] = newDoc2; - newDoc2 = null; - } - Result res = coll.Add(jsonlist).Add(jsonlist1).Execute(); - count = session.SQL("SELECT COUNT(*) FROM test.testCount").Execute().FetchOne()[0]; - schema = session.GetSchema(schemaName); - collection = schema.GetCollection("testCount"); - Assert.AreEqual(2000, collection.Count()); - - r = coll.Remove("_id = :_id").Bind("_id", 1000).Execute(); - Assert.AreEqual(1999, collection.Count()); - } - - [Test, Description("Verify MultiThreading with count")] - public async Task MultithreadCount() - { - _ = await SubProcessA(); - _ = await SubProcessB(); - } - - private Task SubProcessA() - { - using (var sessionA = MySQLX.GetSession(ConnectionString)) - { - Schema schema = sessionA.GetSchema("test"); - var coll = schema.CreateCollection("testCount"); - DbDoc[] jsonlist = new DbDoc[1000]; - for (int i = 0; i < 1000; i++) - { - DbDoc newDoc2 = new DbDoc(); - newDoc2.SetValue("_id", (i + 1000)); - newDoc2.SetValue("F1", ("Field-1-Data-" + i)); - newDoc2.SetValue("F2", ("Field-2-Data-" + i)); - newDoc2.SetValue("F3", (300 + i).ToString()); - jsonlist[i] = newDoc2; - newDoc2 = null; - } - var res = coll.Add(jsonlist).Execute(); - var count = sessionA.SQL("SELECT COUNT(*) FROM test.testCount").Execute().FetchOne()[0]; - var collection = schema.GetCollection("testCount"); - Assert.AreEqual(1000, collection.Count()); - - var r = coll.Remove("_id = :_id").Bind("_id", 1001).Execute(); - Assert.AreEqual(999, collection.Count()); - } - return Task.FromResult(0); - } - - private Task SubProcessB() - { - Thread.Sleep(8000); - using (var sessionB = MySQLX.GetSession(ConnectionString)) - { - Schema schema = session.GetSchema(schemaName); - var coll = schema.GetCollection("testCount"); - - var count = sessionB.SQL("SELECT COUNT(*) FROM test.testCount").Execute().FetchOne()[0]; - schema = sessionB.GetSchema("test"); - var collection = schema.GetCollection("testCount"); - do - { - if (collection.Count() > 5) - { - Assert.AreEqual(999, collection.Count()); - break; - } - } - while (true); - - var r = coll.Remove("_id = :_id").Bind("_id", 1100).Execute(); - Assert.AreEqual(998, collection.Count()); - } - return Task.FromResult(0); - } - - [Test, Description("Verify the behaviour of the dropX method for dropCollection under stressed conditions")] - public void DropUnderStressedConditions() - { - if (!session.Version.isAtLeast(5, 7, 0)) Assert.Ignore("This test is for MySql 5.7 or higher."); - Schema schema = session.GetSchema(schemaName); - - for (var i = 0; i < 10; i++) - { - schema.CreateCollection("my_collection_123456789"); - schema.DropCollection("my_collection_123456789"); - } - - } - - [Test, Description("Verify that dropX method for dropSchema, dropIndex succeeds in stress conditions")] - public void DropObjectsUnderStress() - { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher."); - var schema = session.GetSchema(schemaName); - var testColl = CreateCollection("test123"); - for (var i = 0; i < 150; i++) - { - testColl.Add(new { myId = 1 }).Execute(); - testColl.DropIndex("testIndex"); - testColl.Add(new { myId = 1 }).Execute(); - testColl.DropIndex("testIndex"); - } - - for (var i = 0; i < 1000; i++) - { - session.CreateSchema("validSchema"); - session.DropSchema("validSchema"); - Assert.False(session.GetSchema("validSchema").ExistsInDatabase()); - } - - } - - [Test, Description("Verify that dropX method for dropIndex succeeds when deleted and created again with various combinations")] - public void DropDocuments() - { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher."); - var schema = session.GetSchema(schemaName); - schema.DropCollection("test123"); - var testColl = schema.CreateCollection("test123"); - - var result = testColl.Add(new { myId = 1 }).Add(new { myId = 2 }).Execute(); - result = testColl.Add(new { myId = 1 }).Execute(); - - testColl.DropIndex("testIndex"); - result = testColl.Add(new { myId = 1 }).Execute(); - - testColl.DropIndex("testIndex"); - - testColl.DropIndex("testIndex"); - testColl.DropIndex("testIndex"); - result = testColl.Remove("myId = :myId").Bind("myId", 1).Execute(); - result = testColl.Add(new { myId = 1 }).Execute(); - result = testColl.Remove("myId = :myId").Bind("myId", 1).Execute(); - - } - - [Test, Description("Verify ModifyCollection with level OFF and JSON schema")] - public void SchemaValidation_S1() - { - if (!session.Version.isAtLeast(8, 0, 19)) Assert.Ignore("This test is for MySql 8.0.19 or higher."); - var schema = session.GetSchema(schemaName); - var options = new CreateCollectionOptions(); - var options1 = new ModifyCollectionOptions(); - var val = new Validation(); - var doc1 = "{\"id\": \"http://json-schema.org/geo\"," - + "\"$schema\": \"http://json-schema.org/draft-06/schema#\"," - + "\"description\": \"A Person example\"," - + "\"type\": \"object\"," - + "\"properties\": {" - + "\"name\": {" - + "\"type\": \"string\"" - + " }," - + "\"age\": {" - + "\"type\": \"number\"" - + "}" - + "}," - + "\"required\": [\"name\", \"age\"]" - + "}"; - - session.SQL($"use {schemaName}").Execute(); - val.Level = ValidationLevel.OFF; - val.Schema = doc1; - options.Validation = val; - options.ReuseExisting = false; - var collection = schema.CreateCollection("coll1", options); - collection.Add(@"{ ""name"": ""John"", ""age"": 52 }").Execute(); - var count = session.SQL("select count(*) from coll1").Execute().FetchOne()[0]; - Assert.AreEqual(count, collection.Count()); - - val.Level = ValidationLevel.OFF; - val.Schema = doc1; - options.Validation = val; - options.ReuseExisting = true; - collection = schema.CreateCollection("coll1", options); - collection.Add(@"{ ""name"": ""John"", ""age"": 52 }").Execute(); - count = session.SQL("select count(*) from coll1").Execute().FetchOne()[0]; - Assert.AreEqual(count, collection.Count()); - - val.Level = ValidationLevel.OFF; - val.Schema = doc1; - options.Validation = val; - options.ReuseExisting = true; - collection = schema.CreateCollection("coll2", options); - collection.Add(@"{ ""name"": ""John"", ""age"": 52 }").Execute(); - count = session.SQL("select count(*) from coll2").Execute().FetchOne()[0]; - Assert.AreEqual(count, collection.Count()); - - options.Validation = new Validation() { Level = ValidationLevel.OFF, Schema = doc1 }; - options.ReuseExisting = false; - collection = schema.CreateCollection("coll3", options); - collection.Add(@"{ ""name"": ""Ram"" , ""age"": 22 }").Execute(); - count = session.SQL("select count(*) from coll3").Execute().FetchOne()[0]; - Assert.AreEqual(count, collection.Count()); - - options.Validation = new Validation() { Level = ValidationLevel.OFF, Schema = doc1 }; - options.ReuseExisting = true; - collection = schema.CreateCollection("coll3", options); - collection.Add(@"{ ""name"": ""John"", ""age"": 52 }").Execute(); - count = session.SQL("select count(*) from coll3").Execute().FetchOne()[0]; - Assert.AreEqual(count, collection.Count()); - - var doc3 = "{\"id\": \"http://json-schema.org/geo\"," - + "\"$schema\": \"http://json-schema.org/draft-06/schema#\"," - + "\"description\": \"A geographical coordinate\"," - + "\"type\": \"object\"," - + "\"properties\": {" - + "\"latitude\": {" - + "\"type\": \"number\"" - + " }," - + "\"longitude\": {" - + "\"type\": \"number\"" - + "}" - + "}," - + "\"required\": [\"latitude\", \"longitude\"]" - + "}"; - - val.Level = ValidationLevel.OFF; - val.Schema = doc3; - options1.Validation = val; - collection = schema.ModifyCollection("coll1", options1); - collection.Add(@"{ ""latitude"": 20, ""longitude"": 30 }"); - count = session.SQL("select count(*) from coll1").Execute().FetchOne()[0]; - Assert.AreEqual(count, collection.Count()); - - var doc4 = "{\"id\": \"http://json-schema.org/geo\"," - + "\"$schema\": \"http://json-schema.org/draft-06/schema#\"," - + "\"description\": \"A Person example\"," - + "\"type\": \"object\"," - + "\"properties\": {" - + "\"name\": {" - + "\"type\": \"string\"" - + " }" - + "}," - + "\"required\": [\"name\"]" - + "}"; - - val.Level = ValidationLevel.STRICT; - val.Schema = doc4; - options1.Validation = val; - collection = schema.ModifyCollection("coll3", options1); - collection.Add(@"{ ""name"": ""Samar"" }"); - count = session.SQL("select count(*) from coll3").Execute().FetchOne()[0]; - Assert.AreEqual(count, collection.Count()); - - options1.Validation = new Validation() { Level = ValidationLevel.OFF, Schema = doc1 }; - collection = schema.ModifyCollection("coll2", options1); - collection.Add(@"{ ""name"": ""Ram"" , ""age"": 22 }").Execute(); - count = session.SQL("select count(*) from coll2").Execute().FetchOne()[0]; - Assert.AreEqual(count, collection.Count()); - - val.Level = ValidationLevel.STRICT; - val.Schema = doc1; - options1.Validation = new Validation() { Level = ValidationLevel.STRICT, Schema = doc1 }; - collection = schema.ModifyCollection("coll2", options1); - collection.Add(@"{ ""name"": ""Ram"" , ""age"": 22 }").Execute(); - count = session.SQL("select count(*) from coll2").Execute().FetchOne()[0]; - Assert.AreEqual(count, collection.Count()); - } - - [Test, Description("Checking the createcollection() and ModifyCollection() with either the level or the schema")] - public void SchemaValidation_S2() - { - if (!session.Version.isAtLeast(8, 0, 19)) Assert.Ignore("This test is for MySql 8.0.19 or higher."); - var schema = session.GetSchema(schemaName); - session.SQL($"use {schemaName}").Execute(); - var options = new CreateCollectionOptions(); - var options1 = new ModifyCollectionOptions(); - var doc1 = "{\"id\": \"http://json-schema.org/geo\"," - + "\"$schema\": \"http://json-schema.org/draft-06/schema#\"," - + "\"description\": \"A Person example\"," - + "\"type\": \"object\"," - + "\"properties\": {" - + "\"name\": {" - + "\"type\": \"string\"" - + " }," - + "\"age\": {" - + "\"type\": \"number\"" - + "}" - + "}," - + "\"required\": [\"name\", \"age\"]" - + "}"; - - options.Validation = new Validation { Schema = doc1 }; - options.ReuseExisting = false; - var collection = schema.CreateCollection("coll4", options); - collection.Add(@"{ ""name"": ""John"", ""age"": 52 }").Execute(); - var result = session.SQL("select * from coll4").Execute().FetchAll(); - foreach (Row res in result) - Assert.IsNotNull(res[0]); - var count = session.SQL("select count(*) from coll4").Execute().FetchOne()[0]; - Assert.AreEqual(count, collection.Count()); - - options.Validation = new Validation { Schema = doc1 }; - options.ReuseExisting = true; - collection = schema.CreateCollection("coll4", options); - collection.Add(@"{ ""name"": ""John"", ""age"": 52 }").Execute(); - result = session.SQL("select * from coll4").Execute().FetchAll(); - foreach (Row res in result) - Assert.IsNotNull(res[0]); - count = session.SQL("select count(*) from coll4").Execute().FetchOne()[0]; - Assert.AreEqual(count, collection.Count()); - - options.Validation = new Validation { Schema = doc1 }; - options.ReuseExisting = true; - collection = schema.CreateCollection("colltesting", options); - Assert.Throws(() => ExecuteAddStatement(collection.Add(@"{ ""name"": ""John"", ""age"": ""52"" }"))); - count = session.SQL("select count(*) from colltesting").Execute().FetchOne()[0]; - Assert.AreEqual(count, collection.Count()); - - var doc2 = "{\"id\":\"http://json-schema.org/geo\"," - + "\"$schema\": \"http://json-schema.org/draft-06/schema#\"," - + "\"description\": \"A Person example\"," - + "\"type\": \"object\"," - + "\"properties\": {" - + "\"name\": {\"type\": \"string\"}," - + "\"number\": {\"type\": \"number\"}," - + "\"street_name\": {\"type\": \"string\"} ," - + "\"street_type\": {\"type\": \"string\"}," - + "\"colors\": " - + "{\"type\": \"array\" ," - + "\"description\": \"different colors\"," - + "\"items\": [" - + "{\"type\": \"string\"," - + "\"enum\": [\"red\", \"amber\", \"green\"]" - + "}," - + "{\"type\": \"number\"}," - + "{\"type\": \"boolean\"}"//," - + "{\"type\": \"null\"}," - + "]" - + "}" - + "}," - + "\"required\": [\"name\", \"number\"]" - + "}"; - - options.Validation = new Validation { Schema = doc2 }; - options.ReuseExisting = true; - Assert.Throws(() => schema.CreateCollection("colltesting2", options)); - - options.Validation = new Validation { Level = ValidationLevel.OFF }; ; - options.ReuseExisting = false; - collection = schema.CreateCollection("coll5", options); - collection.Add(@"{ ""name"": ""John"", ""age"": 52 }").Execute(); - result = session.SQL("select * from coll5").Execute().FetchAll(); - foreach (Row res in result) - Assert.IsNotNull(res[0]); - count = session.SQL("select count(*) from coll5").Execute().FetchOne()[0]; - Assert.AreEqual(count, collection.Count()); - - options.Validation = new Validation { Level = ValidationLevel.STRICT }; - options.ReuseExisting = false; - collection = schema.CreateCollection("coll6", options); - collection.Add(@"{ ""name"": ""John"", ""age"": 52 }").Execute(); - result = session.SQL("select * from coll6").Execute().FetchAll(); - foreach (Row res in result) - Assert.IsNotNull(res[0]); - count = session.SQL("select count(*) from coll6").Execute().FetchOne()[0]; - Assert.AreEqual(count, collection.Count()); - - options1.Validation = new Validation() { Schema = doc1 }; - collection = schema.ModifyCollection("coll6", options1); - collection.Add(@"{ ""name"": ""Ram"" , ""age"": 22 }").Execute(); - result = session.SQL("select * from coll6").Execute().FetchAll(); - foreach (Row res in result) - Assert.IsNotNull(res[0]); - count = session.SQL("select count(*) from coll6").Execute().FetchOne()[0]; - Assert.AreEqual(count, collection.Count()); - - options1.Validation = new Validation() { Schema = doc1 }; - collection = schema.ModifyCollection("colltesting", options1); - Assert.Throws(() => ExecuteAddStatement(collection.Add(@"{ ""name"": ""Ram"" , ""age"": ""22"" }"))); - - options1.Validation = new Validation() { Schema = doc2 }; - Assert.Throws(() => collection = schema.ModifyCollection("colltesting2", options1)); - - options1.Validation = new Validation() { Level = ValidationLevel.OFF }; - collection = schema.ModifyCollection("coll4", options1); - collection.Add(@"{ ""name"": ""Ram"" , ""age"": 22 }").Execute(); - result = session.SQL("select * from coll4").Execute().FetchAll(); - foreach (Row res in result) - Assert.IsNotNull(res[0]); - count = session.SQL("select count(*) from coll4").Execute().FetchOne()[0]; - Assert.AreEqual(count, collection.Count()); - - options1.Validation = new Validation() { Level = ValidationLevel.STRICT }; - collection = schema.ModifyCollection("coll5", options1); - collection.Add(@"{ ""name"": ""Ram"" , ""age"": 22 }").Execute(); - result = session.SQL("select * from coll5").Execute().FetchAll(); - foreach (Row res in result) - Assert.IsNotNull(res[0]); - count = session.SQL("select count(*) from coll5").Execute().FetchOne()[0]; - Assert.AreEqual(count, collection.Count()); - - options1.Validation = new Validation() { }; - Assert.Throws(() => schema.ModifyCollection("coll2", options1)); - - string docEnum = "{\"id\":\"http://json-schema.org/draft-06/schema#\",\"$schema\":\"http://json-schema.org/draft-06/schema#\"," - + "\"description\": \"A Person example\",\"type\":\"object\"," - + "\"properties\":{" - + "\"name\":{" - + "\"type\":\"string\"" - + "}," - + "\"number\":{" - + "\"type\":\"number\"" - + "}," - + "\"street_name\":{" - + "\"type\":\"string\"" - + "}," - + "\"street_type\": {" - + "\"type\": \"string\"" - + "}," - + "\"colors\":{" - + "\"type\": \"array\"," - + "\"items\": {" - + "\"type\":\"string\"" - + "}" - + " }," - + "\"consistent\":{" - + "\"type\": \"boolean\"" - + " }," - + "\"Favourite colors\":{" - + "\"enum\": [" - + "\"red\"," - + "\"amber\"," - + "\"green\"" - + "]" - + "}" - + "}" - + "}"; - - options.Validation = new Validation { Schema = docEnum, Level = ValidationLevel.STRICT }; - options.ReuseExisting = true; - collection = schema.CreateCollection("collEnum", options); - collection.Add(@"{ ""name"": ""John"" }").Execute(); - result = session.SQL("select * from collEnum").Execute().FetchAll(); - foreach (Row res in result) - Console.WriteLine("test with enum: " + res[0]); - count = session.SQL("select count(*) from collEnum").Execute().FetchOne()[0]; - Assert.AreEqual(count, collection.Count()); - } - - [Test, Description("Checking the error messages with different level")] - public void SchemaValidation_S3() - { - if (!session.Version.isAtLeast(8, 0, 19)) Assert.Ignore("This test is for MySql 8.0.19 or higher."); - session.SQL($"use {schemaName}").Execute(); - var options = new CreateCollectionOptions(); - var options1 = new ModifyCollectionOptions(); - var doc1 = "{\"id\": \"http://json-schema.org/geo\"," - + "\"$schema\": \"http://json-schema.org/draft-06/schema#\"," - + "\"description\": \"A Person example\"," - + "\"type\": \"object\"," - + "\"properties\": {" - + "\"name\": {" - + "\"type\": \"string\"" - + " }," - + "\"age\": {" - + "\"type\": \"number\"" - + "}" - + "}," - + "\"required\": [\"name\", \"age\"]" - + "}"; - - var schema = session.GetSchema(schemaName); - options.Validation = new Validation { Schema = doc1, Level = ValidationLevel.STRICT }; - options.ReuseExisting = false; - var collection = schema.CreateCollection("coll7", options); - collection.Add(@"{ ""name"": ""John"", ""age"": 52 }").Execute(); - var result = session.SQL("select * from coll7").Execute().FetchAll(); - foreach (Row res in result) - Assert.IsNotNull(res[0]); - var count = session.SQL("select count(*) from coll7").Execute().FetchOne()[0]; - Assert.AreEqual(count, collection.Count()); - - options.Validation = new Validation { Schema = doc1, Level = ValidationLevel.STRICT }; - options.ReuseExisting = false; - collection = schema.CreateCollection("collext", options); - collection.Add(@"{ ""name"": ""John"", ""age"": 52 }").Execute(); - result = session.SQL("select * from collext").Execute().FetchAll(); - foreach (Row res in result) - Assert.IsNotNull(res[0]); ; - count = session.SQL("select count(*) from collext").Execute().FetchOne()[0]; - Assert.AreEqual(count, collection.Count()); - - var doc2 = "{\"id\":\"http://json-schema.org/geo\"," - + "\"$schema\": \"http://json-schema.org/draft-06/schema#\"," - + "\"description\": \"A Person example\"," - + "\"type\": \"object\"," - + "\"properties\": {" - + "\"name\": {\"type\": \"string\"}," - + "\"number\": {\"type\": \"number\"}," - + "\"street_name\": {\"type\": \"string\"} ," - + "\"street_type\": {\"type\": \"string\"}," - + "\"colors\": " - + "{\"type\": \"array\" ," - + "\"description\": \"different colors\"," - + "\"items\": [" - + "{\"type\": \"string\"," - + "\"enum\": [\"red\", \"amber\", \"green\"]" - + "}," - + "{\"type\": \"number\"}," - + "{\"type\": \"boolean\"}"//," - + "{\"type\": \"null\"}," - + "]" - + "}" - + "}," - + "\"required\": [\"name\", \"number\"]" - + "}"; - - options.Validation = new Validation { Schema = doc2, Level = ValidationLevel.STRICT }; - options.ReuseExisting = false; - Assert.Throws(() => schema.CreateCollection("coll8", options)); - - options.Validation = new Validation { Schema = doc1, Level = ValidationLevel.STRICT }; - options.ReuseExisting = true; - collection = schema.CreateCollection("coll8", options); - collection.Add(@"{ ""name"": ""John"", ""age"": 52 }").Execute(); - result = session.SQL("select * from coll8").Execute().FetchAll(); - foreach (Row res in result) - Assert.IsNotNull(res[0]); ; - count = session.SQL("select count(*) from coll8").Execute().FetchOne()[0]; - Assert.AreEqual(count, collection.Count()); - - options.Validation = new Validation { Schema = doc1, Level = ValidationLevel.STRICT }; - options.ReuseExisting = false; - collection = schema.CreateCollection("coll9", options); - Assert.Throws(() => ExecuteAddStatement(collection.Add(@"{""longitude"":""99""}"))); - - options1.Validation = new Validation { Schema = doc1, Level = ValidationLevel.STRICT }; - collection = schema.ModifyCollection("coll7", options1); - Assert.Throws(() => ExecuteAddStatement(collection.Add(@"{ ""number"": ""56"" }"))); - - options.Validation = new Validation { Schema = doc1, Level = ValidationLevel.OFF }; - options.ReuseExisting = false; - collection = schema.CreateCollection("coll10", options); - collection.Add(@"{""longitude"":""99""}").Execute(); - result = session.SQL("select * from coll10").Execute().FetchAll(); - foreach (Row res in result) - Assert.IsNotNull(res[0]); ; - count = session.SQL("select count(*) from coll10").Execute().FetchOne()[0]; - Assert.AreEqual(count, collection.Count()); - - options1.Validation = new Validation { Schema = doc1, Level = ValidationLevel.OFF }; - collection = schema.ModifyCollection("coll10", options1); - collection.Add(@"{ ""name"": 67 }").Execute(); - result = session.SQL("select * from coll10").Execute().FetchAll(); - foreach (Row res in result) - Assert.IsNotNull(res[0]); ; - count = session.SQL("select count(*) from coll10").Execute().FetchOne()[0]; - Assert.AreEqual(count, collection.Count()); - - options.Validation = new Validation { Schema = doc1, Level = ValidationLevel.STRICT }; - options.ReuseExisting = false; - collection = schema.CreateCollection("coll", options); - collection.Add(@"{""_id"":1,""name"": ""John"", ""age"": 52}").Execute(); - result = session.SQL("select * from coll").Execute().FetchAll(); - foreach (Row res in result) - Assert.IsNotNull(res[0]); ; - count = session.SQL("select count(*) from coll").Execute().FetchOne()[0]; - Assert.AreEqual(count, collection.Count()); - } - - /// - /// Bug 30693969 - /// - [Test, Description("Verify ModifyCollection with level OFF and JSON schema with Json schema")] - public void ModifyCollectionSchemaValidation() - { - if (!session.Version.isAtLeast(8, 0, 19)) Assert.Ignore("This test is for MySql 8.0.19 or higher."); - session.SQL($"use {schemaName}").Execute(); - var schema = session.GetSchema(schemaName); - var options = new CreateCollectionOptions(); - var val = new Validation(); - string doc1 = "{" - + " \"id\":\"https://example.com/arrays.schema.json\"," - + " \"$schema\": \"http://json-schema.org/draft-07/schema#\"," - + " \"description\": \"A representation of a person, company, organization, or place\"," - + " \"type\": \"object\"," - + " \"properties\": {" - + " \"fruits\": {" - + " \"type\": \"array\"," - + " \"items\": {" - + "\"type\": \"string\"" - + " }" - + "}," - + "\"vegetables\": {" - + " \"type\": \"array\"," - + "\"items\": { \"$ref\": \"#/definitions/veggie\" }" - + " }" - + "}," - + "\"definitions\": {" - + " \"veggie\": {" - + " \"type\": \"object\"," - + " \"required\": [ \"veggieName\", \"veggieLike\" ]," - + "\"properties\": {" - + " \"veggieName\": {" - + " \"type\": \"string\"," - + " \"description\": \"The name of the vegetable.\"" - + "}," - + "\"veggieLike\": {" - + "\"type\": \"boolean\"," - + "\"description\": \"Do I like this vegetable?\"" - + "}" - + "}" - + "}" - + "}" - + "}"; - - val.Level = ValidationLevel.STRICT; - val.Schema = doc1; - options.Validation = val; - options.ReuseExisting = false; - var collection = schema.CreateCollection("coll20", options); - collection.Add(@"{""fruits"": [ ""apple"", ""orange"", ""pear"" ],""vegetables"": [{""veggieName"": ""potato"",""veggieLike"": true},{""veggieName"": ""broccoli"",""veggieLike"": false}]}").Execute(); - var result = session.SQL("select * from coll20").Execute().FetchAll(); - foreach (Row res in result) - Assert.IsNotNull(res[0]); - var count = session.SQL("select count(*) from coll20").Execute().FetchOne()[0]; - Assert.AreEqual(count, collection.Count()); - - options.Validation = new Validation { Level = ValidationLevel.STRICT, Schema = doc1 }; - options.ReuseExisting = false; - collection = schema.CreateCollection("coll21", options); - collection.Add(@"{""fruits"": [ ""apple"", ""orange"", ""pear"" ],""vegetables"": [{""veggieName"": ""potato"",""veggieLike"": true},{""veggieName"": ""broccoli"",""veggieLike"": false}]}").Execute(); - result = session.SQL("select * from coll21").Execute().FetchAll(); - foreach (Row res in result) - Assert.IsNotNull(res[0]); - count = session.SQL("select count(*) from coll21").Execute().FetchOne()[0]; - Assert.AreEqual(count, collection.Count()); - - val.Level = ValidationLevel.STRICT; - val.Schema = doc1; - options.Validation = val; - options.ReuseExisting = true; - collection = schema.CreateCollection("coll20", options); - collection.Add(@"{""fruits"": [ ""apple"", ""orange"", ""pear"" ],""vegetables"": [{""veggieName"": ""potato"",""veggieLike"": true},{""veggieName"": ""broccoli"",""veggieLike"": false}]}").Execute(); - result = session.SQL("select * from coll20").Execute().FetchAll(); - foreach (Row res in result) - Assert.IsNotNull(res[0]); - count = session.SQL("select count(*) from coll20").Execute().FetchOne()[0]; - Assert.AreEqual(count, collection.Count()); - - options.Validation = new Validation { Level = ValidationLevel.STRICT, Schema = doc1 }; - options.ReuseExisting = true; - collection = schema.CreateCollection("coll21", options); - collection.Add(@"{""fruits"": [ ""apple"", ""orange"", ""pear"" ],""vegetables"": [{""veggieName"": ""potato"",""veggieLike"": true},{""veggieName"": ""broccoli"",""veggieLike"": false}]}").Execute(); - result = session.SQL("select * from coll21").Execute().FetchAll(); - foreach (Row res in result) - Assert.IsNotNull(res[0]); - count = session.SQL("select count(*) from coll21").Execute().FetchOne()[0]; - Assert.AreEqual(count, collection.Count()); - - val.Level = ValidationLevel.OFF; - val.Schema = doc1; - options.Validation = val; - options.ReuseExisting = true; - collection = schema.CreateCollection("coll22", options); - collection.Add(@"{""fruits"": [ 78, ""orange"", ""pear"" ],""vegetables"": [{""veggieName"": ""potato"",""veggieLike"": true},{""veggieName"": ""broccoli"",""veggieLike"": false}]}").Execute(); - result = session.SQL("select * from coll22").Execute().FetchAll(); - foreach (Row res in result) - Assert.IsNotNull(res[0]); - count = session.SQL("select count(*) from coll22").Execute().FetchOne()[0]; - Assert.AreEqual(count, collection.Count()); - } - - [Test, Description("Verify ModifyCollection with level OFF and JSON schema")] - public void SchemaValidationDeleteRecords() - { - // Bug30748283 - if (!session.Version.isAtLeast(8, 0, 19)) Assert.Ignore("This test is for MySql 8.0.19 or higher."); - string doc5 = "{\"id\": \"http://json-schema.org/geo\"," - + "\"$schema\": \"http://json-schema.org/draft-06/schema#\"," - + "\"description\": \"A Person example\"," - + "\"type\": \"object\"," - + "\"properties\": {" - + "\"name\": {" - + "\"type\": \"number\"" - + " }" - + "}," - + "\"required\": [\"name\"]" - + "}"; - - string doc1 = "{\"id\": \"http://json-schema.org/geo\"," - + "\"$schema\": \"http://json-schema.org/draft-06/schema#\"," - + "\"description\": \"A Person example\"," - + "\"type\": \"object\"," - + "\"properties\": {" - + "\"name\": {" - + "\"type\": \"string\"" - + " }" - + ",\"age\": {" - + "\"type\": \"number\"" - + "}" - + "}," - + "\"required\": [\"name\",\"age\"]" - + "}"; - string doc3 = "{\"id\": \"http://json-schema.org/geo\"," - + "\"$schema\": \"http://json-schema.org/draft-06/schema#\"," - + "\"description\": \"A geographical coordinate\"," - + "\"type\": \"object\"," - + "\"properties\": {" - + "\"latitude\": {" - + "\"type\": \"number\"" - + " }," - + "\"longitude\": {" - + "\"type\": \"number\"" - + "}" - + "}," - + "\"required\": [\"latitude\", \"longitude\"]" - + "}"; - - string doc4 = "{\"id\": \"http://json-schema.org/geo\"," - + "\"$schema\": \"http://json-schema.org/draft-06/schema#\"," - + "\"description\": \"A Person example\"," - + "\"type\": \"object\"," - + "\"properties\": {" - + "\"name\": {" - + "\"type\": \"string\"" - + " }" - + "}," - + "\"required\": [\"name\"]" - + "}"; - - session.SQL($"use {schemaName}").Execute(); - var schema = session.GetSchema(schemaName); - var options = new CreateCollectionOptions(); - var options1 = new ModifyCollectionOptions(); - - options.Validation = new Validation { Level = ValidationLevel.STRICT, Schema = doc5 }; - options.ReuseExisting = true; - var collection = schema.CreateCollection("collectiontest", options); - collection.Add(@"{ ""name"": 52 }").Execute(); - var result = session.SQL("select * from collectiontest").Execute().FetchAll(); - foreach (Row res1 in result) - Assert.IsNotNull(res1[0]); - var count = session.SQL("select count(*) from collectiontest").Execute().FetchOne()[0]; - Assert.AreEqual(count, collection.Count()); - - options1.Validation = new Validation { Level = ValidationLevel.STRICT, Schema = doc1 }; - session.SQL("delete from collectiontest").Execute(); - - collection = schema.ModifyCollection("collectiontest", options1); - collection.Add(@"{ ""name"": ""sammeer"",""age"":8 }").Execute(); - var result2 = session.SQL("select * from collectiontest").Execute().FetchAll(); - foreach (Row res2 in result2) - Console.WriteLine(res2[0]); - count = session.SQL("select count(*) from collectiontest").Execute().FetchOne()[0]; - Assert.AreEqual(count, collection.Count()); - - options1.Validation = new Validation { Level = ValidationLevel.OFF, Schema = doc1 }; - collection = schema.ModifyCollection("collectiontest", options1); - collection.Add(@"{ ""name"": 78 }").Execute(); - result = session.SQL("select * from collectiontest").Execute().FetchAll(); - foreach (Row res2 in result) - Assert.IsNotNull(res2[0]); - count = session.SQL("select count(*) from collectiontest").Execute().FetchOne()[0]; - Assert.AreEqual(count, collection.Count()); - - options1.Validation = new Validation { Level = ValidationLevel.STRICT, Schema = doc3 }; - session.SQL("delete from collectiontest").Execute(); - collection = schema.ModifyCollection("collectiontest", options1); - collection.Add(@"{""latitude"": 253, ""longitude"": 525}").Execute(); - result = session.SQL("select * from collectiontest").Execute().FetchAll(); - foreach (Row res2 in result) - Assert.IsNotNull(res2[0]); - count = session.SQL("select count(*) from collectiontest").Execute().FetchOne()[0]; - Assert.AreEqual(count, collection.Count()); - - options1.Validation = new Validation { Level = ValidationLevel.STRICT, Schema = doc4 }; - session.SQL("delete from collectiontest").Execute(); - result = session.SQL("select * from collectiontest").Execute().FetchAll(); - collection = schema.ModifyCollection("collectiontest", options1); - collection.Add(@"{ ""name"": ""Johnny"" }").Execute(); - result = session.SQL("select * from collectiontest").Execute().FetchAll(); - foreach (Row res2 in result) - Assert.IsNotNull(res2[0]); - count = session.SQL("select count(*) from collectiontest").Execute().FetchOne()[0]; - Assert.AreEqual(count, collection.Count()); - - } - - [Test, Description("Test MySQLX plugin Remove Bind Stress")] - public void RemoveBindStress() - { - if (!session.Version.isAtLeast(5, 7, 0)) Assert.Ignore("This test is for MySql 5.7 or higher."); - Collection coll = CreateCollection("test"); - DbDoc[] jsonlist = new DbDoc[10]; - DbDoc[] jsonlist1 = new DbDoc[10]; - for (int i = 0; i < 10; i++) - { - DbDoc newDoc2 = new DbDoc(); - newDoc2.SetValue("_id", (i + 1000)); - newDoc2.SetValue("F1", ("Field-1-Data-" + i)); - newDoc2.SetValue("F2", ("Field-2-Data-" + i)); - newDoc2.SetValue("F3", (300 + i).ToString()); - jsonlist[i] = newDoc2; - newDoc2 = null; - } - - for (int i = 0; i < 10; i++) - { - DbDoc newDoc2 = new DbDoc(); - newDoc2.SetValue("_id", (i + 10000)); - newDoc2.SetValue("F1", ("Field-1-Data-" + i)); - newDoc2.SetValue("F2", ("Field-2-Data-" + i)); - newDoc2.SetValue("F3", (300 + i).ToString()); - jsonlist1[i] = newDoc2; - newDoc2 = null; - } - Result r = coll.Add(jsonlist).Add(jsonlist1).Execute(); - - Assert.AreEqual(20, r.AffectedItemsCount, "Matching"); - - r = coll.Remove("_id = :_id").Bind("_id", 1000).Execute(); - Assert.AreEqual(1, r.AffectedItemsCount, "Matching"); - } - - [Test, Description("Test MySQLX plugin Get Collection as Table")] - public void GetCollectionAsTableStress() - { - if (!session.Version.isAtLeast(5, 7, 0)) Assert.Ignore("This test is for MySql 5.7 or higher."); - Collection testCollection = CreateCollection("test"); - - DbDoc[] jsonlist = new DbDoc[1000]; - for (int i = 0; i < 1000; i++) - { - DbDoc newDoc2 = new DbDoc(); - newDoc2.SetValue("_id", (i + 1000)); - newDoc2.SetValue("F1", ("Field-1-Data-" + i)); - newDoc2.SetValue("F2", ("Field-2-Data-" + i)); - newDoc2.SetValue("F3", (300 + i).ToString()); - jsonlist[i] = newDoc2; - newDoc2 = null; - } - Result r = testCollection.Add(jsonlist).Execute(); - Assert.AreEqual(1000, r.AffectedItemsCount, "Matching"); - - Table test = testSchema.GetCollectionAsTable("test"); - Assert.IsTrue(test.ExistsInDatabase()); - var rows = test.Select("_id").Execute().FetchAll(); - - for (int j = 0; j < rows.Count; j++) - { - var doc = testCollection.Find("_id like :param").Bind("param", (j + 1000)).Execute(); - var docs = doc.FetchAll().Count(); - Assert.AreEqual(1, docs, "Matches"); - } - } - - [Test, Description("Test MySQLX plugin GetCollection Exception Scenario")] - public void GetCollectionException() - { - if (!session.Version.isAtLeast(5, 7, 0)) Assert.Ignore("This test is for MySql 5.7 or higher."); - using (Session sessionPlain = MySQLX.GetSession(ConnectionString)) - { - Schema db = sessionPlain.GetSchema(schemaName); - Collection col = db.GetCollection("my_collection_123456789"); - if (col.ExistsInDatabase()) - { - db.DropCollection("my_collection_123456789"); - col = db.CreateCollection("my_collection_123456789"); - } - else { col = db.CreateCollection("my_collection_123456789"); } - - Collection col1 = db.GetCollection("my_collection_123456789", true); - if (col.ExistsInDatabase()) - { - db.DropCollection("my_collection_123456789"); - col1 = db.CreateCollection("my_collection_123456789"); - } - else { col1 = db.CreateCollection("my_collection_123456789"); } - - var col2 = db.GetTable("my_collection_1234567891"); - Assert.Throws(() => db.GetCollection("my_collection_test", true)); - db.DropCollection("my_collection_123456789"); - } - } - - [Test, Description("Collection GetDocumentIDS Stress(1000 records)")] - public void GetDocumentIDSStress() - { - Collection coll = CreateCollection("test"); - DbDoc[] jsonlist = new DbDoc[1000]; - for (int i = 0; i < 1000; i++) - { - DbDoc newDoc2 = new DbDoc(); - newDoc2.SetValue("_id", (i)); - newDoc2.SetValue("F1", ("Field-1-Data-" + i)); - newDoc2.SetValue("F2", ("Field-2-Data-" + i)); - newDoc2.SetValue("F3", (3 + i).ToString()); - jsonlist[i] = newDoc2; - newDoc2 = null; - } - Result r = coll.Add(jsonlist).Execute(); - Assert.AreEqual(1000, r.AffectedItemsCount, "Matching"); - var documentIds = r.GeneratedIds; - Assert.False(documentIds != null && documentIds.Count > 0); - } - - [Test, Description("Session Performance Test")] - public void SessionPerformanceTest() - { - string json = ""; - int i = 0, j = 0, maxField = 100; - var collection = CreateCollection("test"); - int maxDepth = 97; - json = "{\"_id\":\"1002\",\"XYZ\":1111"; - for (j = 0; j < maxField; j++) - { - json = json + ",\"ARR" + j + "\":["; - for (i = 0; i < maxDepth; i++) - { - json = json + i + ",["; - } - json = json + i; - for (i = maxDepth - 1; i >= 0; i--) - { - json = json + "]," + i; - } - json = json + "]"; - } - json = json + "}"; - - collection.Add(json).Execute(); - json = "{\"_id\":\"1003\",\"XYZ\":2222"; - for (j = 0; j < maxField; j++) - { - json = json + ",\"DATAX" + j + "\":"; - for (i = 0; i < maxDepth; i++) - { - json = json + "{\"D" + i + "\":"; - } - json = json + maxDepth; - for (i = maxDepth - 1; i >= 0; i--) - { - json = json + "}"; - } - } - json = json + "}"; - - collection.Add(json).Execute(); - json = "{\"_id\":\"1001\",\"XYZ\":3333"; - for (j = 0; j < maxField; j++) - { - json = json + ",\"ARR" + j + "\":["; - for (i = 0; i < maxDepth; i++) - { - json = json + i + ",["; - } - json = json + i; - for (i = maxDepth - 1; i >= 0; i--) - { - json = json + "]," + i; - } - json = json + "]"; - } - - for (j = 0; j < maxField; j++) - { - json = json + ",\"DATAX" + j + "\":"; - for (i = 0; i < maxDepth; i++) - { - json = json + "{\"D" + i + "\":"; - } - json = json + maxDepth; - for (i = maxDepth - 1; i >= 0; i--) - { - json = json + "}"; - } - } - json = json + "}"; - collection.Add(json).Execute(); - - // select - string query = "$.ARR" + (maxField - 1); - for (i = 0; i < maxDepth; i++) - { - query = query + "[1]"; - } - query = query + "[0]"; - json = "CAST(" + query + " as SIGNED)= " + maxDepth; - var docs = collection.Find(json).Fields("$._id as _id," + query + " as Arr").Execute(); - var res = docs.FetchAll(); - Assert.AreEqual("1001", res[0]["_id"].ToString(), "Matching the id"); - Assert.AreEqual("1002", res[1]["_id"].ToString(), "Matching the id"); - - query = "$.DATAX" + (maxField - 1); - for (i = 0; i < maxDepth; i++) - { - query = query + ".D" + i; - } - json = "CAST(" + query + " as SIGNED)"; - docs = collection.Find(json + " =" + maxDepth).Fields("$._id as _id ").Execute(); - res = docs.FetchAll(); - Assert.AreEqual("1001", res[0]["_id"].ToString(), "Matching the id"); - Assert.AreEqual("1003", res[1]["_id"].ToString(), "Matching the id"); - } - - /// - /// Bug #34243143 [Connector/NET allows empty string in Set() method which is chained to Modify()] - /// The fix applied for every method in Modify(). - /// - [Test] - public void EmptyStringInModifyMethods() - { - Collection coll = CreateCollection("test"); - object _doc = new { _id = 1, title = "foo" }; - coll.Add(_doc).Execute(); - var result = coll.Find("_id == 1").Execute().FetchOne(); - - Assert.NotNull(result); - Assert.AreEqual(1, result.Id); - - // empty string - var ex = Assert.Throws(() => coll.Modify("_id == 1").Set("", new { title = "bar" }).Execute()); - StringAssert.AreEqualIgnoringCase(ResourcesX.DocPathNullOrEmpty, ex.Message); - ex = Assert.Throws(() => coll.Modify("_id == 1").Unset("").Execute()); - StringAssert.AreEqualIgnoringCase(ResourcesX.DocPathNullOrEmpty, ex.Message); - ex = Assert.Throws(() => coll.Modify("_id == 1").Change("", new { title = "bar" }).Execute()); - StringAssert.AreEqualIgnoringCase(ResourcesX.DocPathNullOrEmpty, ex.Message); - ex = Assert.Throws(() => coll.Modify("_id == 1").ArrayInsert("", new { title = "bar" }).Execute()); - StringAssert.AreEqualIgnoringCase(ResourcesX.DocPathNullOrEmpty, ex.Message); - ex = Assert.Throws(() => coll.Modify("_id == 1").ArrayAppend("", new { title = "bar" }).Execute()); - StringAssert.AreEqualIgnoringCase(ResourcesX.DocPathNullOrEmpty, ex.Message); - - // white space - ex = Assert.Throws(() => coll.Modify("_id == 1").Set(" ", new { title = "bar" }).Execute()); - StringAssert.AreEqualIgnoringCase(ResourcesX.DocPathNullOrEmpty, ex.Message); - ex = Assert.Throws(() => coll.Modify("_id == 1").Unset(" ").Execute()); - StringAssert.AreEqualIgnoringCase(ResourcesX.DocPathNullOrEmpty, ex.Message); - ex = Assert.Throws(() => coll.Modify("_id == 1").Change(" ", new { title = "bar" }).Execute()); - StringAssert.AreEqualIgnoringCase(ResourcesX.DocPathNullOrEmpty, ex.Message); - ex = Assert.Throws(() => coll.Modify("_id == 1").ArrayInsert(" ", new { title = "bar" }).Execute()); - StringAssert.AreEqualIgnoringCase(ResourcesX.DocPathNullOrEmpty, ex.Message); - ex = Assert.Throws(() => coll.Modify("_id == 1").ArrayAppend(" ", new { title = "bar" }).Execute()); - StringAssert.AreEqualIgnoringCase(ResourcesX.DocPathNullOrEmpty, ex.Message); - - // null - ex = Assert.Throws(() => coll.Modify("_id == 1").Set(null, new { title = "bar" }).Execute()); - StringAssert.AreEqualIgnoringCase(ResourcesX.DocPathNullOrEmpty, ex.Message); - ex = Assert.Throws(() => coll.Modify("_id == 1").Change(null, new { title = "bar" }).Execute()); - StringAssert.AreEqualIgnoringCase(ResourcesX.DocPathNullOrEmpty, ex.Message); - ex = Assert.Throws(() => coll.Modify("_id == 1").ArrayInsert(null, new { title = "bar" }).Execute()); - StringAssert.AreEqualIgnoringCase(ResourcesX.DocPathNullOrEmpty, ex.Message); - ex = Assert.Throws(() => coll.Modify("_id == 1").ArrayAppend(null, new { title = "bar" }).Execute()); - StringAssert.AreEqualIgnoringCase(ResourcesX.DocPathNullOrEmpty, ex.Message); - var ex2 = Assert.Throws(() => coll.Modify("_id == 1").Unset(null).Execute()); - } - } -} \ No newline at end of file +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data; +using MySql.Data.MySqlClient; +using MySqlX.XDevAPI; +using MySqlX.XDevAPI.Common; +using MySqlX.XDevAPI.Relational; +using NUnit.Framework; +using NUnit.Framework.Legacy; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace MySqlX.Data.Tests +{ + public class CollectionTests : BaseTest + { + [TearDown] + public void tearDown() + { + session.Schema.DropCollection("test"); + session.Schema.DropCollection("test123"); + session.Schema.DropCollection("testcount"); + session.Schema.DropCollection("coll"); + session.Schema.DropCollection("col20"); + session.Schema.DropCollection("col21"); + session.Schema.DropCollection("col22"); + } + + [Test] + public void GetAllCollections() + { + session.DropSchema("test"); + session.CreateSchema("test"); + Collection book = CreateCollection("book"); + List collections = book.Schema.GetCollections(); + Assert.That(collections, Has.One.Items); + Assert.That(collections[0].Name == "book"); + book.Schema.DropCollection("book"); + } + + [Test] + public void CreateAndDropCollection() + { + Session s = GetSession(); + Schema test = s.GetSchema("test"); + Collection testColl = test.CreateCollection("test"); + Assert.That(CollectionExistsInDatabase(testColl)); + + // Drop existing collection. + test.DropCollection("test"); + Assert.That(CollectionExistsInDatabase(testColl), Is.False); + + // Drop non-existing collection. + test.DropCollection("test"); + Assert.That(CollectionExistsInDatabase(testColl), Is.False); + + //dropCollection when the object to drop contains invalid characters + test.DropCollection("%^&!@~*(&*(*&:>(() => test.DropCollection(string.Empty)); + Assert.Throws(() => test.DropCollection(" ")); + Assert.Throws(() => test.DropCollection(" ")); + Assert.Throws(() => test.DropCollection(null)); + } + + [Test] + public void CreateCollectionIndex() + { + Session session = GetSession(); + Schema test = session.GetSchema(schemaName); + Collection testColl = test.CreateCollection("test"); + Assert.That(CollectionExistsInDatabase(testColl), "ExistsInDatabase failed"); + testColl.CreateIndex("testIndex", "{ \"fields\": [ { \"field\":$.myId, \"type\":\"INT\", \"required\":true } ] }"); + var result = ExecuteAddStatement(testColl.Add(new { myId = 1 }).Add(new { myId = 2 })); + Assert.That(2, Is.EqualTo(result.AffectedItemsCount)); + } + + [Test] + public void DropCollectionIndex() + { + Session session = GetSession(); + Schema test = session.GetSchema(schemaName); + Collection testColl = CreateCollection("test"); + testColl.CreateIndex("testIndex", "{ \"fields\": [ { \"field\":$.myId, \"type\":\"INT\", \"required\":true } ] }"); + + // Drop existing index. + testColl.DropIndex("testIndex"); + + // Drop non-existing index. + testColl.DropIndex("testIndex"); + + //dropIndex contains invalid characters + testColl.DropIndex("%^&!@~*(&*(*&:>(() => testColl.DropIndex(string.Empty)); + Assert.Throws(() => testColl.DropIndex(" ")); + Assert.Throws(() => testColl.DropIndex(" ")); + Assert.Throws(() => testColl.DropIndex(null)); + + } + + [Test] + public void DropSchemaTests() + { + session.DropSchema("validSchema"); + session.CreateSchema("validSchema"); + session.DropSchema("validSchema"); + session.DropSchema("%^&!@~*(&*(*&:>(() => session.DropSchema(string.Empty)); + Assert.Throws(() => session.DropSchema(" ")); + Assert.Throws(() => session.DropSchema(" ")); + Assert.Throws(() => session.DropSchema(null)); + } + + + [Test] + public void ValidateExistence() + { + Session session = GetSession(); + Schema schema = session.GetSchema(schemaName); + var ex = Assert.Throws(() => schema.GetCollection("nonExistentCollection", true)); + Assert.That(ex.Message, Is.EqualTo("Collection 'nonExistentCollection' does not exist.")); + } + + [Test] + public void CountCollection() + { + Session session = GetSession(); + Schema schema = session.GetSchema(schemaName); + CreateCollection("testCount"); + var count = session.SQL("SELECT COUNT(*) FROM test.testCount").Execute().FetchOne()[0]; + + // Zero records + var collection = schema.GetCollection("testCount"); + Assert.That(collection.Count(), Is.EqualTo(count)); + var table = schema.GetTable("testCount"); + Assert.That(table.Count(), Is.EqualTo(count)); + + // Insert some records + var stm = collection.Add(@"{ ""_id"": 1, ""foo"": 1 }") + .Add(@"{ ""_id"": 2, ""foo"": 2 }") + .Add(@"{ ""_id"": 3, ""foo"": 3 }"); + stm.Execute(); + count = session.SQL("SELECT COUNT(*) FROM test.testCount").Execute().FetchOne()[0]; + Assert.That(collection.Count(), Is.EqualTo(count)); + + table.Insert("doc").Values(@"{ ""_id"": 4, ""foo"": 4 }").Execute(); + count = session.SQL("SELECT COUNT(*) FROM test.testCount").Execute().FetchOne()[0]; + Assert.That(table.Count(), Is.EqualTo(count)); + + collection.RemoveOne(2); + count = session.SQL("SELECT COUNT(*) FROM test.testCount").Execute().FetchOne()[0]; + Assert.That(collection.Count(), Is.EqualTo(count)); + Assert.That(table.Count(), Is.EqualTo(count)); + + // Collection/Table does not exist + var ex = Assert.Throws(() => schema.GetCollection("testCount_").Count()); + Assert.That(ex.Message, Is.EqualTo("Collection 'testCount_' does not exist in schema 'test'")); + ex = Assert.Throws(() => schema.GetTable("testCount_").Count()); + Assert.That(ex.Message, Is.EqualTo("Table 'testCount_' does not exist in schema 'test'")); + } + + [Test] + public void ModifyCollectionNoLevelNorSchema() + { + Session s = GetSession(); + Schema test = s.GetSchema("test"); + + // Modify a Collection without passing schema and Level, (Bug#30660917) + test.CreateCollection("coll"); + ModifyCollectionOptions options1 = new ModifyCollectionOptions(); + options1.Validation = new Validation() { }; + Assert.Throws(() => test.ModifyCollection("coll", options1)); + } + + [Test] + public void CreateCollectionWithOptions() + { + Session s = GetSession(); + Schema test = s.GetSchema("test"); + + // CreateCollection Test Cases + + // Create a Collection passing a valid schema and Level + CreateCollectionOptions options = new CreateCollectionOptions(); + Validation val = new Validation(); + val.Level = ValidationLevel.STRICT; + string str = "{\"id\": \"http://json-schema.org/geo\"," + + "\"$schema\": \"http://json-schema.org/draft-06/schema#\"," + + "\"description\": \"A geographical coordinate\"," + + "\"type\": \"object\"," + + "\"properties\": {" + + "\"latitude\": {" + + "\"type\": \"number\"" + + " }," + + "\"longitude\": {" + + "\"type\": \"number\"" + + "}" + + "}," + + "\"required\": [\"latitude\", \"longitude\"]" + + "}"; + val.Schema = str; + options.ReuseExisting = false; + options.Validation = val; + Collection testColl = test.CreateCollection("testWithSchemaValidation", options); + Assert.That(CollectionExistsInDatabase(testColl)); + + //Bug #30830962 + options = new CreateCollectionOptions(); + val = new Validation() { }; + options.Validation = val; + var testbug1 = test.CreateCollection("bug_0962", options); //create collection with empty options + testbug1.Add(@"{ ""latitude"": 20, ""longitude"": 30 }").Execute(); + testbug1.Add(@"{ ""sexo"": 1, ""edad"": 20 }").Execute(); + int.TryParse(session.SQL("SELECT COUNT(*) FROM test.bug_0962").Execute().FetchOne()[0].ToString(), out int expected_count); + Assert.That(expected_count, Is.EqualTo(2)); //Collection is created as STRICT with empty json schema,both records were inserted + + options = new CreateCollectionOptions(); + val = new Validation() { Schema = str }; + options.Validation = val; + testbug1 = test.CreateCollection("bug_0962b", options);// adding an schema from + testbug1.Add(@"{ ""latitude"": 20, ""longitude"": 30 }").Execute(); + var invalidEx = Assert.Throws(() => testbug1.Add(@"{ ""sexo"": 1, ""edad"": 20 }").Execute()); + Assert.That(invalidEx.Message, Does.Contain("Document is not valid according to the schema assigned to collection")); + + // Create a Collection passing a reuse_existing parameter to server + CreateCollectionOptions options_reuse = new CreateCollectionOptions(); + options_reuse.ReuseExisting = false; + options_reuse.Validation = val; + Collection testCol2 = test.CreateCollection("testReuseExisting_1", options_reuse); + Assert.That(CollectionExistsInDatabase(testCol2)); + + //Insert Valid record with Level Strict + var insert_statement = testColl.Add(@"{ ""latitude"": 20, ""longitude"": 30 }"); + insert_statement.Execute(); + var count = session.SQL("SELECT COUNT(*) FROM test.testWithSchemaValidation").Execute().FetchOne()[0]; + Assert.That(testColl.Count(), Is.EqualTo(count)); + + //Insert invalid record with Level Strict + insert_statement = testColl.Add(@"{ ""OtherField"": ""value"", ""Age"": 30 }"); + var invalidInsertEx = Assert.Throws(() => insert_statement.Execute()); + Assert.That(invalidInsertEx.Message, Does.Contain("Document is not valid according to the schema assigned to collection")); + + //Test: Old MySQL Server Version exceptions + if (!(session.Version.isAtLeast(8, 0, 19))) + { + //FR6.2 + var ex1 = Assert.Throws(() => test.CreateCollection("testInvalid", options)); + Assert.That(ex1.Message, Does.Contain("Invalid number of arguments, expected 2 but got 3, " + + "The server doesn't support the requested operation. Please update the MySQL Server and/or Client library")); + + //FR6.3 + test.CreateCollection("testInvalid"); + ModifyCollectionOptions modifyOptions = new ModifyCollectionOptions(); + modifyOptions.Validation = val; + var ex2 = Assert.Throws(() => test.ModifyCollection("testInvalid", modifyOptions)); + Assert.That(ex2.Message, Does.Contain("Invalid mysqlx command modify_collection_options, " + + "The server doesn't support the requested operation. Please update the MySQL Server and/or Client library")); + } + + //Create collection with json schema and level OFF. Try to insert document matches this schema + options = new CreateCollectionOptions(); + options.Validation = new Validation() { Level = ValidationLevel.OFF, Schema = str }; + Collection col_test = test.CreateCollection("Test_2b_1", options); + Assert.That(CollectionExistsInDatabase(col_test)); + insert_statement = col_test.Add(@"{ ""latitude"": 120, ""longitude"": 78 }"); + insert_statement.Execute(); + count = session.SQL("SELECT COUNT(*) FROM test.Test_2b_1").Execute().FetchOne()[0]; + Assert.That(col_test.Count(), Is.EqualTo(count)); + + //Create collection with json schema and level OFF,ReuseExisting set to true, Try to insert + options = new CreateCollectionOptions(); + options.Validation = new Validation() { Level = ValidationLevel.OFF, Schema = str }; + options.ReuseExisting = true; + col_test = test.CreateCollection("Test_2b_2", options); + Assert.That(CollectionExistsInDatabase(col_test)); + insert_statement = col_test.Add(@"{ ""latitude"": 20, ""longitude"": 42 }"); + insert_statement.Execute(); + count = session.SQL("SELECT COUNT(*) FROM test.Test_2b_2").Execute().FetchOne()[0]; + Assert.That(col_test.Count(), Is.EqualTo(count)); + + //Create collection with only schema option, Try to insert + options = new CreateCollectionOptions(); + options.Validation = new Validation() { Schema = str }; + col_test = test.CreateCollection("Test_2b_3", options); + Assert.That(CollectionExistsInDatabase(col_test)); + insert_statement = col_test.Add(@"{ ""latitude"": 5, ""longitude"": 10 }"); + insert_statement.Execute(); + count = session.SQL("SELECT COUNT(*) FROM test.Test_2b_3").Execute().FetchOne()[0]; + Assert.That(col_test.Count(), Is.EqualTo(count)); + + //Create collection with only schema option,ReuseExisting set to true, Try to insert + options = new CreateCollectionOptions(); + options.Validation = new Validation() { Schema = str }; + options.ReuseExisting = true; + col_test = test.CreateCollection("Test_2b_4", options); + Assert.That(CollectionExistsInDatabase(col_test)); + insert_statement = col_test.Add(@"{ ""latitude"": 25, ""longitude"": 52 }"); + insert_statement.Execute(); + count = session.SQL("SELECT COUNT(*) FROM test.Test_2b_4").Execute().FetchOne()[0]; + Assert.That(col_test.Count(), Is.EqualTo(count)); + + //Create collection with only level option + options = new CreateCollectionOptions(); + options.Validation = new Validation() { Level = ValidationLevel.OFF }; + col_test = test.CreateCollection("Test_2b_5", options); + Assert.That(CollectionExistsInDatabase(col_test)); + + //ResuseExisting = false should throw exception for an existing collection + CreateCollectionOptions testReuseOptions = new CreateCollectionOptions(); + testReuseOptions.ReuseExisting = false; + testReuseOptions.Validation = new Validation() { Level = ValidationLevel.OFF }; + test.CreateCollection("testReuse"); + var exreuse = Assert.Throws(() => test.CreateCollection("testReuse", testReuseOptions)); + Assert.That(exreuse.Message, Is.EqualTo("Table 'testReuse' already exists").IgnoreCase); + + //Test: Resuse Existing = True should return existing collection + testReuseOptions.ReuseExisting = true; + var existing = test.CreateCollection("testReuse", testReuseOptions); + Assert.That(CollectionExistsInDatabase(existing)); + + //Create collection and prepare test data with json schema and level STRICT + CreateCollectionOptions prepareOptions = new CreateCollectionOptions(); + prepareOptions.Validation = new Validation() { Level = ValidationLevel.STRICT, Schema = str }; + var res_stm = test.CreateCollection("TestCreateInsert", prepareOptions).Add(@"{ ""latitude"": 25, ""longitude"": 52 }"); + res_stm.Execute(); + var num = session.SQL("SELECT COUNT(*) FROM test.TestCreateInsert").Execute().FetchOne()[0]; + var collection_test = test.GetCollection("TestCreateInsert"); + Assert.That(collection_test.Count(), Is.EqualTo(num)); + + //Passing invalid Schema + options = new CreateCollectionOptions(); + options.Validation = new Validation() { Level = ValidationLevel.STRICT, Schema = "Not Valid JSON Schema" }; + Exception ex_schema = Assert.Throws(() => test.CreateCollection("testInvalidSchema", options)); + Assert.That(ex_schema.Message, Does.Contain(@"The value provided is not a valid JSON document.")); + + //Testing an schema with different data types + str = "{\"id\": \"http://json-schema.org/geo\"," + + "\"$schema\": \"http://json-schema.org/draft-06/schema#\"," + + "\"description\": \"A Person example\"," + + "\"type\": \"object\"," + + "\"properties\": {" + + "\"name\": {" + + "\"type\": \"string\"" + + " }," + + "\"age\": {" + + "\"type\": \"number\"" + + "}" + + "}," + + "\"required\": [\"name\", \"age\"]" + + "}"; + + options = new CreateCollectionOptions(); + options.Validation = new Validation() { Level = ValidationLevel.STRICT, Schema = str }; + Collection person_col = test.CreateCollection("testWithPersonSchema", options); + Assert.That(CollectionExistsInDatabase(person_col)); + person_col.Add(@"{ ""name"": ""John"", ""age"": 52 }").Execute(); + var rows = session.SQL("SELECT COUNT(*) FROM test.testWithPersonSchema").Execute().FetchOne()[0]; + Assert.That(person_col.Count(), Is.EqualTo(rows)); + + // Create an existing collection with different schema + options = new CreateCollectionOptions(); + options.ReuseExisting = true; + options.Validation = new Validation() { Level = ValidationLevel.STRICT, Schema = str }; + Collection col_schema1 = test.CreateCollection("testSchema1", options); + Assert.That(CollectionExistsInDatabase(col_schema1)); + + col_schema1.Add(@"{ ""name"": ""John"", ""age"": 52 }").Execute(); + Assert.That(col_schema1.Count(), Is.EqualTo(1)); + var sqlDefinition1 = session.SQL("SHOW CREATE TABLE test.testSchema1").Execute().FetchOne()[1]; + + + var schema2 = "{\"id\": \"http://json-schema.org/geo\"," + + "\"$schema\": \"http://json-schema.org/draft-06/schema#\"," + + "\"description\": \"A Movies example\"," + + "\"type\": \"object\"," + + "\"properties\": {" + + "\"title\": {" + + "\"type\": \"string\"" + + " }," + + "\"movie\": {" + + "\"type\": \"string\"" + + "}" + + "}," + + "\"required\": [\"title\", \"movie\"]" + + "}"; + + options.Validation = new Validation() { Level = ValidationLevel.STRICT, Schema = schema2 }; + Collection col_schema2 = test.CreateCollection("testSchema1", options); + var sqlDefinition2 = session.SQL("SHOW CREATE TABLE test.testSchema1").Execute().FetchOne()[1]; + Assert.That(sqlDefinition2, Is.EqualTo(sqlDefinition1)); + + //Create a collection without sending reuseExisting parameter and insert record + Collection original_col1 = test.CreateCollection("testOriginal1"); + Assert.That(CollectionExistsInDatabase(original_col1)); + original_col1.Add(@"{ ""name"": ""John"", ""age"": 52 }").Execute(); + rows = session.SQL("SELECT COUNT(*) FROM test.testOriginal1").Execute().FetchOne()[0]; + Assert.That(original_col1.Count(), Is.EqualTo(rows)); + + //Create a new collection sending reuseExisting as true, insert record + Collection original_col2 = test.CreateCollection("testOriginal2", true); + Assert.That(CollectionExistsInDatabase(original_col2)); + original_col2.Add(@"{ ""name"": ""John"", ""age"": 52 }").Execute(); + rows = session.SQL("SELECT COUNT(*) FROM test.testOriginal2").Execute().FetchOne()[0]; + Assert.That(original_col2.Count(), Is.EqualTo(rows)); + + //Create an existing collection sending reuseExisting as true, insert record + Collection original_col3 = test.CreateCollection("testOriginal2", true); + Assert.That(CollectionExistsInDatabase(original_col3)); + original_col3.Add(@"{ ""name"": ""John2"", ""age"": 12 }").Execute(); + Assert.That(original_col3.Count(), Is.EqualTo(2)); + + //Create an existing collection sending reuseExisting as false,exception expected + var ex_existing = Assert.Throws(() => test.CreateCollection("testOriginal2", false)); + Assert.That(ex_existing.Message, Is.EqualTo(@"Table 'testOriginal2' already exists").IgnoreCase); + + //Modify collection with only level option + ModifyCollectionOptions Test_Options = new ModifyCollectionOptions(); + Test_Options.Validation = new Validation() { Level = ValidationLevel.OFF }; + Collection col_Test_2a_1 = test.ModifyCollection("testWithSchemaValidation", Test_Options); + + // Inser valid and invalid records with level set to Off + insert_statement = col_Test_2a_1.Add(@"{ ""latitude"": 20, ""longitude"": 30 }") + .Add(@"{ ""OtherField"": ""value"", ""Age"": 30 }"); + insert_statement.Execute(); + count = session.SQL("SELECT COUNT(*) FROM test.testWithSchemaValidation").Execute().FetchOne()[0]; + Assert.That(col_Test_2a_1.Count(), Is.EqualTo(count)); + + //Modify collection with only schema option + Test_Options.Validation = new Validation() { Schema = "{ }" }; + test.ModifyCollection("testWithSchemaValidation", Test_Options); + var sqlCreate = session.SQL("SHOW CREATE TABLE test.testWithSchemaValidation").Execute().FetchOne()[1]; + Assert.That(sqlCreate.ToString().Contains(@"'{\r\n}'") || sqlCreate.ToString().Contains("{}")); + + //Passing null as parameter to ModifyCollection + var emptyOptions = new ModifyCollectionOptions(); + emptyOptions.Validation = new Validation() { }; + test.CreateCollection("testnull"); + exreuse = Assert.Throws(() => test.ModifyCollection("testnull", null)); + Assert.That(exreuse.Message, Is.EqualTo(@"Arguments value used under ""validation"" must be an object with at least one field")); + + test.DropCollection("testWithSchemaValidation"); + test.DropCollection("bug_0962"); + test.DropCollection("bug_0962b"); + test.DropCollection("testReuseExisting_1"); + test.DropCollection("Test_2b_1"); + test.DropCollection("Test_2b_2"); + test.DropCollection("Test_2b_3"); + test.DropCollection("Test_2b_4"); + test.DropCollection("Test_2b_5"); + test.DropCollection("testReuse"); + test.DropCollection("TestCreateInsert"); + test.DropCollection("testWithPersonSchema"); + test.DropCollection("testSchema1"); + test.DropCollection("testOriginal1"); + test.DropCollection("testOriginal2"); + test.DropCollection("testnull"); + } + + /// + /// Server Bug + /// Bug #31667405 - INCORRECT PREPARED STATEMENT OUTCOME WITH NUMERIC STRINGS IN JSON + /// + [Test] + public void PreparedStatementWithNumericStrings() + { + Collection coll = CreateCollection("test"); + object[] _docs = new[] + { + new { _id = "1", title = "foo" }, + new { _id = "2", title = "bar" } + }; + + ExecuteAddStatement(coll.Add(_docs)); + + var stmt = coll.Find("_id=:v").Bind("v", "1"); + var res = stmt.Execute(); + var values = res.FetchOne(); + Assert.That(Convert.ToInt32(values.values["_id"]), Is.EqualTo(1)); + Assert.That(values.values["title"].ToString(), Is.EqualTo("foo").IgnoreCase); + + res = coll.Find("_id=:v").Bind("v", "2").Execute(); + values = res.FetchOne(); + Assert.That(Convert.ToInt32(values.values["_id"]), Is.EqualTo(2)); + Assert.That(values.values["title"].ToString(), Is.EqualTo("bar").IgnoreCase); + } + + [Test, Description("Verify Count method for Tables,Collections,Collection As Table,Views with different combinations")] + public void AdditionalCountTests() + { + Session session = GetSession(); + Schema schema = session.GetSchema(schemaName); + CreateCollection("testCount"); + var count = session.SQL("SELECT COUNT(*) FROM test.testCount").Execute().FetchOne()[0]; + var collection = schema.GetCollection("testCount"); + var collectionAsTable = schema.GetCollectionAsTable("testCount"); + Assert.That(collection.Count(), Is.EqualTo(count)); + Assert.That(collectionAsTable.Count(), Is.EqualTo(count)); + + session.SQL($"USE {schemaName}").Execute(); + session.SQL("create table test1(name VARCHAR(40), age INT)").Execute(); + count = session.SQL($"SELECT COUNT(*) FROM {schemaName}.test1").Execute().FetchOne()[0]; + Table table = session.GetSchema(schemaName).GetTable("test1"); + Assert.That(collectionAsTable.Count(), Is.EqualTo(count)); + + var result = table.Insert("name", "age") + .Values("MARK", "34") + .Values("richie", "16") + .Values("TEST", "50") + .Execute(); + + Assert.That(result.AffectedItemsCount, Is.EqualTo((ulong)3)); + var selectResult = table.Select().Execute(); + while (selectResult.Next()) ; + Assert.That(selectResult.Rows.Count, Is.EqualTo(3)); + Assert.That(selectResult.Rows.ToArray()[0][0].ToString(), Is.EqualTo("MARK")); + count = session.SQL($"SELECT COUNT(*) FROM {schemaName}.test1").Execute().FetchOne()[0]; + Assert.That(table.Count(), Is.EqualTo(count)); + + // Insert some records + var stm = collection.Add(@"{ ""_id"": 1, ""foo"": 1 }") + .Add(@"{ ""_id"": 2, ""foo"": 2 }") + .Add(@"{ ""_id"": 3, ""foo"": 3 }"); + stm.Execute(); + count = session.SQL("SELECT COUNT(*) FROM test.testCount").Execute().FetchOne()[0]; + Assert.That(collection.Count(), Is.EqualTo(count)); + collectionAsTable = schema.GetCollectionAsTable("testCount"); + Assert.That(collectionAsTable.Count(), Is.EqualTo(count)); + + table = schema.GetTable("testCount"); + table.Insert("doc").Values(@"{ ""_id"": 4, ""foo"": 4 }").Execute(); + count = session.SQL($"SELECT COUNT(*) FROM {schemaName}.testCount").Execute().FetchOne()[0]; + Assert.That(table.Count(), Is.EqualTo(count)); + + collection.RemoveOne(2); + count = session.SQL($"SELECT COUNT(*) FROM {schemaName}.testCount").Execute().FetchOne()[0]; + Assert.That(collection.Count(), Is.EqualTo(count)); + Assert.That(table.Count(), Is.EqualTo(count)); + + // Collection/Table does not exist + Assert.Throws(() => schema.GetCollection("testCount_").Count()); + Assert.Throws(() => schema.GetTable("testCount_").Count()); + + session.SQL("DROP TABLE IF EXISTS test1").Execute(); + session.SQL("CREATE TABLE test1(id1 int,firstname varchar(20))").Execute(); + session.SQL("INSERT INTO test1 values ('1','Rob')").Execute(); + session.SQL("INSERT INTO test1 values ('2','Steve')").Execute(); + session.SQL("CREATE TABLE test2(id2 int,lastname varchar(20))").Execute(); + session.SQL("INSERT INTO test2 values ('1','Williams')").Execute(); + session.SQL("INSERT INTO test2 values ('2','Waugh')").Execute(); + session.SQL("CREATE VIEW view1 AS select * from test1").Execute(); + session.SQL("SELECT * FROM view1").Execute(); + session.SQL("CREATE VIEW view2 AS select * from test2").Execute(); + session.SQL("SELECT * FROM view2").Execute(); + count = session.SQL("SELECT COUNT(*) FROM view1").Execute().FetchOne()[0]; + Assert.That(schema.GetTable("view1").Count(), Is.EqualTo(count)); + schema.DropCollection("testCount"); + session.SQL("DROP TABLE IF EXISTS test1").Execute(); + session.SQL("DROP TABLE IF EXISTS test2").Execute(); + } + + [Test, Description("Verify Expected exceptions in Count")] + public void ExceptionsInCount() + { + Assume.That(session.Version.isAtLeast(8, 0, 0), "This test is for MySql 8.0 or higher"); + var coll = CreateCollection("testCount"); + var docs = new[] + { + new {_id = 1, title = "Book 1", pages = 20}, + new {_id = 2, title = "Book 2", pages = 30}, + new {_id = 3, title = "Book 3", pages = 40}, + new {_id = 4, title = "Book 4", pages = 50} + }; + var r = coll.Add(docs).Execute(); + var count = session.SQL("SELECT COUNT(*) FROM test.testCount").Execute().FetchOne()[0]; + Schema schema = session.GetSchema(schemaName); + var collection = schema.GetCollection("testCount"); + Assert.That(collection.Count(), Is.EqualTo(4)); + + coll.Add(new { _id = 5, title = "Book 5", pages = 60 }).Execute(); + count = session.SQL("SELECT COUNT(*) FROM test.testCount").Execute().FetchOne()[0]; + schema = session.GetSchema(schemaName); + collection = schema.GetCollection("testCount"); + Assert.That(collection.Count(), Is.EqualTo(5)); + + Table table = session.GetSchema("test").GetTable("testCount"); + Assert.That(table.Count(), Is.EqualTo(5)); + + // Expected exceptions. + Assert.Throws(() => coll.RemoveOne(null)); + Assert.Throws(() => coll.RemoveOne("")); + Assert.Throws(() => coll.RemoveOne(string.Empty)); + Assert.Throws(() => coll.RemoveOne(" ")); + + // Remove sending numeric parameter. + Assert.That(coll.RemoveOne(1).AffectedItemsCount, Is.EqualTo(1)); + Assert.That(collection.Count(), Is.EqualTo(4)); + Assert.That(table.Count(), Is.EqualTo(4)); + + // Remove sending string parameter. + Assert.That(coll.RemoveOne("3").AffectedItemsCount, Is.EqualTo(1)); + Assert.That(collection.Count(), Is.EqualTo(3)); + Assert.That(table.Count(), Is.EqualTo(3)); + + // Remove an auto-generated id. + var document = coll.Find("pages = 60").Execute().FetchOne(); + Assert.That(coll.RemoveOne(document.Id).AffectedItemsCount, Is.EqualTo(1)); + Assert.That(collection.Count(), Is.EqualTo(2)); + Assert.That(table.Count(), Is.EqualTo(2)); + + // Remove a non-existing document. + Assert.That(coll.RemoveOne(5).AffectedItemsCount, Is.EqualTo(0)); + Assert.That(collection.Count(), Is.EqualTo(2)); + Assert.That(table.Count(), Is.EqualTo(2)); + + // Add or ReplaceOne + Assert.That(coll.AddOrReplaceOne(5, new { _id = 5, title = "Book 5", pages = 60 }). + AffectedItemsCount, Is.EqualTo(1)); + Assert.That(collection.Count(), Is.EqualTo(3)); + Assert.That(table.Count(), Is.EqualTo(3)); + + // Add or ReplaceOne + Assert.That(coll.AddOrReplaceOne(2, new { title = "Book 50", pages = 60 }). + AffectedItemsCount, Is.EqualTo(2)); + Assert.That(collection.Count(), Is.EqualTo(3)); + Assert.That(table.Count(), Is.EqualTo(3)); + + // Add or ReplaceOne + Assert.That(coll.AddOrReplaceOne(6, new { _id = 6, title = "Book 6", pages = 70 }). + AffectedItemsCount, Is.EqualTo(1)); + Assert.That(collection.Count(), Is.EqualTo(4)); + Assert.That(table.Count(), Is.EqualTo(4)); + + var result = coll.Modify("_id = 5").Set("title", "Book 5").Execute(); + Assert.That(collection.Count(), Is.EqualTo(4)); + Assert.That(table.Count(), Is.EqualTo(4)); + + coll = CreateCollection("testCount"); + + DbDoc[] jsonlist = new DbDoc[1000]; + DbDoc[] jsonlist1 = new DbDoc[1000]; + for (int i = 0; i < 1000; i++) + { + DbDoc newDoc2 = new DbDoc(); + newDoc2.SetValue("_id", (i + 1000)); + newDoc2.SetValue("F1", ("Field-1-Data-" + i)); + newDoc2.SetValue("F2", ("Field-2-Data-" + i)); + newDoc2.SetValue("F3", (300 + i).ToString()); + jsonlist[i] = newDoc2; + newDoc2 = null; + } + + for (int i = 0; i < 1000; i++) + { + DbDoc newDoc2 = new DbDoc(); + newDoc2.SetValue("_id", (i + 10000)); + newDoc2.SetValue("F1", ("Field-1-Data-" + i)); + newDoc2.SetValue("F2", ("Field-2-Data-" + i)); + newDoc2.SetValue("F3", (300 + i).ToString()); + jsonlist1[i] = newDoc2; + newDoc2 = null; + } + Result res = coll.Add(jsonlist).Add(jsonlist1).Execute(); + count = session.SQL("SELECT COUNT(*) FROM test.testCount").Execute().FetchOne()[0]; + schema = session.GetSchema(schemaName); + collection = schema.GetCollection("testCount"); + Assert.That(collection.Count(), Is.EqualTo(2000)); + + r = coll.Remove("_id = :_id").Bind("_id", 1000).Execute(); + Assert.That(collection.Count(), Is.EqualTo(1999)); + } + + [Test, Description("Verify MultiThreading with count")] + public async Task MultithreadCount() + { + _ = await SubProcessA(); + _ = await SubProcessB(); + } + + private Task SubProcessA() + { + using (var sessionA = MySQLX.GetSession(ConnectionString)) + { + Schema schema = sessionA.GetSchema("test"); + var coll = schema.CreateCollection("testCount"); + DbDoc[] jsonlist = new DbDoc[1000]; + for (int i = 0; i < 1000; i++) + { + DbDoc newDoc2 = new DbDoc(); + newDoc2.SetValue("_id", (i + 1000)); + newDoc2.SetValue("F1", ("Field-1-Data-" + i)); + newDoc2.SetValue("F2", ("Field-2-Data-" + i)); + newDoc2.SetValue("F3", (300 + i).ToString()); + jsonlist[i] = newDoc2; + newDoc2 = null; + } + var res = coll.Add(jsonlist).Execute(); + var count = sessionA.SQL("SELECT COUNT(*) FROM test.testCount").Execute().FetchOne()[0]; + var collection = schema.GetCollection("testCount"); + Assert.That(collection.Count(), Is.EqualTo(1000)); + + var r = coll.Remove("_id = :_id").Bind("_id", 1001).Execute(); + Assert.That(collection.Count(), Is.EqualTo(999)); + } + return Task.FromResult(0); + } + + private Task SubProcessB() + { + Thread.Sleep(8000); + using (var sessionB = MySQLX.GetSession(ConnectionString)) + { + Schema schema = session.GetSchema(schemaName); + var coll = schema.GetCollection("testCount"); + + var count = sessionB.SQL("SELECT COUNT(*) FROM test.testCount").Execute().FetchOne()[0]; + schema = sessionB.GetSchema("test"); + var collection = schema.GetCollection("testCount"); + do + { + if (collection.Count() > 5) + { + Assert.That(collection.Count(), Is.EqualTo(999)); + break; + } + } + while (true); + + var r = coll.Remove("_id = :_id").Bind("_id", 1100).Execute(); + Assert.That(collection.Count(), Is.EqualTo(998)); + } + return Task.FromResult(0); + } + + [Test, Description("Verify the behaviour of the dropX method for dropCollection under stressed conditions")] + public void DropUnderStressedConditions() + { + Assume.That(session.Version.isAtLeast(5, 7, 0), "This test is for MySql 5.7 or higher"); + Schema schema = session.GetSchema(schemaName); + + for (var i = 0; i < 10; i++) + { + schema.CreateCollection("my_collection_123456789"); + schema.DropCollection("my_collection_123456789"); + } + + } + + [Test, Description("Verify that dropX method for dropSchema, dropIndex succeeds in stress conditions")] + public void DropObjectsUnderStress() + { + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); + var schema = session.GetSchema(schemaName); + var testColl = CreateCollection("test123"); + for (var i = 0; i < 150; i++) + { + testColl.Add(new { myId = 1 }).Execute(); + testColl.DropIndex("testIndex"); + testColl.Add(new { myId = 1 }).Execute(); + testColl.DropIndex("testIndex"); + } + + for (var i = 0; i < 1000; i++) + { + session.CreateSchema("validSchema"); + session.DropSchema("validSchema"); + Assert.That(session.GetSchema("validSchema").ExistsInDatabase(), Is.False); + } + + } + + [Test, Description("Verify that dropX method for dropIndex succeeds when deleted and created again with various combinations")] + public void DropDocuments() + { + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); + var schema = session.GetSchema(schemaName); + schema.DropCollection("test123"); + var testColl = schema.CreateCollection("test123"); + + var result = testColl.Add(new { myId = 1 }).Add(new { myId = 2 }).Execute(); + result = testColl.Add(new { myId = 1 }).Execute(); + + testColl.DropIndex("testIndex"); + result = testColl.Add(new { myId = 1 }).Execute(); + + testColl.DropIndex("testIndex"); + + testColl.DropIndex("testIndex"); + testColl.DropIndex("testIndex"); + result = testColl.Remove("myId = :myId").Bind("myId", 1).Execute(); + result = testColl.Add(new { myId = 1 }).Execute(); + result = testColl.Remove("myId = :myId").Bind("myId", 1).Execute(); + + } + + [Test, Description("Verify ModifyCollection with level OFF and JSON schema")] + public void SchemaValidation_S1() + { + Assume.That(session.Version.isAtLeast(8, 0, 19), "This test is for MySql 8.0.19 or higher"); + var schema = session.GetSchema(schemaName); + var options = new CreateCollectionOptions(); + var options1 = new ModifyCollectionOptions(); + var val = new Validation(); + var doc1 = "{\"id\": \"http://json-schema.org/geo\"," + + "\"$schema\": \"http://json-schema.org/draft-06/schema#\"," + + "\"description\": \"A Person example\"," + + "\"type\": \"object\"," + + "\"properties\": {" + + "\"name\": {" + + "\"type\": \"string\"" + + " }," + + "\"age\": {" + + "\"type\": \"number\"" + + "}" + + "}," + + "\"required\": [\"name\", \"age\"]" + + "}"; + + session.SQL($"use {schemaName}").Execute(); + val.Level = ValidationLevel.OFF; + val.Schema = doc1; + options.Validation = val; + options.ReuseExisting = false; + var collection = schema.CreateCollection("coll1", options); + collection.Add(@"{ ""name"": ""John"", ""age"": 52 }").Execute(); + var count = session.SQL("select count(*) from coll1").Execute().FetchOne()[0]; + Assert.That(collection.Count(), Is.EqualTo(count)); + + val.Level = ValidationLevel.OFF; + val.Schema = doc1; + options.Validation = val; + options.ReuseExisting = true; + collection = schema.CreateCollection("coll1", options); + collection.Add(@"{ ""name"": ""John"", ""age"": 52 }").Execute(); + count = session.SQL("select count(*) from coll1").Execute().FetchOne()[0]; + Assert.That(collection.Count(), Is.EqualTo(count)); + + val.Level = ValidationLevel.OFF; + val.Schema = doc1; + options.Validation = val; + options.ReuseExisting = true; + collection = schema.CreateCollection("coll2", options); + collection.Add(@"{ ""name"": ""John"", ""age"": 52 }").Execute(); + count = session.SQL("select count(*) from coll2").Execute().FetchOne()[0]; + Assert.That(collection.Count(), Is.EqualTo(count)); + + options.Validation = new Validation() { Level = ValidationLevel.OFF, Schema = doc1 }; + options.ReuseExisting = false; + collection = schema.CreateCollection("coll3", options); + collection.Add(@"{ ""name"": ""Ram"" , ""age"": 22 }").Execute(); + count = session.SQL("select count(*) from coll3").Execute().FetchOne()[0]; + Assert.That(collection.Count(), Is.EqualTo(count)); + + options.Validation = new Validation() { Level = ValidationLevel.OFF, Schema = doc1 }; + options.ReuseExisting = true; + collection = schema.CreateCollection("coll3", options); + collection.Add(@"{ ""name"": ""John"", ""age"": 52 }").Execute(); + count = session.SQL("select count(*) from coll3").Execute().FetchOne()[0]; + Assert.That(collection.Count(), Is.EqualTo(count)); + + var doc3 = "{\"id\": \"http://json-schema.org/geo\"," + + "\"$schema\": \"http://json-schema.org/draft-06/schema#\"," + + "\"description\": \"A geographical coordinate\"," + + "\"type\": \"object\"," + + "\"properties\": {" + + "\"latitude\": {" + + "\"type\": \"number\"" + + " }," + + "\"longitude\": {" + + "\"type\": \"number\"" + + "}" + + "}," + + "\"required\": [\"latitude\", \"longitude\"]" + + "}"; + + val.Level = ValidationLevel.OFF; + val.Schema = doc3; + options1.Validation = val; + collection = schema.ModifyCollection("coll1", options1); + collection.Add(@"{ ""latitude"": 20, ""longitude"": 30 }"); + count = session.SQL("select count(*) from coll1").Execute().FetchOne()[0]; + Assert.That(collection.Count(), Is.EqualTo(count)); + + var doc4 = "{\"id\": \"http://json-schema.org/geo\"," + + "\"$schema\": \"http://json-schema.org/draft-06/schema#\"," + + "\"description\": \"A Person example\"," + + "\"type\": \"object\"," + + "\"properties\": {" + + "\"name\": {" + + "\"type\": \"string\"" + + " }" + + "}," + + "\"required\": [\"name\"]" + + "}"; + + val.Level = ValidationLevel.STRICT; + val.Schema = doc4; + options1.Validation = val; + collection = schema.ModifyCollection("coll3", options1); + collection.Add(@"{ ""name"": ""Samar"" }"); + count = session.SQL("select count(*) from coll3").Execute().FetchOne()[0]; + Assert.That(collection.Count(), Is.EqualTo(count)); + + options1.Validation = new Validation() { Level = ValidationLevel.OFF, Schema = doc1 }; + collection = schema.ModifyCollection("coll2", options1); + collection.Add(@"{ ""name"": ""Ram"" , ""age"": 22 }").Execute(); + count = session.SQL("select count(*) from coll2").Execute().FetchOne()[0]; + Assert.That(collection.Count(), Is.EqualTo(count)); + + val.Level = ValidationLevel.STRICT; + val.Schema = doc1; + options1.Validation = new Validation() { Level = ValidationLevel.STRICT, Schema = doc1 }; + collection = schema.ModifyCollection("coll2", options1); + collection.Add(@"{ ""name"": ""Ram"" , ""age"": 22 }").Execute(); + count = session.SQL("select count(*) from coll2").Execute().FetchOne()[0]; + Assert.That(collection.Count(), Is.EqualTo(count)); + } + + [Test, Description("Checking the createcollection() and ModifyCollection() with either the level or the schema")] + public void SchemaValidation_S2() + { + Assume.That(session.Version.isAtLeast(8, 0, 19), "This test is for MySql 8.0.19 or higher"); + var schema = session.GetSchema(schemaName); + session.SQL($"use {schemaName}").Execute(); + var options = new CreateCollectionOptions(); + var options1 = new ModifyCollectionOptions(); + var doc1 = "{\"id\": \"http://json-schema.org/geo\"," + + "\"$schema\": \"http://json-schema.org/draft-06/schema#\"," + + "\"description\": \"A Person example\"," + + "\"type\": \"object\"," + + "\"properties\": {" + + "\"name\": {" + + "\"type\": \"string\"" + + " }," + + "\"age\": {" + + "\"type\": \"number\"" + + "}" + + "}," + + "\"required\": [\"name\", \"age\"]" + + "}"; + + options.Validation = new Validation { Schema = doc1 }; + options.ReuseExisting = false; + var collection = schema.CreateCollection("coll4", options); + collection.Add(@"{ ""name"": ""John"", ""age"": 52 }").Execute(); + var result = session.SQL("select * from coll4").Execute().FetchAll(); + foreach (Row res in result) + Assert.That(res[0], Is.Not.Null); + var count = session.SQL("select count(*) from coll4").Execute().FetchOne()[0]; + Assert.That(collection.Count(), Is.EqualTo(count)); + + options.Validation = new Validation { Schema = doc1 }; + options.ReuseExisting = true; + collection = schema.CreateCollection("coll4", options); + collection.Add(@"{ ""name"": ""John"", ""age"": 52 }").Execute(); + result = session.SQL("select * from coll4").Execute().FetchAll(); + foreach (Row res in result) + Assert.That(res[0], Is.Not.Null); + count = session.SQL("select count(*) from coll4").Execute().FetchOne()[0]; + Assert.That(collection.Count(), Is.EqualTo(count)); + + options.Validation = new Validation { Schema = doc1 }; + options.ReuseExisting = true; + collection = schema.CreateCollection("colltesting", options); + Assert.Throws(() => ExecuteAddStatement(collection.Add(@"{ ""name"": ""John"", ""age"": ""52"" }"))); + count = session.SQL("select count(*) from colltesting").Execute().FetchOne()[0]; + Assert.That(collection.Count(), Is.EqualTo(count)); + + var doc2 = "{\"id\":\"http://json-schema.org/geo\"," + + "\"$schema\": \"http://json-schema.org/draft-06/schema#\"," + + "\"description\": \"A Person example\"," + + "\"type\": \"object\"," + + "\"properties\": {" + + "\"name\": {\"type\": \"string\"}," + + "\"number\": {\"type\": \"number\"}," + + "\"street_name\": {\"type\": \"string\"} ," + + "\"street_type\": {\"type\": \"string\"}," + + "\"colors\": " + + "{\"type\": \"array\" ," + + "\"description\": \"different colors\"," + + "\"items\": [" + + "{\"type\": \"string\"," + + "\"enum\": [\"red\", \"amber\", \"green\"]" + + "}," + + "{\"type\": \"number\"}," + + "{\"type\": \"boolean\"}"//," + + "{\"type\": \"null\"}," + + "]" + + "}" + + "}," + + "\"required\": [\"name\", \"number\"]" + + "}"; + + options.Validation = new Validation { Schema = doc2 }; + options.ReuseExisting = true; + Assert.Throws(() => schema.CreateCollection("colltesting2", options)); + + options.Validation = new Validation { Level = ValidationLevel.OFF }; ; + options.ReuseExisting = false; + collection = schema.CreateCollection("coll5", options); + collection.Add(@"{ ""name"": ""John"", ""age"": 52 }").Execute(); + result = session.SQL("select * from coll5").Execute().FetchAll(); + foreach (Row res in result) + Assert.That(res[0], Is.Not.Null); + count = session.SQL("select count(*) from coll5").Execute().FetchOne()[0]; + Assert.That(collection.Count(), Is.EqualTo(count)); + + options.Validation = new Validation { Level = ValidationLevel.STRICT }; + options.ReuseExisting = false; + collection = schema.CreateCollection("coll6", options); + collection.Add(@"{ ""name"": ""John"", ""age"": 52 }").Execute(); + result = session.SQL("select * from coll6").Execute().FetchAll(); + foreach (Row res in result) + Assert.That(res[0], Is.Not.Null); + count = session.SQL("select count(*) from coll6").Execute().FetchOne()[0]; + Assert.That(collection.Count(), Is.EqualTo(count)); + + options1.Validation = new Validation() { Schema = doc1 }; + collection = schema.ModifyCollection("coll6", options1); + collection.Add(@"{ ""name"": ""Ram"" , ""age"": 22 }").Execute(); + result = session.SQL("select * from coll6").Execute().FetchAll(); + foreach (Row res in result) + Assert.That(res[0], Is.Not.Null); + count = session.SQL("select count(*) from coll6").Execute().FetchOne()[0]; + Assert.That(collection.Count(), Is.EqualTo(count)); + + options1.Validation = new Validation() { Schema = doc1 }; + collection = schema.ModifyCollection("colltesting", options1); + Assert.Throws(() => ExecuteAddStatement(collection.Add(@"{ ""name"": ""Ram"" , ""age"": ""22"" }"))); + + options1.Validation = new Validation() { Schema = doc2 }; + Assert.Throws(() => collection = schema.ModifyCollection("colltesting2", options1)); + + options1.Validation = new Validation() { Level = ValidationLevel.OFF }; + collection = schema.ModifyCollection("coll4", options1); + collection.Add(@"{ ""name"": ""Ram"" , ""age"": 22 }").Execute(); + result = session.SQL("select * from coll4").Execute().FetchAll(); + foreach (Row res in result) + Assert.That(res[0], Is.Not.Null); + count = session.SQL("select count(*) from coll4").Execute().FetchOne()[0]; + Assert.That(collection.Count(), Is.EqualTo(count)); + + options1.Validation = new Validation() { Level = ValidationLevel.STRICT }; + collection = schema.ModifyCollection("coll5", options1); + collection.Add(@"{ ""name"": ""Ram"" , ""age"": 22 }").Execute(); + result = session.SQL("select * from coll5").Execute().FetchAll(); + foreach (Row res in result) + Assert.That(res[0], Is.Not.Null); + count = session.SQL("select count(*) from coll5").Execute().FetchOne()[0]; + Assert.That(collection.Count(), Is.EqualTo(count)); + + options1.Validation = new Validation() { }; + Assert.Throws(() => schema.ModifyCollection("coll2", options1)); + + string docEnum = "{\"id\":\"http://json-schema.org/draft-06/schema#\",\"$schema\":\"http://json-schema.org/draft-06/schema#\"," + + "\"description\": \"A Person example\",\"type\":\"object\"," + + "\"properties\":{" + + "\"name\":{" + + "\"type\":\"string\"" + + "}," + + "\"number\":{" + + "\"type\":\"number\"" + + "}," + + "\"street_name\":{" + + "\"type\":\"string\"" + + "}," + + "\"street_type\": {" + + "\"type\": \"string\"" + + "}," + + "\"colors\":{" + + "\"type\": \"array\"," + + "\"items\": {" + + "\"type\":\"string\"" + + "}" + + " }," + + "\"consistent\":{" + + "\"type\": \"boolean\"" + + " }," + + "\"Favourite colors\":{" + + "\"enum\": [" + + "\"red\"," + + "\"amber\"," + + "\"green\"" + + "]" + + "}" + + "}" + + "}"; + + options.Validation = new Validation { Schema = docEnum, Level = ValidationLevel.STRICT }; + options.ReuseExisting = true; + collection = schema.CreateCollection("collEnum", options); + collection.Add(@"{ ""name"": ""John"" }").Execute(); + result = session.SQL("select * from collEnum").Execute().FetchAll(); + foreach (Row res in result) + Console.WriteLine("test with enum: " + res[0]); + count = session.SQL("select count(*) from collEnum").Execute().FetchOne()[0]; + Assert.That(collection.Count(), Is.EqualTo(count)); + } + + [Test, Description("Checking the error messages with different level")] + public void SchemaValidation_S3() + { + Assume.That(session.Version.isAtLeast(8, 0, 19), "This test is for MySql 8.0.19 or higher"); + session.SQL($"use {schemaName}").Execute(); + var options = new CreateCollectionOptions(); + var options1 = new ModifyCollectionOptions(); + var doc1 = "{\"id\": \"http://json-schema.org/geo\"," + + "\"$schema\": \"http://json-schema.org/draft-06/schema#\"," + + "\"description\": \"A Person example\"," + + "\"type\": \"object\"," + + "\"properties\": {" + + "\"name\": {" + + "\"type\": \"string\"" + + " }," + + "\"age\": {" + + "\"type\": \"number\"" + + "}" + + "}," + + "\"required\": [\"name\", \"age\"]" + + "}"; + + var schema = session.GetSchema(schemaName); + options.Validation = new Validation { Schema = doc1, Level = ValidationLevel.STRICT }; + options.ReuseExisting = false; + var collection = schema.CreateCollection("coll7", options); + collection.Add(@"{ ""name"": ""John"", ""age"": 52 }").Execute(); + var result = session.SQL("select * from coll7").Execute().FetchAll(); + foreach (Row res in result) + Assert.That(res[0], Is.Not.Null); + var count = session.SQL("select count(*) from coll7").Execute().FetchOne()[0]; + Assert.That(collection.Count(), Is.EqualTo(count)); + + options.Validation = new Validation { Schema = doc1, Level = ValidationLevel.STRICT }; + options.ReuseExisting = false; + collection = schema.CreateCollection("collext", options); + collection.Add(@"{ ""name"": ""John"", ""age"": 52 }").Execute(); + result = session.SQL("select * from collext").Execute().FetchAll(); + foreach (Row res in result) + Assert.That(res[0], Is.Not.Null); ; + count = session.SQL("select count(*) from collext").Execute().FetchOne()[0]; + Assert.That(collection.Count(), Is.EqualTo(count)); + + var doc2 = "{\"id\":\"http://json-schema.org/geo\"," + + "\"$schema\": \"http://json-schema.org/draft-06/schema#\"," + + "\"description\": \"A Person example\"," + + "\"type\": \"object\"," + + "\"properties\": {" + + "\"name\": {\"type\": \"string\"}," + + "\"number\": {\"type\": \"number\"}," + + "\"street_name\": {\"type\": \"string\"} ," + + "\"street_type\": {\"type\": \"string\"}," + + "\"colors\": " + + "{\"type\": \"array\" ," + + "\"description\": \"different colors\"," + + "\"items\": [" + + "{\"type\": \"string\"," + + "\"enum\": [\"red\", \"amber\", \"green\"]" + + "}," + + "{\"type\": \"number\"}," + + "{\"type\": \"boolean\"}"//," + + "{\"type\": \"null\"}," + + "]" + + "}" + + "}," + + "\"required\": [\"name\", \"number\"]" + + "}"; + + options.Validation = new Validation { Schema = doc2, Level = ValidationLevel.STRICT }; + options.ReuseExisting = false; + Assert.Throws(() => schema.CreateCollection("coll8", options)); + + options.Validation = new Validation { Schema = doc1, Level = ValidationLevel.STRICT }; + options.ReuseExisting = true; + collection = schema.CreateCollection("coll8", options); + collection.Add(@"{ ""name"": ""John"", ""age"": 52 }").Execute(); + result = session.SQL("select * from coll8").Execute().FetchAll(); + foreach (Row res in result) + Assert.That(res[0], Is.Not.Null); ; + count = session.SQL("select count(*) from coll8").Execute().FetchOne()[0]; + Assert.That(collection.Count(), Is.EqualTo(count)); + + options.Validation = new Validation { Schema = doc1, Level = ValidationLevel.STRICT }; + options.ReuseExisting = false; + collection = schema.CreateCollection("coll9", options); + Assert.Throws(() => ExecuteAddStatement(collection.Add(@"{""longitude"":""99""}"))); + + options1.Validation = new Validation { Schema = doc1, Level = ValidationLevel.STRICT }; + collection = schema.ModifyCollection("coll7", options1); + Assert.Throws(() => ExecuteAddStatement(collection.Add(@"{ ""number"": ""56"" }"))); + + options.Validation = new Validation { Schema = doc1, Level = ValidationLevel.OFF }; + options.ReuseExisting = false; + collection = schema.CreateCollection("coll10", options); + collection.Add(@"{""longitude"":""99""}").Execute(); + result = session.SQL("select * from coll10").Execute().FetchAll(); + foreach (Row res in result) + Assert.That(res[0], Is.Not.Null); ; + count = session.SQL("select count(*) from coll10").Execute().FetchOne()[0]; + Assert.That(collection.Count(), Is.EqualTo(count)); + + options1.Validation = new Validation { Schema = doc1, Level = ValidationLevel.OFF }; + collection = schema.ModifyCollection("coll10", options1); + collection.Add(@"{ ""name"": 67 }").Execute(); + result = session.SQL("select * from coll10").Execute().FetchAll(); + foreach (Row res in result) + Assert.That(res[0], Is.Not.Null); ; + count = session.SQL("select count(*) from coll10").Execute().FetchOne()[0]; + Assert.That(collection.Count(), Is.EqualTo(count)); + + options.Validation = new Validation { Schema = doc1, Level = ValidationLevel.STRICT }; + options.ReuseExisting = false; + collection = schema.CreateCollection("coll", options); + collection.Add(@"{""_id"":1,""name"": ""John"", ""age"": 52}").Execute(); + result = session.SQL("select * from coll").Execute().FetchAll(); + foreach (Row res in result) + Assert.That(res[0], Is.Not.Null); ; + count = session.SQL("select count(*) from coll").Execute().FetchOne()[0]; + Assert.That(collection.Count(), Is.EqualTo(count)); + } + + /// + /// Bug 30693969 + /// + [Test, Description("Verify ModifyCollection with level OFF and JSON schema with Json schema")] + public void ModifyCollectionSchemaValidation() + { + Assume.That(session.Version.isAtLeast(8, 0, 19), "This test is for MySql 8.0.19 or higher"); + session.SQL($"use {schemaName}").Execute(); + var schema = session.GetSchema(schemaName); + var options = new CreateCollectionOptions(); + var val = new Validation(); + string doc1 = "{" + + " \"id\":\"https://example.com/arrays.schema.json\"," + + " \"$schema\": \"http://json-schema.org/draft-07/schema#\"," + + " \"description\": \"A representation of a person, company, organization, or place\"," + + " \"type\": \"object\"," + + " \"properties\": {" + + " \"fruits\": {" + + " \"type\": \"array\"," + + " \"items\": {" + + "\"type\": \"string\"" + + " }" + + "}," + + "\"vegetables\": {" + + " \"type\": \"array\"," + + "\"items\": { \"$ref\": \"#/definitions/veggie\" }" + + " }" + + "}," + + "\"definitions\": {" + + " \"veggie\": {" + + " \"type\": \"object\"," + + " \"required\": [ \"veggieName\", \"veggieLike\" ]," + + "\"properties\": {" + + " \"veggieName\": {" + + " \"type\": \"string\"," + + " \"description\": \"The name of the vegetable.\"" + + "}," + + "\"veggieLike\": {" + + "\"type\": \"boolean\"," + + "\"description\": \"Do I like this vegetable?\"" + + "}" + + "}" + + "}" + + "}" + + "}"; + + val.Level = ValidationLevel.STRICT; + val.Schema = doc1; + options.Validation = val; + options.ReuseExisting = false; + var collection = schema.CreateCollection("coll20", options); + collection.Add(@"{""fruits"": [ ""apple"", ""orange"", ""pear"" ],""vegetables"": [{""veggieName"": ""potato"",""veggieLike"": true},{""veggieName"": ""broccoli"",""veggieLike"": false}]}").Execute(); + var result = session.SQL("select * from coll20").Execute().FetchAll(); + foreach (Row res in result) + Assert.That(res[0], Is.Not.Null); + var count = session.SQL("select count(*) from coll20").Execute().FetchOne()[0]; + Assert.That(collection.Count(), Is.EqualTo(count)); + + options.Validation = new Validation { Level = ValidationLevel.STRICT, Schema = doc1 }; + options.ReuseExisting = false; + collection = schema.CreateCollection("coll21", options); + collection.Add(@"{""fruits"": [ ""apple"", ""orange"", ""pear"" ],""vegetables"": [{""veggieName"": ""potato"",""veggieLike"": true},{""veggieName"": ""broccoli"",""veggieLike"": false}]}").Execute(); + result = session.SQL("select * from coll21").Execute().FetchAll(); + foreach (Row res in result) + Assert.That(res[0], Is.Not.Null); + count = session.SQL("select count(*) from coll21").Execute().FetchOne()[0]; + Assert.That(collection.Count(), Is.EqualTo(count)); + + val.Level = ValidationLevel.STRICT; + val.Schema = doc1; + options.Validation = val; + options.ReuseExisting = true; + collection = schema.CreateCollection("coll20", options); + collection.Add(@"{""fruits"": [ ""apple"", ""orange"", ""pear"" ],""vegetables"": [{""veggieName"": ""potato"",""veggieLike"": true},{""veggieName"": ""broccoli"",""veggieLike"": false}]}").Execute(); + result = session.SQL("select * from coll20").Execute().FetchAll(); + foreach (Row res in result) + Assert.That(res[0], Is.Not.Null); + count = session.SQL("select count(*) from coll20").Execute().FetchOne()[0]; + Assert.That(collection.Count(), Is.EqualTo(count)); + + options.Validation = new Validation { Level = ValidationLevel.STRICT, Schema = doc1 }; + options.ReuseExisting = true; + collection = schema.CreateCollection("coll21", options); + collection.Add(@"{""fruits"": [ ""apple"", ""orange"", ""pear"" ],""vegetables"": [{""veggieName"": ""potato"",""veggieLike"": true},{""veggieName"": ""broccoli"",""veggieLike"": false}]}").Execute(); + result = session.SQL("select * from coll21").Execute().FetchAll(); + foreach (Row res in result) + Assert.That(res[0], Is.Not.Null); + count = session.SQL("select count(*) from coll21").Execute().FetchOne()[0]; + Assert.That(collection.Count(), Is.EqualTo(count)); + + val.Level = ValidationLevel.OFF; + val.Schema = doc1; + options.Validation = val; + options.ReuseExisting = true; + collection = schema.CreateCollection("coll22", options); + collection.Add(@"{""fruits"": [ 78, ""orange"", ""pear"" ],""vegetables"": [{""veggieName"": ""potato"",""veggieLike"": true},{""veggieName"": ""broccoli"",""veggieLike"": false}]}").Execute(); + result = session.SQL("select * from coll22").Execute().FetchAll(); + foreach (Row res in result) + Assert.That(res[0], Is.Not.Null); + count = session.SQL("select count(*) from coll22").Execute().FetchOne()[0]; + Assert.That(collection.Count(), Is.EqualTo(count)); + } + + [Test, Description("Verify ModifyCollection with level OFF and JSON schema")] + public void SchemaValidationDeleteRecords() + { + // Bug30748283 + Assume.That(session.Version.isAtLeast(8, 0, 19), "This test is for MySql 8.0.19 or higher"); + string doc5 = "{\"id\": \"http://json-schema.org/geo\"," + + "\"$schema\": \"http://json-schema.org/draft-06/schema#\"," + + "\"description\": \"A Person example\"," + + "\"type\": \"object\"," + + "\"properties\": {" + + "\"name\": {" + + "\"type\": \"number\"" + + " }" + + "}," + + "\"required\": [\"name\"]" + + "}"; + + string doc1 = "{\"id\": \"http://json-schema.org/geo\"," + + "\"$schema\": \"http://json-schema.org/draft-06/schema#\"," + + "\"description\": \"A Person example\"," + + "\"type\": \"object\"," + + "\"properties\": {" + + "\"name\": {" + + "\"type\": \"string\"" + + " }" + + ",\"age\": {" + + "\"type\": \"number\"" + + "}" + + "}," + + "\"required\": [\"name\",\"age\"]" + + "}"; + string doc3 = "{\"id\": \"http://json-schema.org/geo\"," + + "\"$schema\": \"http://json-schema.org/draft-06/schema#\"," + + "\"description\": \"A geographical coordinate\"," + + "\"type\": \"object\"," + + "\"properties\": {" + + "\"latitude\": {" + + "\"type\": \"number\"" + + " }," + + "\"longitude\": {" + + "\"type\": \"number\"" + + "}" + + "}," + + "\"required\": [\"latitude\", \"longitude\"]" + + "}"; + + string doc4 = "{\"id\": \"http://json-schema.org/geo\"," + + "\"$schema\": \"http://json-schema.org/draft-06/schema#\"," + + "\"description\": \"A Person example\"," + + "\"type\": \"object\"," + + "\"properties\": {" + + "\"name\": {" + + "\"type\": \"string\"" + + " }" + + "}," + + "\"required\": [\"name\"]" + + "}"; + + session.SQL($"use {schemaName}").Execute(); + var schema = session.GetSchema(schemaName); + var options = new CreateCollectionOptions(); + var options1 = new ModifyCollectionOptions(); + + options.Validation = new Validation { Level = ValidationLevel.STRICT, Schema = doc5 }; + options.ReuseExisting = true; + var collection = schema.CreateCollection("collectiontest", options); + collection.Add(@"{ ""name"": 52 }").Execute(); + var result = session.SQL("select * from collectiontest").Execute().FetchAll(); + foreach (Row res1 in result) + Assert.That(res1[0], Is.Not.Null); + var count = session.SQL("select count(*) from collectiontest").Execute().FetchOne()[0]; + Assert.That(collection.Count(), Is.EqualTo(count)); + + options1.Validation = new Validation { Level = ValidationLevel.STRICT, Schema = doc1 }; + session.SQL("delete from collectiontest").Execute(); + + collection = schema.ModifyCollection("collectiontest", options1); + collection.Add(@"{ ""name"": ""sammeer"",""age"":8 }").Execute(); + var result2 = session.SQL("select * from collectiontest").Execute().FetchAll(); + foreach (Row res2 in result2) + Console.WriteLine(res2[0]); + count = session.SQL("select count(*) from collectiontest").Execute().FetchOne()[0]; + Assert.That(collection.Count(), Is.EqualTo(count)); + + options1.Validation = new Validation { Level = ValidationLevel.OFF, Schema = doc1 }; + collection = schema.ModifyCollection("collectiontest", options1); + collection.Add(@"{ ""name"": 78 }").Execute(); + result = session.SQL("select * from collectiontest").Execute().FetchAll(); + foreach (Row res2 in result) + Assert.That(res2[0], Is.Not.Null); + count = session.SQL("select count(*) from collectiontest").Execute().FetchOne()[0]; + Assert.That(collection.Count(), Is.EqualTo(count)); + + options1.Validation = new Validation { Level = ValidationLevel.STRICT, Schema = doc3 }; + session.SQL("delete from collectiontest").Execute(); + collection = schema.ModifyCollection("collectiontest", options1); + collection.Add(@"{""latitude"": 253, ""longitude"": 525}").Execute(); + result = session.SQL("select * from collectiontest").Execute().FetchAll(); + foreach (Row res2 in result) + Assert.That(res2[0], Is.Not.Null); + count = session.SQL("select count(*) from collectiontest").Execute().FetchOne()[0]; + Assert.That(collection.Count(), Is.EqualTo(count)); + + options1.Validation = new Validation { Level = ValidationLevel.STRICT, Schema = doc4 }; + session.SQL("delete from collectiontest").Execute(); + result = session.SQL("select * from collectiontest").Execute().FetchAll(); + collection = schema.ModifyCollection("collectiontest", options1); + collection.Add(@"{ ""name"": ""Johnny"" }").Execute(); + result = session.SQL("select * from collectiontest").Execute().FetchAll(); + foreach (Row res2 in result) + Assert.That(res2[0], Is.Not.Null); + count = session.SQL("select count(*) from collectiontest").Execute().FetchOne()[0]; + Assert.That(collection.Count(), Is.EqualTo(count)); + + } + + [Test, Description("Test MySQLX plugin Remove Bind Stress")] + public void RemoveBindStress() + { + Assume.That(session.Version.isAtLeast(5, 7, 0), "This test is for MySql 5.7 or higher"); + Collection coll = CreateCollection("test"); + DbDoc[] jsonlist = new DbDoc[10]; + DbDoc[] jsonlist1 = new DbDoc[10]; + for (int i = 0; i < 10; i++) + { + DbDoc newDoc2 = new DbDoc(); + newDoc2.SetValue("_id", (i + 1000)); + newDoc2.SetValue("F1", ("Field-1-Data-" + i)); + newDoc2.SetValue("F2", ("Field-2-Data-" + i)); + newDoc2.SetValue("F3", (300 + i).ToString()); + jsonlist[i] = newDoc2; + newDoc2 = null; + } + + for (int i = 0; i < 10; i++) + { + DbDoc newDoc2 = new DbDoc(); + newDoc2.SetValue("_id", (i + 10000)); + newDoc2.SetValue("F1", ("Field-1-Data-" + i)); + newDoc2.SetValue("F2", ("Field-2-Data-" + i)); + newDoc2.SetValue("F3", (300 + i).ToString()); + jsonlist1[i] = newDoc2; + newDoc2 = null; + } + Result r = coll.Add(jsonlist).Add(jsonlist1).Execute(); + + Assert.That(r.AffectedItemsCount, Is.EqualTo(20), "Matching"); + + r = coll.Remove("_id = :_id").Bind("_id", 1000).Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1), "Matching"); + } + + [Test, Description("Test MySQLX plugin Get Collection as Table")] + public void GetCollectionAsTableStress() + { + Assume.That(session.Version.isAtLeast(5, 7, 0), "This test is for MySql 5.7 or higher"); + Collection testCollection = CreateCollection("test"); + + DbDoc[] jsonlist = new DbDoc[1000]; + for (int i = 0; i < 1000; i++) + { + DbDoc newDoc2 = new DbDoc(); + newDoc2.SetValue("_id", (i + 1000)); + newDoc2.SetValue("F1", ("Field-1-Data-" + i)); + newDoc2.SetValue("F2", ("Field-2-Data-" + i)); + newDoc2.SetValue("F3", (300 + i).ToString()); + jsonlist[i] = newDoc2; + newDoc2 = null; + } + Result r = testCollection.Add(jsonlist).Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1000), "Matching"); + + Table test = testSchema.GetCollectionAsTable("test"); + Assert.That(test.ExistsInDatabase()); + var rows = test.Select("_id").Execute().FetchAll(); + + for (int j = 0; j < rows.Count; j++) + { + var doc = testCollection.Find("_id like :param").Bind("param", (j + 1000)).Execute(); + var docs = doc.FetchAll().Count(); + Assert.That(docs, Is.EqualTo(1), "Matches"); + } + } + + [Test, Description("Test MySQLX plugin GetCollection Exception Scenario")] + public void GetCollectionException() + { + Assume.That(session.Version.isAtLeast(5, 7, 0), "This test is for MySql 5.7 or higher"); + using (Session sessionPlain = MySQLX.GetSession(ConnectionString)) + { + Schema db = sessionPlain.GetSchema(schemaName); + Collection col = db.GetCollection("my_collection_123456789"); + if (col.ExistsInDatabase()) + { + db.DropCollection("my_collection_123456789"); + col = db.CreateCollection("my_collection_123456789"); + } + else { col = db.CreateCollection("my_collection_123456789"); } + + Collection col1 = db.GetCollection("my_collection_123456789", true); + if (col.ExistsInDatabase()) + { + db.DropCollection("my_collection_123456789"); + col1 = db.CreateCollection("my_collection_123456789"); + } + else { col1 = db.CreateCollection("my_collection_123456789"); } + + var col2 = db.GetTable("my_collection_1234567891"); + Assert.Throws(() => db.GetCollection("my_collection_test", true)); + db.DropCollection("my_collection_123456789"); + } + } + + [Test, Description("Collection GetDocumentIDS Stress(1000 records)")] + public void GetDocumentIDSStress() + { + Collection coll = CreateCollection("test"); + DbDoc[] jsonlist = new DbDoc[1000]; + for (int i = 0; i < 1000; i++) + { + DbDoc newDoc2 = new DbDoc(); + newDoc2.SetValue("_id", (i)); + newDoc2.SetValue("F1", ("Field-1-Data-" + i)); + newDoc2.SetValue("F2", ("Field-2-Data-" + i)); + newDoc2.SetValue("F3", (3 + i).ToString()); + jsonlist[i] = newDoc2; + newDoc2 = null; + } + Result r = coll.Add(jsonlist).Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1000), "Matching"); + var documentIds = r.GeneratedIds; + Assert.That(documentIds != null && documentIds.Count > 0, Is.False); + } + + [Test, Description("Session Performance Test")] + public void SessionPerformanceTest() + { + string json = ""; + int i = 0, j = 0, maxField = 100; + var collection = CreateCollection("test"); + int maxDepth = 97; + json = "{\"_id\":\"1002\",\"XYZ\":1111"; + for (j = 0; j < maxField; j++) + { + json = json + ",\"ARR" + j + "\":["; + for (i = 0; i < maxDepth; i++) + { + json = json + i + ",["; + } + json = json + i; + for (i = maxDepth - 1; i >= 0; i--) + { + json = json + "]," + i; + } + json = json + "]"; + } + json = json + "}"; + + collection.Add(json).Execute(); + json = "{\"_id\":\"1003\",\"XYZ\":2222"; + for (j = 0; j < maxField; j++) + { + json = json + ",\"DATAX" + j + "\":"; + for (i = 0; i < maxDepth; i++) + { + json = json + "{\"D" + i + "\":"; + } + json = json + maxDepth; + for (i = maxDepth - 1; i >= 0; i--) + { + json = json + "}"; + } + } + json = json + "}"; + + collection.Add(json).Execute(); + json = "{\"_id\":\"1001\",\"XYZ\":3333"; + for (j = 0; j < maxField; j++) + { + json = json + ",\"ARR" + j + "\":["; + for (i = 0; i < maxDepth; i++) + { + json = json + i + ",["; + } + json = json + i; + for (i = maxDepth - 1; i >= 0; i--) + { + json = json + "]," + i; + } + json = json + "]"; + } + + for (j = 0; j < maxField; j++) + { + json = json + ",\"DATAX" + j + "\":"; + for (i = 0; i < maxDepth; i++) + { + json = json + "{\"D" + i + "\":"; + } + json = json + maxDepth; + for (i = maxDepth - 1; i >= 0; i--) + { + json = json + "}"; + } + } + json = json + "}"; + collection.Add(json).Execute(); + + // select + string query = "$.ARR" + (maxField - 1); + for (i = 0; i < maxDepth; i++) + { + query = query + "[1]"; + } + query = query + "[0]"; + json = "CAST(" + query + " as SIGNED)= " + maxDepth; + var docs = collection.Find(json).Fields("$._id as _id," + query + " as Arr").Execute(); + var res = docs.FetchAll(); + Assert.That(res[0]["_id"].ToString(), Is.EqualTo("1001"), "Matching the id"); + Assert.That(res[1]["_id"].ToString(), Is.EqualTo("1002"), "Matching the id"); + + query = "$.DATAX" + (maxField - 1); + for (i = 0; i < maxDepth; i++) + { + query = query + ".D" + i; + } + json = "CAST(" + query + " as SIGNED)"; + docs = collection.Find(json + " =" + maxDepth).Fields("$._id as _id ").Execute(); + res = docs.FetchAll(); + Assert.That(res[0]["_id"].ToString(), Is.EqualTo("1001"), "Matching the id"); + Assert.That(res[1]["_id"].ToString(), Is.EqualTo("1003"), "Matching the id"); + } + + /// + /// Bug #34243143 [Connector/NET allows empty string in Set() method which is chained to Modify()] + /// The fix applied for every method in Modify(). + /// + [Test] + public void EmptyStringInModifyMethods() + { + Collection coll = CreateCollection("test"); + object _doc = new { _id = 1, title = "foo" }; + coll.Add(_doc).Execute(); + var result = coll.Find("_id == 1").Execute().FetchOne(); + + Assert.That(result, Is.Not.Null); + Assert.That(result.Id, Is.EqualTo(1)); + + // empty string + var ex = Assert.Throws(() => coll.Modify("_id == 1").Set("", new { title = "bar" }).Execute()); + Assert.That(ex.Message, Is.EqualTo(ResourcesX.DocPathNullOrEmpty).IgnoreCase); + ex = Assert.Throws(() => coll.Modify("_id == 1").Unset("").Execute()); + Assert.That(ex.Message, Is.EqualTo(ResourcesX.DocPathNullOrEmpty).IgnoreCase); + ex = Assert.Throws(() => coll.Modify("_id == 1").Change("", new { title = "bar" }).Execute()); + Assert.That(ex.Message, Is.EqualTo(ResourcesX.DocPathNullOrEmpty).IgnoreCase); + ex = Assert.Throws(() => coll.Modify("_id == 1").ArrayInsert("", new { title = "bar" }).Execute()); + Assert.That(ex.Message, Is.EqualTo(ResourcesX.DocPathNullOrEmpty).IgnoreCase); + ex = Assert.Throws(() => coll.Modify("_id == 1").ArrayAppend("", new { title = "bar" }).Execute()); + Assert.That(ex.Message, Is.EqualTo(ResourcesX.DocPathNullOrEmpty).IgnoreCase); + + // white space + ex = Assert.Throws(() => coll.Modify("_id == 1").Set(" ", new { title = "bar" }).Execute()); + Assert.That(ex.Message, Is.EqualTo(ResourcesX.DocPathNullOrEmpty).IgnoreCase); + ex = Assert.Throws(() => coll.Modify("_id == 1").Unset(" ").Execute()); + Assert.That(ex.Message, Is.EqualTo(ResourcesX.DocPathNullOrEmpty).IgnoreCase); + ex = Assert.Throws(() => coll.Modify("_id == 1").Change(" ", new { title = "bar" }).Execute()); + Assert.That(ex.Message, Is.EqualTo(ResourcesX.DocPathNullOrEmpty).IgnoreCase); + ex = Assert.Throws(() => coll.Modify("_id == 1").ArrayInsert(" ", new { title = "bar" }).Execute()); + Assert.That(ex.Message, Is.EqualTo(ResourcesX.DocPathNullOrEmpty).IgnoreCase); + ex = Assert.Throws(() => coll.Modify("_id == 1").ArrayAppend(" ", new { title = "bar" }).Execute()); + Assert.That(ex.Message, Is.EqualTo(ResourcesX.DocPathNullOrEmpty).IgnoreCase); + + // null + ex = Assert.Throws(() => coll.Modify("_id == 1").Set(null, new { title = "bar" }).Execute()); + Assert.That(ex.Message, Is.EqualTo(ResourcesX.DocPathNullOrEmpty).IgnoreCase); + ex = Assert.Throws(() => coll.Modify("_id == 1").Change(null, new { title = "bar" }).Execute()); + Assert.That(ex.Message, Is.EqualTo(ResourcesX.DocPathNullOrEmpty).IgnoreCase); + ex = Assert.Throws(() => coll.Modify("_id == 1").ArrayInsert(null, new { title = "bar" }).Execute()); + Assert.That(ex.Message, Is.EqualTo(ResourcesX.DocPathNullOrEmpty).IgnoreCase); + ex = Assert.Throws(() => coll.Modify("_id == 1").ArrayAppend(null, new { title = "bar" }).Execute()); + Assert.That(ex.Message, Is.EqualTo(ResourcesX.DocPathNullOrEmpty).IgnoreCase); + var ex2 = Assert.Throws(() => coll.Modify("_id == 1").Unset(null).Execute()); + } + } +} diff --git a/MySQL.Data/tests/MySqlX.Data.Tests/CompressionTests.cs b/MySQL.Data/tests/MySqlX.Data.Tests/CompressionTests.cs index d350f50bc..d0a3df97f 100644 --- a/MySQL.Data/tests/MySqlX.Data.Tests/CompressionTests.cs +++ b/MySQL.Data/tests/MySqlX.Data.Tests/CompressionTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2019, 2022, Oracle and/or its affiliates. +// Copyright © 2019, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -31,6 +31,7 @@ using MySqlX.Common; using MySqlX.XDevAPI; using NUnit.Framework; +using NUnit.Framework.Legacy; using System; using System.Collections.Generic; using System.Diagnostics; @@ -58,13 +59,13 @@ public void ConnectionOptionIsValidUsingBuilder() { var builder = new MySqlXConnectionStringBuilder(ConnectionString); builder.Compression = CompressionType.Preferred; - StringAssert.Contains("compression=Preferred", builder.ToString()); + Assert.That(builder.ToString(), Does.Contain("compression=Preferred")); builder.Compression = CompressionType.Required; - StringAssert.Contains("compression=Required", builder.ToString()); + Assert.That(builder.ToString(), Does.Contain("compression=Required")); builder.Compression = CompressionType.Disabled; - StringAssert.Contains("compression=Disabled", builder.ToString()); + Assert.That(builder.ToString(), Does.Contain("compression=Disabled")); } [Test] @@ -72,32 +73,32 @@ public void ConnectionOptionIsValidUsingConnectionUri() { using (var session = MySQLX.GetSession($"{ConnectionStringUri}?compression=PreFerRed")) { - Assert.AreEqual(CompressionType.Preferred, session.Settings.Compression); + Assert.That(session.Settings.Compression, Is.EqualTo(CompressionType.Preferred)); session.Close(); } using (var session = MySQLX.GetSession($"{ConnectionStringUri}?compression=required")) { - Assert.AreEqual(CompressionType.Required, session.Settings.Compression); + Assert.That(session.Settings.Compression, Is.EqualTo(CompressionType.Required)); session.Close(); } using (var session = MySQLX.GetSession($"{ConnectionStringUri}?compression=DISABLED")) { - Assert.AreEqual(CompressionType.Disabled, session.Settings.Compression); + Assert.That(session.Settings.Compression, Is.EqualTo(CompressionType.Disabled)); session.Close(); } // Test whitespace using (var session = MySQLX.GetSession($"{ConnectionStringUri}?compression= DISABLED")) { - Assert.AreEqual(CompressionType.Disabled, session.Settings.Compression); + Assert.That(session.Settings.Compression, Is.EqualTo(CompressionType.Disabled)); session.Close(); } using (var session = MySQLX.GetSession($"{ConnectionStringUri}?compression= DISABLED ")) { - Assert.AreEqual(CompressionType.Disabled, session.Settings.Compression); + Assert.That(session.Settings.Compression, Is.EqualTo(CompressionType.Disabled)); session.Close(); } } @@ -116,7 +117,7 @@ public void ConnectionOptionIsValidUsingAnonymousObject() using (var session = MySQLX.GetSession(connectionData)) { - Assert.AreEqual(CompressionType.Required, session.Settings.Compression); + Assert.That(session.Settings.Compression, Is.EqualTo(CompressionType.Required)); session.Close(); } } @@ -125,36 +126,36 @@ public void ConnectionOptionIsValidUsingAnonymousObject() public void ConnectionOptionIsValidUsingConnectionString() { var builder = new MySqlXConnectionStringBuilder($"server={Host};port={XPort};compression=PreFerRed"); - Assert.AreEqual(CompressionType.Preferred, builder.Compression); + Assert.That(builder.Compression, Is.EqualTo(CompressionType.Preferred)); builder = new MySqlXConnectionStringBuilder($"server={Host};port={XPort};compression=required"); - Assert.AreEqual(CompressionType.Required, builder.Compression); + Assert.That(builder.Compression, Is.EqualTo(CompressionType.Required)); builder = new MySqlXConnectionStringBuilder($"server={Host};port={XPort};compression=DISABLED"); - Assert.AreEqual(CompressionType.Disabled, builder.Compression); + Assert.That(builder.Compression, Is.EqualTo(CompressionType.Disabled)); // Test whitespace builder = new MySqlXConnectionStringBuilder($"server={Host};port={XPort};compression= required"); - Assert.AreEqual(CompressionType.Required, builder.Compression); + Assert.That(builder.Compression, Is.EqualTo(CompressionType.Required)); builder = new MySqlXConnectionStringBuilder($"server={Host};port={XPort};compression= required"); - Assert.AreEqual(CompressionType.Required, builder.Compression); + Assert.That(builder.Compression, Is.EqualTo(CompressionType.Required)); builder = new MySqlXConnectionStringBuilder($"server={Host};port={XPort};compression= required "); - Assert.AreEqual(CompressionType.Required, builder.Compression); + Assert.That(builder.Compression, Is.EqualTo(CompressionType.Required)); } [Test] public void PreferredIsTheDefaultValue() { var builder = new MySqlXConnectionStringBuilder(); - Assert.AreEqual(CompressionType.Preferred, builder.Compression); + Assert.That(builder.Compression, Is.EqualTo(CompressionType.Preferred)); // Empty value is ignored. var updatedConnectionStringUri = ConnectionStringUri + "?compression="; using (var session = MySQLX.GetSession(updatedConnectionStringUri)) { - Assert.AreEqual(CompressionType.Preferred, session.Settings.Compression); + Assert.That(session.Settings.Compression, Is.EqualTo(CompressionType.Preferred)); session.Close(); } @@ -162,7 +163,7 @@ public void PreferredIsTheDefaultValue() updatedConnectionStringUri = ConnectionStringUri + "?compression= "; using (var session = MySQLX.GetSession(updatedConnectionStringUri)) { - Assert.AreEqual(CompressionType.Preferred, session.Settings.Compression); + Assert.That(session.Settings.Compression, Is.EqualTo(CompressionType.Preferred)); session.Close(); } } @@ -174,10 +175,10 @@ public void SettingAnInvalidCompressionTypeRaisesException() foreach (var invalidValue in invalidValues) { var exception = Assert.Throws(() => new MySqlXConnectionStringBuilder($"server={Host};port={XPort};compression={invalidValue}")); - Assert.AreEqual($"The connection property 'compression' acceptable values are: 'preferred', 'required' or 'disabled'. The value '{invalidValue}' is not acceptable.", exception.Message); + Assert.That(exception.Message, Is.EqualTo($"The connection property 'compression' acceptable values are: 'preferred', 'required' or 'disabled'. The value '{invalidValue}' is not acceptable")); exception = Assert.Throws(() => MySQLX.GetSession($"server={Host};port={XPort};user=root;compression={invalidValue}")); - Assert.AreEqual($"The connection property 'compression' acceptable values are: 'preferred', 'required' or 'disabled'. The value '{invalidValue}' is not acceptable.", exception.Message); + Assert.That(exception.Message, Is.EqualTo($"The connection property 'compression' acceptable values are: 'preferred', 'required' or 'disabled'. The value '{invalidValue}' is not acceptable")); } } @@ -186,14 +187,14 @@ public void SessionRetainsTheSpecifiedCompressionType() { using (var session = MySQLX.GetSession(ConnectionStringUri)) { - Assert.AreEqual(CompressionType.Preferred, session.Settings.Compression); + Assert.That(session.Settings.Compression, Is.EqualTo(CompressionType.Preferred)); session.Close(); } var updatedConnectionStringUri = ConnectionStringUri + "?compression=Disabled"; using (var session = MySQLX.GetSession(updatedConnectionStringUri)) { - Assert.AreEqual(CompressionType.Disabled, session.Settings.Compression); + Assert.That(session.Settings.Compression, Is.EqualTo(CompressionType.Disabled)); session.Close(); } } @@ -205,44 +206,44 @@ public void ValidateRequiredCompressionType() if (!session.InternalSession.GetServerVersion().isAtLeast(8, 0, 19)) { var exception = Assert.Throws(() => MySQLX.GetSession($"{ConnectionStringUri}?compression=Required")); - Assert.AreEqual("Compression requested but the server does not support it.", exception.Message); + Assert.That(exception.Message, Is.EqualTo("Compression requested but the server does not support it.")); } else { using var session = MySQLX.GetSession($"{ConnectionStringUri}?compression=Required"); - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } } [Test] public void NegotiationSucceedsWithExpectedCompressionAlgorithm() { - if (!session.InternalSession.GetServerVersion().isAtLeast(8, 0, 19)) Assert.Ignore("Feature only available since v8.0.19"); + Assume.That(session.Version.isAtLeast(8, 0, 19), "This test is for MySql 8.0.19 or higher"); // Validate zstd_stream is the default. using (var session = MySQLX.GetSession(ConnectionStringUri)) { var compressionAlgorithm = session.XSession.GetCompressionAlgorithm(true); - Assert.AreEqual(CompressionAlgorithms.zstd_stream.ToString(), compressionAlgorithm); + Assert.That(compressionAlgorithm, Is.EqualTo(CompressionAlgorithms.zstd_stream.ToString())); compressionAlgorithm = session.XSession.GetCompressionAlgorithm(false); - Assert.AreEqual(CompressionAlgorithms.zstd_stream.ToString(), compressionAlgorithm); + Assert.That(compressionAlgorithm, Is.EqualTo(CompressionAlgorithms.zstd_stream.ToString())); } using (var session = MySQLX.GetSession(ConnectionStringUri + "?compression-algorithms=lz4_message")) { var compressionAlgorithm = session.XSession.GetCompressionAlgorithm(true); - Assert.AreEqual(CompressionAlgorithms.lz4_message.ToString(), compressionAlgorithm); + Assert.That(compressionAlgorithm, Is.EqualTo(CompressionAlgorithms.lz4_message.ToString())); compressionAlgorithm = session.XSession.GetCompressionAlgorithm(false); - Assert.AreEqual(CompressionAlgorithms.lz4_message.ToString(), compressionAlgorithm); + Assert.That(compressionAlgorithm, Is.EqualTo(CompressionAlgorithms.lz4_message.ToString())); } #if !NETFRAMEWORK using (var session = MySQLX.GetSession(ConnectionStringUri + "?compression-algorithms=deflate_stream")) { var compressionAlgorithm = session.XSession.GetCompressionAlgorithm(true); - Assert.AreEqual(CompressionAlgorithms.deflate_stream.ToString(), compressionAlgorithm); + Assert.That(compressionAlgorithm, Is.EqualTo(CompressionAlgorithms.deflate_stream.ToString())); compressionAlgorithm = session.XSession.GetCompressionAlgorithm(false); - Assert.AreEqual(CompressionAlgorithms.deflate_stream.ToString(), compressionAlgorithm); + Assert.That(compressionAlgorithm, Is.EqualTo(CompressionAlgorithms.deflate_stream.ToString())); } #endif } @@ -259,7 +260,7 @@ public void NegotiationWithSpecificCompressionAlgorithm() using (var session = MySQLX.GetSession(updatedConnectionStringUri)) { var compressionAlgorithm = session.XSession.GetCompressionAlgorithm(true); - Assert.AreEqual(CompressionAlgorithms.zstd_stream.ToString(), compressionAlgorithm); + Assert.That(compressionAlgorithm, Is.EqualTo(CompressionAlgorithms.zstd_stream.ToString())); } } @@ -267,18 +268,18 @@ public void NegotiationWithSpecificCompressionAlgorithm() using (var session = MySQLX.GetSession(updatedConnectionStringUri)) { var compressionAlgorithm = session.XSession.GetCompressionAlgorithm(true); - Assert.AreEqual(CompressionAlgorithms.lz4_message.ToString(), compressionAlgorithm); + Assert.That(compressionAlgorithm, Is.EqualTo(CompressionAlgorithms.lz4_message.ToString())); } ExecuteSqlAsRoot($"SET GLOBAL mysqlx_compression_algorithms ={DEFLATE_STREAM}"); #if NETFRAMEWORK var exception = Assert.Throws(() => MySQLX.GetSession(updatedConnectionStringUri)); - Assert.AreEqual("Compression requested but the compression algorithm negotiation failed.", exception.Message); + Assert.That(exception.Message, Is.EqualTo("Compression requested but the compression algorithm negotiation failed.")); #else using (var session = MySQLX.GetSession(updatedConnectionStringUri)) { var compressionAlgorithm = session.XSession.GetCompressionAlgorithm(true); - Assert.AreEqual(CompressionAlgorithms.deflate_stream.ToString(), compressionAlgorithm); + Assert.That(compressionAlgorithm, Is.EqualTo(CompressionAlgorithms.deflate_stream.ToString())); } #endif @@ -287,8 +288,8 @@ public void NegotiationWithSpecificCompressionAlgorithm() using (var session = MySQLX.GetSession(updatedConnectionStringUri)) { var compressionAlgorithm = session.XSession.GetCompressionAlgorithm(true); - Assert.True(Enum.TryParse(compressionAlgorithm, out var algorithm)); - Assert.True(algorithm == CompressionAlgorithms.lz4_message || algorithm == CompressionAlgorithms.zstd_stream); + Assert.That(Enum.TryParse(compressionAlgorithm, out var algorithm)); + Assert.That(algorithm == CompressionAlgorithms.lz4_message || algorithm == CompressionAlgorithms.zstd_stream); } } @@ -321,13 +322,13 @@ public void ConfigurableCompressionAlgorithms() using (var session = MySQLX.GetSession(ConnectionStringUri + "?compression-algorithms=lz4_message;")) { var compressionAlgorithm = session.XSession.GetCompressionAlgorithm(true); - Assert.AreEqual(CompressionAlgorithms.lz4_message.ToString(), compressionAlgorithm); + Assert.That(compressionAlgorithm, Is.EqualTo(CompressionAlgorithms.lz4_message.ToString())); } using (var session = MySQLX.GetSession(ConnectionString + ";compression-algorithms=lz4_message;")) { var compressionAlgorithm = session.XSession.GetCompressionAlgorithm(true); - Assert.AreEqual(CompressionAlgorithms.lz4_message.ToString(), compressionAlgorithm); + Assert.That(compressionAlgorithm, Is.EqualTo(CompressionAlgorithms.lz4_message.ToString())); } #if NETFRAMEWORK @@ -335,13 +336,13 @@ public void ConfigurableCompressionAlgorithms() using (var session = MySQLX.GetSession(new { server = Host, port = XPort, uid = "test", password = "test", compressionalgorithms = "deflate_stream" })) { var compressionAlgorithm = session.XSession.GetCompressionAlgorithm(true); - Assert.IsNull(compressionAlgorithm); + Assert.That(compressionAlgorithm, Is.Null); } #else using (var session = MySQLX.GetSession(new { server = Host, port = XPort, uid = "test", password = "test", compressionalgorithms = "deflate_stream" })) { var compressionAlgorithm = session.XSession.GetCompressionAlgorithm(true); - StringAssert.AreEqualIgnoringCase(CompressionAlgorithms.deflate_stream.ToString(), compressionAlgorithm); + Assert.That(compressionAlgorithm, Is.EqualTo(CompressionAlgorithms.deflate_stream.ToString()).IgnoreCase); } #endif @@ -349,7 +350,7 @@ public void ConfigurableCompressionAlgorithms() using (var session = MySQLX.GetSession(sb.GetConnectionString(true))) { var compressionAlgorithm = session.XSession.GetCompressionAlgorithm(true); - Assert.AreEqual(CompressionAlgorithms.lz4_message.ToString(), compressionAlgorithm); + Assert.That(compressionAlgorithm, Is.EqualTo(CompressionAlgorithms.lz4_message.ToString())); } // FR1_2 Create session with option compression-algorithms and set the option with no value either by not including the property in the connection string @@ -357,13 +358,13 @@ public void ConfigurableCompressionAlgorithms() using (var session = MySQLX.GetSession($"server={Host};port={XPort};uid=test;password=test;")) { var compressionAlgorithm = session.XSession.GetCompressionAlgorithm(true); - Assert.True(Enum.TryParse(compressionAlgorithm, out var result)); + Assert.That(Enum.TryParse(compressionAlgorithm, out var result)); } using (var session = MySQLX.GetSession(ConnectionString + ";compression-algorithms=")) { var compressionAlgorithm = session.XSession.GetCompressionAlgorithm(true); - Assert.True(Enum.TryParse(compressionAlgorithm, out var result)); + Assert.That(Enum.TryParse(compressionAlgorithm, out var result)); } // FR2_1,FR2_2 Create session with option compression-algorithms and set the value with multiple compression algorithms for @@ -371,13 +372,13 @@ public void ConfigurableCompressionAlgorithms() using (var session = MySQLX.GetSession(ConnectionStringUri + "?compression-algorithms=lz4_message,zstd_stream,deflate_stream;")) { var compressionAlgorithm = session.XSession.GetCompressionAlgorithm(true); - Assert.AreEqual(CompressionAlgorithms.lz4_message.ToString(), compressionAlgorithm); + Assert.That(compressionAlgorithm, Is.EqualTo(CompressionAlgorithms.lz4_message.ToString())); } using (var session = MySQLX.GetSession(ConnectionString + ";compression-algorithms=lz4_message,zstd_stream,deflate_stream;")) { var compressionAlgorithm = session.XSession.GetCompressionAlgorithm(true); - Assert.AreEqual(CompressionAlgorithms.lz4_message.ToString(), compressionAlgorithm); + Assert.That(compressionAlgorithm, Is.EqualTo(CompressionAlgorithms.lz4_message.ToString())); } #if NETFRAMEWORK @@ -385,13 +386,13 @@ public void ConfigurableCompressionAlgorithms() using (var session = MySQLX.GetSession(new { server = Host, port = XPort, uid = "test", password = "test", compressionalgorithms = "deflate_stream,lz4_message,zstd_stream" })) { var compressionAlgorithm = session.XSession.GetCompressionAlgorithm(true); - Assert.AreEqual(CompressionAlgorithms.lz4_message.ToString(), compressionAlgorithm); + Assert.That(compressionAlgorithm, Is.EqualTo(CompressionAlgorithms.lz4_message.ToString())); } #else using (var session = MySQLX.GetSession(new { server = Host, port = XPort, uid = "test", password = "test", compressionalgorithms = "deflate_stream,lz4_message,zstd_stream" })) { var compressionAlgorithm = session.XSession.GetCompressionAlgorithm(true); - StringAssert.AreEqualIgnoringCase(CompressionAlgorithms.deflate_stream.ToString(), compressionAlgorithm); + Assert.That(compressionAlgorithm, Is.EqualTo(CompressionAlgorithms.deflate_stream.ToString()).IgnoreCase); } #endif @@ -399,40 +400,40 @@ public void ConfigurableCompressionAlgorithms() using (var session = MySQLX.GetSession(sb.GetConnectionString(true))) { var compressionAlgorithm = session.XSession.GetCompressionAlgorithm(true); - Assert.AreEqual(CompressionAlgorithms.lz4_message.ToString(), compressionAlgorithm); + Assert.That(compressionAlgorithm, Is.EqualTo(CompressionAlgorithms.lz4_message.ToString())); } // FR3 Create session with option compression-algorithms and set the option with Algorithm aliases lz4, zstd, and deflate. using (var session = MySQLX.GetSession(ConnectionString + ";compression-algorithms=lz4,zstd,deflate;")) { var compressionAlgorithm = session.XSession.GetCompressionAlgorithm(true); - Assert.AreEqual(CompressionAlgorithms.lz4_message.ToString(), compressionAlgorithm); + Assert.That(compressionAlgorithm, Is.EqualTo(CompressionAlgorithms.lz4_message.ToString())); } using (var session = MySQLX.GetSession(ConnectionStringUri + "?compression-algorithms=lz4,deflate_stream")) { var compressionAlgorithm = session.XSession.GetCompressionAlgorithm(true); - Assert.AreEqual(CompressionAlgorithms.lz4_message.ToString(), compressionAlgorithm); + Assert.That(compressionAlgorithm, Is.EqualTo(CompressionAlgorithms.lz4_message.ToString())); } // FR4_1 Create session with option compression-algorithms.Set the option with unsupported and supported algorithms by client. using (var session = MySQLX.GetSession(ConnectionString + ";compression=required;compression-algorithms=NotSupported,lz4,SomethingElse;")) { var compressionAlgorithm = session.XSession.GetCompressionAlgorithm(true); - Assert.AreEqual(CompressionAlgorithms.lz4_message.ToString(), compressionAlgorithm); + Assert.That(compressionAlgorithm, Is.EqualTo(CompressionAlgorithms.lz4_message.ToString())); } using (var session = MySQLX.GetSession(ConnectionStringUri + "?compression-algorithms=lz4,NotSupported")) { var compressionAlgorithm = session.XSession.GetCompressionAlgorithm(true); - Assert.AreEqual(CompressionAlgorithms.lz4_message.ToString(), compressionAlgorithm); + Assert.That(compressionAlgorithm, Is.EqualTo(CompressionAlgorithms.lz4_message.ToString())); } sb = new MySqlXConnectionStringBuilder($"server={Host};port={XPort};uid=test;password=test;compression-algorithms=[NotValid,INVALID,NOTSUPPORTED,lz4]"); using (var session = MySQLX.GetSession(sb.GetConnectionString(true))) { var compressionAlgorithm = session.XSession.GetCompressionAlgorithm(true); - Assert.AreEqual(CompressionAlgorithms.lz4_message.ToString(), compressionAlgorithm); + Assert.That(compressionAlgorithm, Is.EqualTo(CompressionAlgorithms.lz4_message.ToString())); } // FR4_2 Create session and set invalid values to the compression-algorithm option to check if the connection is uncompressed when @@ -440,26 +441,26 @@ public void ConfigurableCompressionAlgorithms() using (var session = MySQLX.GetSession(ConnectionString + ";compression-algorithms=NotSupported,SomethingElse;")) { var compressionAlgorithm = session.XSession.GetCompressionAlgorithm(true); - Assert.IsNull(compressionAlgorithm); + Assert.That(compressionAlgorithm, Is.Null); } using (var session = MySQLX.GetSession(ConnectionString + ";compression=disabled;compression-algorithms=lz4,NotSupported,SomethingElse;")) { var compressionAlgorithm = session.XSession.GetCompressionAlgorithm(true); - Assert.IsNull(compressionAlgorithm); + Assert.That(compressionAlgorithm, Is.Null); } using (var session = MySQLX.GetSession(ConnectionString + ";compression=preferred;compression-algorithms=[NotSupported,SomethingElse];")) { var compressionAlgorithm = session.XSession.GetCompressionAlgorithm(true); - Assert.IsNull(compressionAlgorithm); + Assert.That(compressionAlgorithm, Is.Null); } // FR4_3 Create session and set invalid values to the compression-algorithm option. // The connection should terminate with an error when compression option is set to required. Exception ex = Assert.Throws(() => MySQLX.GetSession(ConnectionString + ";compression=required;compression-algorithms=NotSupported,SomethingElse;")); - Assert.AreEqual("Compression requested but the compression algorithm negotiation failed.", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Compression requested but the compression algorithm negotiation failed")); // FR4_4 Start server with specific compression algorithm and create session with option // compression-algorithms.Set the option with multiple compression algorithms. @@ -467,7 +468,7 @@ public void ConfigurableCompressionAlgorithms() using (var session = MySQLX.GetSession(ConnectionString + ";compression=preferred;compression-algorithms=[lz4_message,deflate,zstd];")) { var compressionAlgorithm = session.XSession.GetCompressionAlgorithm(true); - Assert.AreEqual(CompressionAlgorithms.lz4_message.ToString(), compressionAlgorithm); + Assert.That(compressionAlgorithm, Is.EqualTo(CompressionAlgorithms.lz4_message.ToString())); } // FR4_5 Start the server with a specific compression algorithm and use some other in the client and when compression option is either @@ -476,19 +477,19 @@ public void ConfigurableCompressionAlgorithms() using (var session = MySQLX.GetSession(ConnectionString + ";compression-algorithms=[lz4_message]")) { var compressionAlgorithm = session.XSession.GetCompressionAlgorithm(true); - Assert.IsNull(compressionAlgorithm); + Assert.That(compressionAlgorithm, Is.Null); } using (var session = MySQLX.GetSession(ConnectionString + ";compression=preferred;compression-algorithms=[lz4_message]")) { var compressionAlgorithm = session.XSession.GetCompressionAlgorithm(true); - Assert.IsNull(compressionAlgorithm); + Assert.That(compressionAlgorithm, Is.Null); } using (var session = MySQLX.GetSession(ConnectionString + ";compression=disabled;compression-algorithms=[lz4_message]")) { var compressionAlgorithm = session.XSession.GetCompressionAlgorithm(true); - Assert.IsNull(compressionAlgorithm); + Assert.That(compressionAlgorithm, Is.Null); } //FR4_6,FR_5 Start the server with a specific compression algorithm and use some other in the client and when compression option is set to required.Verify the behaviour @@ -496,7 +497,7 @@ public void ConfigurableCompressionAlgorithms() using (var session = MySQLX.GetSession(ConnectionString + ";compression=required;")) { var compressionAlgorithm = session.XSession.GetCompressionAlgorithm(true); - Assert.AreEqual(CompressionAlgorithms.lz4_message.ToString(), compressionAlgorithm); + Assert.That(compressionAlgorithm, Is.EqualTo(CompressionAlgorithms.lz4_message.ToString())); var ele = new List(); for (int i = 0; i < 1000; i++) { @@ -507,23 +508,23 @@ public void ConfigurableCompressionAlgorithms() var result = ExecuteAddStatement(coll.Add(ele.ToArray())); var result1 = session.SQL("select * from performance_schema.session_status where variable_name='Mysqlx_bytes_sent_uncompressed_frame' ").Execute().FetchOne()[1]; var result2 = session.SQL("select * from performance_schema.session_status where variable_name='Mysqlx_bytes_received_uncompressed_frame' ").Execute().FetchOne()[1]; - Assert.Greater(int.Parse(result1.ToString()), int.Parse(result2.ToString())); + Assert.That(int.Parse(result1.ToString()), Is.GreaterThan(int.Parse(result2.ToString()))); var result3 = session.SQL("select * from performance_schema.session_status where variable_name='Mysqlx_bytes_sent_compressed_payload' ").Execute().FetchOne()[1]; var result4 = session.SQL("select * from performance_schema.session_status where variable_name='Mysqlx_bytes_received_compressed_payload' ").Execute().FetchOne()[1]; - Assert.Greater(int.Parse(result3.ToString()), int.Parse(result4.ToString())); + Assert.That(int.Parse(result3.ToString()), Is.GreaterThan(int.Parse(result4.ToString()))); } using (var session = MySQLX.GetSession(ConnectionString + ";compression=required;compression-algorithms=[lz4_message]")) { var compressionAlgorithm = session.XSession.GetCompressionAlgorithm(true); - Assert.AreEqual(CompressionAlgorithms.lz4_message.ToString(), compressionAlgorithm); + Assert.That(compressionAlgorithm, Is.EqualTo(CompressionAlgorithms.lz4_message.ToString())); } // Server algorithm not contain user defined algorithm, with compression preferred using (var session = MySQLX.GetSession(ConnectionStringUri + "?compression-algorithms=[zstd];")) { var compressionAlgorithm = session.XSession.GetCompressionAlgorithm(true); - Assert.IsNull(compressionAlgorithm); + Assert.That(compressionAlgorithm, Is.Null); var ele = new List(); for (int i = 0; i < 1000; i++) @@ -535,14 +536,14 @@ public void ConfigurableCompressionAlgorithms() var result = ExecuteAddStatement(coll.Add(ele.ToArray())); var result1 = session.SQL("select * from performance_schema.session_status where variable_name='Mysqlx_bytes_sent_uncompressed_frame' ").Execute().FetchOne()[1]; var result2 = session.SQL("select * from performance_schema.session_status where variable_name='Mysqlx_bytes_received_uncompressed_frame' ").Execute().FetchOne()[1]; - Assert.AreEqual(result1, result2); + Assert.That(result2, Is.EqualTo(result1)); var result3 = session.SQL("select * from performance_schema.session_status where variable_name='Mysqlx_bytes_sent_compressed_payload' ").Execute().FetchOne()[1]; var result4 = session.SQL("select * from performance_schema.session_status where variable_name='Mysqlx_bytes_received_compressed_payload' ").Execute().FetchOne()[1]; - Assert.AreEqual(result3, result4); + Assert.That(result4, Is.EqualTo(result3)); } Exception ex_args = Assert.Throws(() => MySQLX.GetSession(ConnectionString + ";compression=required;compression_algorithms=[lz4_message]")); - StringAssert.Contains("Option not supported", ex_args.Message); + Assert.That(ex_args.Message, Does.Contain("Option not supported")); } [Test] @@ -557,24 +558,24 @@ public void CompressionAlgorithms_Bugs() using (var session = MySQLX.GetSession(ConnectionString + ";compression=required;compression-algorithms=[];")) { var compressionAlgorithm = session.XSession.GetCompressionAlgorithm(true); - Assert.IsNotNull(compressionAlgorithm); + Assert.That(compressionAlgorithm, Is.Not.Null); } // With only deflate available,Exeption expected ExecuteSqlAsRoot(@"SET GLOBAL mysqlx_compression_algorithms = ""DEFLATE_STREAM"" "); Exception ex_bug1 = Assert.Throws(() => MySQLX.GetSession(ConnectionString + ";compression=required;compression-algorithms=[];")); - StringAssert.Contains("Compression requested but the compression algorithm negotiation failed", ex_bug1.Message); + Assert.That(ex_bug1.Message, Does.Contain("Compression requested but the compression algorithm negotiation failed")); #else using (var session = MySQLX.GetSession(ConnectionString + ";compression=required;compression-algorithms=[];")) { var compressionAlgorithm = session.XSession.GetCompressionAlgorithm(true); - Assert.IsNotNull(compressionAlgorithm); + Assert.That(compressionAlgorithm, Is.Not.Null); } // With only deflate available,compression is expected ExecuteSqlAsRoot(@"SET GLOBAL mysqlx_compression_algorithms = ""DEFLATE_STREAM"" "); using (var session = MySQLX.GetSession(ConnectionString + ";compression=required;compression-algorithms=[];")) { var compressionAlgorithm = session.XSession.GetCompressionAlgorithm(true); - Assert.AreEqual(CompressionAlgorithms.deflate_stream.ToString(), compressionAlgorithm); + Assert.That(compressionAlgorithm, Is.EqualTo(CompressionAlgorithms.deflate_stream.ToString())); } #endif @@ -583,12 +584,12 @@ public void CompressionAlgorithms_Bugs() #if NETFRAMEWORK // Exeption expected due to compression=required Exception ex_bug2 = Assert.Throws(() => MySQLX.GetSession(ConnectionString + ";compression=required;compression-algorithms=deflate_stream;")); - StringAssert.Contains("is not supported in .NET Framework", ex_bug2.Message); + Assert.That(ex_bug2.Message, Does.Contain("is not supported in .NET Framework")); #else using (var session = MySQLX.GetSession(ConnectionString + ";compression=required;compression-algorithms=deflate_stream;")) { var compressionAlgorithm = session.XSession.GetCompressionAlgorithm(true); - Assert.AreEqual(CompressionAlgorithms.deflate_stream.ToString(), compressionAlgorithm); + Assert.That(compressionAlgorithm, Is.EqualTo(CompressionAlgorithms.deflate_stream.ToString())); } #endif } @@ -600,7 +601,7 @@ public void CompressionAlgorithms_Bugs() { // This line ensures that the list of supported compression algorithms is set to its default value. ExecuteSqlAsRoot(@"SET GLOBAL mysqlx_compression_algorithms = ""ZSTD_STREAM,LZ4_MESSAGE,DEFLATE_STREAM"" "); - Assert.True(success); + Assert.That(success); } } @@ -617,7 +618,7 @@ public void CompressionAlgorithms_Bugs() [Test, Description("Connection Compression tests to verify the values of compress option with connection string, uri, anonymous object, string builder")] public void ConnectionStringCombinations() { - if (!session.Version.isAtLeast(8, 0, 19)) Assert.Ignore("This test is for MySql Server 8.0.19 or higher."); + Assume.That(session.Version.isAtLeast(8, 0, 19), "This test is for MySql 8.0.19 or higher"); MySqlXConnectionStringBuilder sb = new MySqlXConnectionStringBuilder(ConnectionString); sb.SslCa = sslCa; @@ -629,17 +630,17 @@ public void ConnectionStringCombinations() { //ConnectionString session1 = MySQLX.GetSession(ConnectionStringUserWithSSLPEM + " ;Auth=AUTO;sslmode=" + modes[j] + ";compression=" + compressValue[i]); - Assert.AreEqual(SessionState.Open, session1.XSession.SessionState); + Assert.That(session1.XSession.SessionState, Is.EqualTo(SessionState.Open)); session1.Close(); //Uri session2 = MySQLX.GetSession(connSSLURI + "&sslmode=" + modes[j] + "&compression=" + compressValue[i]); - Assert.AreEqual(SessionState.Open, session2.XSession.SessionState); + Assert.That(session2.XSession.SessionState, Is.EqualTo(SessionState.Open)); session2.Close(); //Anonymous Object session3 = MySQLX.GetSession(new { server = sb.Server, user = sb.UserID, port = sb.Port, password = sb.Password, SslCa = sslCa, SslCert = sslCert, SslKey = sslKey, Auth = MySqlAuthenticationMode.AUTO, sslmode = modes[j], compression = compressValue[i] }); - Assert.AreEqual(SessionState.Open, session3.XSession.SessionState); + Assert.That(session3.XSession.SessionState, Is.EqualTo(SessionState.Open)); session3.Close(); //MySqlXConnectionStringBuilder @@ -647,7 +648,7 @@ public void ConnectionStringCombinations() sb.Auth = MySqlAuthenticationMode.AUTO; sb.Compression = compressValue[i]; session4 = MySQLX.GetSession(sb.ConnectionString); - Assert.AreEqual(SessionState.Open, session4.XSession.SessionState); + Assert.That(session4.XSession.SessionState, Is.EqualTo(SessionState.Open)); session4.Close(); } } @@ -656,20 +657,20 @@ public void ConnectionStringCombinations() for (int i = 0; i < 3; i++) { session1 = MySQLX.GetSession(ConnectionString + ";auth=AUTO;compression=" + compressValue[i]); - Assert.AreEqual(SessionState.Open, session1.XSession.SessionState); + Assert.That(session1.XSession.SessionState, Is.EqualTo(SessionState.Open)); session1.Close(); session2 = MySQLX.GetSession(ConnectionStringUri + "?compression=" + compressValue[i]); - Assert.AreEqual(SessionState.Open, session2.XSession.SessionState); + Assert.That(session2.XSession.SessionState, Is.EqualTo(SessionState.Open)); session2.Close(); session3 = MySQLX.GetSession(new { server = sb.Server, user = sb.UserID, port = sb.Port, password = sb.Password, compression = compressValue[i] }); - Assert.AreEqual(SessionState.Open, session3.XSession.SessionState); + Assert.That(session3.XSession.SessionState, Is.EqualTo(SessionState.Open)); session3.Close(); sb.Compression = compressValue[i]; session4 = MySQLX.GetSession(sb.ConnectionString); - Assert.AreEqual(SessionState.Open, session4.XSession.SessionState); + Assert.That(session4.XSession.SessionState, Is.EqualTo(SessionState.Open)); session4.Close(); } } @@ -678,23 +679,23 @@ public void ConnectionStringCombinations() [Test, Description("Verifying the connection pooling with compression option")] public void CompressionWithPolling() { - if (!session.Version.isAtLeast(8, 0, 19)) Assert.Ignore("This test is for MySql 8.0.19 or higher."); + Assume.That(session.Version.isAtLeast(8, 0, 19), "This test is for MySql 8.0.19 or higher"); for (int i = 0; i < 3; i++) { client = MySQLX.GetClient(ConnectionString + ";compression=" + compressValue[i], new { pooling = new { maxSize = 2, queueTimeout = 2000 } }); session1 = client.GetSession(); - Assert.AreEqual(SessionState.Open, session1.XSession.SessionState); + Assert.That(session1.XSession.SessionState, Is.EqualTo(SessionState.Open)); session1.Close(); session2 = client.GetSession(); - Assert.AreEqual(SessionState.Open, session2.XSession.SessionState); + Assert.That(session2.XSession.SessionState, Is.EqualTo(SessionState.Open)); session2.Close(); session1 = client.GetSession(); - Assert.AreEqual(SessionState.Open, session1.XSession.SessionState); + Assert.That(session1.XSession.SessionState, Is.EqualTo(SessionState.Open)); session2 = client.GetSession(); - Assert.AreEqual(SessionState.Open, session2.XSession.SessionState); + Assert.That(session2.XSession.SessionState, Is.EqualTo(SessionState.Open)); Assert.Throws(() => client.GetSession()); session1.Close(); @@ -705,7 +706,7 @@ public void CompressionWithPolling() [Test, Description("Verify if data sent is compressed")] public void VerifyDataSentCompression() { - if (!session.Version.isAtLeast(8, 0, 19)) Assert.Ignore("This test is for MySql 8.0.19 or higher."); + Assume.That(session.Version.isAtLeast(8, 0, 19), "This test is for MySql 8.0.19 or higher"); int BYTESIZE = 20000; string[] compressValue1 = new string[] { "preferred", "required", "required" }; string[] compressValue2 = new string[] { "disabled", "disabled", "preferred" }; @@ -730,17 +731,17 @@ public void VerifyDataSentCompression() schema.GetCollection("compressed"); var reader = session2.SQL("Select count(*) from compressed").Execute().FetchOne()[0]; var reader2 = session2.SQL("Select * from compressed").Execute().FetchAll(); - Assert.AreEqual("1", reader.ToString()); + Assert.That(reader.ToString(), Is.EqualTo("1")); // Results of compression when its value for session1 is: compressValue1[i] and for session2 is: compressValue2[i] var result1 = session1.SQL("select * from performance_schema.session_status where variable_name='Mysqlx_bytes_sent_uncompressed_frame' ").Execute().FetchOne()[1]; - Assert.IsNotNull(result1); + Assert.That(result1, Is.Not.Null); var result2 = session1.SQL("select * from performance_schema.session_status where variable_name='Mysqlx_bytes_received_uncompressed_frame' ").Execute().FetchOne()[1]; - Assert.IsNotNull(result2); + Assert.That(result2, Is.Not.Null); var result3 = session1.SQL("select * from performance_schema.session_status where variable_name='Mysqlx_bytes_sent_compressed_payload' ").Execute().FetchOne()[1]; - Assert.IsNotNull(result3); + Assert.That(result3, Is.Not.Null); var result4 = session1.SQL("select * from performance_schema.session_status where variable_name='Mysqlx_bytes_received_compressed_payload' ").Execute().FetchOne()[1]; - Assert.IsNotNull(result4); + Assert.That(result4, Is.Not.Null); if (Convert.ToInt32(result4) == 0 || Convert.ToInt32(result2) == 0) { Assert.Fail("Compression failed"); @@ -748,13 +749,13 @@ public void VerifyDataSentCompression() // Results of compression when its value for session2 is: compressValue1[i] and for session2 is: compressValue2[i] var result21 = session2.SQL("select * from performance_schema.session_status where variable_name='Mysqlx_bytes_sent_uncompressed_frame' ").Execute().FetchOne()[1]; - Assert.IsNotNull(result21); + Assert.That(result21, Is.Not.Null); var result22 = session2.SQL("select * from performance_schema.session_status where variable_name='Mysqlx_bytes_received_uncompressed_frame' ").Execute().FetchOne()[1]; - Assert.IsNotNull(result22); + Assert.That(result22, Is.Not.Null); var result23 = session2.SQL("select * from performance_schema.session_status where variable_name='Mysqlx_bytes_sent_compressed_payload' ").Execute().FetchOne()[1]; - Assert.IsNotNull(result23); + Assert.That(result23, Is.Not.Null); var result24 = session2.SQL("select * from performance_schema.session_status where variable_name='Mysqlx_bytes_received_compressed_payload' ").Execute().FetchOne()[1]; - Assert.IsNotNull(result24); + Assert.That(result24, Is.Not.Null); session1.Close(); session2.Close(); } @@ -763,7 +764,7 @@ public void VerifyDataSentCompression() [Test, Description("Verify if data read is compressed")] public void VerifyDataReadCompression() { - if (!session.Version.isAtLeast(8, 0, 19)) Assert.Ignore("This test is for MySql 8.0.19 or higher."); + Assume.That(session.Version.isAtLeast(8, 0, 19), "This test is for MySql 8.0.19 or higher"); const int BYTESIZE = 20000; string[] compressValue1 = new string[] { "preferred", "required" }; for (int i = 0; i < 2; i++) @@ -786,25 +787,25 @@ public void VerifyDataReadCompression() schema.GetCollection("compressed"); var reader = session2.SQL("Select count(*) from compressed").Execute().FetchOne()[0]; var reader2 = session2.SQL("Select * from compressed").Execute().FetchAll(); - Assert.AreEqual("1", reader.ToString()); + Assert.That(reader.ToString(), Is.EqualTo("1")); var result1 = session1.SQL("select * from performance_schema.session_status where variable_name='Mysqlx_bytes_sent_uncompressed_frame' ").Execute().FetchOne()[1]; - Assert.IsNotNull(result1); + Assert.That(result1, Is.Not.Null); var result2 = session1.SQL("select * from performance_schema.session_status where variable_name='Mysqlx_bytes_received_uncompressed_frame' ").Execute().FetchOne()[1]; - Assert.IsNotNull(result2); + Assert.That(result2, Is.Not.Null); var result3 = session1.SQL("select * from performance_schema.session_status where variable_name='Mysqlx_bytes_sent_compressed_payload' ").Execute().FetchOne()[1]; - Assert.IsNotNull(result3); + Assert.That(result3, Is.Not.Null); var result4 = session1.SQL("select * from performance_schema.session_status where variable_name='Mysqlx_bytes_received_compressed_payload' ").Execute().FetchOne()[1]; - Assert.IsNotNull(result4); + Assert.That(result4, Is.Not.Null); var result21 = session2.SQL("select * from performance_schema.session_status where variable_name='Mysqlx_bytes_sent_uncompressed_frame' ").Execute().FetchOne()[1]; - Assert.IsNotNull(result21); + Assert.That(result21, Is.Not.Null); var result22 = session2.SQL("select * from performance_schema.session_status where variable_name='Mysqlx_bytes_received_uncompressed_frame' ").Execute().FetchOne()[1]; - Assert.IsNotNull(result22); + Assert.That(result22, Is.Not.Null); var result23 = session2.SQL("select * from performance_schema.session_status where variable_name='Mysqlx_bytes_sent_compressed_payload' ").Execute().FetchOne()[1]; - Assert.IsNotNull(result23); + Assert.That(result23, Is.Not.Null); var result24 = session2.SQL("select * from performance_schema.session_status where variable_name='Mysqlx_bytes_received_compressed_payload' ").Execute().FetchOne()[1]; - Assert.IsNotNull(result24); + Assert.That(result24, Is.Not.Null); session1.Close(); session2.Close(); } @@ -814,7 +815,7 @@ public void VerifyDataReadCompression() [Test, Description("Verifying the threshold for compression")] public void CompressionThreshold() { - if (!session.Version.isAtLeast(8, 0, 19)) Assert.Ignore("This test is for MySql 8.0.19 or higher."); + Assume.That(session.Version.isAtLeast(8, 0, 19), "This test is for MySql 8.0.19 or higher"); using (session1 = MySQLX.GetSession(ConnectionString + ";compression=required")) { session1.SQL("DROP database if exists compression").Execute(); @@ -827,13 +828,13 @@ public void CompressionThreshold() collection.Add(doc1).Execute(); var result1 = session1.SQL("select * from performance_schema.session_status where variable_name='Mysqlx_bytes_sent_uncompressed_frame' ").Execute().FetchOne()[1]; - Assert.IsNotNull(result1); + Assert.That(result1, Is.Not.Null); var result2 = session1.SQL("select * from performance_schema.session_status where variable_name='Mysqlx_bytes_received_uncompressed_frame' ").Execute().FetchOne()[1]; - Assert.IsNotNull(result2); + Assert.That(result2, Is.Not.Null); var result3 = session1.SQL("select * from performance_schema.session_status where variable_name='Mysqlx_bytes_sent_compressed_payload' ").Execute().FetchOne()[1]; - Assert.IsNotNull(result3); + Assert.That(result3, Is.Not.Null); var result4 = session1.SQL("select * from performance_schema.session_status where variable_name='Mysqlx_bytes_received_compressed_payload' ").Execute().FetchOne()[1]; - Assert.IsNotNull(result4); + Assert.That(result4, Is.Not.Null); if (!Platform.IsWindows()) if (Convert.ToInt32(result2) != 0 || Convert.ToInt32(result4) != 0) @@ -845,13 +846,13 @@ public void CompressionThreshold() collection2.Add(doc2).Execute(); var result1b = session1.SQL("select * from performance_schema.session_status where variable_name='Mysqlx_bytes_sent_uncompressed_frame' ").Execute().FetchOne()[1]; - Assert.IsNotNull(result1b); + Assert.That(result1b, Is.Not.Null); var result2b = session1.SQL("select * from performance_schema.session_status where variable_name='Mysqlx_bytes_received_uncompressed_frame' ").Execute().FetchOne()[1]; - Assert.IsNotNull(result2b); + Assert.That(result2b, Is.Not.Null); var result3b = session1.SQL("select * from performance_schema.session_status where variable_name='Mysqlx_bytes_sent_compressed_payload' ").Execute().FetchOne()[1]; - Assert.IsNotNull(result3b); + Assert.That(result3b, Is.Not.Null); var result4b = session1.SQL("select * from performance_schema.session_status where variable_name='Mysqlx_bytes_received_compressed_payload' ").Execute().FetchOne()[1]; - Assert.IsNotNull(result4b); + Assert.That(result4b, Is.Not.Null); if (Convert.ToInt32(result4b) == 0 || Convert.ToInt32(result2b) == 0) Assert.Fail("Compression failed"); @@ -862,13 +863,13 @@ public void CompressionThreshold() collection3.Add(doc3).Execute(); var result1c = session1.SQL("select * from performance_schema.session_status where variable_name='Mysqlx_bytes_sent_uncompressed_frame' ").Execute().FetchOne()[1]; - Assert.IsNotNull(result1c); + Assert.That(result1c, Is.Not.Null); var result2c = session1.SQL("select * from performance_schema.session_status where variable_name='Mysqlx_bytes_received_uncompressed_frame' ").Execute().FetchOne()[1]; - Assert.IsNotNull(result2c); + Assert.That(result2c, Is.Not.Null); var result3c = session1.SQL("select * from performance_schema.session_status where variable_name='Mysqlx_bytes_sent_compressed_payload' ").Execute().FetchOne()[1]; - Assert.IsNotNull(result3c); + Assert.That(result3c, Is.Not.Null); var result4c = session1.SQL("select * from performance_schema.session_status where variable_name='Mysqlx_bytes_received_compressed_payload' ").Execute().FetchOne()[1]; - Assert.IsNotNull(result4c); + Assert.That(result4c, Is.Not.Null); if (Convert.ToInt32(result4c) == 0 || Convert.ToInt32(result2c) == 0) Assert.Fail("Compression failed"); @@ -878,7 +879,7 @@ public void CompressionThreshold() [Test, Description("Checking the network latency")] public void NetworkLatency() { - if (!session.Version.isAtLeast(8, 0, 19)) Assert.Ignore("This test is for MySql 8.0.19 or higher."); + Assume.That(session.Version.isAtLeast(8, 0, 19), "This test is for MySql 8.0.19 or higher"); const int BYTESIZE = 20000; Stopwatch watch1 = new Stopwatch(); Stopwatch watch2 = new Stopwatch(); @@ -911,7 +912,7 @@ public void NetworkLatency() watch2.Stop(); } - Assert.True(watch1.ElapsedTicks != watch2.ElapsedTicks, + Assert.That(watch1.ElapsedTicks != watch2.ElapsedTicks, $"Watch1: {watch1.ElapsedMilliseconds}, Watch2: {watch2.ElapsedMilliseconds}"); } #endregion @@ -932,4 +933,4 @@ protected string GenerateDummyText(string textToRepeat, int timesToRepeat) #endregion Methods } -} \ No newline at end of file +} diff --git a/MySQL.Data/tests/MySqlX.Data.Tests/CrudInsertTests.cs b/MySQL.Data/tests/MySqlX.Data.Tests/CrudInsertTests.cs index 69a02b978..80e1d31ef 100644 --- a/MySQL.Data/tests/MySqlX.Data.Tests/CrudInsertTests.cs +++ b/MySQL.Data/tests/MySqlX.Data.Tests/CrudInsertTests.cs @@ -1,2506 +1,2507 @@ -// Copyright (c) 2015, 2023, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data; -using MySql.Data.Common; -using MySql.Data.MySqlClient; -using MySqlX.Common; -using MySqlX.XDevAPI; -using MySqlX.XDevAPI.Common; -using MySqlX.XDevAPI.CRUD; -using MySqlX.XDevAPI.Relational; -using NUnit.Framework; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace MySqlX.Data.Tests -{ - public class CrudInsertTests : BaseTest - { - [Test] - public void InsertSingleDbDocWithId() - { - Collection coll = CreateCollection("test"); - Result r = ExecuteAddStatement(coll.Add(@"{ ""_id"": 1, ""foo"": 1 }")); - Assert.AreEqual(1, r.AffectedItemsCount); - Assert.AreEqual(1, coll.Count()); - } - - [Test] - public void InsertSingleDbDocWithoutId() - { - Collection coll = CreateCollection("test"); - var stmt = coll.Add("{ \"foo\": 1 }"); - if (!session.Version.isAtLeast(8, 0, 5)) - { - // Code 5115 Document is missing a required field - Assert.AreEqual(5115u, Assert.Throws(() => ExecuteAddStatement(stmt)).Code); - return; - } - Result r = ExecuteAddStatement(stmt); - Assert.AreEqual(1, r.AffectedItemsCount); - Assert.AreEqual(1, coll.Count()); - Assert.That(r.GeneratedIds, Has.One.Items); - Assert.False(string.IsNullOrWhiteSpace(r.GeneratedIds[0])); - } - - [Test] - public void InsertMultipleDbDocWithoutId() - { - Collection coll = CreateCollection("test"); - var stmt = coll.Add("{ \"foo\": 1 }") - .Add("{ \"amber\": 2 }") - .Add("{ \"any\": 3 }"); - if (!session.Version.isAtLeast(8, 0, 5)) - { - // Code 5115 Document is missing a required field - Assert.AreEqual(5115u, Assert.Throws(() => ExecuteAddStatement(stmt)).Code); - return; - } - Result r = ExecuteAddStatement(stmt); - Assert.AreEqual(3, r.AffectedItemsCount); - Assert.AreEqual(3, coll.Count()); - Assert.AreEqual(3, r.GeneratedIds.Count); - } - - [Test] - public void InsertAnonymousObjectWithId() - { - var obj = new { _id = "5", name = "Sakila", age = 15 }; - - Collection coll = CreateCollection("test"); - Result r = ExecuteAddStatement(coll.Add(obj)); - Assert.AreEqual(1, r.AffectedItemsCount); - //TODO: pull object and verify data - Assert.AreEqual(1, coll.Count()); - } - - [Test] - public void InsertAnonymousObjectWithNoId() - { - var obj = new { name = "Sakila", age = 15 }; - - Collection coll = CreateCollection("test"); - var stmt = coll.Add(obj); - if (!session.Version.isAtLeast(8, 0, 5)) - { - // Code 5115 Document is missing a required field - Assert.AreEqual(5115u, Assert.Throws(() => ExecuteAddStatement(stmt)).Code); - return; - } - Result r = ExecuteAddStatement(stmt); - Assert.AreEqual(1, r.AffectedItemsCount); - //TODO: pull object and verify data - Assert.AreEqual(1, coll.Count()); - Assert.That(r.GeneratedIds, Has.One.Items); - Assert.False(string.IsNullOrWhiteSpace(r.GeneratedIds[0])); - } - - [Test] - public void InsertMultipleAnonymousObjectsWithId() - { - Collection coll = CreateCollection("test"); - var docs = new[] - { - new { _id = 1, title = "Book 1", pages = 20 }, - new { _id = 2, title = "Book 2", pages = 30 }, - new { _id = 3, title = "Book 3", pages = 40 }, - new { _id = 4, title = "Book 4", pages = 50 }, - }; - Result r = ExecuteAddStatement(coll.Add(docs)); - Assert.AreEqual(4, r.AffectedItemsCount); - Assert.AreEqual(4, coll.Count()); - } - - [Test] - public void ValidatesDocumentIds() - { - Collection coll = CreateCollection("test"); - var stmt = coll.Add(new { name = "Book 1" }); - if (!session.Version.isAtLeast(8, 0, 5)) - { - // Code 5115 Document is missing a required field - Assert.AreEqual(5115u, Assert.Throws(() => ExecuteAddStatement(stmt)).Code); - return; - } - Result result = ExecuteAddStatement(stmt); - Assert.AreEqual(1, result.AffectedItemsCount); - - result = ExecuteModifyStatement(coll.Modify($"_id = '{result.GeneratedIds[0]}'").Set("pages", "20")); - Assert.AreEqual(1, result.AffectedItemsCount); - CollectionAssert.IsEmpty(result.GeneratedIds); - } - - [Test] - public void ReuseStatement() - { - Collection coll = CreateCollection("test"); - var docs = new[] - { - new { _id = 1, title = "Book 1", pages = 20 }, - new { _id = 2, title = "Book 2", pages = 30 }, - new { _id = 3, title = "Book 3", pages = 40 }, - new { _id = 4, title = "Book 4", pages = 50 }, - }; - var stmt = coll.Add(new { _id = 0 }); - foreach (var doc in docs) - { - stmt.Add(doc); - } - Result r = ExecuteAddStatement(stmt); - Assert.AreEqual((ulong)docs.Length + 1, r.AffectedItemsCount); - Assert.AreEqual(5, coll.Count()); - } - - [Test] - public void EmptyDocArray() - { - Collection coll = CreateCollection("test"); - - var insertResult = ExecuteAddStatement(coll.Add(new DbDoc[] { })); - Assert.AreEqual(0ul, insertResult.AffectedItemsCount); - - var result = ExecuteFindStatement(coll.Find()).FetchAll(); - CollectionAssert.IsEmpty(result); - } - - [Test] - public void NullParameter() - { - Collection coll = CreateCollection("test"); - - Assert.Throws(() => ExecuteAddStatement(coll.Add(null))); - } - - [Test] - public void InsertingArray() - { - var docs = new[] - { - new { id = 1, title = "Book 1" }, - new { id = 2, title = "Book 2" }, - }; - DbDoc d2 = new DbDoc(); - d2.SetValue("_id", 1); - d2.SetValue("books", docs); - d2.SetValue("pages", 20); - - Collection coll = CreateCollection("test"); - ExecuteAddStatement(coll.Add(d2)); - var result = ExecuteFindStatement(coll.Find()).FetchAll(); - Assert.That(result, Has.One.Items); - Assert.AreEqual(d2.ToString(), result[0].ToString()); - } - - [Test] - public void CompareGuids() - { - Guid guid1 = new Guid(); - Guid guid2 = new Guid(); - Assert.AreEqual(0, Tools.CompareGuids(guid1, guid2)); - Assert.AreEqual(0, Tools.CompareGuids(guid1.ToString(), guid2.ToString())); - - guid1 = Guid.NewGuid(); - guid2 = Guid.NewGuid(); - Assert.True(Tools.CompareGuids(guid1, guid2) != 0); - Assert.True(Tools.CompareGuids(guid1.ToString(), guid2.ToString()) != 0); - } - - [Test] - public void InsertNullValuesAsDbDoc() - { - Collection collection = CreateCollection("test"); - - var nullValues = new String[] { null, "null", "NULL" }; - var docs = new DbDoc[3]; - for (int i = 0; i < docs.Length; i++) - { - docs[i] = new DbDoc(); - docs[i].SetValue("a", nullValues[i]); - docs[i].SetValue("_id", (i + 1)); - } - - ExecuteAddStatement(collection.Add(docs)); - var result = ExecuteFindStatement(collection.Find()).FetchAll(); - Assert.AreEqual(docs.Length, result.Count); - - for (int i = 0; i < docs.Length; i++) - Assert.AreEqual(docs[i].ToString(), result[i].ToString()); - } - - [Test] - public void InsertNullValuesAsJson() - { - var docs = new[] - { - @"{ ""_id"": 1, ""foo"": null}", - @"{ ""_id"": 2, ""foo"": null }", - @"{ ""_id"": 3, ""foo"": ""null"" }", - @"{ ""_id"": 4, ""foo"": ""NULL"" }", - }; - - Collection collection = CreateCollection("test"); - ExecuteAddStatement(collection.Add(docs)); - var result = ExecuteFindStatement(collection.Find()).FetchAll(); - Assert.AreEqual(docs.Length, result.Count); - for (int i = 0; i < docs.Length; i++) - { - var currentDoc = new DbDoc(docs[i]); - var resultingDoc = new DbDoc(result[i]); - Assert.AreEqual(currentDoc.Id, resultingDoc.Id); - Assert.AreEqual(currentDoc["foo"], resultingDoc["foo"]); - } - } - - [Test] - public void AddOrReplaceOne() - { - if (!session.Version.isAtLeast(8, 0, 3)) return; - - Collection collection = CreateCollection("test"); - var docs = new[] - { - new { _id = 1, title = "Book 1", pages = 20 }, - new { _id = 2, title = "Book 2", pages = 30 }, - new { _id = 3, title = "Book 3", pages = 40 }, - new { _id = 4, title = "Book 4", pages = 50 }, - }; - Result result = ExecuteAddStatement(collection.Add(docs)); - Assert.AreEqual(4, result.AffectedItemsCount); - - // Add a document. - Assert.AreEqual(1, collection.AddOrReplaceOne(5, new { _id = 5, title = "Book 5", pages = 60 }).AffectedItemsCount); - Assert.True(collection.GetOne(5) != null); - - Assert.AreEqual(1, collection.AddOrReplaceOne("6", new { title = "Book 6", pages = 70 }).AffectedItemsCount); - Assert.True(collection.GetOne(6) != null); - Assert.True(collection.GetOne("6") != null); - - // Replace a document. - Assert.AreEqual(2, collection.AddOrReplaceOne(1, new { _id = 1, title = "Book X", pages = 10 }).AffectedItemsCount); - DbDoc document = collection.GetOne(1); - Assert.AreEqual(1, Convert.ToInt32(document.Id)); - Assert.AreEqual("Book X", document["title"]); - Assert.AreEqual(10, Convert.ToInt32(document["pages"])); - - Assert.AreEqual(2, collection.AddOrReplaceOne(1, new { title = "Book Y", pages = 9, other = "value" }).AffectedItemsCount); - document = collection.GetOne(1); - Assert.AreEqual(1, Convert.ToInt32(document.Id)); - Assert.AreEqual("Book Y", document["title"]); - Assert.AreEqual(9, Convert.ToInt32(document["pages"])); - Assert.AreEqual("value", document["other"]); - - // Expected exceptions. - Assert.Throws(() => collection.AddOrReplaceOne(null, docs[1])); - Assert.Throws(() => collection.AddOrReplaceOne("", docs[1])); - Assert.Throws(() => collection.AddOrReplaceOne(" ", docs[1])); - Assert.Throws(() => collection.AddOrReplaceOne(string.Empty, docs[1])); - Assert.Throws(() => collection.AddOrReplaceOne("1", null)); - Assert.Throws(() => collection.AddOrReplaceOne(4, new DbDoc("{ \"_id\": 2, \"title\": \"Book\", \"pages\": 60 }")), - ResourcesX.ReplaceWithNoMatchingId); - } - - #region WL14389 - - [Test, Description("Test MySQLX plugin Collection Scenarios - with Create a valid collection and reuse existing object")] - public void CreateCollectionAndReuseObject() - { - using (Session sessionPlain = MySQLX.GetSession(ConnectionString)) - { - var col = CreateCollection("my_collection_123456789"); - object[] data = new object[] - { - new { _id = 1, title = "Book 1", pages = 20 }, - new { _id = 2, title = "Book 2", pages = 30 }, - new { _id = 3, title = "Book 3", pages = 40 }, - new { _id = 4, title = "Book 4", pages = 50 }, - }; - Result result = col.Add(data).Execute(); - var data1 = col.Remove("_id = 1").Execute(); - Assert.AreEqual(1, (int)data1.AffectedItemsCount, "Matching the deleted record count"); - data1 = col.Remove("_id = 2").Execute(); - Assert.AreEqual(1, (int)data1.AffectedItemsCount, "Matching the deleted record count"); - data1 = col.Remove("_id = 3").Execute(); - Assert.AreEqual(1, (int)data1.AffectedItemsCount, "Matching the deleted record count"); - data1 = col.Remove("_id = 4").Execute(); - Assert.AreEqual(1, (int)data1.AffectedItemsCount, "Matching the deleted record count"); - sessionPlain.Close(); - } - } - - [Test, Description("Collection Scenarios - with Create a collection with emptyname")] - public void CreateCollectionEmptyName() - { - Schema db = session.GetSchema(schemaName); - Assert.Throws(() => db.CreateCollection(null)); - } - - [Test, Description("Test MySQLX plugin Collection Scenarios - with Create a collection which exists without reuse existing object")] - public void CreateCollectionWithoutReuseExistingObject() - { - Schema db = session.GetSchema(schemaName); - var col = CreateCollection("my_collection_123456789"); - col = db.GetCollection("my_collection_123456789", true); - Assert.IsNotNull(col); - Assert.Throws(() => db.CreateCollection("my_collection_123456789", false)); - } - - [Test, Description("Test MySQLX plugin Collection Scenarios - Add Objects,Find with condition")] - public void CollectionAddObjectsFindCondition() - { - Schema db = session.GetSchema(schemaName); - Collection col = CreateCollection("my_collection_1"); - var docs = new[] - { - new { _id = 1, title = "Book 1", pages = 20 }, - new { _id = 2, title = "Book 2", pages = 30 }, - new { _id = 3, title = "Book 3", pages = 40 }, - new { _id = 4, title = "Book 4", pages = 50 }, - }; - Result result = col.Add(docs).Execute(); - - Assert.AreEqual(4, (int)result.AffectedItemsCount, "Matching the updated record count"); - var foundDocs = col.Find("pages > 20").Execute(); - Assert.AreEqual(true, foundDocs.Next(), "Next Node Exist"); - Assert.AreEqual("Book 2", foundDocs.Current["title"], "Matching the Node Value"); - Assert.AreEqual(true, foundDocs.Next(), "Next Node Exist"); - Assert.AreEqual("Book 3", foundDocs.Current["title"], "Matching the Node Value"); - Assert.AreEqual(true, foundDocs.Next(), "Next Node Exist"); - Assert.AreEqual("Book 4", foundDocs.Current["title"], "Matching the Node Value"); - Assert.AreEqual(false, foundDocs.Next(), "Next Node doesnot Exist"); - db.DropCollection("my_collection_1"); - } - - [Test, Description("Test MySQLX plugin Collection Scenarios - Add Objects,Find without parameters")] - public void CollectionAddFindNoParams() - { - if (!session.Version.isAtLeast(5, 7, 0)) Assert.Ignore("This test is for MySql 5.7 or higher."); - Collection col = CreateCollection("my_collection_1"); - var docs = new[] - { - new { _id = 1, title = "Book 1", pages = 20 }, - new { _id = 2, title = "Book 2", pages = 30 }, - new { _id = 3, title = "Book 3", pages = 40 }, - new { _id = 4, title = "Book 4", pages = 50 }, - }; - - var result = col.Add(docs).Execute(); - Assert.AreEqual(4, (int)result.AffectedItemsCount, "Matching the updated record count"); - var foundDocs = col.Find().Execute(); - Assert.AreEqual(true, foundDocs.Next(), "Next Node Exist"); - Assert.AreEqual("Book 1", foundDocs.Current["title"], "Matching the Node Value"); - Assert.AreEqual(true, foundDocs.Next(), "Next Node Exist"); - Assert.AreEqual("Book 2", foundDocs.Current["title"], "Matching the Node Value"); - Assert.AreEqual(true, foundDocs.Next(), "Next Node Exist"); - Assert.AreEqual("Book 3", foundDocs.Current["title"], "Matching the Node Value"); - Assert.AreEqual(true, foundDocs.Next(), "Next Node Exist"); - Assert.AreEqual("Book 4", foundDocs.Current["title"], "Matching the Node Value"); - Assert.AreEqual(false, foundDocs.Next(), "Next Node doesnot Exist"); - } - - [Test, Description("Test MySQLX plugin Collection Scenarios - Add/Remove JSON Object with id")] - public void CollectionAddRemoveJSONObjectID() - { - if (!session.Version.isAtLeast(5, 7, 0)) Assert.Ignore("This test is for MySql 5.7 or higher."); - using (var sessionPlain = MySQLX.GetSession(ConnectionString + ";sslmode=" + MySqlSslMode.Required)) - { - Schema db = sessionPlain.GetSchema(schemaName); - Collection col = CreateCollection("my_collection_1"); - DbDoc DbDocs = new DbDoc(); - DbDocs.SetValue("_id", "0"); - DbDocs.SetValue("title", "Book 0"); - DbDocs.SetValue("pages", "10"); - var result = col.Add(DbDocs).Execute(); - Assert.AreEqual(1, (int)result.AffectedItemsCount, "Matching the updated record count"); - DbDoc jsonremovedoc = new DbDoc(); - jsonremovedoc.SetValue("_id", "0"); - var foundDocs = col.Remove("_id='0'").Execute(); - Assert.AreEqual(1, (int)foundDocs.AffectedItemsCount, "Matching the deleted record count"); - db.DropCollection("my_collection_1"); - sessionPlain.Close(); - } - } - - [Test, Description("Test MySQLX plugin Collection Scenarios - Add/Remove with condition")] - public void CollectionAddRemoveJSONObjectCondition() - { - if (!session.Version.isAtLeast(5, 7, 0)) Assert.Ignore("This test is for MySql 5.7 or higher."); - Schema db = session.GetSchema(schemaName); - Collection col = CreateCollection("my_collection_1"); - DbDoc DbDocs = new DbDoc(); - DbDocs.SetValue("_id", "0"); - DbDocs.SetValue("title", "Book 0"); - DbDocs.SetValue("pages", "10"); - var result = col.Add(DbDocs).Execute(); - Assert.AreEqual(1, (int)result.AffectedItemsCount, "Matching the updated record count"); - var foundDocs = col.Remove("pages > 0").Execute(); - Assert.AreEqual(1, (int)foundDocs.AffectedItemsCount, "Matching the deleted record count"); - db.DropCollection("my_collection_1"); - } - - [Test, Description("Test MySQLX plugin Collection Scenarios - Add,Remove with condition limit")] - public void CollectionAddRemoveObjectConditionLimit() - { - if (!session.Version.isAtLeast(5, 7, 0)) Assert.Ignore("This test is for MySql 5.7 or higher."); - Schema db = session.GetSchema(schemaName); - Collection col = CreateCollection("my_collection_1"); - var docs = new[] - { - new { _id = 0, title = "Book 0", pages = 10 }, - new { _id = 1, title = "Book 1", pages = 20 }, - new { _id = 2, title = "Book 2", pages = 30 }, - new { _id = 3, title = "Book 3", pages = 40 }, - new { _id = 4, title = "Book 4", pages = 50 }, - }; - var result = col.Add(docs).Execute(); - Assert.AreEqual(5, (int)result.AffectedItemsCount, "Matching the updated record count"); - var foundDocs = col.Remove("_id=1").Execute(); - Assert.AreEqual(1, (int)foundDocs.AffectedItemsCount, "Matching the deleted record count"); - docs = new[] - { - new { _id = 1, title = "Book 1", pages = 20 }, - }; - result = col.Add(docs).Execute(); - Assert.AreEqual(1, (int)result.AffectedItemsCount, "Matching the updated record count"); - result = col.Remove("pages > 10").Limit(1).Execute(); - Assert.AreEqual(1, (int)result.AffectedItemsCount, "Matching the updated record count"); - result = col.Remove("pages > 10").Limit(3).Execute(); - Assert.AreEqual(3, (int)result.AffectedItemsCount, "Matching the updated record count"); - Assert.Throws(() => col.Remove("pages > 10").Limit(0).Execute()); - db.DropCollection("my_collection_1"); - } - - [Test, Description("Test MySQLX plugin Collection Scenarios - Add/Remove 200 JSON records ")] - public void CollectionAddRemove200JSONRecords() - { - if (!session.Version.isAtLeast(5, 7, 0)) Assert.Ignore("This test is for MySql 5.7 or higher."); - Collection col = CreateCollection("my_collection_1"); - var numOfRecords = 200; - - DbDoc[] jsonlist = new DbDoc[numOfRecords]; - for (int i = 0; i < numOfRecords; i++) - { - DbDoc newDoc2 = new DbDoc(); - newDoc2.SetValue("_id", (i + 1000).ToString()); - newDoc2.SetValue("F1", ("Field-1-Data-" + i)); - newDoc2.SetValue("F2", ("Field-2-Data-" + i)); - newDoc2.SetValue("F3", (300 + i).ToString()); - jsonlist[i] = newDoc2; - newDoc2 = null; - } - var res = col.Add(jsonlist).Execute(); - - Assert.AreEqual(jsonlist[0].ToString(), jsonlist[0].ToString(), "String Match being done"); - for (int i = 0; i < numOfRecords; i++) - { - var data1 = col.Remove($"_id = '{i + 1000}'").Execute(); - Assert.AreEqual(1, (int)data1.AffectedItemsCount, "Matching the deleted record count"); - } - } - - [Test, Description("Test MySQLX plugin Collection Scenarios - Add/Remove documents with limit and orderby ")] - public void CollectionAddRemoveJSONRecordsLimitOrderBy() - { - if (!session.Version.isAtLeast(5, 7, 0)) Assert.Ignore("This test is for MySql 5.7 or higher."); - Schema db = session.GetSchema(schemaName); - Collection col = CreateCollection("my_collection_1"); - - DbDoc[] jsonlist = new DbDoc[10]; - for (int i = 0; i < 10; i++) - { - DbDoc newDoc2 = new DbDoc(); - newDoc2.SetValue("_id", (i).ToString()); - newDoc2.SetValue("F1", ("Field-1-Data-" + i)); - newDoc2.SetValue("F2", ("Field-2-Data-" + i)); - newDoc2.SetValue("F3", (300 + i)); - jsonlist[i] = newDoc2; - newDoc2 = null; - } - col.Add(jsonlist).Execute(); - Assert.AreEqual(jsonlist[0].ToString(), jsonlist[0].ToString(), "String Match being done"); - - Result result = col.Remove("F3 > 305").Limit(1).Execute(); - Assert.AreEqual(1, (int)result.AffectedItemsCount, "Match being done"); - - result = col.Remove("F3 > 303").Sort("F3 DESC").Execute(); - Assert.AreEqual(5, (int)result.AffectedItemsCount, "Match being done"); - - result = col.Remove("F3 > 303").Sort("F3 DESC").Execute(); - Assert.AreEqual(0, (int)result.AffectedItemsCount, "Match being done"); - - result = col.Remove("F3 = 303").Sort("F2 DESC").Execute(); - Assert.AreEqual(1, (int)result.AffectedItemsCount, "Match being done"); - - result = col.Remove("F3 < 301").Sort("F2 DESC").Execute(); - Assert.AreEqual(1, (int)result.AffectedItemsCount, "Match being done"); - - result = col.Remove("F3 < 301").Sort("F2 DESC").Execute(); - Assert.AreEqual(0, (int)result.AffectedItemsCount, "Match being done"); - - db.DropCollection("my_collection_1"); - - } - - [Test, Description("Test MySQLX plugin Collection Scenarios - Add Single/Multiple Docs - Remove Condition/ID/Condition-Limit/Condition-Limit-OrderBy/Bind")] - public void CollectionAddRemoveDocsLimitOrderByBind() - { - if (!session.Version.isAtLeast(5, 7, 0)) Assert.Ignore("This test is for MySql 5.7 or higher."); - Collection col = CreateCollection("my_collection_1"); - DbDoc DbDocs = new DbDoc(); - DbDocs.SetValue("_id", 100000); - DbDocs.SetValue("title", "Book 0"); - DbDocs.SetValue("pages", 10); - var result = col.Add(DbDocs).Execute(); - Assert.AreEqual(1, (int)result.AffectedItemsCount, "Matching the updated record count"); - var foundDocs = col.Remove("pages > 0").Execute(); - Assert.AreEqual(1, (int)foundDocs.AffectedItemsCount, "Matching the deleted record count"); - - var docs = new { _id = 100001, title = "Book 1", pages = 20 }; - result = col.Add(docs).Execute(); - Assert.AreEqual(1, (int)result.AffectedItemsCount, "Matching the updated record count"); - - foundDocs = col.Remove("pages=20").Execute(); - Assert.AreEqual(1, (int)foundDocs.AffectedItemsCount, "Matching the deleted record count"); - - docs = new { _id = -100001, title = "Book 1", pages = 20 }; - result = col.Add(docs).Execute(); - Assert.AreEqual(1, (int)result.AffectedItemsCount, "Matching the updated record count"); - - foundDocs = col.Remove("pages=20").Execute(); - Assert.AreEqual(1, (int)foundDocs.AffectedItemsCount, "Matching the deleted record count"); - var docs1 = new[] - { - new { _id = -100001, title = "Book 0", pages = 10 }, - new { _id = 0, title = "Book 1", pages = 20 }, - new { _id = 100001, title = "Book 2", pages = 30 }, - new { _id = 10000001, title = "Book 3", pages = 40 } - }; - result = col.Add(docs1).Execute(); - Assert.AreEqual(4, (int)result.AffectedItemsCount, "Matching the updated record count"); - - foundDocs = col.Remove("pages > 10").Execute(); - Assert.AreEqual(3, (int)foundDocs.AffectedItemsCount, "Matching the deleted record count"); - - foundDocs = col.Remove("pages=10").Execute(); - Assert.AreEqual(1, (int)foundDocs.AffectedItemsCount, "Matching the deleted record count"); - docs1 = new[] - { - new { _id = -100001, title = "Book 0", pages = 10 }, - new { _id = 0, title = "Book 1", pages = 20 }, - new { _id = 100001, title = "Book 2", pages = 30 }, - new { _id = 10000001, title = "Book 3", pages = 40 }, - new { _id = 10000009, title = "Book 4", pages = 50 } - }; - result = col.Add(docs1).Execute(); - Assert.AreEqual(5, (int)result.AffectedItemsCount, "Matching the updated record count"); - - foundDocs = col.Remove("pages = 40").Execute(); - Assert.AreEqual(1, (int)foundDocs.AffectedItemsCount, "Matching the deleted record count"); - - foundDocs = col.Remove("pages >= 10").Execute(); - Assert.AreEqual(4, (int)foundDocs.AffectedItemsCount, "Matching the deleted record count"); - - result = col.Add(docs1).Execute(); - Assert.AreEqual(5, (int)result.AffectedItemsCount, "Matching the updated record count"); - foundDocs = col.Remove("pages = 40").Limit(1).Execute(); - Assert.AreEqual(1, (int)foundDocs.AffectedItemsCount, "Matching the deleted record count"); - foundDocs = col.Remove("pages <= 50").Execute(); - Assert.AreEqual(4, (int)foundDocs.AffectedItemsCount, "Matching the deleted record count"); - - result = col.Add(docs1).Execute(); - Assert.AreEqual(5, (int)result.AffectedItemsCount, "Matching the updated record count"); - foundDocs = col.Remove("pages = 40").Limit(1).Sort("title").Execute(); - Assert.AreEqual(1, (int)foundDocs.AffectedItemsCount, "Matching the deleted record count"); - foundDocs = col.Remove("pages <= 50").Execute(); - Assert.AreEqual(4, (int)foundDocs.AffectedItemsCount, "Matching the deleted record count"); - - docs1 = new[] - { - new { _id = 1, title = "Book 1", pages = 20 }, - new { _id = 2, title = "Book 2", pages = 30 }, - new { _id = 3, title = "Book 3", pages = 40 }, - new { _id = 4, title = "Book 4", pages = 50 }, - }; - - result = col.Add(docs1).Execute(); - Assert.AreEqual(4, (int)result.AffectedItemsCount, "Matching the updated record count"); - foundDocs = col.Remove("pages = :Pages").Bind("pAges", 50).Execute(); - Assert.AreEqual(1, (int)foundDocs.AffectedItemsCount, "Matching the deleted record count"); - } - - [Test, Description("Test MySQLX plugin Collection Scenarios - Add Single/Multiple Docs - Remove Condition/ID/Condition-Limit/Condition-Limit-OrderBy/Bind using invalid conditions")] - public void CollectionRemoveDocsLimitOrderByBindNegative() - { - if (!session.Version.isAtLeast(5, 7, 0)) Assert.Ignore("This test is for MySql 5.7 or higher."); - Schema db = session.GetSchema(schemaName); - var col = db.CreateCollection("my_collection_1", true); - - DbDoc DbDocs = new DbDoc(); - DbDocs.SetValue("_id", 100000); - DbDocs.SetValue("title", "Book 0"); - DbDocs.SetValue("pages", 10); - var result = col.Add(DbDocs).Execute(); - - Assert.AreEqual(1, (int)result.AffectedItemsCount, "Matching the updated record count"); - var foundDocs = col.Remove("pages > 10").Execute(); - Assert.AreEqual(0, (int)foundDocs.AffectedItemsCount, "Matching the deleted record count"); - - var docs = new { _id = 100001, title = "Book 1", pages = 20 }; - result = col.Add(docs).Execute(); - Assert.AreEqual(1, (int)result.AffectedItemsCount, "Matching the updated record count"); - - foundDocs = col.Remove("pages >= 10").Execute(); - Assert.AreEqual(2, (int)foundDocs.AffectedItemsCount, "Matching the deleted record count"); - - docs = new { _id = -100001, title = "Book 1", pages = 20 }; - result = col.Add(docs).Execute(); - Assert.AreEqual(1, (int)result.AffectedItemsCount, "Matching the updated record count"); - - foundDocs = col.Remove("pages > 10").Execute(); - Assert.AreEqual(1, (int)foundDocs.AffectedItemsCount, "Matching the deleted record count"); - - - var docs1 = new[] - { - new { _id = -100001, title = "Book 0", pages = 10 }, - new { _id = 0, title = "Book 1", pages = 20 }, - new { _id = 100001, title = "Book 2", pages = 30 }, - new { _id = 10000001, title = "Book 3", pages = 40 } - }; - result = col.Add(docs1).Execute(); - Assert.AreEqual(4, (int)result.AffectedItemsCount, "Matching the updated record count"); - - foundDocs = col.Remove("pages > 50").Execute(); - Assert.AreEqual(0, (int)foundDocs.AffectedItemsCount, "Matching the deleted record count"); - - foundDocs = col.Remove("pages < 50").Execute(); - Assert.AreEqual(4, (int)foundDocs.AffectedItemsCount, "Matching the deleted record count"); - - docs1 = new[] - { - new { _id = -100001, title = "Book 0", pages = 10 }, - new { _id = 0, title = "Book 1", pages = 20 }, - new { _id = 100001, title = "Book 2", pages = 30 }, - new { _id = 10000001, title = "Book 3", pages = 40 }, - new { _id = 10000009, title = "Book 4", pages = 50 } - }; - result = col.Add(docs1).Execute(); - Assert.AreEqual(5, (int)result.AffectedItemsCount, "Matching the updated record count"); - - foundDocs = col.Remove("pages = 0").Execute(); - Assert.AreEqual(0, (int)foundDocs.AffectedItemsCount, "Matching the deleted record count"); - - foundDocs = col.Remove("pages <= 50").Execute(); - Assert.AreEqual(5, (int)foundDocs.AffectedItemsCount, "Matching the deleted record count"); - - result = col.Add(docs1).Execute(); - Assert.AreEqual(5, (int)result.AffectedItemsCount, "Matching the updated record count"); - foundDocs = col.Remove("pages = 60").Limit(1).Execute(); - Assert.AreEqual(0, (int)foundDocs.AffectedItemsCount, "Matching the deleted record count"); - - foundDocs = col.Remove("pages <= 50").Execute(); - Assert.AreEqual(5, (int)foundDocs.AffectedItemsCount, "Matching the deleted record count"); - - result = col.Add(docs1).Execute(); - Assert.AreEqual(5, (int)result.AffectedItemsCount, "Matching the updated record count"); - foundDocs = col.Remove("pages = 04").Limit(1).Sort("title").Execute(); - Assert.AreEqual(0, (int)foundDocs.AffectedItemsCount, "Matching the deleted record count"); - foundDocs = col.Remove("pages <= 50").Execute(); - Assert.AreEqual(5, (int)foundDocs.AffectedItemsCount, "Matching the deleted record count"); - - docs1 = new[] - { - new { _id = 1, title = "Book 1", pages = 20 }, - new { _id = 2, title = "Book 2", pages = 30 }, - new { _id = 3, title = "Book 3", pages = 40 }, - new { _id = 4, title = "Book 4", pages = 50 }, - }; - - result = col.Add(docs1).Execute(); - Assert.AreEqual(4, (int)result.AffectedItemsCount, "Matching the updated record count"); - foundDocs = col.Remove("pages1 = :Pages").Bind("pAges", 50).Execute(); - Assert.AreEqual(0, (int)foundDocs.AffectedItemsCount, "Matching the deleted record count"); - foundDocs = col.Remove("pages = :Pages").Bind("pAges", 51).Execute(); - Assert.AreEqual(0, (int)foundDocs.AffectedItemsCount, "Matching the deleted record count"); - foundDocs = col.Remove("pages = :Pages").Bind("pAges", 50).Execute(); - Assert.AreEqual(1, (int)foundDocs.AffectedItemsCount, "Matching the deleted record count"); - db.DropCollection("my_collection_1"); - - } - - [Test, Description("Test MySQLX plugin - MYSQLCNET_680 Allow Reuse Statement after execute Positive1(after a succesful execute)")] - public void AllowReuseStatementAfterExecutePositive1() - { - if (!session.Version.isAtLeast(5, 7, 0)) Assert.Ignore("This test is for MySql 5.7 or higher."); - Schema db = session.GetSchema(schemaName); - var col = db.CreateCollection("my_collection_123456789"); - object[] data = new object[] - { - new { _id = 1, title = "Book 1", pages = 10 }, - new { _id = 2, title = "Book 2", pages = 20 }, - new { _id = 3, title = "Book 3", pages = 30 }, - new { _id = 4, title = "Book 4", pages = 40 }, - new { _id = 5, title = "Book 5", pages = 50 }, - new { _id = 6, title = "Book 6", pages = 60 }, - new { _id = 7, title = "Book 7", pages = 70 }, - new { _id = 8, title = "Book 8", pages = 80 }, - }; - Result result = col.Add(data).Execute(); - Assert.AreEqual(8, (int)result.AffectedItemsCount, "Matching the added record count"); - var data1 = col.Remove("_id=1").Execute(); - Assert.AreEqual(1, (int)data1.AffectedItemsCount, "Matching the deleted record count"); - data1 = col.Remove("pages = :Pages").Bind("pAges", 80).Execute(); - Assert.AreEqual(1, (int)data1.AffectedItemsCount, "Matching the deleted record count"); - data1 = col.Remove("pages = :Pages").Bind("pAges", 70).Execute(); - Assert.AreEqual(1, (int)data1.AffectedItemsCount, "Matching the deleted record count"); - var remData = col.Remove("_id = :param1 AND title = :param2"); - data1 = remData.Bind("param1", 5).Bind("param2", "Book 5").Execute(); - Assert.AreEqual(1, (int)data1.AffectedItemsCount, "Matching the deleted record count"); - data1 = remData.Bind("param1", 6).Bind("param2", "Book 6").Execute(); - Assert.AreEqual(1, (int)data1.AffectedItemsCount, "Matching the deleted record count"); - db.DropCollection("my_collection_123456789"); - } - - [Test, Description("Test MySQLX plugin - MYSQLCNET_680 Allow Reuse Statement after execute-Positive2(after an unsuccessful execute)")] - public void AllowReuseStatementAfterExecutePositive2() - { - var col = CreateCollection("my_collection_123456789"); - object[] data = new object[] - { - new { _id = 1, title = "Book 1", pages = 10 }, - new { _id = 2, title = "Book 2", pages = 20 }, - new { _id = 3, title = "Book 3", pages = 30 }, - new { _id = 4, title = "Book 4", pages = 40 }, - new { _id = 5, title = "Book 5", pages = 50 }, - new { _id = 6, title = "Book 6", pages = 60 }, - new { _id = 7, title = "Book 7", pages = 70 }, - new { _id = 8, title = "Book 8", pages = 80 }, - }; - Result result = col.Add(data).Execute(); - Assert.AreEqual(8, (int)result.AffectedItemsCount, "Matching the added record count"); - var data1 = col.Remove("_id=1").Execute(); - Assert.AreEqual(1, (int)data1.AffectedItemsCount, "Matching the deleted record count"); - data1 = col.Remove("pages = :Pages").Bind("pAges", 80).Execute(); - Assert.AreEqual(1, (int)data1.AffectedItemsCount, "Matching the deleted record count"); - data1 = col.Remove("pages = :Pages").Bind("pAges", 70).Execute(); - Assert.AreEqual(1, (int)data1.AffectedItemsCount, "Matching the deleted record count"); - var remData = col.Remove("_id = :param1 AND title = :param2"); - - data1 = remData.Bind("param1", 35).Bind("param2", "Book 33").Execute(); - Assert.AreEqual(0, (int)data1.AffectedItemsCount, "Matching the deleted record count"); - - data1 = remData.Bind("param1", 6).Bind("param2", "Book 6").Execute(); - Assert.AreEqual(1, (int)data1.AffectedItemsCount, "Matching the deleted record count"); - testSchema.DropCollection("my_collection_123456789"); - } - - [Test, Description("Test MySQLX plugin - MYSQLCNET 755 Collection GetDocumentID")] - public void CollectionGetDocumentID() - { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher."); - Collection coll = CreateCollection("test"); - var docs = new[] - { - new { _id = 100, title = "Book 100", pages = 1000 }, - }; - Result result = coll.Add(docs).Execute(); - var documentIds = result.GeneratedIds; - Assert.False(documentIds != null && documentIds.Count > 0); - - coll = CreateCollection("test"); - var docs1 = new[] - { - new { title = "Book 1", pages = 100 }, - }; - var r = coll.Add(docs1); - var result1 = r.Execute(); - var documentIds1 = result.GeneratedIds; - HashSet firstset = new HashSet(); - for (int i = 0; i < documentIds.Count; i++) - { - if (documentIds1 != null) - { - Assert.AreEqual(documentIds1[i].ToString(), documentIds1[i].ToString(), "Matching the document ID with unique id"); - } - if (!firstset.Add(documentIds1[i])) - { - break; - } - } - - coll = CreateCollection("test"); - docs = new[] - { - new { _id = 100, title = "Book 100", pages = 1000 }, - new { _id = 200, title = "Book 200", pages = 2000 }, - new { _id = 300, title = "Book 300", pages = 3000 }, - new { _id = 400, title = "Book 400", pages = 4000 }, - }; - - var r1 = coll.Add(docs).Execute(); - documentIds = r1.GeneratedIds; - Assert.False(documentIds != null && documentIds.Count > 0); - - coll = CreateCollection("test"); - docs1 = new[] - { - new { title = "Book 1", pages = 100 }, - new { title = "Book 2", pages = 200 }, - new { title = "Book 3", pages = 300 }, - new { title = "Book 4", pages = 400 }, - }; - - var stmt = coll.Add(docs1); - result1 = stmt.Execute(); - documentIds1 = result1.GeneratedIds; - firstset = new HashSet(); - for (int i = 0; i < documentIds1.Count; i++) - { - if (documentIds != null) - { - Assert.AreEqual(documentIds1[i].ToString(), documentIds1[i].ToString(), "Matching the document ID with unique id"); - } - - if (!firstset.Add(documentIds1[i])) - { - break; - } - } - } - - [Test, Description("Test MySQLX UUID Scenario-1(Check UUID is not generated when JSON doc is added using collection.add() with _id fields)")] - public void CheckDocUUIDScenario1() - { - var col = CreateCollection("my_collection_123456789"); - object[] data = new object[] - { - new { _id = 1, title = "Book 1", pages = 20 }, - new { _id = 2, title = "Book 2", pages = 30 }, - new { _id = 3, title = "Book 3", pages = 40 }, - new { _id = 4, title = "Book 4", pages = 50 }, - }; - Result result = col.Add(data).Execute(); - var documentIds = result.GeneratedIds; - Assert.False(documentIds != null && documentIds.Count > 0); - } - - [Test, Description("Test MySQLX UUID Scenario-2(Check UUID generated when multiple JSON docs are added using collection.add().add()..without _id fields)")] - public void CheckDocUUIDScenario2() - { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher."); - var col = CreateCollection("my_collection_123456789"); - object[] data1 = new object[] - { - new { title ="Book 1", pages = 20 }, - new { title = "Book 2", pages = 30 }, - new { title = "Book 3", pages = 40 }, - new { title = "Book 4", pages = 50 } - }; - - object[] data2 = new object[] - { - new { title = "Book 5", pages = 60 }, - new {title = "Book 6", pages = 70 }, - new { title = "Book 7", pages = 80 }, - new { title = "Book 8", pages = 90 }, - }; - var stmt = col.Add(data1).Add(data2); - var result = stmt.Execute(); - var documentIds = result.GeneratedIds; - HashSet firstset = new HashSet(); - for (int i = 0; i < documentIds.Count; i++) - { - if (documentIds != null) - { - Assert.AreEqual(documentIds[i].ToString(), documentIds[i].ToString(), "Matching the document ID with unique id"); - } - if (!firstset.Add(documentIds[i])) - { - Console.WriteLine("Contains duplicate ID"); - break; - } - } - } - - [Test, Description("Test MySQLX UUID Scenario-2(Check UUID generated when multiple JSON docs are added using collection.add(doc, doc, doc... ) without _id fields)")] - public void CheckDocUUIDScenario3() - { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher."); - var col = CreateCollection("my_collection_123456789"); - var stmt = col.Add(@"{ ""foo"": 1 }", @"{""foo"": 2 }", @"{ ""foo"": 3 }", @"{ ""foo"": 4 }"); - Result r = col.Add(@"{ ""foo"": 1 }", @"{""foo"": 2 }", @"{ ""foo"": 3 }", @"{ ""foo"": 4 }").Execute(); - long count = col.Count(); - Assert.AreEqual(count, 4, "Matching the Collection Count"); - var documentIds = r.GeneratedIds; - if (documentIds != null) - { - Assert.AreEqual(documentIds[0].ToString(), documentIds[0].ToString(), "Matching the document ID without unique id"); - Assert.AreEqual(documentIds[1].ToString(), documentIds[1].ToString(), "Matching the document ID without unique id"); - Assert.AreEqual(documentIds[2].ToString(), documentIds[2].ToString(), "Matching the document ID without unique id"); - Assert.AreEqual(documentIds[3].ToString(), documentIds[3].ToString(), "Matching the document ID without unique id"); - } - - var collectionName = col.Name; - Assert.AreEqual(collectionName, "my_collection_123456789", "Matching the collection Name"); - Assert.AreEqual(schemaName, col.Schema.Name, "Matching the Schema Name"); - } - - [Test, Description("Test MySQLX UUID Scenario-4(Check UUID generated when multiple JSON docs are added using some containing and some not containing _id fields)")] - public void CheckDocUUIDScenario4() - { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher."); - var col = CreateCollection("my_collection_123456789"); - object[] data1 = new object[] - { - new { _id = 1, title = "Book 1", pages = 20 }, - new { _id = 2, title = "Book 2", pages = 30 }, - new { _id = 3, title = "Book 3", pages = 40 }, - new { title = "Book 4", pages = 50 } - }; - - object[] data2 = new object[] - { - new { title = "Book 5", pages = 60 }, - new { _id = 6,title = "Book 6", pages = 70 }, - new { title = "Book 7", pages = 80 }, - new { title = "Book 8", pages = 90 }, - }; - - var stmt = col.Add(data1).Add(data2); - Result result = stmt.Execute(); - var documentIdsCount = result.GeneratedIds.Count; - var documentIds = result.GeneratedIds; - Assert.AreEqual(4, documentIdsCount, "Matching the document ID count"); - if (documentIds != null) - { - Assert.AreEqual(documentIds[0].ToString(), documentIds[0].ToString(), "Matching the document ID with unique id"); - Assert.AreEqual(documentIds[1].ToString(), documentIds[1].ToString(), "Matching the document ID with unique id"); - Assert.AreEqual(documentIds[2].ToString(), documentIds[2].ToString(), "Matching the document ID with unique id"); - Assert.AreEqual(documentIds[3].ToString(), documentIds[3].ToString(), "Matching the document ID without unique id"); - } - } - - [Test, Description("Test MySQLX UUID Scenario-5(Check that UUID is not generated by adding multiple doc from the same collection in a session with _id fields)")] - public void CheckDocUUIDScenario5() - { - Collection testCollection = CreateCollection("test"); - DbDoc[] jsonlist = new DbDoc[1000]; - for (int i = 0; i < 1000; i++) - { - DbDoc newDoc2 = new DbDoc(); - newDoc2.SetValue("_id", (i + 1000)); - newDoc2.SetValue("F1", ("Field-1-Data-" + i)); - newDoc2.SetValue("F2", ("Field-2-Data-" + i)); - newDoc2.SetValue("F3", (300 + i).ToString()); - jsonlist[i] = newDoc2; - newDoc2 = null; - } - Result r = testCollection.Add(jsonlist).Execute(); - Assert.AreEqual(1000, r.AffectedItemsCount, "Matching"); - var documentIds = r.GeneratedIds; - Assert.False(documentIds != null && documentIds.Count > 0); - - Schema testSchema = session.GetSchema(schemaName); - Table test = testSchema.GetCollectionAsTable("test"); - Assert.AreEqual(true, test.ExistsInDatabase(), "Matching"); - } - - [Test, Description("Test MySQLX UUID Scenario-6(Check that no duplicate UUID is generated by adding multiple doc from the same collection in a session when there are no _id fields)")] - public void CheckDocUUIDScenario6() - { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher."); - Collection testCollection = CreateCollection("test"); - DbDoc[] jsonlist = new DbDoc[1000]; - for (int i = 0; i < 1000; i++) - { - DbDoc newDoc2 = new DbDoc(); - newDoc2.SetValue("F1", ("Field-1-Data-" + i)); - newDoc2.SetValue("F2", ("Field-2-Data-" + i)); - newDoc2.SetValue("F3", (300 + i).ToString()); - jsonlist[i] = newDoc2; - newDoc2 = null; - } - - var r = testCollection.Add(jsonlist); - var result = r.Execute(); - var countgenerateIDs = result.GeneratedIds.Count; - Assert.AreEqual(1000, countgenerateIDs, "Count of the ID generated by the server"); - for (int i = 0; i < countgenerateIDs; i++) - { - var generatedIDs1 = result.GeneratedIds[i]; - Assert.AreEqual(generatedIDs1, generatedIDs1, "ID generated by the server"); - } - - Schema testSchema = session.GetSchema(schemaName); - Table test = testSchema.GetCollectionAsTable("test"); - Assert.AreEqual(true, test.ExistsInDatabase(), "Matching"); - } - - [Test, Description("Test MySQLX UUID Scenario-7(Check UUID generated when multiple JSON docs are added using collection.add(doc, doc, doc... ) when docs contains _id fields with negative numbers,big positive numbers)")] - public void CheckDocUUIDScenario7() - { - var col = CreateCollection("my_collection_123456789"); - object[] data1 = new object[] - { - new { _id = -1, title = "Book 1", pages = 20 }, - new { _id = 200000000, title = "Book 2", pages = 30 }, - new { _id = -300000000, title = "Book 3", pages = 40 }, - new { title = "Book 4", pages = 50 } - }; - - object[] data2 = new object[] - { - new { title = "Book 5", pages = 60 }, - new { _id = 60000000000000,title = "Book 6", pages = 70 }, - new { title = "Book 7", pages = 80 }, - new { title = "Book 8", pages = 90 }, - }; - - var r = col.Add(data1).Add(data2); - var result = r.Execute(); - var countgenerateIDs = result.GeneratedIds.Count; - Assert.AreEqual(4, countgenerateIDs, "Count of the ID generated by the server"); - for (int i = 0; i < countgenerateIDs; i++) - { - var generatedIDs1 = result.GeneratedIds[i]; - Assert.AreEqual(generatedIDs1, generatedIDs1, "ID generated by the server"); - } - - } - - [Test, Description("Test MySQLX UUID Scenario-8(Check UUID generated when multiple JSON docs are added using collection.add(doc, doc, doc... ) when docs contains _id fields with zero,strings)")] - public void CheckDocUUIDScenario8() - { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher."); - var col = CreateCollection("my_collection_123456789"); - object[] data1 = new object[] - { - new { _id = 0, title = "Book 1", pages = 20 }, - new { _id = "test1", title = "Book 2", pages = 30 }, - new { _id = "^%$^&&%)(*&", title = "Book 3", pages = 40 }, - new { title = "Book 4", pages = 50 } - }; - - object[] data2 = new object[] - { - new { title = "Book 5", pages = 60 }, - new { _id = 60000000000000,title = "Book 6", pages = 70 }, - new { title = "Book 7", pages = 80 }, - new { title = "Book 8", pages = 90 }, - }; - - var r = col.Add(data1).Add(data2); - var result = r.Execute(); - var countgenerateIDs = result.GeneratedIds.Count; - Assert.AreEqual(4, countgenerateIDs, "Count of the ID generated by the server"); - for (int i = 0; i < countgenerateIDs; i++) - { - var generatedIDs1 = result.GeneratedIds[i]; - Assert.AreEqual(generatedIDs1, generatedIDs1, "ID generated by the server"); - } - - } - - [Test, Description("Test MySQLX UUID Scenario-9(Check the behaviour when JSON docs are added using collection.add(doc) when docs contains _id fields with (blank)")] - public void CheckDocUUIDScenario9() - { - Collection testCollection = CreateCollection("test"); - DbDoc[] jsonlist = new DbDoc[1]; - for (int i = 0; i < 1; i++) - { - DbDoc newDoc2 = new DbDoc(); - newDoc2.SetValue("_id", " "); - newDoc2.SetValue("F1", ("Field-1-Data-" + i)); - newDoc2.SetValue("F2", ("Field-2-Data-" + i)); - newDoc2.SetValue("F3", (300 + i).ToString()); - jsonlist[i] = newDoc2; - } - - Result result = testCollection.Add(jsonlist).Execute(); - //ID with blank could be added as per bug#27627861 as client will not do any validation and server will do" - Assert.IsNotNull(result); - - Schema testSchema = session.GetSchema("test"); - Table test = testSchema.GetCollectionAsTable("test"); - Assert.AreEqual(true, test.ExistsInDatabase(), "Matching"); - } - - [Test, Description("Test MySQLX plugin Collection JSON Depth Scenarios")] - public void CollectionAddJSONDepth() - { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher."); - int i, maxArrayelement = 100; - Collection col = CreateCollection("my_collection_1"); - Collection col1 = CreateCollection("my_collection_2"); - - DbDoc d1 = new DbDoc(); - for (i = 0; i < maxArrayelement; i++) - { - d1.SetValue("_id" + "_" + i.ToString(), 10000); - d1.SetValue("person" + "_" + i.ToString(), "Person" + "_" + i.ToString()); - } - - var result = col1.Add(d1).Execute(); - Assert.Greater(result.AffectedItemsCount, 0); - - var data1 = new DbDoc(@"{ ""_id"": 1, ""pages"": 20, - ""person"": { ""name"": ""Fred"", ""age"": 45 } - }"); - var data2 = new DbDoc(@"{ ""_id"": 1, ""pages"": 20, - ""books"": [ - {""_id"" : 1, ""title"" : ""Book 1""}, - { ""_id"" : 2, ""title"" : ""Book 2"" } - ] - }"); - DbDoc d2 = new DbDoc(); - d2.SetValue("_id", 1); - d2.SetValue("pages", 20); - d2.SetValue("taker1", data1); - d2.SetValue("taker2", data2); - - result = col.Add(d2).Execute(); - Assert.Greater(result.AffectedItemsCount, 0); - - var result1 = col1.Find().Execute().FetchAll(); - Assert.AreEqual(1, result1.Count); - var result2 = col.Find().Execute().FetchAll(); - Assert.AreEqual(1, result2.Count); - } - - [Test, Description("Test MySQLX plugin Collection Add function with null")] - public void CollectionAddNullFind() - { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher."); - int i = 1; - Collection col = CreateCollection("my_collection_1"); - var d1 = new DbDoc(); - d1.SetValue("id" + "_" + i.ToString(), "test"); - Assert.AreEqual(1, col.Add(d1).Execute().AffectedItemsCount); - var result1 = col.Find(null).Execute(); - Assert.AreEqual(0, result1.AffectedItemsCount); - Assert.Throws(() => col.Add(null).Execute()); - var result2 = col.Add().Execute(); - Assert.AreEqual(0, result2.AffectedItemsCount); - } - - [Test, Description("Test MySQLX plugin Invalid JSON String")] - public void InvalidJSONString() - { - Collection col = CreateCollection("my_collection_1"); - String json = ""; - json = "{'_id':'1004','F1': [] }"; - Exception ex = Assert.Throws(() => col.Add(json).Execute()); - StringAssert.Contains("The value provided is not a valid JSON document", ex.Message); - } - - [Test, Description("Test MySQLX plugin JSON String long expression")] - public void JSONStringLongExpression() - { - if (Platform.IsMacOSX()) Assert.Ignore("Check failure on MacOS: stack overflow");// TO DO - - Collection col = CreateCollection("my_collection_1"); - String json = "", - query2 = ""; - json = "{\"_id\":\"1004\",\"F1\": 1234 }"; - col.Add(json).Execute(); - query2 = "-1+"; - for (int i = 0; i < 230; i++) - { - query2 = query2 + "("; - } - - query2 = query2 + "(100+2)"; - for (int i = 230; i > 0; i--) - { - query2 = query2 + ")"; - } - - var docs = col.Find().Fields(("{'X':" + query2 + "}")).Execute(); - var res = col.Modify("$.F1 = 1234").Set("F1", query2).Limit(1).Execute(); - Assert.AreEqual(1, res.AffectedItemsCount); - } - - [Test, Description("Test MySQLX plugin Binary Expression")] - public void BinaryExpression() - { - String json = ""; - Collection col = CreateCollection("my_collection_1"); - Collection col1 = CreateCollection("my_collection_2"); - json = "{\"_id\":\"1004\",\"F1\": 123,\"F2\":\"#\" }"; - col.Add(json).Execute(); - - var docs1 = col.Find().Fields("$._id as _id", "1 << 4 as tmp").Execute(); - var res = docs1.FetchAll(); - StringAssert.AreEqualIgnoringCase("1004", res[0].Id.ToString()); - - docs1 = col.Find().Fields("$._id as _id", "$.F2 ^ 1 as tmp").Execute(); - res = docs1.FetchAll(); - StringAssert.AreEqualIgnoringCase("1004", res[0].Id.ToString()); - col.Add("{\"_id\":\"100001\",\"x1\":\"31\", \"x2\":\"13\", \"x3\":\"8\", \"x4\":\"18446744073709551614\"}").Execute(); - docs1 = col.Find("CAST($.x1 as SIGNED) | pow(2,$.x1) = $.x1").Fields("$._id as _id, $.x1 as x1, $.x2 as x2, $.x3 as x3 , $.x2 | pow(2,$.x1) as tmp").Execute(); - res = docs1.FetchAll(); - Assert.IsNotNull(res); - docs1 = col.Find("~16 = ~CAST($.F2 as SIGNED)").Fields("$._id as _id,$.F2 as f2, ~1 as tmp").Execute(); - res = docs1.FetchAll(); - Assert.IsNotNull(res); - int maxrec = 100; - DbDoc newDoc = new DbDoc(); - newDoc.SetValue("_id", maxrec + 1000); - newDoc.SetValue("F1", "Field-1-Data-" + maxrec); - newDoc.SetValue("F2", "Field-2-Data-" + maxrec); - newDoc.SetValue("F3", 300 + maxrec); - col1.Add(newDoc).Execute(); - - json = "{'_id':'" + (maxrec + 1000 + 1) + "','F1':'Field-1-Data-" + (maxrec + 1) + "','F2':'Field-2-Data-" + (maxrec + 1) + "','F3':" + (300 + maxrec + 1) + "}"; - json = json.Replace("'", "\""); - var res1 = col1.Add(json).Execute(); - Assert.AreEqual(1, res1.AffectedItemsCount); - json = "{'F1': 'Field-1-Data-9999','F2': 'Field-2-Data-9999','F3': 'Field-3-Data-9999'}".Replace("'", "\""); - col1.Add(json).Add(json.Replace("9", "8")).Execute(); - Assert.AreEqual(1, res1.AffectedItemsCount); - - var docs = col1.Find("$._id = 1100").Fields("$_id as _id,$.F1 as f1, $.F2 as f2, $.F3 as f3").Execute(); - var res2 = docs.FetchOne(); - Assert.AreEqual("1100", res2["_id"].ToString()); - Assert.AreEqual("Field-1-Data-100", res2["f1"].ToString()); - Assert.AreEqual("Field-2-Data-100", res2["f2"].ToString()); - Assert.AreEqual("400", res2["f3"].ToString()); - - } - - [Test, Description("Test MySQLX plugin Invalid JSON String long expression")] - public void JSONStringSpecialCharacters() - { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher."); - Collection col = CreateCollection("my_collection_1"); - String[] splName = {"+", "*", "/", "a+b", "#1", "%", "&", "@1", "!1", "~", "^", - "(", ")", "{", "}", "[", "]", "|", "JSON", "ADD", "JSON_EXTRACT", "JSON_OBJECT", - "?", "=", "+", ";", ",", ":", "<", ">", "-"}; - for (int i = 0; i < splName.Length; i++) - { - col.Add("{\"" + splName[i] + "\":\"data" + i + "\",\"ID\":" + i + "}").Execute(); - var docs = col.Find("$.ID = " + i).Fields("$.`" + splName[i] + "` as col1,$.ID as Id").Execute(); - var res = docs.FetchOne(); - Assert.AreEqual(i.ToString(), res["Id"].ToString(), "Matching the ID"); - if (i == 30) - Assert.AreEqual("data" + i, "data30", "Matching the String"); - else - Assert.AreEqual("data" + i, res["col1"].ToString(), "Matching the String"); - } - } - - [Test, Description("Test MySQLX plugin Collections Chained Insert")] - public void CollectionsChainedInsert() - { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher."); - Collection col = CreateCollection("my_collection_1"); - DbDoc newDoc = new DbDoc(); - newDoc.SetValue("F1", 1); - - DbDoc newDoc1 = new DbDoc(); - newDoc1.SetValue("F1", 2); - - DbDoc newDoc2 = new DbDoc(); - newDoc2.SetValue("F1", 3); - - DbDoc[] jsonlist = new DbDoc[5]; - for (int i = 0; i < 5; i++) - { - DbDoc newDoc3 = new DbDoc(); - newDoc3.SetValue("F1", 4 + i); - jsonlist[i] = newDoc3; - newDoc3 = null; - } - - DbDoc[] jsonlist1 = new DbDoc[5]; - for (int i = 0; i < 5; i++) - { - DbDoc newDoc4 = new DbDoc(); - newDoc4.SetValue("F1", 10 + i); - jsonlist1[i] = newDoc4; - newDoc4 = null; - } - - DbDoc[] jsonlist2 = new DbDoc[5]; - for (int i = 0; i < 5; i++) - { - DbDoc newDoc5 = new DbDoc(); - newDoc5.SetValue("F1", 100 + i); - jsonlist2[i] = newDoc5; - newDoc5 = null; - } - - var tabRes = col.Add(newDoc).Add(newDoc1).Execute(); - Assert.AreEqual(2, tabRes.AffectedItemsCount, "Matching the affected records"); - - tabRes = col.Add(jsonlist).Add(newDoc2).Execute(); - Assert.AreEqual(6, tabRes.AffectedItemsCount, "Matching the affected records"); - - tabRes = col.Add(jsonlist1).Add(jsonlist2).Execute(); - Assert.AreEqual(10, tabRes.AffectedItemsCount, "Matching the affected records"); - } - - [Test, Description("Test MySQLX plugin Collection Add Array")] - public void CollectionAddArray() - { - if (!Platform.IsWindows()) Assert.Ignore("This test is for Windows OS only."); - if (!session.Version.isAtLeast(5, 7, 0)) Assert.Ignore("This test is for MySql 5, 7, 0 or higher."); - int maxrec = 5; - var col = CreateCollection("my_collection_1"); - DbDoc[] jsonlist = new DbDoc[maxrec]; - for (int i = 0; i < maxrec; i++) - { - DbDoc newDoc2 = new DbDoc(); - newDoc2.SetValue("_id", i); - newDoc2.SetValue("F1", "Field-1-Data-" + i); - newDoc2.SetValue("ARR_INT", new DbDoc(@"{""values"":[1, 2, 3, 4, 5, 6, 7, 8, 9]}")); - newDoc2.SetValue("ARR_STR", new DbDoc(@"{""values"":""['DATA1', 'DATA2', 'DATA3', 'DATA4', 'DATA5', 'DATA6']""}")); - newDoc2.SetValue("ARR_LIT", new DbDoc(@"{""values"":""[null, true, false, null, true, false, null, true, false]""}")); - newDoc2.SetValue("ARR_ARR", new DbDoc(@"{""values"":[[1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5]]}")); - - col.Add(newDoc2).Execute(); - jsonlist[i] = newDoc2; - } - - jsonlist = null; - var res = col.Find().Execute().FetchAll(); - Assert.AreEqual(5, res.Count, "Matching the find count"); - } - - [Test, Description("Test MySQLX plugin Collection JSON Scenarios")] - public void CollectionAddJSONDocs() - { - if (!Platform.IsWindows()) Assert.Ignore("This test is for Windows OS only."); - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher."); - - Collection col = CreateCollection("my_collection_1"); - string json = @"{ ""_id"": 0, ""title"": ""Book 0"" ,""pages"": 10,""name"": ""Jeoff Archer""}"; - Result r = col.Add(json).Execute(); - - Assert.AreEqual(1, (int)r.AffectedItemsCount, "Matching Affected Records Count"); - var foundDocs = col.Find("pages > 5").Execute(); - Assert.AreEqual(1, foundDocs.Count(), "Matching Count"); - - json = @"{ ""_id"" : 99950, ""city"" : ""KETCHIKAN"", ""loc"" : ""[ -133.18479, 55.942471 ]"", ""pop"" : 422, ""state"" : ""AK"" }"; - r = col.Add(json).Execute(); - - DbDoc d = new DbDoc(@"{ ""id"": 1, ""pages"": 20, - ""person"": { ""name"": ""Fred"", ""age"": 45 } - }"); - DbDoc d2 = new DbDoc(); - d2.SetValue("id", 1); - d2.SetValue("pages", 20); - d2.SetValue("person", new { name = "Fred", age = 45 }); - - Assert.AreEqual(d.Equals(d2), true, "Matching"); - col.Add(d).Execute(); - - d = new DbDoc(@"{""id"":100,""FirstName"":""xyz"",""lastname"":""pqr"", - ""address"": - {""house"":44,""city"":""Delhi"",""country"":""india""}}"); - col.Add(d).Execute(); - - d = new DbDoc(@"{""customerId"":100,""FirstName"":""xyz"",""lastname"":""pqr"", - ""address"": - {""house"":44,""city"":""Delhi"",""country"":""india""}, - ""employer"": - {""cmpName"":""ABC"",""type"":""IT""}}"); - col.Add(d).Execute(); - - d = new DbDoc(@"{ ""id"": 1, ""pages"": 20, - ""books"": [ - {""_id"" : 1, ""title"" : ""Book 1""}, - { ""_id"" : 2, ""title"" : ""Book 2"" } - ] - }"); - col.Add(d).Execute(); - - var docs = new[] { new { _id = 1, title = "Book 1" }, new { _id = 2, title = "Book 2" } }; - d2 = new DbDoc(); - d2.SetValue("id", 100); - d2.SetValue("pages", 20); - d2.SetValue("books", docs); - col.Add(d2).Execute(); - - var result = col.Find("$._id = 0").Fields("$._id as _id,$.name as name, $.pages as pages, $.title as title").Execute(); - var res1 = result.FetchOne(); - Assert.AreEqual(0, res1["_id"]); - Assert.AreEqual("Jeoff Archer", res1["name"]); - Assert.AreEqual(10, res1["pages"]); - Assert.AreEqual("Book 0", res1["title"]); - - result = col.Find("$._id > 0").Fields().Execute(); - var res2 = result.FetchAll(); - Assert.AreEqual(6, res2.Count()); - - DbDoc test = new DbDoc(); - test.SetValue("_id", 1); - test.SetValue("name", "ABBBBBBBBBBBBBBXXXXXXXXXXXXXXXYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYTTTTTTYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYABBBBBBBBBBBBBBXXXXXXXXXXXXXXXYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYTTTTTTYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYABBBBBBBBBBBBBBXXXXXXXXXXXXXXXYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYTTTTTTYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYABBBBBBBBBBBBBBXXXXXXXXXXXXXXXYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYTTTTTTYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYABBBBBBBBBBBBBBXXXXXXXXXXXXXXXYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYTTTTTTYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY"); - var coll = CreateCollection("my_collection_123456789"); - var res = coll.Add(test).Execute(); - foundDocs = coll.Find().Execute(); - var docs1 = foundDocs.FetchAll(); - Assert.AreEqual(1, docs1.Count); - } - - [Test, Description("Verify that the field and column _id has a value when it's not given to a document-Scenario-1(single document add)")] - public void VerifyIDField() - { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("this test is for MySql 8.0.11 or higher."); - List idStringList = new List(); - var col = CreateCollection("my_collection"); - Result result = null; - string generatedIDs1 = null, generatedIDs2 = null; - int countgenerateIDs = 0; - // Anonymous Object Array - object[] data = new object[] { new { title = "Book 1", pages = 30 } }; - var stmt = col.Add(data); - result = stmt.Execute(); - generatedIDs1 = result.GeneratedIds[0]; - Assert.AreEqual(generatedIDs1, generatedIDs1, "ID generated by the server"); - VerifyGeneratedID(generatedIDs1); - countgenerateIDs = result.GeneratedIds.Count; - Assert.AreEqual(1, countgenerateIDs, "Count of the ID generated by the server"); - for (int i = 0; i < countgenerateIDs; i++) - { - idStringList.Add(result.GeneratedIds[i]); - } - - // DbDoc - DbDoc DbDocs = new DbDoc(); - DbDocs.SetValue("title", "Book 0"); - DbDocs.SetValue("pages", 10); - stmt = col.Add(DbDocs); - result = stmt.Execute(); - generatedIDs2 = result.GeneratedIds[0]; - Assert.AreEqual(generatedIDs2, generatedIDs2, "ID generated by the server"); - VerifyGeneratedID(generatedIDs2); - countgenerateIDs = result.GeneratedIds.Count; - Assert.AreEqual(1, countgenerateIDs, "Count of the ID generated by the server"); - for (int i = 0; i < countgenerateIDs; i++) - { - idStringList.Add(result.GeneratedIds[i]); - } - - // Anonymous Object - var docs = new { title = "Book 1", pages = 20 }; - stmt = col.Add(docs); - result = stmt.Execute(); - generatedIDs1 = result.GeneratedIds[0]; - Assert.AreEqual(generatedIDs1, generatedIDs1, "ID generated by the server"); - VerifyGeneratedID(generatedIDs1); - countgenerateIDs = result.GeneratedIds.Count; - Assert.AreEqual(1, countgenerateIDs, "Count of the ID generated by the server"); - for (int i = 0; i < countgenerateIDs; i++) - { - idStringList.Add(result.GeneratedIds[i]); - } - - // JSON - stmt = col.Add("{ \"foo\": 100 }"); - result = stmt.Execute(); - generatedIDs2 = result.GeneratedIds[0]; - Assert.AreEqual(generatedIDs2, generatedIDs2, "ID generated by the server"); - VerifyGeneratedID(generatedIDs2); - countgenerateIDs = result.GeneratedIds.Count; - Assert.AreEqual(1, countgenerateIDs, "Count of the ID generated by the server"); - for (int i = 0; i < countgenerateIDs; i++) - { - idStringList.Add(result.GeneratedIds[i]); - } - - int j = 1; - for (int i = 0; i < idStringList.Count; i++) - { - if (j == idStringList.Count) - { - break; - } - VerifySequence(idStringList[i], idStringList[j]); - j++; - } - } - - [Test, Description("Unique _ids generated server side for multiple documents, single add and generated ids count should be number of docs added-Scenario3")] - public void VerifyIDFieldScenario3() - { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("this test is for MySql 8.0.11 or higher."); - List idStringList = new List(); - var col = CreateCollection("my_collection"); - Result result = null; - string generatedIDs1 = null; - int countgenerateIDs = 0; - HashSet firstset = new HashSet(); - - object[] data1 = new object[] - { - new { title = "Book 1", pages = 20 }, - new { title = "Book 2", pages = 30 }, - new { title = "Book 3", pages = 40 }, - new { title = "Book 4", pages = 50 } - }; - - var stmt = col.Add(data1); - result = stmt.Execute(); - countgenerateIDs = result.GeneratedIds.Count; - Assert.AreEqual(4, countgenerateIDs, "Count of the ID generated by the server"); - for (int i = 0; i < countgenerateIDs; i++) - { - generatedIDs1 = result.GeneratedIds[i]; - Assert.AreEqual(generatedIDs1, generatedIDs1, "ID generated by the server"); - VerifyGeneratedID(generatedIDs1); - Assert.False(!firstset.Add(generatedIDs1)); - } - - for (int i = 0; i < countgenerateIDs; i++) - { - idStringList.Add(result.GeneratedIds[i]); - } - - stmt = col.Add(@"{ ""foo"": 1 }", @"{""foo"": 2 }", @"{ ""foo"": 3 }", @"{ ""foo"": 4 }"); - result = stmt.Execute(); - countgenerateIDs = result.GeneratedIds.Count; - Assert.AreEqual(4, countgenerateIDs, "Count of the ID generated by the server"); - for (int i = 0; i < countgenerateIDs; i++) - { - generatedIDs1 = result.GeneratedIds[i]; - Assert.AreEqual(generatedIDs1, generatedIDs1, "ID generated by the server"); - VerifyGeneratedID(generatedIDs1); - Assert.False(!firstset.Add(generatedIDs1)); - } - - for (int i = 0; i < countgenerateIDs; i++) - { - idStringList.Add(result.GeneratedIds[i]); - } - - int j = 1; - for (int i = 0; i < idStringList.Count; i++) - { - if (j == idStringList.Count) - { - break; - } - VerifySequence(idStringList[i], idStringList[j]); - j++; - } - } - - [Test, Description("Verify that the field and column _id has a value when it's not given to a document-Scenario-1(single document add)-when doc already exists")] - public void VerifyIDFieldScenario4() - { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("this test is for MySql 8.0.11 or higher."); - List idStringList = new List(); - var col = CreateCollection("my_collection"); - Result result = null; - string generatedIDs1 = null, generatedIDs2 = null; - int countgenerateIDs = 0; - object[] data = null; - data = new object[] - { - new { title ="Book 0", pages = 10 }, - new { title ="Book 5", pages = 60, _id = 6} - }; - result = col.Add(data).Execute(); - countgenerateIDs = result.GeneratedIds.Count; - generatedIDs1 = result.GeneratedIds[0]; - Assert.AreEqual(1, countgenerateIDs, "Count of the ID generated by the server"); - for (int i = 0; i < countgenerateIDs; i++) - { - idStringList.Add(result.GeneratedIds[i]); - } - - // Anonymous Object Array - data = new object[] { new { title = "Book 1", pages = 30 } }; - var stmt = col.Add(data); - result = stmt.Execute(); - generatedIDs1 = result.GeneratedIds[0]; - Assert.AreEqual(generatedIDs1, generatedIDs1, "ID generated by the server"); - VerifyGeneratedID(generatedIDs1); - countgenerateIDs = result.GeneratedIds.Count; - Assert.AreEqual(1, countgenerateIDs, "Count of the ID generated by the server"); - for (int i = 0; i < countgenerateIDs; i++) - { - idStringList.Add(result.GeneratedIds[i]); - } - - col = CreateCollection("my_collection"); - data = null; - data = new object[] - { - new { title ="Book 0", pages = 10 }, - new { title ="Book 5", pages = 60, _id = 6} - }; - result = col.Add(data).Execute(); - countgenerateIDs = result.GeneratedIds.Count; - generatedIDs1 = result.GeneratedIds[0]; - Assert.AreEqual(1, countgenerateIDs, "Count of the ID generated by the server"); - for (int i = 0; i < countgenerateIDs; i++) - { - idStringList.Add(result.GeneratedIds[i]); - } - - // DbDoc - DbDoc DbDocs = new DbDoc(); - DbDocs.SetValue("title", "Book 0"); - DbDocs.SetValue("pages", 10); - stmt = col.Add(DbDocs); - result = stmt.Execute(); - generatedIDs2 = result.GeneratedIds[0]; - Assert.AreEqual(generatedIDs2, generatedIDs2, "ID generated by the server"); - VerifyGeneratedID(generatedIDs2); - countgenerateIDs = result.GeneratedIds.Count; - Assert.AreEqual(1, countgenerateIDs, "Count of the ID generated by the server"); - for (int i = 0; i < countgenerateIDs; i++) - { - idStringList.Add(result.GeneratedIds[i]); - } - - col = CreateCollection("my_collection"); - data = null; - data = new object[] - { - new { title ="Book 0", pages = 10 }, - new { title ="Book 5", pages = 60, _id = 6} - }; - result = col.Add(data).Execute(); - countgenerateIDs = result.GeneratedIds.Count; - generatedIDs1 = result.GeneratedIds[0]; - Assert.AreEqual(1, countgenerateIDs, "Count of the ID generated by the server"); - for (int i = 0; i < countgenerateIDs; i++) - { - idStringList.Add(result.GeneratedIds[i]); - } - - // Anonymous Object - var docs = new { title = "Book 1", pages = 20 }; - stmt = col.Add(docs); - result = stmt.Execute(); - generatedIDs1 = result.GeneratedIds[0]; - Assert.AreEqual(generatedIDs1, generatedIDs1, "ID generated by the server"); - VerifyGeneratedID(generatedIDs1); - countgenerateIDs = result.GeneratedIds.Count; - Assert.AreEqual(1, countgenerateIDs, "Count of the ID generated by the server"); - for (int i = 0; i < countgenerateIDs; i++) - { - idStringList.Add(result.GeneratedIds[i]); - } - - col = CreateCollection("my_collection"); - data = null; - data = new object[] - { - new { title ="Book 0", pages = 10 }, - new { title ="Book 5", pages = 60, _id = 6} - }; - result = col.Add(data).Execute(); - countgenerateIDs = result.GeneratedIds.Count; - generatedIDs1 = result.GeneratedIds[0]; - Assert.AreEqual(1, countgenerateIDs, "Count of the ID generated by the server"); - for (int i = 0; i < countgenerateIDs; i++) - { - idStringList.Add(result.GeneratedIds[i]); - } - - //JSON - stmt = col.Add("{ \"foo\": 100 }"); - result = stmt.Execute(); - generatedIDs2 = result.GeneratedIds[0]; - Assert.AreEqual(generatedIDs2, generatedIDs2, "ID generated by the server"); - VerifyGeneratedID(generatedIDs2); - countgenerateIDs = result.GeneratedIds.Count; - Assert.AreEqual(1, countgenerateIDs, "Count of the ID generated by the server"); - for (int i = 0; i < countgenerateIDs; i++) - { - idStringList.Add(result.GeneratedIds[i]); - } - - int j = 1; - for (int i = 0; i < idStringList.Count; i++) - { - if (j == idStringList.Count) - { - break; - } - VerifySequence(idStringList[i], idStringList[j]); - j++; - } - } - - [Test, Description("Unique _ids generated server side for multiple documents,multiple add and generated ids count should be number of docs added-when doc already exists Scenario2")] - public void VerifyIDFieldScenario5() - { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("this test is for MySql 8.0.11 or higher."); - List idStringList = new List(); - Result result = null; - string generatedIDs1 = null; - int countgenerateIDs = 0; - var col = CreateCollection("my_collection"); - object[] data = null; - - data = new object[] - { - new { title ="Book 0", pages = 10 }, - new { title ="Book 5", pages = 60, _id = 6} - }; - result = col.Add(data).Execute(); - countgenerateIDs = result.GeneratedIds.Count; - generatedIDs1 = result.GeneratedIds[0]; - Assert.AreEqual(1, countgenerateIDs, "Count of the ID generated by the server"); - for (int i = 0; i < countgenerateIDs; i++) - { - idStringList.Add(result.GeneratedIds[i]); - } - - HashSet firstset = new HashSet(); - // Anonymous Object Array - object[] data1 = new object[] { new { title ="Book 1", pages = 20 } - }; - object[] data2 = new object[] { new { title = "Book 5", pages = 60 } }; - - var stmt = col.Add(data1).Add(data2); - result = stmt.Execute(); - countgenerateIDs = result.GeneratedIds.Count; - Assert.AreEqual(2, countgenerateIDs, "Count of the ID generated by the server"); - for (int i = 0; i < countgenerateIDs; i++) - { - generatedIDs1 = result.GeneratedIds[i]; - Assert.AreEqual(generatedIDs1, generatedIDs1, "ID generated by the server"); - VerifyGeneratedID(generatedIDs1); - Assert.False(!firstset.Add(generatedIDs1)); - } - for (int i = 0; i < countgenerateIDs; i++) - { - idStringList.Add(result.GeneratedIds[i]); - } - - col = CreateCollection("my_collection"); - data = new object[] - { - new { title ="Book 0", pages = 10 }, - new { title ="Book 5", pages = 60, _id = 6} - }; - result = col.Add(data).Execute(); - countgenerateIDs = result.GeneratedIds.Count; - generatedIDs1 = result.GeneratedIds[0]; - Assert.AreEqual(1, countgenerateIDs, "Count of the ID generated by the server"); - for (int i = 0; i < countgenerateIDs; i++) - { - idStringList.Add(result.GeneratedIds[i]); - } - - // DbDoc - DbDoc DbDocs1 = new DbDoc(); - DbDocs1.SetValue("title", "Book 0"); - DbDocs1.SetValue("pages", 10); - DbDoc DbDocs2 = new DbDoc(); - DbDocs2.SetValue("title", "Book 1"); - DbDocs2.SetValue("pages", 20); - stmt = col.Add(DbDocs1).Add(DbDocs2); - result = stmt.Execute(); - countgenerateIDs = result.GeneratedIds.Count; - Assert.AreEqual(2, countgenerateIDs, "Count of the ID generated by the server"); - for (int i = 0; i < countgenerateIDs; i++) - { - generatedIDs1 = result.GeneratedIds[i]; - Assert.AreEqual(generatedIDs1, generatedIDs1, "ID generated by the server"); - VerifyGeneratedID(generatedIDs1); - Assert.False(!firstset.Add(generatedIDs1)); - } - for (int i = 0; i < countgenerateIDs; i++) - { - idStringList.Add(result.GeneratedIds[i]); - } - - col = CreateCollection("my_collection"); - - data = new object[] - { - new { title ="Book 0", pages = 10 }, - new { title ="Book 5", pages = 60, _id = 6} - }; - result = col.Add(data).Execute(); - countgenerateIDs = result.GeneratedIds.Count; - generatedIDs1 = result.GeneratedIds[0]; - Assert.AreEqual(1, countgenerateIDs, "Count of the ID generated by the server"); - for (int i = 0; i < countgenerateIDs; i++) - { - idStringList.Add(result.GeneratedIds[i]); - } - - // Anonymous Object - var docs1 = new { title = "Book 1", pages = 20 }; - var docs2 = new { title = "Book 2", pages = 30 }; - stmt = col.Add(docs1).Add(docs2); - - result = stmt.Execute(); - countgenerateIDs = result.GeneratedIds.Count; - Assert.AreEqual(2, countgenerateIDs, "Count of the ID generated by the server"); - for (int i = 0; i < countgenerateIDs; i++) - { - generatedIDs1 = result.GeneratedIds[i]; - Assert.AreEqual(generatedIDs1, generatedIDs1, "ID generated by the server"); - VerifyGeneratedID(generatedIDs1); - Assert.False(!firstset.Add(generatedIDs1)); - } - for (int i = 0; i < countgenerateIDs; i++) - { - idStringList.Add(result.GeneratedIds[i]); - } - - col = CreateCollection("my_collection"); - data = new object[] - { - new { title ="Book 0", pages = 10 }, - new { title ="Book 5", pages = 60, _id = 6} - }; - result = col.Add(data).Execute(); - countgenerateIDs = result.GeneratedIds.Count; - generatedIDs1 = result.GeneratedIds[0]; - Assert.AreEqual(1, countgenerateIDs, "Count of the ID generated by the server"); - for (int i = 0; i < countgenerateIDs; i++) - { - idStringList.Add(result.GeneratedIds[i]); - } - - // JSON - stmt = col.Add("{ \"foo1\": 100 }").Add("{ \"foo2\": 200 }"); - result = stmt.Execute(); - countgenerateIDs = result.GeneratedIds.Count; - Assert.AreEqual(2, countgenerateIDs, "Count of the ID generated by the server"); - for (int i = 0; i < countgenerateIDs; i++) - { - generatedIDs1 = result.GeneratedIds[i]; - Assert.AreEqual(generatedIDs1, generatedIDs1, "ID generated by the server"); - VerifyGeneratedID(generatedIDs1); - if (!firstset.Add(generatedIDs1)) - { - break; - } - } - for (int i = 0; i < countgenerateIDs; i++) - { - idStringList.Add(result.GeneratedIds[i]); - } - - int j = 1; - for (int i = 0; i < idStringList.Count; i++) - { - if (j == idStringList.Count) - { - break; - } - VerifySequence(idStringList[i], idStringList[j]); - j++; - } - } - - [Test, Description("Unique _ids generated server side for multiple documents, single add and generated ids count should be number of docs added-when doc already exists Scenario3")] - public void VerifyIDFieldScenario6() - { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("this test is for MySql 8.0.11 or higher."); - List idStringList = new List(); - var col = CreateCollection("my_collection"); - Result result = null; - string generatedIDs1 = null; - int countgenerateIDs = 0; - object[] data = null; - - data = new object[] - { - new { title ="Book 0", pages = 10 }, - new { title ="Book 5", pages = 60, _id = 6} - }; - result = col.Add(data).Execute(); - countgenerateIDs = result.GeneratedIds.Count; - generatedIDs1 = result.GeneratedIds[0]; - Assert.AreEqual(1, countgenerateIDs, "Count of the ID generated by the server"); - for (int i = 0; i < countgenerateIDs; i++) - { - idStringList.Add(result.GeneratedIds[i]); - } - - HashSet firstset = new HashSet(); - // Anonymous Object Array - object[] data1 = new object[] - { - new { title ="Book 1", pages = 20 }, - new { title = "Book 2", pages = 30 }, - new { title = "Book 3", pages = 40 }, - new { title = "Book 4", pages = 50 } - }; - - var stmt = col.Add(data1); - result = stmt.Execute(); - countgenerateIDs = result.GeneratedIds.Count; - Assert.AreEqual(4, countgenerateIDs, "Count of the ID generated by the server"); - for (int i = 0; i < countgenerateIDs; i++) - { - generatedIDs1 = result.GeneratedIds[i]; - Assert.AreEqual(generatedIDs1, generatedIDs1, "ID generated by the server"); - VerifyGeneratedID(generatedIDs1); - Assert.False(!firstset.Add(generatedIDs1)); - } - for (int i = 0; i < countgenerateIDs; i++) - { - idStringList.Add(result.GeneratedIds[i]); - } - - col = CreateCollection("my_collection"); - result = col.Add(@"{ ""foo"": 0, ""_id"":0 }", @"{""foo"": 5 }").Execute(); - countgenerateIDs = result.GeneratedIds.Count; - generatedIDs1 = result.GeneratedIds[0]; - Assert.AreEqual(1, countgenerateIDs, "Count of the ID generated by the server"); - for (int i = 0; i < countgenerateIDs; i++) - { - idStringList.Add(result.GeneratedIds[i]); - } - - // JSON - stmt = col.Add(@"{ ""foo"": 1 }", @"{""foo"": 2 }", @"{ ""foo"": 3 }", @"{ ""foo"": 4 }"); - result = stmt.Execute(); - countgenerateIDs = result.GeneratedIds.Count; - Assert.AreEqual(4, countgenerateIDs, "Count of the ID generated by the server"); - for (int i = 0; i < countgenerateIDs; i++) - { - generatedIDs1 = result.GeneratedIds[i]; - Assert.AreEqual(generatedIDs1, generatedIDs1, "ID generated by the server"); - VerifyGeneratedID(generatedIDs1); - Assert.False(!firstset.Add(generatedIDs1)); - } - for (int i = 0; i < countgenerateIDs; i++) - { - idStringList.Add(result.GeneratedIds[i]); - } - - int j = 1; - for (int i = 0; i < idStringList.Count; i++) - { - if (j == idStringList.Count) - { - break; - } - VerifySequence(idStringList[i], idStringList[j]); - j++; - } - } - - [Test, Description("Client provided _id shouldnt be discarded and generatedids() should give empty list for anonymous object array -single document add")] - public void VerifyIDFieldScenario7() - { - var col = CreateCollection("my_collection"); - object[] data = new object[] - { - new { _id = "1e9c92fda74ed311944e00059a3c7a00", title = "Book 0", pages = 10 }, - }; - Result result = col.Add(data).Execute(); - var generatedIDs = result.GeneratedIds; - Assert.AreEqual(0, generatedIDs.Count, "Matches"); - var doc = col.Find("_id like :param").Bind("param", "1e9c92fda74ed311944e00059a3c7a00").Execute(); - var docs = doc.FetchAll().Count(); - Assert.AreEqual(1, docs, "Matches"); - - //Anonymous Object - var data1 = new { _id = "1e9c92fda74ed311944e00059a3c7a01", title = "Book 0", pages = 10 }; - result = col.Add(data1).Execute(); - - generatedIDs = result.GeneratedIds; - Assert.AreEqual(0, generatedIDs.Count, "Matches"); - doc = col.Find("_id like :param").Bind("param", "1e9c92fda74ed311944e00059a3c7a01").Execute(); - docs = doc.FetchAll().Count(); - Assert.AreEqual(1, docs, "Matches"); - - // DbDoc - DbDoc DbDocs = new DbDoc(); - DbDocs.SetValue("title", "Book 0"); - DbDocs.SetValue("pages", 10); - DbDocs.SetValue("_id", "1e9c92fda74ed311944e00059a3c7a02"); - result = col.Add(DbDocs).Execute(); - - generatedIDs = result.GeneratedIds; - Assert.AreEqual(0, generatedIDs.Count, "Matches"); - doc = col.Find("_id like :param").Bind("param", "1e9c92fda74ed311944e00059a3c7a02").Execute(); - docs = doc.FetchAll().Count(); - Assert.AreEqual(1, docs, "Matches"); - - //JSON - result = col.Add("{\"_id\":\"1e9c92fda74ed311944e00059a3c7a03\",\"title\": \"Book 0\",\"pages\": 10}").Execute(); - generatedIDs = result.GeneratedIds; - Assert.AreEqual(0, generatedIDs.Count, "Matches"); - doc = col.Find("_id like :param").Bind("param", "1e9c92fda74ed311944e00059a3c7a03").Execute(); - docs = doc.FetchAll().Count(); - Assert.AreEqual(1, docs, "Matches"); - } - - [Test, Description("Client provided _id shouldnt be discarded and generatedids() should give empty list for anonymous object array -multiple documents multiple add with negative number")] - public void VerifyIDFieldScenario8() - { - var col = CreateCollection("my_collection"); - object[] data1 = new object[] - { - new { _id = "1e9c92fda74ed311944e00059a3c7a00", title = "Book 0", pages = 10 } - }; - object[] data2 = new object[] - { - new { _id = -1, title = "Book 0", pages = 10 } - }; - Result result = col.Add(data1).Add(data2).Execute(); - var generatedIDs = result.GeneratedIds; - Assert.AreEqual(0, generatedIDs.Count, "Matches"); - var doc = col.Find("_id like :param").Bind("param", "1e9c92fda74ed311944e00059a3c7a00").Execute(); - var docs = doc.FetchAll().Count(); - Assert.AreEqual(1, docs, "Matches"); - doc = col.Find("_id like :param").Bind("param", -1).Execute(); - docs = doc.FetchAll().Count(); - Assert.AreEqual(1, docs, "Matches"); - - // Anonymous Object - var data3 = new { _id = "1e9c92fda74ed311944e00059a3c7a01", title = "Book 0", pages = 10 }; - var data4 = new { _id = -2, title = "Book 0", pages = 10 }; - result = col.Add(data3).Add(data4).Execute(); - generatedIDs = result.GeneratedIds; - Assert.AreEqual(0, generatedIDs.Count, "Matches"); - doc = col.Find("_id like :param").Bind("param", "1e9c92fda74ed311944e00059a3c7a01").Execute(); - docs = doc.FetchAll().Count(); - Assert.AreEqual(1, docs, "Matches"); - doc = col.Find("_id like :param").Bind("param", -2).Execute(); - docs = doc.FetchAll().Count(); - Assert.AreEqual(1, docs, "Matches"); - - //DbDoc - DbDoc DbDocs1 = new DbDoc(); - DbDocs1.SetValue("title", "Book 0"); - DbDocs1.SetValue("pages", 10); - DbDocs1.SetValue("_id", "1e9c92fda74ed311944e00059a3c7a02"); - DbDoc DbDocs2 = new DbDoc(); - DbDocs2.SetValue("title", "Book 0"); - DbDocs2.SetValue("pages", 10); - DbDocs2.SetValue("_id", -3); - result = col.Add(DbDocs1).Add(DbDocs2).Execute(); - generatedIDs = result.GeneratedIds; - Assert.AreEqual(0, generatedIDs.Count, "Matches"); - doc = col.Find("_id like :param").Bind("param", "1e9c92fda74ed311944e00059a3c7a02").Execute(); - docs = doc.FetchAll().Count(); - Assert.AreEqual(1, docs, "Matches"); - doc = col.Find("_id like :param").Bind("param", -3).Execute(); - docs = doc.FetchAll().Count(); - Assert.AreEqual(1, docs, "Matches"); - - // JSON - result = col.Add("{\"_id\":\"1e9c92fda74ed311944e00059a3c7a03\",\"title\": \"Book 0\",\"pages\": 10}"). - Add("{\"_id\":-4,\"title\": \"Book 0\",\"pages\": 10}"). - Execute(); - generatedIDs = result.GeneratedIds; - Assert.AreEqual(0, generatedIDs.Count, "Matches"); - doc = col.Find("_id like :param").Bind("param", "1e9c92fda74ed311944e00059a3c7a03").Execute(); - docs = doc.FetchAll().Count(); - Assert.AreEqual(1, docs, "Matches"); - doc = col.Find("_id like :param").Bind("param", -4).Execute(); - docs = doc.FetchAll().Count(); - Assert.AreEqual(1, docs, "Matches"); - } - - [Test, Description("Client provided _id shouldnt be discarded and generatedids() should give empty list for anonymous object array -multiple documents single add with negative number,zero and big positive numbers")] - public void VerifyIDFieldScenario9() - { - var col = CreateCollection("my_collection"); - // Anonymous Object Array - object[] idList = new object[] { "1e9c92fda74ed311944e00059a3c7a00", -1, 60000000000000, -3000000000000, 0 }; - object[] data1 = new object[] - { - new { _id = idList[0], title = "Book 0", pages = 10 }, - new { _id = idList[1], title = "Book 0", pages = 10 }, - new { _id = idList[2] , title = "Book 0", pages = 10 }, - new { _id = idList[3], title = "Book 0", pages = 10 }, - new { _id = idList[4], title = "Book 0", pages = 10 } - }; - Result result = col.Add(data1).Execute(); - var generatedIDs = result.GeneratedIds; - Assert.AreEqual(0, generatedIDs.Count, "Matches"); - for (int i = 0; i < idList.Length; i++) - { - var doc = col.Find("_id like :param").Bind("param", idList[i]).Execute(); - var docs = doc.FetchAll().Count(); - Assert.AreEqual(1, docs, "Matches the Document ID"); - } - } - - [Test, Description("documents single add with blank id")] - public void CollectionAddBlankId() - { - var col = CreateCollection("my_collection"); - // Anonymous Object Array - object[] idList = new object[] { "", " " }; - object[] data1 = new object[] - { - new { _id = idList[0], title = "Book 0", pages = 10 } - }; - object[] data2 = new object[] - { - new { _id = idList[1], title = "Book 0", pages = 10 } - }; - Result result1 = col.Add(data1).Execute(); - Assert.AreEqual(1, result1.AffectedItemsCount); - result1 = null; - - col = CreateCollection("my_collection"); - result1 = col.Add(data2).Execute(); - Assert.AreEqual(1, result1.AffectedItemsCount); - result1 = null; - - col = CreateCollection("my_collection"); - // DbDoc - DbDoc DbDocs1 = new DbDoc(); - DbDocs1.SetValue("title", "Book 0"); - DbDocs1.SetValue("pages", 10); - DbDocs1.SetValue("_id", ""); - result1 = col.Add(DbDocs1).Execute(); - Assert.AreEqual(1, result1.AffectedItemsCount); - result1 = null; - - col = CreateCollection("my_collection"); - DbDoc DbDocs2 = new DbDoc(); - DbDocs2.SetValue("title", "Book 1"); - DbDocs2.SetValue("pages", 20); - DbDocs2.SetValue("_id", " "); - result1 = col.Add(DbDocs2).Execute(); - Assert.AreEqual(1, result1.AffectedItemsCount); - result1 = null; - - // JSON - col = CreateCollection("my_collection"); - result1 = col.Add("{\"_id\":\"\",\"title\": \"Book 0\",\"pages\": 10}").Execute(); - Assert.AreEqual(1, result1.AffectedItemsCount); - result1 = null; - - col = CreateCollection("my_collection"); - result1 = col.Add("{\"_id\":\" \",\"title\": \"Book 0\",\"pages\": 10}").Execute(); - Assert.AreEqual(1, result1.AffectedItemsCount); - result1 = null; - - } - - [Test, Description("Multiple documents with same id")] - public void CollectionAddMultipleDocsSameId() - { - var col = CreateCollection("my_collection"); - string exception = "Document contains a field value that is not unique but required to be"; - // DbDoc - DbDoc DbDocs1 = new DbDoc(); - DbDocs1.SetValue("title", "Book 0"); - DbDocs1.SetValue("pages", 10); - DbDocs1.SetValue("_id", 1); - DbDoc DbDocs2 = new DbDoc(); - DbDocs2.SetValue("title", "Book 1"); - DbDocs2.SetValue("pages", 20); - DbDocs2.SetValue("_id", 1); - var ex = Assert.Throws(() => col.Add(DbDocs1).Add(DbDocs2).Execute()); - Assert.AreEqual(exception, ex.Message, "Checking the exception"); - - // JSON - ex = Assert.Throws(() => col.Add("{\"_id\":1,\"title\": \"Book 0\",\"pages\": 10}"). - Add("{\"_id\":1,\"title\": \"Book 1\",\"pages\": 20}").Execute()); - Assert.AreEqual(exception, ex.Message, "Checking the exception"); - - // Anonymous Object Array - object[] data1 = new object[] - { - new { _id = 1, title = "Book 0", pages = 10 } - }; - object[] data2 = new object[] - { - new { _id = 1, title = "Book 1", pages = 20 } - }; - ex = Assert.Throws(() => col.Add(data1).Add(data2).Execute()); - Assert.AreEqual(exception, ex.Message, "Checking the exception"); - } - - [Test, Description("Verify the behaviour if a sequence is incremented by the user and added as _id for the document")] - public void VerifySequenceAndIdAdded() - { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher."); - string incrementedString = null, generatedString = null; - var col = CreateCollection("my_collection"); - Result result = null; - string generatedIDs1 = null; - int countgenerateIDs = 0; - // Anonymous Object Array - object[] data = new object[] { new { title = "Book 1", pages = 30 } }; - var stmt = col.Add(data); - - result = stmt.Execute(); - generatedIDs1 = result.GeneratedIds[0]; - Assert.AreEqual(generatedIDs1, generatedIDs1, "ID generated by the server"); - VerifyGeneratedID(generatedIDs1); - countgenerateIDs = result.GeneratedIds.Count; - Assert.AreEqual(1, countgenerateIDs, "Count of the ID generated by the server"); - generatedString = generatedIDs1; - incrementedString = Increment(generatedIDs1, Mode.AlphaNumeric); - - data = new object[] { new { title = "Book 2", pages = 40, _id = generatedString } }; - stmt = col.Add(data); - string exception = "Document contains a field value that is not unique but required to be"; - Exception ex = Assert.Throws(() => stmt.Execute()); - Assert.AreEqual(exception, ex.Message, "Matching the exception"); - - data = new object[] { new { title = "Book 3", pages = 50, _id = incrementedString } }; - stmt = col.Add(data); - result = stmt.Execute(); - Assert.IsNotNull(result); - - data = new object[] { new { title = "Book 4", pages = 60 } }; - stmt = col.Add(data); - ex = Assert.Throws(() => stmt.Execute()); - Assert.AreEqual(exception, ex.Message, "Matching the exception"); - - } - - [Test, Description("documents inserted concurrently by two threads")] - public async Task CollectionConcurrentAdd() - { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher."); - - CreateCollection("my_collection"); - var r1 = await CollectionAddThread1(); - _ = await CollectionAddThread2(); - Assert.AreEqual(1000, r1); - } - public Task CollectionAddThread1() - { - List idStringList = new List(); - var col = CreateCollection("my_collection"); - DbDoc[] jsonlist = new DbDoc[1000]; - for (int i = 0; i < 1000; i++) - { - DbDoc newDoc2 = new DbDoc(); - newDoc2.SetValue("F1", ("Field-1-Data-" + i)); - newDoc2.SetValue("F2", ("Field-2-Data-" + i)); - newDoc2.SetValue("F3", (3 + i).ToString()); - jsonlist[i] = newDoc2; - newDoc2 = null; - } - Result r = col.Add(jsonlist).Execute(); - Assert.AreEqual(1000, r.AffectedItemsCount, "Matching"); - int countgenerateIDs = r.GeneratedIds.Count; - for (int i = 0; i < countgenerateIDs; i++) - { - idStringList.Add(r.GeneratedIds[i]); - } - - int j = 1; - for (int i = 0; i < idStringList.Count; i++) - { - if (j == idStringList.Count) - { - break; - } - VerifySequence(idStringList[i], idStringList[j]); - j++; - } - return Task.FromResult((int)r.AffectedItemsCount); - } - - public Task CollectionAddThread2() - { - List idStringList = new List(); - var col = CreateCollection("my_collection1"); - DbDoc[] jsonlist = new DbDoc[1000]; - for (int i = 0; i < 1000; i++) - { - DbDoc newDoc2 = new DbDoc(); - newDoc2.SetValue("F4", ("Field-1-Data-" + i)); - newDoc2.SetValue("F5", ("Field-2-Data-" + i)); - newDoc2.SetValue("F6", (3 + i).ToString()); - jsonlist[i] = newDoc2; - newDoc2 = null; - } - Result r = col.Add(jsonlist).Execute(); - Assert.AreEqual(1000, r.AffectedItemsCount, "Matching"); - int countgenerateIDs = r.GeneratedIds.Count; - for (int i = 0; i < countgenerateIDs; i++) - { - idStringList.Add(r.GeneratedIds[i]); - } - - int j = 1; - for (int i = 0; i < idStringList.Count; i++) - { - if (j == idStringList.Count) - { - break; - } - VerifySequence(idStringList[i], idStringList[j]); - j++; - } - return Task.FromResult(0); - } - - ///// - ///// Bug24397888 - ///// - [Test, Description("WHEN A DBDOC IS PASSED AS OBJ TO SETVALUE OF ANOTHER DBDOC IT CONVERTS TO BLANK")] - public void DbDocAsObjectConvertToBlank() - { - string newLine = Platform.IsWindows() ? "\r\n" : "\n"; - - var col = CreateCollection("my_collection"); - var data1 = new DbDoc(@"{ ""id"": 1, ""pages"": 20, - ""person"": { ""name"": ""Fred"", ""age"": 45 } - }"); - DbDoc d2 = new DbDoc(); - d2.SetValue("id", 1); - d2.SetValue("pages", 20); - d2.SetValue("taker1", data1); - string expected = $"{{{newLine} \"id\": 1, {newLine} \"pages\": 20, {newLine} \"taker1\": {{{newLine} \"id\": 1, {newLine} \"pages\": 20, {newLine} \"person\": {{{newLine} \"name\": \"Fred\", {newLine} \"age\": 45{newLine} }}{newLine} }}{newLine}}}"; - Assert.AreEqual(expected, d2.ToString()); - } - - [Test, Description("ADDITION OF OBJ FAILS AFTER CREATE INDEX IN 5.7.12 SERVER(WORKS WITH 5.7.9)")] - public void AdditionOfObject() - { - Collection testColl = CreateCollection("test"); - testColl.CreateIndex("testIndex", "{\"fields\": [ { \"field\":$.myId, \"type\":\"INT\" , \"required\":true} ] }"); - testColl.CreateIndex("testIndex1", "{\"fields\": [ { \"field\":$.myAge, \"type\":\"FLOAT\" , \"required\":true} ] }"); - var result = testColl.Add(new { myId = 1, myAge = 35.1, _id = 1 }).Execute(); - Assert.AreEqual(1, result.AffectedItemsCount); - } - - [Test, Description("Test valid insert at Depth n for multiple arrays))")] - public void InsertAtNDepth() - { - if (!session.Version.isAtLeast(8, 0, 3)) return; - string json = ""; - int i = 0, j = 0, maxField = 100; - var collection = CreateCollection("test"); - int maxDepth = 97; - json = "{\"_id\":\"1002\",\"XYZ\":1111"; - for (j = 0; j < maxField; j++) - { - json = json + ",\"ARR" + j + "\":["; - for (i = 0; i < maxDepth; i++) - { - json = json + i + ",["; - } - json = json + i; - for (i = maxDepth - 1; i >= 0; i--) - { - json = json + "]," + i; - } - json = json + "]"; - } - json = json + "}"; - - var res = collection.Add(json).Execute(); - Assert.AreEqual(1, res.AffectedItemsCount); - } - - #endregion WL14389 - - #region Methods - - public void VerifyGeneratedID(string input) - { - byte[] array = Encoding.ASCII.GetBytes(input); - Assert.False(array.Length < 28); - - byte[] uniquePrefix = new byte[4]; - Array.Copy(array, 0, uniquePrefix, 0, 4); - - Assert.AreEqual(System.Text.Encoding.UTF8.GetString(uniquePrefix), System.Text.Encoding.UTF8.GetString(uniquePrefix), - "Unique Prefix of the Generated ID"); - - byte[] startTimeStamp = new byte[8]; - Array.Copy(array, 4, startTimeStamp, 0, 8); - Assert.AreEqual(System.Text.Encoding.UTF8.GetString(startTimeStamp), System.Text.Encoding.UTF8.GetString(startTimeStamp), - "StartTimeStamp of the Generated ID"); - - byte[] serial = new byte[16]; - Array.Copy(array, 12, serial, 0, 16); - Assert.AreEqual(System.Text.Encoding.UTF8.GetString(serial), System.Text.Encoding.UTF8.GetString(serial), - "Serial Number of the Generated ID"); - } - - public bool VerifySequence(string input1, string input2) - { - byte[] array1 = Encoding.ASCII.GetBytes(input1); - Assert.False(array1.Length < 28); - byte[] array2 = Encoding.ASCII.GetBytes(input2); - Assert.False(array2.Length < 28); - Assert.AreNotEqual(input1, input2); - string incrementedString = Increment(input1, Mode.AlphaNumeric); - if (incrementedString.Equals(input2)) - { - return true; - } - else - { - return false; - } - } - public static string Increment(string text, Mode mode) - { - var textArr = text.ToCharArray(); - var characters = new List(); - - if (mode == Mode.AlphaNumeric || mode == Mode.Numeric) - for (char c = '0'; c <= '9'; c++) - characters.Add(c); - - if (mode == Mode.AlphaNumeric || mode == Mode.Alpha) - for (char c = 'a'; c <= 'f'; c++) - characters.Add(c); - - // Loop from end to beginning - for (int i = textArr.Length - 1; i >= 0; i--) - { - if (textArr[i] == characters.Last()) - { - textArr[i] = characters.First(); - } - else - { - textArr[i] = characters[characters.IndexOf(textArr[i]) + 1]; - break; - } - } - - return new string(textArr); - } - public enum Mode - { - AlphaNumeric = 1, - Alpha = 2, - Numeric = 3 - } - - #endregion Methods - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data; +using MySql.Data.Common; +using MySql.Data.MySqlClient; +using MySqlX.Common; +using MySqlX.XDevAPI; +using MySqlX.XDevAPI.Common; +using MySqlX.XDevAPI.CRUD; +using MySqlX.XDevAPI.Relational; +using NUnit.Framework; +using NUnit.Framework.Legacy; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MySqlX.Data.Tests +{ + public class CrudInsertTests : BaseTest + { + [Test] + public void InsertSingleDbDocWithId() + { + Collection coll = CreateCollection("test"); + Result r = ExecuteAddStatement(coll.Add(@"{ ""_id"": 1, ""foo"": 1 }")); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); + Assert.That(coll.Count(), Is.EqualTo(1)); + } + + [Test] + public void InsertSingleDbDocWithoutId() + { + Collection coll = CreateCollection("test"); + var stmt = coll.Add("{ \"foo\": 1 }"); + if (!session.Version.isAtLeast(8, 0, 5)) + { + // Code 5115 Document is missing a required field + Assert.That(Assert.Throws(() => ExecuteAddStatement(stmt)).Code, Is.EqualTo(5115u)); + return; + } + Result r = ExecuteAddStatement(stmt); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); + Assert.That(coll.Count(), Is.EqualTo(1)); + Assert.That(r.GeneratedIds, Has.One.Items); + Assert.That(string.IsNullOrWhiteSpace(r.GeneratedIds[0]), Is.False); + } + + [Test] + public void InsertMultipleDbDocWithoutId() + { + Collection coll = CreateCollection("test"); + var stmt = coll.Add("{ \"foo\": 1 }") + .Add("{ \"amber\": 2 }") + .Add("{ \"any\": 3 }"); + if (!session.Version.isAtLeast(8, 0, 5)) + { + // Code 5115 Document is missing a required field + Assert.That(Assert.Throws(() => ExecuteAddStatement(stmt)).Code, Is.EqualTo(5115u)); + return; + } + Result r = ExecuteAddStatement(stmt); + Assert.That(r.AffectedItemsCount, Is.EqualTo(3)); + Assert.That(coll.Count(), Is.EqualTo(3)); + Assert.That(r.GeneratedIds.Count, Is.EqualTo(3)); + } + + [Test] + public void InsertAnonymousObjectWithId() + { + var obj = new { _id = "5", name = "Sakila", age = 15 }; + + Collection coll = CreateCollection("test"); + Result r = ExecuteAddStatement(coll.Add(obj)); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); + //TODO: pull object and verify data + Assert.That(coll.Count(), Is.EqualTo(1)); + } + + [Test] + public void InsertAnonymousObjectWithNoId() + { + var obj = new { name = "Sakila", age = 15 }; + + Collection coll = CreateCollection("test"); + var stmt = coll.Add(obj); + if (!session.Version.isAtLeast(8, 0, 5)) + { + // Code 5115 Document is missing a required field + Assert.That(Assert.Throws(() => ExecuteAddStatement(stmt)).Code, Is.EqualTo(5115u)); + return; + } + Result r = ExecuteAddStatement(stmt); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); + //TODO: pull object and verify data + Assert.That(coll.Count(), Is.EqualTo(1)); + Assert.That(r.GeneratedIds, Has.One.Items); + Assert.That(string.IsNullOrWhiteSpace(r.GeneratedIds[0]), Is.False); + } + + [Test] + public void InsertMultipleAnonymousObjectsWithId() + { + Collection coll = CreateCollection("test"); + var docs = new[] + { + new { _id = 1, title = "Book 1", pages = 20 }, + new { _id = 2, title = "Book 2", pages = 30 }, + new { _id = 3, title = "Book 3", pages = 40 }, + new { _id = 4, title = "Book 4", pages = 50 }, + }; + Result r = ExecuteAddStatement(coll.Add(docs)); + Assert.That(r.AffectedItemsCount, Is.EqualTo(4)); + Assert.That(coll.Count(), Is.EqualTo(4)); + } + + [Test] + public void ValidatesDocumentIds() + { + Collection coll = CreateCollection("test"); + var stmt = coll.Add(new { name = "Book 1" }); + if (!session.Version.isAtLeast(8, 0, 5)) + { + // Code 5115 Document is missing a required field + Assert.That(Assert.Throws(() => ExecuteAddStatement(stmt)).Code, Is.EqualTo(5115u)); + return; + } + Result result = ExecuteAddStatement(stmt); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1)); + + result = ExecuteModifyStatement(coll.Modify($"_id = '{result.GeneratedIds[0]}'").Set("pages", "20")); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1)); + Assert.That(result.GeneratedIds, Is.Empty); + } + + [Test] + public void ReuseStatement() + { + Collection coll = CreateCollection("test"); + var docs = new[] + { + new { _id = 1, title = "Book 1", pages = 20 }, + new { _id = 2, title = "Book 2", pages = 30 }, + new { _id = 3, title = "Book 3", pages = 40 }, + new { _id = 4, title = "Book 4", pages = 50 }, + }; + var stmt = coll.Add(new { _id = 0 }); + foreach (var doc in docs) + { + stmt.Add(doc); + } + Result r = ExecuteAddStatement(stmt); + Assert.That(r.AffectedItemsCount, Is.EqualTo((ulong)docs.Length + 1)); + Assert.That(coll.Count(), Is.EqualTo(5)); + } + + [Test] + public void EmptyDocArray() + { + Collection coll = CreateCollection("test"); + + var insertResult = ExecuteAddStatement(coll.Add(new DbDoc[] { })); + Assert.That(insertResult.AffectedItemsCount, Is.EqualTo(0ul)); + + var result = ExecuteFindStatement(coll.Find()).FetchAll(); + Assert.That(result, Is.Empty); + } + + [Test] + public void NullParameter() + { + Collection coll = CreateCollection("test"); + + Assert.Throws(() => ExecuteAddStatement(coll.Add(null))); + } + + [Test] + public void InsertingArray() + { + var docs = new[] + { + new { id = 1, title = "Book 1" }, + new { id = 2, title = "Book 2" }, + }; + DbDoc d2 = new DbDoc(); + d2.SetValue("_id", 1); + d2.SetValue("books", docs); + d2.SetValue("pages", 20); + + Collection coll = CreateCollection("test"); + ExecuteAddStatement(coll.Add(d2)); + var result = ExecuteFindStatement(coll.Find()).FetchAll(); + Assert.That(result, Has.One.Items); + Assert.That(result[0].ToString(), Is.EqualTo(d2.ToString())); + } + + [Test] + public void CompareGuids() + { + Guid guid1 = new Guid(); + Guid guid2 = new Guid(); + Assert.That(Tools.CompareGuids(guid1, guid2), Is.EqualTo(0)); + Assert.That(Tools.CompareGuids(guid1.ToString(), guid2.ToString()), Is.EqualTo(0)); + + guid1 = Guid.NewGuid(); + guid2 = Guid.NewGuid(); + Assert.That(Tools.CompareGuids(guid1, guid2) != 0); + Assert.That(Tools.CompareGuids(guid1.ToString(), guid2.ToString()) != 0); + } + + [Test] + public void InsertNullValuesAsDbDoc() + { + Collection collection = CreateCollection("test"); + + var nullValues = new String[] { null, "null", "NULL" }; + var docs = new DbDoc[3]; + for (int i = 0; i < docs.Length; i++) + { + docs[i] = new DbDoc(); + docs[i].SetValue("a", nullValues[i]); + docs[i].SetValue("_id", (i + 1)); + } + + ExecuteAddStatement(collection.Add(docs)); + var result = ExecuteFindStatement(collection.Find()).FetchAll(); + Assert.That(result.Count, Is.EqualTo(docs.Length)); + + for (int i = 0; i < docs.Length; i++) + Assert.That(result[i].ToString(), Is.EqualTo(docs[i].ToString())); + } + + [Test] + public void InsertNullValuesAsJson() + { + var docs = new[] + { + @"{ ""_id"": 1, ""foo"": null}", + @"{ ""_id"": 2, ""foo"": null }", + @"{ ""_id"": 3, ""foo"": ""null"" }", + @"{ ""_id"": 4, ""foo"": ""NULL"" }", + }; + + Collection collection = CreateCollection("test"); + ExecuteAddStatement(collection.Add(docs)); + var result = ExecuteFindStatement(collection.Find()).FetchAll(); + Assert.That(result.Count, Is.EqualTo(docs.Length)); + for (int i = 0; i < docs.Length; i++) + { + var currentDoc = new DbDoc(docs[i]); + var resultingDoc = new DbDoc(result[i]); + Assert.That(resultingDoc.Id, Is.EqualTo(currentDoc.Id)); + Assert.That(resultingDoc["foo"], Is.EqualTo(currentDoc["foo"])); + } + } + + [Test] + public void AddOrReplaceOne() + { + if (!session.Version.isAtLeast(8, 0, 3)) return; + + Collection collection = CreateCollection("test"); + var docs = new[] + { + new { _id = 1, title = "Book 1", pages = 20 }, + new { _id = 2, title = "Book 2", pages = 30 }, + new { _id = 3, title = "Book 3", pages = 40 }, + new { _id = 4, title = "Book 4", pages = 50 }, + }; + Result result = ExecuteAddStatement(collection.Add(docs)); + Assert.That(result.AffectedItemsCount, Is.EqualTo(4)); + + // Add a document. + Assert.That(collection.AddOrReplaceOne(5, new { _id = 5, title = "Book 5", pages = 60 }).AffectedItemsCount, Is.EqualTo(1)); + Assert.That(collection.GetOne(5) != null); + + Assert.That(collection.AddOrReplaceOne("6", new { title = "Book 6", pages = 70 }).AffectedItemsCount, Is.EqualTo(1)); + Assert.That(collection.GetOne(6) != null); + Assert.That(collection.GetOne("6") != null); + + // Replace a document. + Assert.That(collection.AddOrReplaceOne(1, new { _id = 1, title = "Book X", pages = 10 }).AffectedItemsCount, Is.EqualTo(2)); + DbDoc document = collection.GetOne(1); + Assert.That(Convert.ToInt32(document.Id), Is.EqualTo(1)); + Assert.That(document["title"], Is.EqualTo("Book X")); + Assert.That(Convert.ToInt32(document["pages"]), Is.EqualTo(10)); + + Assert.That(collection.AddOrReplaceOne(1, new { title = "Book Y", pages = 9, other = "value" }).AffectedItemsCount, Is.EqualTo(2)); + document = collection.GetOne(1); + Assert.That(Convert.ToInt32(document.Id), Is.EqualTo(1)); + Assert.That(document["title"], Is.EqualTo("Book Y")); + Assert.That(Convert.ToInt32(document["pages"]), Is.EqualTo(9)); + Assert.That(document["other"], Is.EqualTo("value")); + + // Expected exceptions. + Assert.Throws(() => collection.AddOrReplaceOne(null, docs[1])); + Assert.Throws(() => collection.AddOrReplaceOne("", docs[1])); + Assert.Throws(() => collection.AddOrReplaceOne(" ", docs[1])); + Assert.Throws(() => collection.AddOrReplaceOne(string.Empty, docs[1])); + Assert.Throws(() => collection.AddOrReplaceOne("1", null)); + Assert.Throws(() => collection.AddOrReplaceOne(4, new DbDoc("{ \"_id\": 2, \"title\": \"Book\", \"pages\": 60 }")), + ResourcesX.ReplaceWithNoMatchingId); + } + + #region WL14389 + + [Test, Description("Test MySQLX plugin Collection Scenarios - with Create a valid collection and reuse existing object")] + public void CreateCollectionAndReuseObject() + { + using (Session sessionPlain = MySQLX.GetSession(ConnectionString)) + { + var col = CreateCollection("my_collection_123456789"); + object[] data = new object[] + { + new { _id = 1, title = "Book 1", pages = 20 }, + new { _id = 2, title = "Book 2", pages = 30 }, + new { _id = 3, title = "Book 3", pages = 40 }, + new { _id = 4, title = "Book 4", pages = 50 }, + }; + Result result = col.Add(data).Execute(); + var data1 = col.Remove("_id = 1").Execute(); + Assert.That((int)data1.AffectedItemsCount, Is.EqualTo(1), "Matching the deleted record count"); + data1 = col.Remove("_id = 2").Execute(); + Assert.That((int)data1.AffectedItemsCount, Is.EqualTo(1), "Matching the deleted record count"); + data1 = col.Remove("_id = 3").Execute(); + Assert.That((int)data1.AffectedItemsCount, Is.EqualTo(1), "Matching the deleted record count"); + data1 = col.Remove("_id = 4").Execute(); + Assert.That((int)data1.AffectedItemsCount, Is.EqualTo(1), "Matching the deleted record count"); + sessionPlain.Close(); + } + } + + [Test, Description("Collection Scenarios - with Create a collection with emptyname")] + public void CreateCollectionEmptyName() + { + Schema db = session.GetSchema(schemaName); + Assert.Throws(() => db.CreateCollection(null)); + } + + [Test, Description("Test MySQLX plugin Collection Scenarios - with Create a collection which exists without reuse existing object")] + public void CreateCollectionWithoutReuseExistingObject() + { + Schema db = session.GetSchema(schemaName); + var col = CreateCollection("my_collection_123456789"); + col = db.GetCollection("my_collection_123456789", true); + Assert.That(col, Is.Not.Null); + Assert.Throws(() => db.CreateCollection("my_collection_123456789", false)); + } + + [Test, Description("Test MySQLX plugin Collection Scenarios - Add Objects,Find with condition")] + public void CollectionAddObjectsFindCondition() + { + Schema db = session.GetSchema(schemaName); + Collection col = CreateCollection("my_collection_1"); + var docs = new[] + { + new { _id = 1, title = "Book 1", pages = 20 }, + new { _id = 2, title = "Book 2", pages = 30 }, + new { _id = 3, title = "Book 3", pages = 40 }, + new { _id = 4, title = "Book 4", pages = 50 }, + }; + Result result = col.Add(docs).Execute(); + + Assert.That((int)result.AffectedItemsCount, Is.EqualTo(4), "Matching the updated record count"); + var foundDocs = col.Find("pages > 20").Execute(); + Assert.That(foundDocs.Next(), Is.EqualTo(true), "Next Node Exist"); + Assert.That(foundDocs.Current["title"], Is.EqualTo("Book 2"), "Matching the Node Value"); + Assert.That(foundDocs.Next(), Is.EqualTo(true), "Next Node Exist"); + Assert.That(foundDocs.Current["title"], Is.EqualTo("Book 3"), "Matching the Node Value"); + Assert.That(foundDocs.Next(), Is.EqualTo(true), "Next Node Exist"); + Assert.That(foundDocs.Current["title"], Is.EqualTo("Book 4"), "Matching the Node Value"); + Assert.That(foundDocs.Next(), Is.EqualTo(false), "Next Node doesnot Exist"); + db.DropCollection("my_collection_1"); + } + + [Test, Description("Test MySQLX plugin Collection Scenarios - Add Objects,Find without parameters")] + public void CollectionAddFindNoParams() + { + Assume.That(session.Version.isAtLeast(5, 7, 0), "This test is for MySql 5.7 or higher"); + Collection col = CreateCollection("my_collection_1"); + var docs = new[] + { + new { _id = 1, title = "Book 1", pages = 20 }, + new { _id = 2, title = "Book 2", pages = 30 }, + new { _id = 3, title = "Book 3", pages = 40 }, + new { _id = 4, title = "Book 4", pages = 50 }, + }; + + var result = col.Add(docs).Execute(); + Assert.That((int)result.AffectedItemsCount, Is.EqualTo(4), "Matching the updated record count"); + var foundDocs = col.Find().Execute(); + Assert.That(foundDocs.Next(), Is.EqualTo(true), "Next Node Exist"); + Assert.That(foundDocs.Current["title"], Is.EqualTo("Book 1"), "Matching the Node Value"); + Assert.That(foundDocs.Next(), Is.EqualTo(true), "Next Node Exist"); + Assert.That(foundDocs.Current["title"], Is.EqualTo("Book 2"), "Matching the Node Value"); + Assert.That(foundDocs.Next(), Is.EqualTo(true), "Next Node Exist"); + Assert.That(foundDocs.Current["title"], Is.EqualTo("Book 3"), "Matching the Node Value"); + Assert.That(foundDocs.Next(), Is.EqualTo(true), "Next Node Exist"); + Assert.That(foundDocs.Current["title"], Is.EqualTo("Book 4"), "Matching the Node Value"); + Assert.That(foundDocs.Next(), Is.EqualTo(false), "Next Node doesnot Exist"); + } + + [Test, Description("Test MySQLX plugin Collection Scenarios - Add/Remove JSON Object with id")] + public void CollectionAddRemoveJSONObjectID() + { + Assume.That(session.Version.isAtLeast(5, 7, 0), "This test is for MySql 5.7 or higher"); + using (var sessionPlain = MySQLX.GetSession(ConnectionString + ";sslmode=" + MySqlSslMode.Required)) + { + Schema db = sessionPlain.GetSchema(schemaName); + Collection col = CreateCollection("my_collection_1"); + DbDoc DbDocs = new DbDoc(); + DbDocs.SetValue("_id", "0"); + DbDocs.SetValue("title", "Book 0"); + DbDocs.SetValue("pages", "10"); + var result = col.Add(DbDocs).Execute(); + Assert.That((int)result.AffectedItemsCount, Is.EqualTo(1), "Matching the updated record count"); + DbDoc jsonremovedoc = new DbDoc(); + jsonremovedoc.SetValue("_id", "0"); + var foundDocs = col.Remove("_id='0'").Execute(); + Assert.That((int)foundDocs.AffectedItemsCount, Is.EqualTo(1), "Matching the deleted record count"); + db.DropCollection("my_collection_1"); + sessionPlain.Close(); + } + } + + [Test, Description("Test MySQLX plugin Collection Scenarios - Add/Remove with condition")] + public void CollectionAddRemoveJSONObjectCondition() + { + Assume.That(session.Version.isAtLeast(5, 7, 0), "This test is for MySql 5.7 or higher"); + Schema db = session.GetSchema(schemaName); + Collection col = CreateCollection("my_collection_1"); + DbDoc DbDocs = new DbDoc(); + DbDocs.SetValue("_id", "0"); + DbDocs.SetValue("title", "Book 0"); + DbDocs.SetValue("pages", "10"); + var result = col.Add(DbDocs).Execute(); + Assert.That((int)result.AffectedItemsCount, Is.EqualTo(1), "Matching the updated record count"); + var foundDocs = col.Remove("pages > 0").Execute(); + Assert.That((int)foundDocs.AffectedItemsCount, Is.EqualTo(1), "Matching the deleted record count"); + db.DropCollection("my_collection_1"); + } + + [Test, Description("Test MySQLX plugin Collection Scenarios - Add,Remove with condition limit")] + public void CollectionAddRemoveObjectConditionLimit() + { + Assume.That(session.Version.isAtLeast(5, 7, 0), "This test is for MySql 5.7 or higher"); + Schema db = session.GetSchema(schemaName); + Collection col = CreateCollection("my_collection_1"); + var docs = new[] + { + new { _id = 0, title = "Book 0", pages = 10 }, + new { _id = 1, title = "Book 1", pages = 20 }, + new { _id = 2, title = "Book 2", pages = 30 }, + new { _id = 3, title = "Book 3", pages = 40 }, + new { _id = 4, title = "Book 4", pages = 50 }, + }; + var result = col.Add(docs).Execute(); + Assert.That((int)result.AffectedItemsCount, Is.EqualTo(5), "Matching the updated record count"); + var foundDocs = col.Remove("_id=1").Execute(); + Assert.That((int)foundDocs.AffectedItemsCount, Is.EqualTo(1), "Matching the deleted record count"); + docs = new[] + { + new { _id = 1, title = "Book 1", pages = 20 }, + }; + result = col.Add(docs).Execute(); + Assert.That((int)result.AffectedItemsCount, Is.EqualTo(1), "Matching the updated record count"); + result = col.Remove("pages > 10").Limit(1).Execute(); + Assert.That((int)result.AffectedItemsCount, Is.EqualTo(1), "Matching the updated record count"); + result = col.Remove("pages > 10").Limit(3).Execute(); + Assert.That((int)result.AffectedItemsCount, Is.EqualTo(3), "Matching the updated record count"); + Assert.Throws(() => col.Remove("pages > 10").Limit(0).Execute()); + db.DropCollection("my_collection_1"); + } + + [Test, Description("Test MySQLX plugin Collection Scenarios - Add/Remove 200 JSON records ")] + public void CollectionAddRemove200JSONRecords() + { + Assume.That(session.Version.isAtLeast(5, 7, 0), "This test is for MySql 5.7 or higher"); + Collection col = CreateCollection("my_collection_1"); + var numOfRecords = 200; + + DbDoc[] jsonlist = new DbDoc[numOfRecords]; + for (int i = 0; i < numOfRecords; i++) + { + DbDoc newDoc2 = new DbDoc(); + newDoc2.SetValue("_id", (i + 1000).ToString()); + newDoc2.SetValue("F1", ("Field-1-Data-" + i)); + newDoc2.SetValue("F2", ("Field-2-Data-" + i)); + newDoc2.SetValue("F3", (300 + i).ToString()); + jsonlist[i] = newDoc2; + newDoc2 = null; + } + var res = col.Add(jsonlist).Execute(); + + Assert.That(jsonlist[0].ToString(), Is.EqualTo(jsonlist[0].ToString()), "String Match being done"); + for (int i = 0; i < numOfRecords; i++) + { + var data1 = col.Remove($"_id = '{i + 1000}'").Execute(); + Assert.That((int)data1.AffectedItemsCount, Is.EqualTo(1), "Matching the deleted record count"); + } + } + + [Test, Description("Test MySQLX plugin Collection Scenarios - Add/Remove documents with limit and orderby ")] + public void CollectionAddRemoveJSONRecordsLimitOrderBy() + { + Assume.That(session.Version.isAtLeast(5, 7, 0), "This test is for MySql 5.7 or higher"); + Schema db = session.GetSchema(schemaName); + Collection col = CreateCollection("my_collection_1"); + + DbDoc[] jsonlist = new DbDoc[10]; + for (int i = 0; i < 10; i++) + { + DbDoc newDoc2 = new DbDoc(); + newDoc2.SetValue("_id", (i).ToString()); + newDoc2.SetValue("F1", ("Field-1-Data-" + i)); + newDoc2.SetValue("F2", ("Field-2-Data-" + i)); + newDoc2.SetValue("F3", (300 + i)); + jsonlist[i] = newDoc2; + newDoc2 = null; + } + col.Add(jsonlist).Execute(); + Assert.That(jsonlist[0].ToString(), Is.EqualTo(jsonlist[0].ToString()), "String Match being done"); + + Result result = col.Remove("F3 > 305").Limit(1).Execute(); + Assert.That((int)result.AffectedItemsCount, Is.EqualTo(1), "Match being done"); + + result = col.Remove("F3 > 303").Sort("F3 DESC").Execute(); + Assert.That((int)result.AffectedItemsCount, Is.EqualTo(5), "Match being done"); + + result = col.Remove("F3 > 303").Sort("F3 DESC").Execute(); + Assert.That((int)result.AffectedItemsCount, Is.EqualTo(0), "Match being done"); + + result = col.Remove("F3 = 303").Sort("F2 DESC").Execute(); + Assert.That((int)result.AffectedItemsCount, Is.EqualTo(1), "Match being done"); + + result = col.Remove("F3 < 301").Sort("F2 DESC").Execute(); + Assert.That((int)result.AffectedItemsCount, Is.EqualTo(1), "Match being done"); + + result = col.Remove("F3 < 301").Sort("F2 DESC").Execute(); + Assert.That((int)result.AffectedItemsCount, Is.EqualTo(0), "Match being done"); + + db.DropCollection("my_collection_1"); + + } + + [Test, Description("Test MySQLX plugin Collection Scenarios - Add Single/Multiple Docs - Remove Condition/ID/Condition-Limit/Condition-Limit-OrderBy/Bind")] + public void CollectionAddRemoveDocsLimitOrderByBind() + { + Assume.That(session.Version.isAtLeast(5, 7, 0), "This test is for MySql 5.7 or higher"); + Collection col = CreateCollection("my_collection_1"); + DbDoc DbDocs = new DbDoc(); + DbDocs.SetValue("_id", 100000); + DbDocs.SetValue("title", "Book 0"); + DbDocs.SetValue("pages", 10); + var result = col.Add(DbDocs).Execute(); + Assert.That((int)result.AffectedItemsCount, Is.EqualTo(1), "Matching the updated record count"); + var foundDocs = col.Remove("pages > 0").Execute(); + Assert.That((int)foundDocs.AffectedItemsCount, Is.EqualTo(1), "Matching the deleted record count"); + + var docs = new { _id = 100001, title = "Book 1", pages = 20 }; + result = col.Add(docs).Execute(); + Assert.That((int)result.AffectedItemsCount, Is.EqualTo(1), "Matching the updated record count"); + + foundDocs = col.Remove("pages=20").Execute(); + Assert.That((int)foundDocs.AffectedItemsCount, Is.EqualTo(1), "Matching the deleted record count"); + + docs = new { _id = -100001, title = "Book 1", pages = 20 }; + result = col.Add(docs).Execute(); + Assert.That((int)result.AffectedItemsCount, Is.EqualTo(1), "Matching the updated record count"); + + foundDocs = col.Remove("pages=20").Execute(); + Assert.That((int)foundDocs.AffectedItemsCount, Is.EqualTo(1), "Matching the deleted record count"); + var docs1 = new[] + { + new { _id = -100001, title = "Book 0", pages = 10 }, + new { _id = 0, title = "Book 1", pages = 20 }, + new { _id = 100001, title = "Book 2", pages = 30 }, + new { _id = 10000001, title = "Book 3", pages = 40 } + }; + result = col.Add(docs1).Execute(); + Assert.That((int)result.AffectedItemsCount, Is.EqualTo(4), "Matching the updated record count"); + + foundDocs = col.Remove("pages > 10").Execute(); + Assert.That((int)foundDocs.AffectedItemsCount, Is.EqualTo(3), "Matching the deleted record count"); + + foundDocs = col.Remove("pages=10").Execute(); + Assert.That((int)foundDocs.AffectedItemsCount, Is.EqualTo(1), "Matching the deleted record count"); + docs1 = new[] + { + new { _id = -100001, title = "Book 0", pages = 10 }, + new { _id = 0, title = "Book 1", pages = 20 }, + new { _id = 100001, title = "Book 2", pages = 30 }, + new { _id = 10000001, title = "Book 3", pages = 40 }, + new { _id = 10000009, title = "Book 4", pages = 50 } + }; + result = col.Add(docs1).Execute(); + Assert.That((int)result.AffectedItemsCount, Is.EqualTo(5), "Matching the updated record count"); + + foundDocs = col.Remove("pages = 40").Execute(); + Assert.That((int)foundDocs.AffectedItemsCount, Is.EqualTo(1), "Matching the deleted record count"); + + foundDocs = col.Remove("pages >= 10").Execute(); + Assert.That((int)foundDocs.AffectedItemsCount, Is.EqualTo(4), "Matching the deleted record count"); + + result = col.Add(docs1).Execute(); + Assert.That((int)result.AffectedItemsCount, Is.EqualTo(5), "Matching the updated record count"); + foundDocs = col.Remove("pages = 40").Limit(1).Execute(); + Assert.That((int)foundDocs.AffectedItemsCount, Is.EqualTo(1), "Matching the deleted record count"); + foundDocs = col.Remove("pages <= 50").Execute(); + Assert.That((int)foundDocs.AffectedItemsCount, Is.EqualTo(4), "Matching the deleted record count"); + + result = col.Add(docs1).Execute(); + Assert.That((int)result.AffectedItemsCount, Is.EqualTo(5), "Matching the updated record count"); + foundDocs = col.Remove("pages = 40").Limit(1).Sort("title").Execute(); + Assert.That((int)foundDocs.AffectedItemsCount, Is.EqualTo(1), "Matching the deleted record count"); + foundDocs = col.Remove("pages <= 50").Execute(); + Assert.That((int)foundDocs.AffectedItemsCount, Is.EqualTo(4), "Matching the deleted record count"); + + docs1 = new[] + { + new { _id = 1, title = "Book 1", pages = 20 }, + new { _id = 2, title = "Book 2", pages = 30 }, + new { _id = 3, title = "Book 3", pages = 40 }, + new { _id = 4, title = "Book 4", pages = 50 }, + }; + + result = col.Add(docs1).Execute(); + Assert.That((int)result.AffectedItemsCount, Is.EqualTo(4), "Matching the updated record count"); + foundDocs = col.Remove("pages = :Pages").Bind("pAges", 50).Execute(); + Assert.That((int)foundDocs.AffectedItemsCount, Is.EqualTo(1), "Matching the deleted record count"); + } + + [Test, Description("Test MySQLX plugin Collection Scenarios - Add Single/Multiple Docs - Remove Condition/ID/Condition-Limit/Condition-Limit-OrderBy/Bind using invalid conditions")] + public void CollectionRemoveDocsLimitOrderByBindNegative() + { + Assume.That(session.Version.isAtLeast(5, 7, 0), "This test is for MySql 5.7 or higher"); + Schema db = session.GetSchema(schemaName); + var col = db.CreateCollection("my_collection_1", true); + + DbDoc DbDocs = new DbDoc(); + DbDocs.SetValue("_id", 100000); + DbDocs.SetValue("title", "Book 0"); + DbDocs.SetValue("pages", 10); + var result = col.Add(DbDocs).Execute(); + + Assert.That((int)result.AffectedItemsCount, Is.EqualTo(1), "Matching the updated record count"); + var foundDocs = col.Remove("pages > 10").Execute(); + Assert.That((int)foundDocs.AffectedItemsCount, Is.EqualTo(0), "Matching the deleted record count"); + + var docs = new { _id = 100001, title = "Book 1", pages = 20 }; + result = col.Add(docs).Execute(); + Assert.That((int)result.AffectedItemsCount, Is.EqualTo(1), "Matching the updated record count"); + + foundDocs = col.Remove("pages >= 10").Execute(); + Assert.That((int)foundDocs.AffectedItemsCount, Is.EqualTo(2), "Matching the deleted record count"); + + docs = new { _id = -100001, title = "Book 1", pages = 20 }; + result = col.Add(docs).Execute(); + Assert.That((int)result.AffectedItemsCount, Is.EqualTo(1), "Matching the updated record count"); + + foundDocs = col.Remove("pages > 10").Execute(); + Assert.That((int)foundDocs.AffectedItemsCount, Is.EqualTo(1), "Matching the deleted record count"); + + + var docs1 = new[] + { + new { _id = -100001, title = "Book 0", pages = 10 }, + new { _id = 0, title = "Book 1", pages = 20 }, + new { _id = 100001, title = "Book 2", pages = 30 }, + new { _id = 10000001, title = "Book 3", pages = 40 } + }; + result = col.Add(docs1).Execute(); + Assert.That((int)result.AffectedItemsCount, Is.EqualTo(4), "Matching the updated record count"); + + foundDocs = col.Remove("pages > 50").Execute(); + Assert.That((int)foundDocs.AffectedItemsCount, Is.EqualTo(0), "Matching the deleted record count"); + + foundDocs = col.Remove("pages < 50").Execute(); + Assert.That((int)foundDocs.AffectedItemsCount, Is.EqualTo(4), "Matching the deleted record count"); + + docs1 = new[] + { + new { _id = -100001, title = "Book 0", pages = 10 }, + new { _id = 0, title = "Book 1", pages = 20 }, + new { _id = 100001, title = "Book 2", pages = 30 }, + new { _id = 10000001, title = "Book 3", pages = 40 }, + new { _id = 10000009, title = "Book 4", pages = 50 } + }; + result = col.Add(docs1).Execute(); + Assert.That((int)result.AffectedItemsCount, Is.EqualTo(5), "Matching the updated record count"); + + foundDocs = col.Remove("pages = 0").Execute(); + Assert.That((int)foundDocs.AffectedItemsCount, Is.EqualTo(0), "Matching the deleted record count"); + + foundDocs = col.Remove("pages <= 50").Execute(); + Assert.That((int)foundDocs.AffectedItemsCount, Is.EqualTo(5), "Matching the deleted record count"); + + result = col.Add(docs1).Execute(); + Assert.That((int)result.AffectedItemsCount, Is.EqualTo(5), "Matching the updated record count"); + foundDocs = col.Remove("pages = 60").Limit(1).Execute(); + Assert.That((int)foundDocs.AffectedItemsCount, Is.EqualTo(0), "Matching the deleted record count"); + + foundDocs = col.Remove("pages <= 50").Execute(); + Assert.That((int)foundDocs.AffectedItemsCount, Is.EqualTo(5), "Matching the deleted record count"); + + result = col.Add(docs1).Execute(); + Assert.That((int)result.AffectedItemsCount, Is.EqualTo(5), "Matching the updated record count"); + foundDocs = col.Remove("pages = 04").Limit(1).Sort("title").Execute(); + Assert.That((int)foundDocs.AffectedItemsCount, Is.EqualTo(0), "Matching the deleted record count"); + foundDocs = col.Remove("pages <= 50").Execute(); + Assert.That((int)foundDocs.AffectedItemsCount, Is.EqualTo(5), "Matching the deleted record count"); + + docs1 = new[] + { + new { _id = 1, title = "Book 1", pages = 20 }, + new { _id = 2, title = "Book 2", pages = 30 }, + new { _id = 3, title = "Book 3", pages = 40 }, + new { _id = 4, title = "Book 4", pages = 50 }, + }; + + result = col.Add(docs1).Execute(); + Assert.That((int)result.AffectedItemsCount, Is.EqualTo(4), "Matching the updated record count"); + foundDocs = col.Remove("pages1 = :Pages").Bind("pAges", 50).Execute(); + Assert.That((int)foundDocs.AffectedItemsCount, Is.EqualTo(0), "Matching the deleted record count"); + foundDocs = col.Remove("pages = :Pages").Bind("pAges", 51).Execute(); + Assert.That((int)foundDocs.AffectedItemsCount, Is.EqualTo(0), "Matching the deleted record count"); + foundDocs = col.Remove("pages = :Pages").Bind("pAges", 50).Execute(); + Assert.That((int)foundDocs.AffectedItemsCount, Is.EqualTo(1), "Matching the deleted record count"); + db.DropCollection("my_collection_1"); + + } + + [Test, Description("Test MySQLX plugin - MYSQLCNET_680 Allow Reuse Statement after execute Positive1(after a succesful execute)")] + public void AllowReuseStatementAfterExecutePositive1() + { + Assume.That(session.Version.isAtLeast(5, 7, 0), "This test is for MySql 5.7 or higher"); + Schema db = session.GetSchema(schemaName); + var col = db.CreateCollection("my_collection_123456789"); + object[] data = new object[] + { + new { _id = 1, title = "Book 1", pages = 10 }, + new { _id = 2, title = "Book 2", pages = 20 }, + new { _id = 3, title = "Book 3", pages = 30 }, + new { _id = 4, title = "Book 4", pages = 40 }, + new { _id = 5, title = "Book 5", pages = 50 }, + new { _id = 6, title = "Book 6", pages = 60 }, + new { _id = 7, title = "Book 7", pages = 70 }, + new { _id = 8, title = "Book 8", pages = 80 }, + }; + Result result = col.Add(data).Execute(); + Assert.That((int)result.AffectedItemsCount, Is.EqualTo(8), "Matching the added record count"); + var data1 = col.Remove("_id=1").Execute(); + Assert.That((int)data1.AffectedItemsCount, Is.EqualTo(1), "Matching the deleted record count"); + data1 = col.Remove("pages = :Pages").Bind("pAges", 80).Execute(); + Assert.That((int)data1.AffectedItemsCount, Is.EqualTo(1), "Matching the deleted record count"); + data1 = col.Remove("pages = :Pages").Bind("pAges", 70).Execute(); + Assert.That((int)data1.AffectedItemsCount, Is.EqualTo(1), "Matching the deleted record count"); + var remData = col.Remove("_id = :param1 AND title = :param2"); + data1 = remData.Bind("param1", 5).Bind("param2", "Book 5").Execute(); + Assert.That((int)data1.AffectedItemsCount, Is.EqualTo(1), "Matching the deleted record count"); + data1 = remData.Bind("param1", 6).Bind("param2", "Book 6").Execute(); + Assert.That((int)data1.AffectedItemsCount, Is.EqualTo(1), "Matching the deleted record count"); + db.DropCollection("my_collection_123456789"); + } + + [Test, Description("Test MySQLX plugin - MYSQLCNET_680 Allow Reuse Statement after execute-Positive2(after an unsuccessful execute)")] + public void AllowReuseStatementAfterExecutePositive2() + { + var col = CreateCollection("my_collection_123456789"); + object[] data = new object[] + { + new { _id = 1, title = "Book 1", pages = 10 }, + new { _id = 2, title = "Book 2", pages = 20 }, + new { _id = 3, title = "Book 3", pages = 30 }, + new { _id = 4, title = "Book 4", pages = 40 }, + new { _id = 5, title = "Book 5", pages = 50 }, + new { _id = 6, title = "Book 6", pages = 60 }, + new { _id = 7, title = "Book 7", pages = 70 }, + new { _id = 8, title = "Book 8", pages = 80 }, + }; + Result result = col.Add(data).Execute(); + Assert.That((int)result.AffectedItemsCount, Is.EqualTo(8), "Matching the added record count"); + var data1 = col.Remove("_id=1").Execute(); + Assert.That((int)data1.AffectedItemsCount, Is.EqualTo(1), "Matching the deleted record count"); + data1 = col.Remove("pages = :Pages").Bind("pAges", 80).Execute(); + Assert.That((int)data1.AffectedItemsCount, Is.EqualTo(1), "Matching the deleted record count"); + data1 = col.Remove("pages = :Pages").Bind("pAges", 70).Execute(); + Assert.That((int)data1.AffectedItemsCount, Is.EqualTo(1), "Matching the deleted record count"); + var remData = col.Remove("_id = :param1 AND title = :param2"); + + data1 = remData.Bind("param1", 35).Bind("param2", "Book 33").Execute(); + Assert.That((int)data1.AffectedItemsCount, Is.EqualTo(0), "Matching the deleted record count"); + + data1 = remData.Bind("param1", 6).Bind("param2", "Book 6").Execute(); + Assert.That((int)data1.AffectedItemsCount, Is.EqualTo(1), "Matching the deleted record count"); + testSchema.DropCollection("my_collection_123456789"); + } + + [Test, Description("Test MySQLX plugin - MYSQLCNET 755 Collection GetDocumentID")] + public void CollectionGetDocumentID() + { + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); + Collection coll = CreateCollection("test"); + var docs = new[] + { + new { _id = 100, title = "Book 100", pages = 1000 }, + }; + Result result = coll.Add(docs).Execute(); + var documentIds = result.GeneratedIds; + Assert.That(documentIds != null && documentIds.Count > 0, Is.False); + + coll = CreateCollection("test"); + var docs1 = new[] + { + new { title = "Book 1", pages = 100 }, + }; + var r = coll.Add(docs1); + var result1 = r.Execute(); + var documentIds1 = result.GeneratedIds; + HashSet firstset = new HashSet(); + for (int i = 0; i < documentIds.Count; i++) + { + if (documentIds1 != null) + { + Assert.That(documentIds1[i].ToString(), Is.EqualTo(documentIds1[i].ToString()), "Matching the document ID with unique id"); + } + if (!firstset.Add(documentIds1[i])) + { + break; + } + } + + coll = CreateCollection("test"); + docs = new[] + { + new { _id = 100, title = "Book 100", pages = 1000 }, + new { _id = 200, title = "Book 200", pages = 2000 }, + new { _id = 300, title = "Book 300", pages = 3000 }, + new { _id = 400, title = "Book 400", pages = 4000 }, + }; + + var r1 = coll.Add(docs).Execute(); + documentIds = r1.GeneratedIds; + Assert.That(documentIds != null && documentIds.Count > 0, Is.False); + + coll = CreateCollection("test"); + docs1 = new[] + { + new { title = "Book 1", pages = 100 }, + new { title = "Book 2", pages = 200 }, + new { title = "Book 3", pages = 300 }, + new { title = "Book 4", pages = 400 }, + }; + + var stmt = coll.Add(docs1); + result1 = stmt.Execute(); + documentIds1 = result1.GeneratedIds; + firstset = new HashSet(); + for (int i = 0; i < documentIds1.Count; i++) + { + if (documentIds != null) + { + Assert.That(documentIds1[i].ToString(), Is.EqualTo(documentIds1[i].ToString()), "Matching the document ID with unique id"); + } + + if (!firstset.Add(documentIds1[i])) + { + break; + } + } + } + + [Test, Description("Test MySQLX UUID Scenario-1(Check UUID is not generated when JSON doc is added using collection.add() with _id fields)")] + public void CheckDocUUIDScenario1() + { + var col = CreateCollection("my_collection_123456789"); + object[] data = new object[] + { + new { _id = 1, title = "Book 1", pages = 20 }, + new { _id = 2, title = "Book 2", pages = 30 }, + new { _id = 3, title = "Book 3", pages = 40 }, + new { _id = 4, title = "Book 4", pages = 50 }, + }; + Result result = col.Add(data).Execute(); + var documentIds = result.GeneratedIds; + Assert.That(documentIds != null && documentIds.Count > 0, Is.False); + } + + [Test, Description("Test MySQLX UUID Scenario-2(Check UUID generated when multiple JSON docs are added using collection.add().add()..without _id fields)")] + public void CheckDocUUIDScenario2() + { + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); + var col = CreateCollection("my_collection_123456789"); + object[] data1 = new object[] + { + new { title ="Book 1", pages = 20 }, + new { title = "Book 2", pages = 30 }, + new { title = "Book 3", pages = 40 }, + new { title = "Book 4", pages = 50 } + }; + + object[] data2 = new object[] + { + new { title = "Book 5", pages = 60 }, + new {title = "Book 6", pages = 70 }, + new { title = "Book 7", pages = 80 }, + new { title = "Book 8", pages = 90 }, + }; + var stmt = col.Add(data1).Add(data2); + var result = stmt.Execute(); + var documentIds = result.GeneratedIds; + HashSet firstset = new HashSet(); + for (int i = 0; i < documentIds.Count; i++) + { + if (documentIds != null) + { + Assert.That(documentIds[i].ToString(), Is.EqualTo(documentIds[i].ToString()), "Matching the document ID with unique id"); + } + if (!firstset.Add(documentIds[i])) + { + Console.WriteLine("Contains duplicate ID"); + break; + } + } + } + + [Test, Description("Test MySQLX UUID Scenario-2(Check UUID generated when multiple JSON docs are added using collection.add(doc, doc, doc... ) without _id fields)")] + public void CheckDocUUIDScenario3() + { + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); + var col = CreateCollection("my_collection_123456789"); + var stmt = col.Add(@"{ ""foo"": 1 }", @"{""foo"": 2 }", @"{ ""foo"": 3 }", @"{ ""foo"": 4 }"); + Result r = col.Add(@"{ ""foo"": 1 }", @"{""foo"": 2 }", @"{ ""foo"": 3 }", @"{ ""foo"": 4 }").Execute(); + long count = col.Count(); + Assert.That(4, Is.EqualTo(count), "Matching the Collection Count"); + var documentIds = r.GeneratedIds; + if (documentIds != null) + { + Assert.That(documentIds[0].ToString(), Is.EqualTo(documentIds[0].ToString()), "Matching the document ID without unique id"); + Assert.That(documentIds[1].ToString(), Is.EqualTo(documentIds[1].ToString()), "Matching the document ID without unique id"); + Assert.That(documentIds[2].ToString(), Is.EqualTo(documentIds[2].ToString()), "Matching the document ID without unique id"); + Assert.That(documentIds[3].ToString(), Is.EqualTo(documentIds[3].ToString()), "Matching the document ID without unique id"); + } + + var collectionName = col.Name; + Assert.That("my_collection_123456789", Is.EqualTo(collectionName), "Matching the collection Name"); + Assert.That(col.Schema.Name, Is.EqualTo(schemaName), "Matching the Schema Name"); + } + + [Test, Description("Test MySQLX UUID Scenario-4(Check UUID generated when multiple JSON docs are added using some containing and some not containing _id fields)")] + public void CheckDocUUIDScenario4() + { + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); + var col = CreateCollection("my_collection_123456789"); + object[] data1 = new object[] + { + new { _id = 1, title = "Book 1", pages = 20 }, + new { _id = 2, title = "Book 2", pages = 30 }, + new { _id = 3, title = "Book 3", pages = 40 }, + new { title = "Book 4", pages = 50 } + }; + + object[] data2 = new object[] + { + new { title = "Book 5", pages = 60 }, + new { _id = 6,title = "Book 6", pages = 70 }, + new { title = "Book 7", pages = 80 }, + new { title = "Book 8", pages = 90 }, + }; + + var stmt = col.Add(data1).Add(data2); + Result result = stmt.Execute(); + var documentIdsCount = result.GeneratedIds.Count; + var documentIds = result.GeneratedIds; + Assert.That(documentIdsCount, Is.EqualTo(4), "Matching the document ID count"); + if (documentIds != null) + { + Assert.That(documentIds[0].ToString(), Is.EqualTo(documentIds[0].ToString()), "Matching the document ID with unique id"); + Assert.That(documentIds[1].ToString(), Is.EqualTo(documentIds[1].ToString()), "Matching the document ID with unique id"); + Assert.That(documentIds[2].ToString(), Is.EqualTo(documentIds[2].ToString()), "Matching the document ID with unique id"); + Assert.That(documentIds[3].ToString(), Is.EqualTo(documentIds[3].ToString()), "Matching the document ID without unique id"); + } + } + + [Test, Description("Test MySQLX UUID Scenario-5(Check that UUID is not generated by adding multiple doc from the same collection in a session with _id fields)")] + public void CheckDocUUIDScenario5() + { + Collection testCollection = CreateCollection("test"); + DbDoc[] jsonlist = new DbDoc[1000]; + for (int i = 0; i < 1000; i++) + { + DbDoc newDoc2 = new DbDoc(); + newDoc2.SetValue("_id", (i + 1000)); + newDoc2.SetValue("F1", ("Field-1-Data-" + i)); + newDoc2.SetValue("F2", ("Field-2-Data-" + i)); + newDoc2.SetValue("F3", (300 + i).ToString()); + jsonlist[i] = newDoc2; + newDoc2 = null; + } + Result r = testCollection.Add(jsonlist).Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1000), "Matching"); + var documentIds = r.GeneratedIds; + Assert.That(documentIds != null && documentIds.Count > 0, Is.False); + + Schema testSchema = session.GetSchema(schemaName); + Table test = testSchema.GetCollectionAsTable("test"); + Assert.That(test.ExistsInDatabase(), Is.EqualTo(true), "Matching"); + } + + [Test, Description("Test MySQLX UUID Scenario-6(Check that no duplicate UUID is generated by adding multiple doc from the same collection in a session when there are no _id fields)")] + public void CheckDocUUIDScenario6() + { + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); + Collection testCollection = CreateCollection("test"); + DbDoc[] jsonlist = new DbDoc[1000]; + for (int i = 0; i < 1000; i++) + { + DbDoc newDoc2 = new DbDoc(); + newDoc2.SetValue("F1", ("Field-1-Data-" + i)); + newDoc2.SetValue("F2", ("Field-2-Data-" + i)); + newDoc2.SetValue("F3", (300 + i).ToString()); + jsonlist[i] = newDoc2; + newDoc2 = null; + } + + var r = testCollection.Add(jsonlist); + var result = r.Execute(); + var countgenerateIDs = result.GeneratedIds.Count; + Assert.That(countgenerateIDs, Is.EqualTo(1000), "Count of the ID generated by the server"); + for (int i = 0; i < countgenerateIDs; i++) + { + var generatedIDs1 = result.GeneratedIds[i]; + Assert.That(generatedIDs1, Is.EqualTo(generatedIDs1), "ID generated by the server"); + } + + Schema testSchema = session.GetSchema(schemaName); + Table test = testSchema.GetCollectionAsTable("test"); + Assert.That(test.ExistsInDatabase(), Is.EqualTo(true), "Matching"); + } + + [Test, Description("Test MySQLX UUID Scenario-7(Check UUID generated when multiple JSON docs are added using collection.add(doc, doc, doc... ) when docs contains _id fields with negative numbers,big positive numbers)")] + public void CheckDocUUIDScenario7() + { + var col = CreateCollection("my_collection_123456789"); + object[] data1 = new object[] + { + new { _id = -1, title = "Book 1", pages = 20 }, + new { _id = 200000000, title = "Book 2", pages = 30 }, + new { _id = -300000000, title = "Book 3", pages = 40 }, + new { title = "Book 4", pages = 50 } + }; + + object[] data2 = new object[] + { + new { title = "Book 5", pages = 60 }, + new { _id = 60000000000000,title = "Book 6", pages = 70 }, + new { title = "Book 7", pages = 80 }, + new { title = "Book 8", pages = 90 }, + }; + + var r = col.Add(data1).Add(data2); + var result = r.Execute(); + var countgenerateIDs = result.GeneratedIds.Count; + Assert.That(countgenerateIDs, Is.EqualTo(4), "Count of the ID generated by the server"); + for (int i = 0; i < countgenerateIDs; i++) + { + var generatedIDs1 = result.GeneratedIds[i]; + Assert.That(generatedIDs1, Is.EqualTo(generatedIDs1), "ID generated by the server"); + } + + } + + [Test, Description("Test MySQLX UUID Scenario-8(Check UUID generated when multiple JSON docs are added using collection.add(doc, doc, doc... ) when docs contains _id fields with zero,strings)")] + public void CheckDocUUIDScenario8() + { + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); + var col = CreateCollection("my_collection_123456789"); + object[] data1 = new object[] + { + new { _id = 0, title = "Book 1", pages = 20 }, + new { _id = "test1", title = "Book 2", pages = 30 }, + new { _id = "^%$^&&%)(*&", title = "Book 3", pages = 40 }, + new { title = "Book 4", pages = 50 } + }; + + object[] data2 = new object[] + { + new { title = "Book 5", pages = 60 }, + new { _id = 60000000000000,title = "Book 6", pages = 70 }, + new { title = "Book 7", pages = 80 }, + new { title = "Book 8", pages = 90 }, + }; + + var r = col.Add(data1).Add(data2); + var result = r.Execute(); + var countgenerateIDs = result.GeneratedIds.Count; + Assert.That(countgenerateIDs, Is.EqualTo(4), "Count of the ID generated by the server"); + for (int i = 0; i < countgenerateIDs; i++) + { + var generatedIDs1 = result.GeneratedIds[i]; + Assert.That(generatedIDs1, Is.EqualTo(generatedIDs1), "ID generated by the server"); + } + + } + + [Test, Description("Test MySQLX UUID Scenario-9(Check the behaviour when JSON docs are added using collection.add(doc) when docs contains _id fields with (blank)")] + public void CheckDocUUIDScenario9() + { + Collection testCollection = CreateCollection("test"); + DbDoc[] jsonlist = new DbDoc[1]; + for (int i = 0; i < 1; i++) + { + DbDoc newDoc2 = new DbDoc(); + newDoc2.SetValue("_id", " "); + newDoc2.SetValue("F1", ("Field-1-Data-" + i)); + newDoc2.SetValue("F2", ("Field-2-Data-" + i)); + newDoc2.SetValue("F3", (300 + i).ToString()); + jsonlist[i] = newDoc2; + } + + Result result = testCollection.Add(jsonlist).Execute(); + //ID with blank could be added as per bug#27627861 as client will not do any validation and server will do" + Assert.That(result, Is.Not.Null); + + Schema testSchema = session.GetSchema("test"); + Table test = testSchema.GetCollectionAsTable("test"); + Assert.That(test.ExistsInDatabase(), Is.EqualTo(true), "Matching"); + } + + [Test, Description("Test MySQLX plugin Collection JSON Depth Scenarios")] + public void CollectionAddJSONDepth() + { + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); + int i, maxArrayelement = 100; + Collection col = CreateCollection("my_collection_1"); + Collection col1 = CreateCollection("my_collection_2"); + + DbDoc d1 = new DbDoc(); + for (i = 0; i < maxArrayelement; i++) + { + d1.SetValue("_id" + "_" + i.ToString(), 10000); + d1.SetValue("person" + "_" + i.ToString(), "Person" + "_" + i.ToString()); + } + + var result = col1.Add(d1).Execute(); + Assert.That(result.AffectedItemsCount, Is.GreaterThan(0)); + + var data1 = new DbDoc(@"{ ""_id"": 1, ""pages"": 20, + ""person"": { ""name"": ""Fred"", ""age"": 45 } + }"); + var data2 = new DbDoc(@"{ ""_id"": 1, ""pages"": 20, + ""books"": [ + {""_id"" : 1, ""title"" : ""Book 1""}, + { ""_id"" : 2, ""title"" : ""Book 2"" } + ] + }"); + DbDoc d2 = new DbDoc(); + d2.SetValue("_id", 1); + d2.SetValue("pages", 20); + d2.SetValue("taker1", data1); + d2.SetValue("taker2", data2); + + result = col.Add(d2).Execute(); + Assert.That(result.AffectedItemsCount, Is.GreaterThan(0)); + + var result1 = col1.Find().Execute().FetchAll(); + Assert.That(result1.Count, Is.EqualTo(1)); + var result2 = col.Find().Execute().FetchAll(); + Assert.That(result2.Count, Is.EqualTo(1)); + } + + [Test, Description("Test MySQLX plugin Collection Add function with null")] + public void CollectionAddNullFind() + { + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); + int i = 1; + Collection col = CreateCollection("my_collection_1"); + var d1 = new DbDoc(); + d1.SetValue("id" + "_" + i.ToString(), "test"); + Assert.That(col.Add(d1).Execute().AffectedItemsCount, Is.EqualTo(1)); + var result1 = col.Find(null).Execute(); + Assert.That(result1.AffectedItemsCount, Is.EqualTo(0)); + Assert.Throws(() => col.Add(null).Execute()); + var result2 = col.Add().Execute(); + Assert.That(result2.AffectedItemsCount, Is.EqualTo(0)); + } + + [Test, Description("Test MySQLX plugin Invalid JSON String")] + public void InvalidJSONString() + { + Collection col = CreateCollection("my_collection_1"); + String json = ""; + json = "{'_id':'1004','F1': [] }"; + Exception ex = Assert.Throws(() => col.Add(json).Execute()); + Assert.That(ex.Message, Does.Contain("The value provided is not a valid JSON document")); + } + + [Test, Description("Test MySQLX plugin JSON String long expression")] + public void JSONStringLongExpression() + { + Assume.That(!Platform.IsMacOSX(), "Check failure on MacOs: stack overflow");//TO DO + + Collection col = CreateCollection("my_collection_1"); + String json = "", + query2 = ""; + json = "{\"_id\":\"1004\",\"F1\": 1234 }"; + col.Add(json).Execute(); + query2 = "-1+"; + for (int i = 0; i < 230; i++) + { + query2 = query2 + "("; + } + + query2 = query2 + "(100+2)"; + for (int i = 230; i > 0; i--) + { + query2 = query2 + ")"; + } + + var docs = col.Find().Fields(("{'X':" + query2 + "}")).Execute(); + var res = col.Modify("$.F1 = 1234").Set("F1", query2).Limit(1).Execute(); + Assert.That(res.AffectedItemsCount, Is.EqualTo(1)); + } + + [Test, Description("Test MySQLX plugin Binary Expression")] + public void BinaryExpression() + { + String json = ""; + Collection col = CreateCollection("my_collection_1"); + Collection col1 = CreateCollection("my_collection_2"); + json = "{\"_id\":\"1004\",\"F1\": 123,\"F2\":\"#\" }"; + col.Add(json).Execute(); + + var docs1 = col.Find().Fields("$._id as _id", "1 << 4 as tmp").Execute(); + var res = docs1.FetchAll(); + Assert.That(res[0].Id.ToString(), Is.EqualTo("1004").IgnoreCase); + + docs1 = col.Find().Fields("$._id as _id", "$.F2 ^ 1 as tmp").Execute(); + res = docs1.FetchAll(); + Assert.That(res[0].Id.ToString(), Is.EqualTo("1004").IgnoreCase); + col.Add("{\"_id\":\"100001\",\"x1\":\"31\", \"x2\":\"13\", \"x3\":\"8\", \"x4\":\"18446744073709551614\"}").Execute(); + docs1 = col.Find("CAST($.x1 as SIGNED) | pow(2,$.x1) = $.x1").Fields("$._id as _id, $.x1 as x1, $.x2 as x2, $.x3 as x3 , $.x2 | pow(2,$.x1) as tmp").Execute(); + res = docs1.FetchAll(); + Assert.That(res, Is.Not.Null); + docs1 = col.Find("~16 = ~CAST($.F2 as SIGNED)").Fields("$._id as _id,$.F2 as f2, ~1 as tmp").Execute(); + res = docs1.FetchAll(); + Assert.That(res, Is.Not.Null); + int maxrec = 100; + DbDoc newDoc = new DbDoc(); + newDoc.SetValue("_id", maxrec + 1000); + newDoc.SetValue("F1", "Field-1-Data-" + maxrec); + newDoc.SetValue("F2", "Field-2-Data-" + maxrec); + newDoc.SetValue("F3", 300 + maxrec); + col1.Add(newDoc).Execute(); + + json = "{'_id':'" + (maxrec + 1000 + 1) + "','F1':'Field-1-Data-" + (maxrec + 1) + "','F2':'Field-2-Data-" + (maxrec + 1) + "','F3':" + (300 + maxrec + 1) + "}"; + json = json.Replace("'", "\""); + var res1 = col1.Add(json).Execute(); + Assert.That(res1.AffectedItemsCount, Is.EqualTo(1)); + json = "{'F1': 'Field-1-Data-9999','F2': 'Field-2-Data-9999','F3': 'Field-3-Data-9999'}".Replace("'", "\""); + col1.Add(json).Add(json.Replace("9", "8")).Execute(); + Assert.That(res1.AffectedItemsCount, Is.EqualTo(1)); + + var docs = col1.Find("$._id = 1100").Fields("$_id as _id,$.F1 as f1, $.F2 as f2, $.F3 as f3").Execute(); + var res2 = docs.FetchOne(); + Assert.That(res2["_id"].ToString(), Is.EqualTo("1100")); + Assert.That(res2["f1"].ToString(), Is.EqualTo("Field-1-Data-100")); + Assert.That(res2["f2"].ToString(), Is.EqualTo("Field-2-Data-100")); + Assert.That(res2["f3"].ToString(), Is.EqualTo("400")); + + } + + [Test, Description("Test MySQLX plugin Invalid JSON String long expression")] + public void JSONStringSpecialCharacters() + { + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); + Collection col = CreateCollection("my_collection_1"); + String[] splName = {"+", "*", "/", "a+b", "#1", "%", "&", "@1", "!1", "~", "^", + "(", ")", "{", "}", "[", "]", "|", "JSON", "ADD", "JSON_EXTRACT", "JSON_OBJECT", + "?", "=", "+", ";", ",", ":", "<", ">", "-"}; + for (int i = 0; i < splName.Length; i++) + { + col.Add("{\"" + splName[i] + "\":\"data" + i + "\",\"ID\":" + i + "}").Execute(); + var docs = col.Find("$.ID = " + i).Fields("$.`" + splName[i] + "` as col1,$.ID as Id").Execute(); + var res = docs.FetchOne(); + Assert.That(res["Id"].ToString(), Is.EqualTo(i.ToString()), "Matching the ID"); + if (i == 30) + Assert.That("data30", Is.EqualTo("data" + i), "Matching the String"); + else + Assert.That(res["col1"].ToString(), Is.EqualTo("data" + i), "Matching the String"); + } + } + + [Test, Description("Test MySQLX plugin Collections Chained Insert")] + public void CollectionsChainedInsert() + { + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); + Collection col = CreateCollection("my_collection_1"); + DbDoc newDoc = new DbDoc(); + newDoc.SetValue("F1", 1); + + DbDoc newDoc1 = new DbDoc(); + newDoc1.SetValue("F1", 2); + + DbDoc newDoc2 = new DbDoc(); + newDoc2.SetValue("F1", 3); + + DbDoc[] jsonlist = new DbDoc[5]; + for (int i = 0; i < 5; i++) + { + DbDoc newDoc3 = new DbDoc(); + newDoc3.SetValue("F1", 4 + i); + jsonlist[i] = newDoc3; + newDoc3 = null; + } + + DbDoc[] jsonlist1 = new DbDoc[5]; + for (int i = 0; i < 5; i++) + { + DbDoc newDoc4 = new DbDoc(); + newDoc4.SetValue("F1", 10 + i); + jsonlist1[i] = newDoc4; + newDoc4 = null; + } + + DbDoc[] jsonlist2 = new DbDoc[5]; + for (int i = 0; i < 5; i++) + { + DbDoc newDoc5 = new DbDoc(); + newDoc5.SetValue("F1", 100 + i); + jsonlist2[i] = newDoc5; + newDoc5 = null; + } + + var tabRes = col.Add(newDoc).Add(newDoc1).Execute(); + Assert.That(tabRes.AffectedItemsCount, Is.EqualTo(2), "Matching the affected records"); + + tabRes = col.Add(jsonlist).Add(newDoc2).Execute(); + Assert.That(tabRes.AffectedItemsCount, Is.EqualTo(6), "Matching the affected records"); + + tabRes = col.Add(jsonlist1).Add(jsonlist2).Execute(); + Assert.That(tabRes.AffectedItemsCount, Is.EqualTo(10), "Matching the affected records"); + } + + [Test, Description("Test MySQLX plugin Collection Add Array")] + public void CollectionAddArray() + { + Assume.That(Platform.IsWindows(), "This test is for Windows OS only."); + Assume.That(session.Version.isAtLeast(5, 7, 0), "This test is for MySql 5.7 or higher"); + int maxrec = 5; + var col = CreateCollection("my_collection_1"); + DbDoc[] jsonlist = new DbDoc[maxrec]; + for (int i = 0; i < maxrec; i++) + { + DbDoc newDoc2 = new DbDoc(); + newDoc2.SetValue("_id", i); + newDoc2.SetValue("F1", "Field-1-Data-" + i); + newDoc2.SetValue("ARR_INT", new DbDoc(@"{""values"":[1, 2, 3, 4, 5, 6, 7, 8, 9]}")); + newDoc2.SetValue("ARR_STR", new DbDoc(@"{""values"":""['DATA1', 'DATA2', 'DATA3', 'DATA4', 'DATA5', 'DATA6']""}")); + newDoc2.SetValue("ARR_LIT", new DbDoc(@"{""values"":""[null, true, false, null, true, false, null, true, false]""}")); + newDoc2.SetValue("ARR_ARR", new DbDoc(@"{""values"":[[1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5]]}")); + + col.Add(newDoc2).Execute(); + jsonlist[i] = newDoc2; + } + + jsonlist = null; + var res = col.Find().Execute().FetchAll(); + Assert.That(res.Count, Is.EqualTo(5), "Matching the find count"); + } + + [Test, Description("Test MySQLX plugin Collection JSON Scenarios")] + public void CollectionAddJSONDocs() + { + Assume.That(Platform.IsWindows(), "This test is for Windows OS only."); + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); + + Collection col = CreateCollection("my_collection_1"); + string json = @"{ ""_id"": 0, ""title"": ""Book 0"" ,""pages"": 10,""name"": ""Jeoff Archer""}"; + Result r = col.Add(json).Execute(); + + Assert.That((int)r.AffectedItemsCount, Is.EqualTo(1), "Matching Affected Records Count"); + var foundDocs = col.Find("pages > 5").Execute(); + Assert.That(foundDocs.Count(), Is.EqualTo(1), "Matching Count"); + + json = @"{ ""_id"" : 99950, ""city"" : ""KETCHIKAN"", ""loc"" : ""[ -133.18479, 55.942471 ]"", ""pop"" : 422, ""state"" : ""AK"" }"; + r = col.Add(json).Execute(); + + DbDoc d = new DbDoc(@"{ ""id"": 1, ""pages"": 20, + ""person"": { ""name"": ""Fred"", ""age"": 45 } + }"); + DbDoc d2 = new DbDoc(); + d2.SetValue("id", 1); + d2.SetValue("pages", 20); + d2.SetValue("person", new { name = "Fred", age = 45 }); + + Assert.That(true, Is.EqualTo(d.Equals(d2)), "Matching"); + col.Add(d).Execute(); + + d = new DbDoc(@"{""id"":100,""FirstName"":""xyz"",""lastname"":""pqr"", + ""address"": + {""house"":44,""city"":""Delhi"",""country"":""india""}}"); + col.Add(d).Execute(); + + d = new DbDoc(@"{""customerId"":100,""FirstName"":""xyz"",""lastname"":""pqr"", + ""address"": + {""house"":44,""city"":""Delhi"",""country"":""india""}, + ""employer"": + {""cmpName"":""ABC"",""type"":""IT""}}"); + col.Add(d).Execute(); + + d = new DbDoc(@"{ ""id"": 1, ""pages"": 20, + ""books"": [ + {""_id"" : 1, ""title"" : ""Book 1""}, + { ""_id"" : 2, ""title"" : ""Book 2"" } + ] + }"); + col.Add(d).Execute(); + + var docs = new[] { new { _id = 1, title = "Book 1" }, new { _id = 2, title = "Book 2" } }; + d2 = new DbDoc(); + d2.SetValue("id", 100); + d2.SetValue("pages", 20); + d2.SetValue("books", docs); + col.Add(d2).Execute(); + + var result = col.Find("$._id = 0").Fields("$._id as _id,$.name as name, $.pages as pages, $.title as title").Execute(); + var res1 = result.FetchOne(); + Assert.That(res1["_id"], Is.EqualTo(0)); + Assert.That(res1["name"], Is.EqualTo("Jeoff Archer")); + Assert.That(res1["pages"], Is.EqualTo(10)); + Assert.That(res1["title"], Is.EqualTo("Book 0")); + + result = col.Find("$._id > 0").Fields().Execute(); + var res2 = result.FetchAll(); + Assert.That(res2.Count(), Is.EqualTo(6)); + + DbDoc test = new DbDoc(); + test.SetValue("_id", 1); + test.SetValue("name", "ABBBBBBBBBBBBBBXXXXXXXXXXXXXXXYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYTTTTTTYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYABBBBBBBBBBBBBBXXXXXXXXXXXXXXXYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYTTTTTTYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYABBBBBBBBBBBBBBXXXXXXXXXXXXXXXYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYTTTTTTYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYABBBBBBBBBBBBBBXXXXXXXXXXXXXXXYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYTTTTTTYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYABBBBBBBBBBBBBBXXXXXXXXXXXXXXXYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYTTTTTTYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY"); + var coll = CreateCollection("my_collection_123456789"); + var res = coll.Add(test).Execute(); + foundDocs = coll.Find().Execute(); + var docs1 = foundDocs.FetchAll(); + Assert.That(docs1.Count, Is.EqualTo(1)); + } + + [Test, Description("Verify that the field and column _id has a value when it's not given to a document-Scenario-1(single document add)")] + public void VerifyIDField() + { + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); + List idStringList = new List(); + var col = CreateCollection("my_collection"); + Result result = null; + string generatedIDs1 = null, generatedIDs2 = null; + int countgenerateIDs = 0; + // Anonymous Object Array + object[] data = new object[] { new { title = "Book 1", pages = 30 } }; + var stmt = col.Add(data); + result = stmt.Execute(); + generatedIDs1 = result.GeneratedIds[0]; + Assert.That(generatedIDs1, Is.EqualTo(generatedIDs1), "ID generated by the server"); + VerifyGeneratedID(generatedIDs1); + countgenerateIDs = result.GeneratedIds.Count; + Assert.That(countgenerateIDs, Is.EqualTo(1), "Count of the ID generated by the server"); + for (int i = 0; i < countgenerateIDs; i++) + { + idStringList.Add(result.GeneratedIds[i]); + } + + // DbDoc + DbDoc DbDocs = new DbDoc(); + DbDocs.SetValue("title", "Book 0"); + DbDocs.SetValue("pages", 10); + stmt = col.Add(DbDocs); + result = stmt.Execute(); + generatedIDs2 = result.GeneratedIds[0]; + Assert.That(generatedIDs2, Is.EqualTo(generatedIDs2), "ID generated by the server"); + VerifyGeneratedID(generatedIDs2); + countgenerateIDs = result.GeneratedIds.Count; + Assert.That(countgenerateIDs, Is.EqualTo(1), "Count of the ID generated by the server"); + for (int i = 0; i < countgenerateIDs; i++) + { + idStringList.Add(result.GeneratedIds[i]); + } + + // Anonymous Object + var docs = new { title = "Book 1", pages = 20 }; + stmt = col.Add(docs); + result = stmt.Execute(); + generatedIDs1 = result.GeneratedIds[0]; + Assert.That(generatedIDs1, Is.EqualTo(generatedIDs1), "ID generated by the server"); + VerifyGeneratedID(generatedIDs1); + countgenerateIDs = result.GeneratedIds.Count; + Assert.That(countgenerateIDs, Is.EqualTo(1), "Count of the ID generated by the server"); + for (int i = 0; i < countgenerateIDs; i++) + { + idStringList.Add(result.GeneratedIds[i]); + } + + // JSON + stmt = col.Add("{ \"foo\": 100 }"); + result = stmt.Execute(); + generatedIDs2 = result.GeneratedIds[0]; + Assert.That(generatedIDs2, Is.EqualTo(generatedIDs2), "ID generated by the server"); + VerifyGeneratedID(generatedIDs2); + countgenerateIDs = result.GeneratedIds.Count; + Assert.That(countgenerateIDs, Is.EqualTo(1), "Count of the ID generated by the server"); + for (int i = 0; i < countgenerateIDs; i++) + { + idStringList.Add(result.GeneratedIds[i]); + } + + int j = 1; + for (int i = 0; i < idStringList.Count; i++) + { + if (j == idStringList.Count) + { + break; + } + VerifySequence(idStringList[i], idStringList[j]); + j++; + } + } + + [Test, Description("Unique _ids generated server side for multiple documents, single add and generated ids count should be number of docs added-Scenario3")] + public void VerifyIDFieldScenario3() + { + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); + List idStringList = new List(); + var col = CreateCollection("my_collection"); + Result result = null; + string generatedIDs1 = null; + int countgenerateIDs = 0; + HashSet firstset = new HashSet(); + + object[] data1 = new object[] + { + new { title = "Book 1", pages = 20 }, + new { title = "Book 2", pages = 30 }, + new { title = "Book 3", pages = 40 }, + new { title = "Book 4", pages = 50 } + }; + + var stmt = col.Add(data1); + result = stmt.Execute(); + countgenerateIDs = result.GeneratedIds.Count; + Assert.That(countgenerateIDs, Is.EqualTo(4), "Count of the ID generated by the server"); + for (int i = 0; i < countgenerateIDs; i++) + { + generatedIDs1 = result.GeneratedIds[i]; + Assert.That(generatedIDs1, Is.EqualTo(generatedIDs1), "ID generated by the server"); + VerifyGeneratedID(generatedIDs1); + Assert.That(!firstset.Add(generatedIDs1), Is.False); + } + + for (int i = 0; i < countgenerateIDs; i++) + { + idStringList.Add(result.GeneratedIds[i]); + } + + stmt = col.Add(@"{ ""foo"": 1 }", @"{""foo"": 2 }", @"{ ""foo"": 3 }", @"{ ""foo"": 4 }"); + result = stmt.Execute(); + countgenerateIDs = result.GeneratedIds.Count; + Assert.That(countgenerateIDs, Is.EqualTo(4), "Count of the ID generated by the server"); + for (int i = 0; i < countgenerateIDs; i++) + { + generatedIDs1 = result.GeneratedIds[i]; + Assert.That(generatedIDs1, Is.EqualTo(generatedIDs1), "ID generated by the server"); + VerifyGeneratedID(generatedIDs1); + Assert.That(!firstset.Add(generatedIDs1), Is.False); + } + + for (int i = 0; i < countgenerateIDs; i++) + { + idStringList.Add(result.GeneratedIds[i]); + } + + int j = 1; + for (int i = 0; i < idStringList.Count; i++) + { + if (j == idStringList.Count) + { + break; + } + VerifySequence(idStringList[i], idStringList[j]); + j++; + } + } + + [Test, Description("Verify that the field and column _id has a value when it's not given to a document-Scenario-1(single document add)-when doc already exists")] + public void VerifyIDFieldScenario4() + { + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); + List idStringList = new List(); + var col = CreateCollection("my_collection"); + Result result = null; + string generatedIDs1 = null, generatedIDs2 = null; + int countgenerateIDs = 0; + object[] data = null; + data = new object[] + { + new { title ="Book 0", pages = 10 }, + new { title ="Book 5", pages = 60, _id = 6} + }; + result = col.Add(data).Execute(); + countgenerateIDs = result.GeneratedIds.Count; + generatedIDs1 = result.GeneratedIds[0]; + Assert.That(countgenerateIDs, Is.EqualTo(1), "Count of the ID generated by the server"); + for (int i = 0; i < countgenerateIDs; i++) + { + idStringList.Add(result.GeneratedIds[i]); + } + + // Anonymous Object Array + data = new object[] { new { title = "Book 1", pages = 30 } }; + var stmt = col.Add(data); + result = stmt.Execute(); + generatedIDs1 = result.GeneratedIds[0]; + Assert.That(generatedIDs1, Is.EqualTo(generatedIDs1), "ID generated by the server"); + VerifyGeneratedID(generatedIDs1); + countgenerateIDs = result.GeneratedIds.Count; + Assert.That(countgenerateIDs, Is.EqualTo(1), "Count of the ID generated by the server"); + for (int i = 0; i < countgenerateIDs; i++) + { + idStringList.Add(result.GeneratedIds[i]); + } + + col = CreateCollection("my_collection"); + data = null; + data = new object[] + { + new { title ="Book 0", pages = 10 }, + new { title ="Book 5", pages = 60, _id = 6} + }; + result = col.Add(data).Execute(); + countgenerateIDs = result.GeneratedIds.Count; + generatedIDs1 = result.GeneratedIds[0]; + Assert.That(countgenerateIDs, Is.EqualTo(1), "Count of the ID generated by the server"); + for (int i = 0; i < countgenerateIDs; i++) + { + idStringList.Add(result.GeneratedIds[i]); + } + + // DbDoc + DbDoc DbDocs = new DbDoc(); + DbDocs.SetValue("title", "Book 0"); + DbDocs.SetValue("pages", 10); + stmt = col.Add(DbDocs); + result = stmt.Execute(); + generatedIDs2 = result.GeneratedIds[0]; + Assert.That(generatedIDs2, Is.EqualTo(generatedIDs2), "ID generated by the server"); + VerifyGeneratedID(generatedIDs2); + countgenerateIDs = result.GeneratedIds.Count; + Assert.That(countgenerateIDs, Is.EqualTo(1), "Count of the ID generated by the server"); + for (int i = 0; i < countgenerateIDs; i++) + { + idStringList.Add(result.GeneratedIds[i]); + } + + col = CreateCollection("my_collection"); + data = null; + data = new object[] + { + new { title ="Book 0", pages = 10 }, + new { title ="Book 5", pages = 60, _id = 6} + }; + result = col.Add(data).Execute(); + countgenerateIDs = result.GeneratedIds.Count; + generatedIDs1 = result.GeneratedIds[0]; + Assert.That(countgenerateIDs, Is.EqualTo(1), "Count of the ID generated by the server"); + for (int i = 0; i < countgenerateIDs; i++) + { + idStringList.Add(result.GeneratedIds[i]); + } + + // Anonymous Object + var docs = new { title = "Book 1", pages = 20 }; + stmt = col.Add(docs); + result = stmt.Execute(); + generatedIDs1 = result.GeneratedIds[0]; + Assert.That(generatedIDs1, Is.EqualTo(generatedIDs1), "ID generated by the server"); + VerifyGeneratedID(generatedIDs1); + countgenerateIDs = result.GeneratedIds.Count; + Assert.That(countgenerateIDs, Is.EqualTo(1), "Count of the ID generated by the server"); + for (int i = 0; i < countgenerateIDs; i++) + { + idStringList.Add(result.GeneratedIds[i]); + } + + col = CreateCollection("my_collection"); + data = null; + data = new object[] + { + new { title ="Book 0", pages = 10 }, + new { title ="Book 5", pages = 60, _id = 6} + }; + result = col.Add(data).Execute(); + countgenerateIDs = result.GeneratedIds.Count; + generatedIDs1 = result.GeneratedIds[0]; + Assert.That(countgenerateIDs, Is.EqualTo(1), "Count of the ID generated by the server"); + for (int i = 0; i < countgenerateIDs; i++) + { + idStringList.Add(result.GeneratedIds[i]); + } + + //JSON + stmt = col.Add("{ \"foo\": 100 }"); + result = stmt.Execute(); + generatedIDs2 = result.GeneratedIds[0]; + Assert.That(generatedIDs2, Is.EqualTo(generatedIDs2), "ID generated by the server"); + VerifyGeneratedID(generatedIDs2); + countgenerateIDs = result.GeneratedIds.Count; + Assert.That(countgenerateIDs, Is.EqualTo(1), "Count of the ID generated by the server"); + for (int i = 0; i < countgenerateIDs; i++) + { + idStringList.Add(result.GeneratedIds[i]); + } + + int j = 1; + for (int i = 0; i < idStringList.Count; i++) + { + if (j == idStringList.Count) + { + break; + } + VerifySequence(idStringList[i], idStringList[j]); + j++; + } + } + + [Test, Description("Unique _ids generated server side for multiple documents,multiple add and generated ids count should be number of docs added-when doc already exists Scenario2")] + public void VerifyIDFieldScenario5() + { + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); + List idStringList = new List(); + Result result = null; + string generatedIDs1 = null; + int countgenerateIDs = 0; + var col = CreateCollection("my_collection"); + object[] data = null; + + data = new object[] + { + new { title ="Book 0", pages = 10 }, + new { title ="Book 5", pages = 60, _id = 6} + }; + result = col.Add(data).Execute(); + countgenerateIDs = result.GeneratedIds.Count; + generatedIDs1 = result.GeneratedIds[0]; + Assert.That(countgenerateIDs, Is.EqualTo(1), "Count of the ID generated by the server"); + for (int i = 0; i < countgenerateIDs; i++) + { + idStringList.Add(result.GeneratedIds[i]); + } + + HashSet firstset = new HashSet(); + // Anonymous Object Array + object[] data1 = new object[] { new { title ="Book 1", pages = 20 } + }; + object[] data2 = new object[] { new { title = "Book 5", pages = 60 } }; + + var stmt = col.Add(data1).Add(data2); + result = stmt.Execute(); + countgenerateIDs = result.GeneratedIds.Count; + Assert.That(countgenerateIDs, Is.EqualTo(2), "Count of the ID generated by the server"); + for (int i = 0; i < countgenerateIDs; i++) + { + generatedIDs1 = result.GeneratedIds[i]; + Assert.That(generatedIDs1, Is.EqualTo(generatedIDs1), "ID generated by the server"); + VerifyGeneratedID(generatedIDs1); + Assert.That(!firstset.Add(generatedIDs1), Is.False); + } + for (int i = 0; i < countgenerateIDs; i++) + { + idStringList.Add(result.GeneratedIds[i]); + } + + col = CreateCollection("my_collection"); + data = new object[] + { + new { title ="Book 0", pages = 10 }, + new { title ="Book 5", pages = 60, _id = 6} + }; + result = col.Add(data).Execute(); + countgenerateIDs = result.GeneratedIds.Count; + generatedIDs1 = result.GeneratedIds[0]; + Assert.That(countgenerateIDs, Is.EqualTo(1), "Count of the ID generated by the server"); + for (int i = 0; i < countgenerateIDs; i++) + { + idStringList.Add(result.GeneratedIds[i]); + } + + // DbDoc + DbDoc DbDocs1 = new DbDoc(); + DbDocs1.SetValue("title", "Book 0"); + DbDocs1.SetValue("pages", 10); + DbDoc DbDocs2 = new DbDoc(); + DbDocs2.SetValue("title", "Book 1"); + DbDocs2.SetValue("pages", 20); + stmt = col.Add(DbDocs1).Add(DbDocs2); + result = stmt.Execute(); + countgenerateIDs = result.GeneratedIds.Count; + Assert.That(countgenerateIDs, Is.EqualTo(2), "Count of the ID generated by the server"); + for (int i = 0; i < countgenerateIDs; i++) + { + generatedIDs1 = result.GeneratedIds[i]; + Assert.That(generatedIDs1, Is.EqualTo(generatedIDs1), "ID generated by the server"); + VerifyGeneratedID(generatedIDs1); + Assert.That(!firstset.Add(generatedIDs1), Is.False); + } + for (int i = 0; i < countgenerateIDs; i++) + { + idStringList.Add(result.GeneratedIds[i]); + } + + col = CreateCollection("my_collection"); + + data = new object[] + { + new { title ="Book 0", pages = 10 }, + new { title ="Book 5", pages = 60, _id = 6} + }; + result = col.Add(data).Execute(); + countgenerateIDs = result.GeneratedIds.Count; + generatedIDs1 = result.GeneratedIds[0]; + Assert.That(countgenerateIDs, Is.EqualTo(1), "Count of the ID generated by the server"); + for (int i = 0; i < countgenerateIDs; i++) + { + idStringList.Add(result.GeneratedIds[i]); + } + + // Anonymous Object + var docs1 = new { title = "Book 1", pages = 20 }; + var docs2 = new { title = "Book 2", pages = 30 }; + stmt = col.Add(docs1).Add(docs2); + + result = stmt.Execute(); + countgenerateIDs = result.GeneratedIds.Count; + Assert.That(countgenerateIDs, Is.EqualTo(2), "Count of the ID generated by the server"); + for (int i = 0; i < countgenerateIDs; i++) + { + generatedIDs1 = result.GeneratedIds[i]; + Assert.That(generatedIDs1, Is.EqualTo(generatedIDs1), "ID generated by the server"); + VerifyGeneratedID(generatedIDs1); + Assert.That(!firstset.Add(generatedIDs1), Is.False); + } + for (int i = 0; i < countgenerateIDs; i++) + { + idStringList.Add(result.GeneratedIds[i]); + } + + col = CreateCollection("my_collection"); + data = new object[] + { + new { title ="Book 0", pages = 10 }, + new { title ="Book 5", pages = 60, _id = 6} + }; + result = col.Add(data).Execute(); + countgenerateIDs = result.GeneratedIds.Count; + generatedIDs1 = result.GeneratedIds[0]; + Assert.That(countgenerateIDs, Is.EqualTo(1), "Count of the ID generated by the server"); + for (int i = 0; i < countgenerateIDs; i++) + { + idStringList.Add(result.GeneratedIds[i]); + } + + // JSON + stmt = col.Add("{ \"foo1\": 100 }").Add("{ \"foo2\": 200 }"); + result = stmt.Execute(); + countgenerateIDs = result.GeneratedIds.Count; + Assert.That(countgenerateIDs, Is.EqualTo(2), "Count of the ID generated by the server"); + for (int i = 0; i < countgenerateIDs; i++) + { + generatedIDs1 = result.GeneratedIds[i]; + Assert.That(generatedIDs1, Is.EqualTo(generatedIDs1), "ID generated by the server"); + VerifyGeneratedID(generatedIDs1); + if (!firstset.Add(generatedIDs1)) + { + break; + } + } + for (int i = 0; i < countgenerateIDs; i++) + { + idStringList.Add(result.GeneratedIds[i]); + } + + int j = 1; + for (int i = 0; i < idStringList.Count; i++) + { + if (j == idStringList.Count) + { + break; + } + VerifySequence(idStringList[i], idStringList[j]); + j++; + } + } + + [Test, Description("Unique _ids generated server side for multiple documents, single add and generated ids count should be number of docs added-when doc already exists Scenario3")] + public void VerifyIDFieldScenario6() + { + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); + List idStringList = new List(); + var col = CreateCollection("my_collection"); + Result result = null; + string generatedIDs1 = null; + int countgenerateIDs = 0; + object[] data = null; + + data = new object[] + { + new { title ="Book 0", pages = 10 }, + new { title ="Book 5", pages = 60, _id = 6} + }; + result = col.Add(data).Execute(); + countgenerateIDs = result.GeneratedIds.Count; + generatedIDs1 = result.GeneratedIds[0]; + Assert.That(countgenerateIDs, Is.EqualTo(1), "Count of the ID generated by the server"); + for (int i = 0; i < countgenerateIDs; i++) + { + idStringList.Add(result.GeneratedIds[i]); + } + + HashSet firstset = new HashSet(); + // Anonymous Object Array + object[] data1 = new object[] + { + new { title ="Book 1", pages = 20 }, + new { title = "Book 2", pages = 30 }, + new { title = "Book 3", pages = 40 }, + new { title = "Book 4", pages = 50 } + }; + + var stmt = col.Add(data1); + result = stmt.Execute(); + countgenerateIDs = result.GeneratedIds.Count; + Assert.That(countgenerateIDs, Is.EqualTo(4), "Count of the ID generated by the server"); + for (int i = 0; i < countgenerateIDs; i++) + { + generatedIDs1 = result.GeneratedIds[i]; + Assert.That(generatedIDs1, Is.EqualTo(generatedIDs1), "ID generated by the server"); + VerifyGeneratedID(generatedIDs1); + Assert.That(!firstset.Add(generatedIDs1), Is.False); + } + for (int i = 0; i < countgenerateIDs; i++) + { + idStringList.Add(result.GeneratedIds[i]); + } + + col = CreateCollection("my_collection"); + result = col.Add(@"{ ""foo"": 0, ""_id"":0 }", @"{""foo"": 5 }").Execute(); + countgenerateIDs = result.GeneratedIds.Count; + generatedIDs1 = result.GeneratedIds[0]; + Assert.That(countgenerateIDs, Is.EqualTo(1), "Count of the ID generated by the server"); + for (int i = 0; i < countgenerateIDs; i++) + { + idStringList.Add(result.GeneratedIds[i]); + } + + // JSON + stmt = col.Add(@"{ ""foo"": 1 }", @"{""foo"": 2 }", @"{ ""foo"": 3 }", @"{ ""foo"": 4 }"); + result = stmt.Execute(); + countgenerateIDs = result.GeneratedIds.Count; + Assert.That(countgenerateIDs, Is.EqualTo(4), "Count of the ID generated by the server"); + for (int i = 0; i < countgenerateIDs; i++) + { + generatedIDs1 = result.GeneratedIds[i]; + Assert.That(generatedIDs1, Is.EqualTo(generatedIDs1), "ID generated by the server"); + VerifyGeneratedID(generatedIDs1); + Assert.That(!firstset.Add(generatedIDs1), Is.False); + } + for (int i = 0; i < countgenerateIDs; i++) + { + idStringList.Add(result.GeneratedIds[i]); + } + + int j = 1; + for (int i = 0; i < idStringList.Count; i++) + { + if (j == idStringList.Count) + { + break; + } + VerifySequence(idStringList[i], idStringList[j]); + j++; + } + } + + [Test, Description("Client provided _id shouldnt be discarded and generatedids() should give empty list for anonymous object array -single document add")] + public void VerifyIDFieldScenario7() + { + var col = CreateCollection("my_collection"); + object[] data = new object[] + { + new { _id = "1e9c92fda74ed311944e00059a3c7a00", title = "Book 0", pages = 10 }, + }; + Result result = col.Add(data).Execute(); + var generatedIDs = result.GeneratedIds; + Assert.That(generatedIDs.Count, Is.EqualTo(0), "Matches"); + var doc = col.Find("_id like :param").Bind("param", "1e9c92fda74ed311944e00059a3c7a00").Execute(); + var docs = doc.FetchAll().Count(); + Assert.That(docs, Is.EqualTo(1), "Matches"); + + //Anonymous Object + var data1 = new { _id = "1e9c92fda74ed311944e00059a3c7a01", title = "Book 0", pages = 10 }; + result = col.Add(data1).Execute(); + + generatedIDs = result.GeneratedIds; + Assert.That(generatedIDs.Count, Is.EqualTo(0), "Matches"); + doc = col.Find("_id like :param").Bind("param", "1e9c92fda74ed311944e00059a3c7a01").Execute(); + docs = doc.FetchAll().Count(); + Assert.That(docs, Is.EqualTo(1), "Matches"); + + // DbDoc + DbDoc DbDocs = new DbDoc(); + DbDocs.SetValue("title", "Book 0"); + DbDocs.SetValue("pages", 10); + DbDocs.SetValue("_id", "1e9c92fda74ed311944e00059a3c7a02"); + result = col.Add(DbDocs).Execute(); + + generatedIDs = result.GeneratedIds; + Assert.That(generatedIDs.Count, Is.EqualTo(0), "Matches"); + doc = col.Find("_id like :param").Bind("param", "1e9c92fda74ed311944e00059a3c7a02").Execute(); + docs = doc.FetchAll().Count(); + Assert.That(docs, Is.EqualTo(1), "Matches"); + + //JSON + result = col.Add("{\"_id\":\"1e9c92fda74ed311944e00059a3c7a03\",\"title\": \"Book 0\",\"pages\": 10}").Execute(); + generatedIDs = result.GeneratedIds; + Assert.That(generatedIDs.Count, Is.EqualTo(0), "Matches"); + doc = col.Find("_id like :param").Bind("param", "1e9c92fda74ed311944e00059a3c7a03").Execute(); + docs = doc.FetchAll().Count(); + Assert.That(docs, Is.EqualTo(1), "Matches"); + } + + [Test, Description("Client provided _id shouldnt be discarded and generatedids() should give empty list for anonymous object array -multiple documents multiple add with negative number")] + public void VerifyIDFieldScenario8() + { + var col = CreateCollection("my_collection"); + object[] data1 = new object[] + { + new { _id = "1e9c92fda74ed311944e00059a3c7a00", title = "Book 0", pages = 10 } + }; + object[] data2 = new object[] + { + new { _id = -1, title = "Book 0", pages = 10 } + }; + Result result = col.Add(data1).Add(data2).Execute(); + var generatedIDs = result.GeneratedIds; + Assert.That(generatedIDs.Count, Is.EqualTo(0), "Matches"); + var doc = col.Find("_id like :param").Bind("param", "1e9c92fda74ed311944e00059a3c7a00").Execute(); + var docs = doc.FetchAll().Count(); + Assert.That(docs, Is.EqualTo(1), "Matches"); + doc = col.Find("_id like :param").Bind("param", -1).Execute(); + docs = doc.FetchAll().Count(); + Assert.That(docs, Is.EqualTo(1), "Matches"); + + // Anonymous Object + var data3 = new { _id = "1e9c92fda74ed311944e00059a3c7a01", title = "Book 0", pages = 10 }; + var data4 = new { _id = -2, title = "Book 0", pages = 10 }; + result = col.Add(data3).Add(data4).Execute(); + generatedIDs = result.GeneratedIds; + Assert.That(generatedIDs.Count, Is.EqualTo(0), "Matches"); + doc = col.Find("_id like :param").Bind("param", "1e9c92fda74ed311944e00059a3c7a01").Execute(); + docs = doc.FetchAll().Count(); + Assert.That(docs, Is.EqualTo(1), "Matches"); + doc = col.Find("_id like :param").Bind("param", -2).Execute(); + docs = doc.FetchAll().Count(); + Assert.That(docs, Is.EqualTo(1), "Matches"); + + //DbDoc + DbDoc DbDocs1 = new DbDoc(); + DbDocs1.SetValue("title", "Book 0"); + DbDocs1.SetValue("pages", 10); + DbDocs1.SetValue("_id", "1e9c92fda74ed311944e00059a3c7a02"); + DbDoc DbDocs2 = new DbDoc(); + DbDocs2.SetValue("title", "Book 0"); + DbDocs2.SetValue("pages", 10); + DbDocs2.SetValue("_id", -3); + result = col.Add(DbDocs1).Add(DbDocs2).Execute(); + generatedIDs = result.GeneratedIds; + Assert.That(generatedIDs.Count, Is.EqualTo(0), "Matches"); + doc = col.Find("_id like :param").Bind("param", "1e9c92fda74ed311944e00059a3c7a02").Execute(); + docs = doc.FetchAll().Count(); + Assert.That(docs, Is.EqualTo(1), "Matches"); + doc = col.Find("_id like :param").Bind("param", -3).Execute(); + docs = doc.FetchAll().Count(); + Assert.That(docs, Is.EqualTo(1), "Matches"); + + // JSON + result = col.Add("{\"_id\":\"1e9c92fda74ed311944e00059a3c7a03\",\"title\": \"Book 0\",\"pages\": 10}"). + Add("{\"_id\":-4,\"title\": \"Book 0\",\"pages\": 10}"). + Execute(); + generatedIDs = result.GeneratedIds; + Assert.That(generatedIDs.Count, Is.EqualTo(0), "Matches"); + doc = col.Find("_id like :param").Bind("param", "1e9c92fda74ed311944e00059a3c7a03").Execute(); + docs = doc.FetchAll().Count(); + Assert.That(docs, Is.EqualTo(1), "Matches"); + doc = col.Find("_id like :param").Bind("param", -4).Execute(); + docs = doc.FetchAll().Count(); + Assert.That(docs, Is.EqualTo(1), "Matches"); + } + + [Test, Description("Client provided _id shouldnt be discarded and generatedids() should give empty list for anonymous object array -multiple documents single add with negative number,zero and big positive numbers")] + public void VerifyIDFieldScenario9() + { + var col = CreateCollection("my_collection"); + // Anonymous Object Array + object[] idList = new object[] { "1e9c92fda74ed311944e00059a3c7a00", -1, 60000000000000, -3000000000000, 0 }; + object[] data1 = new object[] + { + new { _id = idList[0], title = "Book 0", pages = 10 }, + new { _id = idList[1], title = "Book 0", pages = 10 }, + new { _id = idList[2] , title = "Book 0", pages = 10 }, + new { _id = idList[3], title = "Book 0", pages = 10 }, + new { _id = idList[4], title = "Book 0", pages = 10 } + }; + Result result = col.Add(data1).Execute(); + var generatedIDs = result.GeneratedIds; + Assert.That(generatedIDs.Count, Is.EqualTo(0), "Matches"); + for (int i = 0; i < idList.Length; i++) + { + var doc = col.Find("_id like :param").Bind("param", idList[i]).Execute(); + var docs = doc.FetchAll().Count(); + Assert.That(docs, Is.EqualTo(1), "Matches the Document ID"); + } + } + + [Test, Description("documents single add with blank id")] + public void CollectionAddBlankId() + { + var col = CreateCollection("my_collection"); + // Anonymous Object Array + object[] idList = new object[] { "", " " }; + object[] data1 = new object[] + { + new { _id = idList[0], title = "Book 0", pages = 10 } + }; + object[] data2 = new object[] + { + new { _id = idList[1], title = "Book 0", pages = 10 } + }; + Result result1 = col.Add(data1).Execute(); + Assert.That(result1.AffectedItemsCount, Is.EqualTo(1)); + result1 = null; + + col = CreateCollection("my_collection"); + result1 = col.Add(data2).Execute(); + Assert.That(result1.AffectedItemsCount, Is.EqualTo(1)); + result1 = null; + + col = CreateCollection("my_collection"); + // DbDoc + DbDoc DbDocs1 = new DbDoc(); + DbDocs1.SetValue("title", "Book 0"); + DbDocs1.SetValue("pages", 10); + DbDocs1.SetValue("_id", ""); + result1 = col.Add(DbDocs1).Execute(); + Assert.That(result1.AffectedItemsCount, Is.EqualTo(1)); + result1 = null; + + col = CreateCollection("my_collection"); + DbDoc DbDocs2 = new DbDoc(); + DbDocs2.SetValue("title", "Book 1"); + DbDocs2.SetValue("pages", 20); + DbDocs2.SetValue("_id", " "); + result1 = col.Add(DbDocs2).Execute(); + Assert.That(result1.AffectedItemsCount, Is.EqualTo(1)); + result1 = null; + + // JSON + col = CreateCollection("my_collection"); + result1 = col.Add("{\"_id\":\"\",\"title\": \"Book 0\",\"pages\": 10}").Execute(); + Assert.That(result1.AffectedItemsCount, Is.EqualTo(1)); + result1 = null; + + col = CreateCollection("my_collection"); + result1 = col.Add("{\"_id\":\" \",\"title\": \"Book 0\",\"pages\": 10}").Execute(); + Assert.That(result1.AffectedItemsCount, Is.EqualTo(1)); + result1 = null; + + } + + [Test, Description("Multiple documents with same id")] + public void CollectionAddMultipleDocsSameId() + { + var col = CreateCollection("my_collection"); + string exception = "Document contains a field value that is not unique but required to be"; + // DbDoc + DbDoc DbDocs1 = new DbDoc(); + DbDocs1.SetValue("title", "Book 0"); + DbDocs1.SetValue("pages", 10); + DbDocs1.SetValue("_id", 1); + DbDoc DbDocs2 = new DbDoc(); + DbDocs2.SetValue("title", "Book 1"); + DbDocs2.SetValue("pages", 20); + DbDocs2.SetValue("_id", 1); + var ex = Assert.Throws(() => col.Add(DbDocs1).Add(DbDocs2).Execute()); + Assert.That(ex.Message, Is.EqualTo(exception), "Checking the exception"); + + // JSON + ex = Assert.Throws(() => col.Add("{\"_id\":1,\"title\": \"Book 0\",\"pages\": 10}"). + Add("{\"_id\":1,\"title\": \"Book 1\",\"pages\": 20}").Execute()); + Assert.That(ex.Message, Is.EqualTo(exception), "Checking the exception"); + + // Anonymous Object Array + object[] data1 = new object[] + { + new { _id = 1, title = "Book 0", pages = 10 } + }; + object[] data2 = new object[] + { + new { _id = 1, title = "Book 1", pages = 20 } + }; + ex = Assert.Throws(() => col.Add(data1).Add(data2).Execute()); + Assert.That(ex.Message, Is.EqualTo(exception), "Checking the exception"); + } + + [Test, Description("Verify the behaviour if a sequence is incremented by the user and added as _id for the document")] + public void VerifySequenceAndIdAdded() + { + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); + string incrementedString = null, generatedString = null; + var col = CreateCollection("my_collection"); + Result result = null; + string generatedIDs1 = null; + int countgenerateIDs = 0; + // Anonymous Object Array + object[] data = new object[] { new { title = "Book 1", pages = 30 } }; + var stmt = col.Add(data); + + result = stmt.Execute(); + generatedIDs1 = result.GeneratedIds[0]; + Assert.That(generatedIDs1, Is.EqualTo(generatedIDs1), "ID generated by the server"); + VerifyGeneratedID(generatedIDs1); + countgenerateIDs = result.GeneratedIds.Count; + Assert.That(countgenerateIDs, Is.EqualTo(1), "Count of the ID generated by the server"); + generatedString = generatedIDs1; + incrementedString = Increment(generatedIDs1, Mode.AlphaNumeric); + + data = new object[] { new { title = "Book 2", pages = 40, _id = generatedString } }; + stmt = col.Add(data); + string exception = "Document contains a field value that is not unique but required to be"; + Exception ex = Assert.Throws(() => stmt.Execute()); + Assert.That(ex.Message, Is.EqualTo(exception), "Matching the exception"); + + data = new object[] { new { title = "Book 3", pages = 50, _id = incrementedString } }; + stmt = col.Add(data); + result = stmt.Execute(); + Assert.That(result, Is.Not.Null); + + data = new object[] { new { title = "Book 4", pages = 60 } }; + stmt = col.Add(data); + ex = Assert.Throws(() => stmt.Execute()); + Assert.That(ex.Message, Is.EqualTo(exception), "Matching the exception"); + + } + + [Test, Description("documents inserted concurrently by two threads")] + public async Task CollectionConcurrentAdd() + { + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); + + CreateCollection("my_collection"); + var r1 = await CollectionAddThread1(); + _ = await CollectionAddThread2(); + Assert.That(r1, Is.EqualTo(1000)); + } + public Task CollectionAddThread1() + { + List idStringList = new List(); + var col = CreateCollection("my_collection"); + DbDoc[] jsonlist = new DbDoc[1000]; + for (int i = 0; i < 1000; i++) + { + DbDoc newDoc2 = new DbDoc(); + newDoc2.SetValue("F1", ("Field-1-Data-" + i)); + newDoc2.SetValue("F2", ("Field-2-Data-" + i)); + newDoc2.SetValue("F3", (3 + i).ToString()); + jsonlist[i] = newDoc2; + newDoc2 = null; + } + Result r = col.Add(jsonlist).Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1000), "Matching"); + int countgenerateIDs = r.GeneratedIds.Count; + for (int i = 0; i < countgenerateIDs; i++) + { + idStringList.Add(r.GeneratedIds[i]); + } + + int j = 1; + for (int i = 0; i < idStringList.Count; i++) + { + if (j == idStringList.Count) + { + break; + } + VerifySequence(idStringList[i], idStringList[j]); + j++; + } + return Task.FromResult((int)r.AffectedItemsCount); + } + + public Task CollectionAddThread2() + { + List idStringList = new List(); + var col = CreateCollection("my_collection1"); + DbDoc[] jsonlist = new DbDoc[1000]; + for (int i = 0; i < 1000; i++) + { + DbDoc newDoc2 = new DbDoc(); + newDoc2.SetValue("F4", ("Field-1-Data-" + i)); + newDoc2.SetValue("F5", ("Field-2-Data-" + i)); + newDoc2.SetValue("F6", (3 + i).ToString()); + jsonlist[i] = newDoc2; + newDoc2 = null; + } + Result r = col.Add(jsonlist).Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1000), "Matching"); + int countgenerateIDs = r.GeneratedIds.Count; + for (int i = 0; i < countgenerateIDs; i++) + { + idStringList.Add(r.GeneratedIds[i]); + } + + int j = 1; + for (int i = 0; i < idStringList.Count; i++) + { + if (j == idStringList.Count) + { + break; + } + VerifySequence(idStringList[i], idStringList[j]); + j++; + } + return Task.FromResult(0); + } + + ///// + ///// Bug24397888 + ///// + [Test, Description("WHEN A DBDOC IS PASSED AS OBJ TO SETVALUE OF ANOTHER DBDOC IT CONVERTS TO BLANK")] + public void DbDocAsObjectConvertToBlank() + { + string newLine = Platform.IsWindows() ? "\r\n" : "\n"; + + var col = CreateCollection("my_collection"); + var data1 = new DbDoc(@"{ ""id"": 1, ""pages"": 20, + ""person"": { ""name"": ""Fred"", ""age"": 45 } + }"); + DbDoc d2 = new DbDoc(); + d2.SetValue("id", 1); + d2.SetValue("pages", 20); + d2.SetValue("taker1", data1); + string expected = $"{{{newLine} \"id\": 1, {newLine} \"pages\": 20, {newLine} \"taker1\": {{{newLine} \"id\": 1, {newLine} \"pages\": 20, {newLine} \"person\": {{{newLine} \"name\": \"Fred\", {newLine} \"age\": 45{newLine} }}{newLine} }}{newLine}}}"; + Assert.That(d2.ToString(), Is.EqualTo(expected)); + } + + [Test, Description("ADDITION OF OBJ FAILS AFTER CREATE INDEX IN 5.7.12 SERVER(WORKS WITH 5.7.9)")] + public void AdditionOfObject() + { + Collection testColl = CreateCollection("test"); + testColl.CreateIndex("testIndex", "{\"fields\": [ { \"field\":$.myId, \"type\":\"INT\" , \"required\":true} ] }"); + testColl.CreateIndex("testIndex1", "{\"fields\": [ { \"field\":$.myAge, \"type\":\"FLOAT\" , \"required\":true} ] }"); + var result = testColl.Add(new { myId = 1, myAge = 35.1, _id = 1 }).Execute(); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1)); + } + + [Test, Description("Test valid insert at Depth n for multiple arrays))")] + public void InsertAtNDepth() + { + if (!session.Version.isAtLeast(8, 0, 3)) return; + string json = ""; + int i = 0, j = 0, maxField = 100; + var collection = CreateCollection("test"); + int maxDepth = 97; + json = "{\"_id\":\"1002\",\"XYZ\":1111"; + for (j = 0; j < maxField; j++) + { + json = json + ",\"ARR" + j + "\":["; + for (i = 0; i < maxDepth; i++) + { + json = json + i + ",["; + } + json = json + i; + for (i = maxDepth - 1; i >= 0; i--) + { + json = json + "]," + i; + } + json = json + "]"; + } + json = json + "}"; + + var res = collection.Add(json).Execute(); + Assert.That(res.AffectedItemsCount, Is.EqualTo(1)); + } + + #endregion WL14389 + + #region Methods + + public void VerifyGeneratedID(string input) + { + byte[] array = Encoding.ASCII.GetBytes(input); + Assert.That(array.Length < 28, Is.False); + + byte[] uniquePrefix = new byte[4]; + Array.Copy(array, 0, uniquePrefix, 0, 4); + + Assert.That(System.Text.Encoding.UTF8.GetString(uniquePrefix), Is.EqualTo(System.Text.Encoding.UTF8.GetString(uniquePrefix)), + "Unique Prefix of the Generated ID"); + + byte[] startTimeStamp = new byte[8]; + Array.Copy(array, 4, startTimeStamp, 0, 8); + Assert.That(System.Text.Encoding.UTF8.GetString(startTimeStamp), Is.EqualTo(System.Text.Encoding.UTF8.GetString(startTimeStamp)), + "StartTimeStamp of the Generated ID"); + + byte[] serial = new byte[16]; + Array.Copy(array, 12, serial, 0, 16); + Assert.That(System.Text.Encoding.UTF8.GetString(serial), Is.EqualTo(System.Text.Encoding.UTF8.GetString(serial)), + "Serial Number of the Generated ID"); + } + + public bool VerifySequence(string input1, string input2) + { + byte[] array1 = Encoding.ASCII.GetBytes(input1); + Assert.That(array1.Length < 28, Is.False); + byte[] array2 = Encoding.ASCII.GetBytes(input2); + Assert.That(array2.Length < 28, Is.False); + Assert.That(input2, Is.Not.EqualTo(input1)); + string incrementedString = Increment(input1, Mode.AlphaNumeric); + if (incrementedString.Equals(input2)) + { + return true; + } + else + { + return false; + } + } + public static string Increment(string text, Mode mode) + { + var textArr = text.ToCharArray(); + var characters = new List(); + + if (mode == Mode.AlphaNumeric || mode == Mode.Numeric) + for (char c = '0'; c <= '9'; c++) + characters.Add(c); + + if (mode == Mode.AlphaNumeric || mode == Mode.Alpha) + for (char c = 'a'; c <= 'f'; c++) + characters.Add(c); + + // Loop from end to beginning + for (int i = textArr.Length - 1; i >= 0; i--) + { + if (textArr[i] == characters.Last()) + { + textArr[i] = characters.First(); + } + else + { + textArr[i] = characters[characters.IndexOf(textArr[i]) + 1]; + break; + } + } + + return new string(textArr); + } + public enum Mode + { + AlphaNumeric = 1, + Alpha = 2, + Numeric = 3 + } + + #endregion Methods + } +} diff --git a/MySQL.Data/tests/MySqlX.Data.Tests/CrudRemoveTests.cs b/MySQL.Data/tests/MySqlX.Data.Tests/CrudRemoveTests.cs index 7d394bf52..a35f65908 100644 --- a/MySQL.Data/tests/MySqlX.Data.Tests/CrudRemoveTests.cs +++ b/MySQL.Data/tests/MySqlX.Data.Tests/CrudRemoveTests.cs @@ -1,380 +1,381 @@ -// Copyright (c) 2015, 2022, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySqlX.XDevAPI; -using MySqlX.XDevAPI.Common; -using NUnit.Framework; -using System; -using System.Collections.Generic; - -namespace MySqlX.Data.Tests -{ - public class CrudRemoveTests : BaseTest - { - [Test] - public void RemoveSingleDocumentById() - { - Collection coll = CreateCollection("test"); - var docs = new[]{ - new { _id = 12, title = "Book 1", pages = 20 }, - new { _id = 34, title = "Book 2", pages = 30 }, - new { _id = 56, title = "Book 3", pages = 40 }, - }; - Result r = ExecuteAddStatement(coll.Add(docs)); - Assert.AreEqual(3, r.AffectedItemsCount); - - // Remove with condition. - r = ExecuteRemoveStatement(coll.Remove("_id = 12")); - Assert.AreEqual(1, r.AffectedItemsCount); - - // Remove by ID. - r = coll.RemoveOne(34); - Assert.AreEqual(1, r.AffectedItemsCount); - - var ex = Assert.Throws(() => coll.Remove("")); -#if !NETFRAMEWORK - Assert.AreEqual("Parameter can't be null or empty. (Parameter 'condition')", ex.Message); -#else - Assert.AreEqual("Parameter can't be null or empty.\r\nParameter name: condition", ex.Message); -#endif - } - - [Test] - public void RemoveMultipleDocuments() - { - Collection coll = CreateCollection("test"); - var docs = new[] - { - new { _id = 1, title = "Book 1", pages = 20 }, - new { _id = 2, title = "Book 2", pages = 30 }, - new { _id = 3, title = "Book 3", pages = 40 }, - new { _id = 4, title = "Book 4", pages = 50 }, - }; - Result r = ExecuteAddStatement(coll.Add(docs)); - Assert.AreEqual(4, r.AffectedItemsCount); - - r = ExecuteRemoveStatement(coll.Remove("pages > 20")); - Assert.AreEqual(3, r.AffectedItemsCount); - } - - [Test] - public void RemoveMultipleDocumentsWithLimit() - { - Collection coll = CreateCollection("test"); - var docs = new[] - { - new { _id = 1, title = "Book 1", pages = 20 }, - new { _id = 2, title = "Book 2", pages = 30 }, - new { _id = 3, title = "Book 3", pages = 40 }, - new { _id = 4, title = "Book 4", pages = 50 }, - }; - Result r = ExecuteAddStatement(coll.Add(docs)); - Assert.AreEqual(4, r.AffectedItemsCount); - - r = ExecuteRemoveStatement(coll.Remove("pages > 20").Limit(1)); - Assert.AreEqual(1, r.AffectedItemsCount); - - // Limit out of range. - Assert.Throws(() => ExecuteRemoveStatement(coll.Remove("True").Limit(0))); - Assert.Throws(() => ExecuteRemoveStatement(coll.Remove("True").Limit(-2))); - Assert.Throws(() => ExecuteRemoveStatement(coll.Remove("pages > 10").Limit(0))); - Assert.Throws(() => ExecuteRemoveStatement(coll.Remove("pages > 20").Limit(-3))); - } - - [Test] - public void RemoveMultipleDocumentsWithLimitAndOrder() - { - Collection coll = CreateCollection("test"); - var docs = new[] - { - new { _id = 1, title = "Book 1", pages = 20 }, - new { _id = 2, title = "Book 2", pages = 30 }, - new { _id = 3, title = "Book 3", pages = 40 }, - new { _id = 4, title = "Book 4", pages = 50 }, - }; - Result r = ExecuteAddStatement(coll.Add(docs)); - Assert.AreEqual(4, r.AffectedItemsCount); - - r = ExecuteRemoveStatement(coll.Remove("pages > 20").Limit(1)); - Assert.AreEqual(1, r.AffectedItemsCount); - } - - [Test] - public void RemovingDocWithNoIdThrowsException() - { - Collection coll = CreateCollection("test"); - DbDoc doc = new DbDoc(); - Exception ex = Assert.Throws(() => ExecuteRemoveStatement(coll.Remove("_id = :id").Bind("id", doc.Id))); - } - - [Test] - public void RemoveBind() - { - Collection coll = CreateCollection("test"); - var docs = new[] - { - new { _id = 1, title = "Book 1", pages = 20 }, - new { _id = 2, title = "Book 2", pages = 30 }, - new { _id = 3, title = "Book 3", pages = 40 }, - new { _id = 4, title = "Book 4", pages = 50 }, - }; - Result r = ExecuteAddStatement(coll.Add(docs)); - Assert.AreEqual(4, r.AffectedItemsCount); - - r = ExecuteRemoveStatement(coll.Remove("pages = :Pages").Bind("pAges", 50)); - Assert.AreEqual(1, r.AffectedItemsCount); - - var jsonParams = new { pages1 = 30, pages2 = 40 }; - var res = coll.Remove("pages = :Pages1 || pages = :Pages2").Bind(jsonParams).Execute(); - Assert.AreEqual(2, res.AffectedItemsCount); - - DbDoc docParams = new DbDoc(new { pages1 = 10, pages2 = 20 }); - coll.Remove("pages = :Pages1 || pages = :Pages2").Bind(docParams).Execute(); - Assert.True(res.AffectedItemsCount > 0); - } - - [Test] - public void RemoveAll() - { - Collection collection = CreateCollection("test"); - var docs = new[] - { - new { _id = 1, title = "Book 1", pages = 20 }, - new { _id = 2, title = "Book 2", pages = 30 }, - new { _id = 3, title = "Book 3", pages = 40 }, - new { _id = 4, title = "Book 4", pages = 50 }, - }; - Result result = ExecuteAddStatement(collection.Add(docs)); - Assert.AreEqual(4, result.AffectedItemsCount); - - // Condition can't be null or empty. - string errorMessage = string.Empty; -#if !NETFRAMEWORK - errorMessage = "Parameter can't be null or empty. (Parameter 'condition')"; -#else - errorMessage = "Parameter can't be null or empty.\r\nParameter name: condition"; -#endif - Exception ex = Assert.Throws(() => ExecuteRemoveStatement(collection.Remove(string.Empty))); - Assert.AreEqual(errorMessage, ex.Message); - ex = Assert.Throws(() => ExecuteRemoveStatement(collection.Remove(""))); - Assert.AreEqual(errorMessage, ex.Message); - ex = Assert.Throws(() => ExecuteRemoveStatement(collection.Remove(" "))); - Assert.AreEqual(errorMessage, ex.Message); - ex = Assert.Throws(() => ExecuteRemoveStatement(collection.Remove(" "))); - Assert.AreEqual(errorMessage, ex.Message); - - // Sending an expression that evaluates to true applies changes on all documents. - result = ExecuteRemoveStatement(collection.Remove("true")); - Assert.AreEqual(4, result.AffectedItemsCount); - } - - [Test] - public void RemoveWithInOperator() - { - if (!session.InternalSession.GetServerVersion().isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher"); - - Collection collection = CreateCollection("test"); - var docs = new[] - { - new DbDoc("{ \"a\": 1, \"b\": \"foo\", \"c\": { \"d\": true, \"e\": [1,2,3] }, \"f\": [ {\"x\":5}, {\"x\":7 } ] }"), - new DbDoc("{ \"a\": 2, \"b\": \"foo2\", \"c\": { \"d\": true, \"e\": [4,5,6] }, \"f\": [ {\"x\":5}, {\"x\":8 } ] }"), - new DbDoc("{ \"a\": 1, \"b\": \"foo3\", \"c\": { \"d\": true, \"e\": [1,4,3] }, \"f\": [ {\"x\":6}, {\"x\":9 } ] }"), - }; - Result result = ExecuteAddStatement(collection.Add(docs)); - Assert.AreEqual(3, result.AffectedItemsCount); - - Assert.AreEqual(1, ExecuteRemoveStatement(collection.Remove("a IN (2,3)")).AffectedItemsCount); - Assert.AreEqual(2, ExecuteFindStatement(collection.Find()).FetchAll().Count); - - Assert.AreEqual(0, ExecuteRemoveStatement(collection.Remove("a IN [3]")).AffectedItemsCount); - Assert.AreEqual(2, ExecuteFindStatement(collection.Find()).FetchAll().Count); - - Assert.AreEqual(2, ExecuteRemoveStatement(collection.Remove("1 IN c.e")).AffectedItemsCount); - CollectionAssert.IsEmpty(ExecuteFindStatement(collection.Find()).FetchAll()); - } - - [Test] - public void RemoveOne() - { - Collection collection = CreateCollection("test"); - var docs = new[] - { - new { _id = 1, title = "Book 1", pages = 20 }, - new { _id = 2, title = "Book 2", pages = 30 }, - new { _id = 3, title = "Book 3", pages = 40 }, - new { _id = 4, title = "Book 4", pages = 50 }, - }; - Result result = ExecuteAddStatement(collection.Add(docs)); - Assert.AreEqual(4, result.AffectedItemsCount); - - ExecuteAddStatement(collection.Add(new { _id = 5, title = "Book 5", pages = 60 })); - Assert.AreEqual(5, ExecuteFindStatement(collection.Find()).FetchAll().Count); - - // Remove sending numeric parameter. - Assert.AreEqual(1, collection.RemoveOne(1).AffectedItemsCount); - Assert.AreEqual(4, ExecuteFindStatement(collection.Find()).FetchAll().Count); - - // Remove sending string parameter. - Assert.AreEqual(1, collection.RemoveOne("3").AffectedItemsCount); - Assert.AreEqual(3, ExecuteFindStatement(collection.Find()).FetchAll().Count); - - // Remove an auto-generated id. - DbDoc document = ExecuteFindStatement(collection.Find("pages = 60")).FetchOne(); - Assert.AreEqual(1, collection.RemoveOne(document.Id).AffectedItemsCount); - Assert.AreEqual(2, ExecuteFindStatement(collection.Find()).FetchAll().Count); - - // Remove a non-existing document. - Assert.AreEqual(0, collection.RemoveOne(5).AffectedItemsCount); - Assert.AreEqual(2, ExecuteFindStatement(collection.Find()).FetchAll().Count); - - // Expected exceptions. - Assert.Throws(() => collection.RemoveOne(null)); - Assert.Throws(() => collection.RemoveOne("")); - Assert.Throws(() => collection.RemoveOne(string.Empty)); - } - - #region WL14389 - - [Test, Description("MySQLX CNET Forbid remove() with no condition-Scenario-2")] - public void ForbidRemoveWithNoCondition() - { - Collection collection = CreateCollection("test"); - var docs = new[] - { - new { _id = 1, title = "Book 1", pages = 20 }, - new { _id = 2, title = "Book 2", pages = 30 }, - new { _id = 3, title = "Book 3", pages = 40 }, - new { _id = 4, title = "Book 4", pages = 50 }, - }; - Result result = collection.Add(docs).Execute(); - Assert.AreEqual(4, result.AffectedItemsCount); - - result = collection.Remove("_id = 1").Execute(); - Assert.AreEqual(1, result.AffectedItemsCount); - result = collection.Remove("_id = 10").Execute(); - Assert.AreEqual(0, result.AffectedItemsCount); - result = collection.Remove("_id = 2").Execute(); - Assert.AreEqual(1, result.AffectedItemsCount); - result = collection.Remove("_id = 10").Execute(); - Assert.AreEqual(0, result.AffectedItemsCount); - Assert.Throws(() => collection.Remove("")); - } - - [Test, Description("Test MySQLX plugin MySQL Net 846 - Collection Unset Multiple")] - public void CollectionUnsetMultiple() - { - Collection col = CreateCollection("my_collection_1"); - - var d1 = new DbDoc(); - d1.SetValue("_id", 1); - d1.SetValue("books", "test1"); - d1.SetValue("count", 10); - - var d2 = new DbDoc(); - d2.SetValue("_id", 2); - d2.SetValue("books", "test2"); - d2.SetValue("count", 20); - - var d3 = new DbDoc(); - d3.SetValue("_id", 3); - d3.SetValue("books", "test3"); - d3.SetValue("count", 30); - - var d4 = new DbDoc(); - d4.SetValue("_id", 4); - d4.SetValue("books", "test4"); - d4.SetValue("count", 40); - - var d5 = new DbDoc(); - d5.SetValue("_id", 5); - d5.SetValue("books", "test5"); - d5.SetValue("count", 50); - - var d6 = new DbDoc(); - d6.SetValue("_id", 6); - d6.SetValue("books", "test6"); - d6.SetValue("count", 0); - - var d7 = new DbDoc(); - d7.SetValue("_id", 0); - d7.SetValue("books", "test7"); - d7.SetValue("count", 60); - - var final = col.Add(d1, d2).Add(d3).Execute(); - - var res1 = col.Find().Fields("{\"_id\":\"1\",\"books\": \"test1\" }").Fields("{\"_id\":\"2\",\"books\": \"test2\" }").Fields("{\"_id\":\"3\",\"books\": \"test3\" }").Execute().FetchAll(); - res1 = col.Find().Fields(new string[] { "_id", "books", "count" }).Execute().FetchAll(); - Assert.AreEqual(3, res1.Count, "Matching the find count"); - Assert.AreEqual(d1.ToString(), res1[0].ToString(), "Matching the doc string 1"); - Assert.AreEqual(d2.ToString(), res1[1].ToString(), "Matching the doc string 2"); - Assert.AreEqual(d3.ToString(), res1[2].ToString(), "Matching the doc string 3"); - final = col.Add(new DbDoc[] { d4, d5 }).Execute(); - var res2 = col.Find().Fields("$._id as _id,$.books as books, $.count as count").Execute().FetchAll(); - Assert.AreEqual(5, res2.Count, "Matching the find count"); - Assert.AreEqual(d1.ToString(), res2[0].ToString(), "Matching the doc string 1"); - Assert.AreEqual(d2.ToString(), res2[1].ToString(), "Matching the doc string 2"); - Assert.AreEqual(d3.ToString(), res2[2].ToString(), "Matching the doc string 3"); - Assert.AreEqual(d4.ToString(), res2[3].ToString(), "Matching the doc string 4"); - Assert.AreEqual(d5.ToString(), res2[4].ToString(), "Matching the doc string 5"); - final = col.Add(d6, d7).Execute(); - var res3 = col.Find().Sort("count ASC").Execute().FetchAll(); - Assert.AreEqual(d6.ToString(), res3[0].ToString(), "Matching the doc string 7"); - Assert.AreEqual(d1.ToString(), res3[1].ToString(), "Matching the doc string 1"); - Assert.AreEqual(d2.ToString(), res3[2].ToString(), "Matching the doc string 2"); - Assert.AreEqual(d3.ToString(), res3[3].ToString(), "Matching the doc string 3"); - Assert.AreEqual(d4.ToString(), res3[4].ToString(), "Matching the doc string 4"); - Assert.AreEqual(d5.ToString(), res3[5].ToString(), "Matching the doc string 5"); - Assert.AreEqual(d7.ToString(), res3[6].ToString(), "Matching the doc string 6"); - var res4 = col.Find().Sort("count DESC").Execute().FetchAll(); - Assert.AreEqual(d7.ToString(), res4[0].ToString(), "Matching the doc string 6"); - Assert.AreEqual(d5.ToString(), res4[1].ToString(), "Matching the doc string 1"); - Assert.AreEqual(d4.ToString(), res4[2].ToString(), "Matching the doc string 2"); - Assert.AreEqual(d3.ToString(), res4[3].ToString(), "Matching the doc string 3"); - Assert.AreEqual(d2.ToString(), res4[4].ToString(), "Matching the doc string 4"); - Assert.AreEqual(d1.ToString(), res4[5].ToString(), "Matching the doc string 5"); - Assert.AreEqual(d6.ToString(), res4[6].ToString(), "Matching the doc string 7"); - //Unset with multiple variables not supported - col.Modify("_id = 1").Unset(new string[] { "count", "books" }).Execute(); - col.Modify("_id = 1").Set("count", 10).Set("books", "test1").Execute(); - - } - - [Test, Description("Test MySQLX plugin RemovingItemUsingDbDoc")] - public void RemovingItemUsingDbDoc() - { - Collection coll = CreateCollection("test"); - DbDoc doc = new DbDoc(new { _id = 1, title = "Book 1", pages = 20 }); - Result r = coll.Add(doc).Execute(); - Assert.AreEqual(1, (int)r.AffectedItemsCount, "Match being done"); - r = coll.Remove("_id=1").Execute(); - Assert.AreEqual(1, (int)r.AffectedItemsCount, "Match being done"); - } - - #endregion WL14389 - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySqlX.XDevAPI; +using MySqlX.XDevAPI.Common; +using NUnit.Framework; +using NUnit.Framework.Legacy; +using System; +using System.Collections.Generic; + +namespace MySqlX.Data.Tests +{ + public class CrudRemoveTests : BaseTest + { + [Test] + public void RemoveSingleDocumentById() + { + Collection coll = CreateCollection("test"); + var docs = new[]{ + new { _id = 12, title = "Book 1", pages = 20 }, + new { _id = 34, title = "Book 2", pages = 30 }, + new { _id = 56, title = "Book 3", pages = 40 }, + }; + Result r = ExecuteAddStatement(coll.Add(docs)); + Assert.That(r.AffectedItemsCount, Is.EqualTo(3)); + + // Remove with condition. + r = ExecuteRemoveStatement(coll.Remove("_id = 12")); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); + + // Remove by ID. + r = coll.RemoveOne(34); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); + + var ex = Assert.Throws(() => coll.Remove("")); +#if !NETFRAMEWORK + Assert.That(ex.Message, Is.EqualTo("Parameter can't be null or empty (Parameter 'condition')")); +#else + Assert.That(ex.Message, Is.EqualTo("Parameter can't be null or empty\r\nParameter name: condition")); +#endif + } + + [Test] + public void RemoveMultipleDocuments() + { + Collection coll = CreateCollection("test"); + var docs = new[] + { + new { _id = 1, title = "Book 1", pages = 20 }, + new { _id = 2, title = "Book 2", pages = 30 }, + new { _id = 3, title = "Book 3", pages = 40 }, + new { _id = 4, title = "Book 4", pages = 50 }, + }; + Result r = ExecuteAddStatement(coll.Add(docs)); + Assert.That(r.AffectedItemsCount, Is.EqualTo(4)); + + r = ExecuteRemoveStatement(coll.Remove("pages > 20")); + Assert.That(r.AffectedItemsCount, Is.EqualTo(3)); + } + + [Test] + public void RemoveMultipleDocumentsWithLimit() + { + Collection coll = CreateCollection("test"); + var docs = new[] + { + new { _id = 1, title = "Book 1", pages = 20 }, + new { _id = 2, title = "Book 2", pages = 30 }, + new { _id = 3, title = "Book 3", pages = 40 }, + new { _id = 4, title = "Book 4", pages = 50 }, + }; + Result r = ExecuteAddStatement(coll.Add(docs)); + Assert.That(r.AffectedItemsCount, Is.EqualTo(4)); + + r = ExecuteRemoveStatement(coll.Remove("pages > 20").Limit(1)); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); + + // Limit out of range. + Assert.Throws(() => ExecuteRemoveStatement(coll.Remove("True").Limit(0))); + Assert.Throws(() => ExecuteRemoveStatement(coll.Remove("True").Limit(-2))); + Assert.Throws(() => ExecuteRemoveStatement(coll.Remove("pages > 10").Limit(0))); + Assert.Throws(() => ExecuteRemoveStatement(coll.Remove("pages > 20").Limit(-3))); + } + + [Test] + public void RemoveMultipleDocumentsWithLimitAndOrder() + { + Collection coll = CreateCollection("test"); + var docs = new[] + { + new { _id = 1, title = "Book 1", pages = 20 }, + new { _id = 2, title = "Book 2", pages = 30 }, + new { _id = 3, title = "Book 3", pages = 40 }, + new { _id = 4, title = "Book 4", pages = 50 }, + }; + Result r = ExecuteAddStatement(coll.Add(docs)); + Assert.That(r.AffectedItemsCount, Is.EqualTo(4)); + + r = ExecuteRemoveStatement(coll.Remove("pages > 20").Limit(1)); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); + } + + [Test] + public void RemovingDocWithNoIdThrowsException() + { + Collection coll = CreateCollection("test"); + DbDoc doc = new DbDoc(); + Exception ex = Assert.Throws(() => ExecuteRemoveStatement(coll.Remove("_id = :id").Bind("id", doc.Id))); + } + + [Test] + public void RemoveBind() + { + Collection coll = CreateCollection("test"); + var docs = new[] + { + new { _id = 1, title = "Book 1", pages = 20 }, + new { _id = 2, title = "Book 2", pages = 30 }, + new { _id = 3, title = "Book 3", pages = 40 }, + new { _id = 4, title = "Book 4", pages = 50 }, + }; + Result r = ExecuteAddStatement(coll.Add(docs)); + Assert.That(r.AffectedItemsCount, Is.EqualTo(4)); + + r = ExecuteRemoveStatement(coll.Remove("pages = :Pages").Bind("pAges", 50)); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); + + var jsonParams = new { pages1 = 30, pages2 = 40 }; + var res = coll.Remove("pages = :Pages1 || pages = :Pages2").Bind(jsonParams).Execute(); + Assert.That(res.AffectedItemsCount, Is.EqualTo(2)); + + DbDoc docParams = new DbDoc(new { pages1 = 10, pages2 = 20 }); + coll.Remove("pages = :Pages1 || pages = :Pages2").Bind(docParams).Execute(); + Assert.That(res.AffectedItemsCount > 0); + } + + [Test] + public void RemoveAll() + { + Collection collection = CreateCollection("test"); + var docs = new[] + { + new { _id = 1, title = "Book 1", pages = 20 }, + new { _id = 2, title = "Book 2", pages = 30 }, + new { _id = 3, title = "Book 3", pages = 40 }, + new { _id = 4, title = "Book 4", pages = 50 }, + }; + Result result = ExecuteAddStatement(collection.Add(docs)); + Assert.That(result.AffectedItemsCount, Is.EqualTo(4)); + + // Condition can't be null or empty. + string errorMessage = string.Empty; +#if !NETFRAMEWORK + errorMessage = "Parameter can't be null or empty (Parameter 'condition')"; +#else + errorMessage = "Parameter can't be null or empty\r\nParameter name: condition"; +#endif + Exception ex = Assert.Throws(() => ExecuteRemoveStatement(collection.Remove(string.Empty))); + Assert.That(ex.Message, Is.EqualTo(errorMessage)); + ex = Assert.Throws(() => ExecuteRemoveStatement(collection.Remove(""))); + Assert.That(ex.Message, Is.EqualTo(errorMessage)); + ex = Assert.Throws(() => ExecuteRemoveStatement(collection.Remove(" "))); + Assert.That(ex.Message, Is.EqualTo(errorMessage)); + ex = Assert.Throws(() => ExecuteRemoveStatement(collection.Remove(" "))); + Assert.That(ex.Message, Is.EqualTo(errorMessage)); + + // Sending an expression that evaluates to true applies changes on all documents. + result = ExecuteRemoveStatement(collection.Remove("true")); + Assert.That(result.AffectedItemsCount, Is.EqualTo(4)); + } + + [Test] + public void RemoveWithInOperator() + { + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); + + Collection collection = CreateCollection("test"); + var docs = new[] + { + new DbDoc("{ \"a\": 1, \"b\": \"foo\", \"c\": { \"d\": true, \"e\": [1,2,3] }, \"f\": [ {\"x\":5}, {\"x\":7 } ] }"), + new DbDoc("{ \"a\": 2, \"b\": \"foo2\", \"c\": { \"d\": true, \"e\": [4,5,6] }, \"f\": [ {\"x\":5}, {\"x\":8 } ] }"), + new DbDoc("{ \"a\": 1, \"b\": \"foo3\", \"c\": { \"d\": true, \"e\": [1,4,3] }, \"f\": [ {\"x\":6}, {\"x\":9 } ] }"), + }; + Result result = ExecuteAddStatement(collection.Add(docs)); + Assert.That(result.AffectedItemsCount, Is.EqualTo(3)); + + Assert.That(ExecuteRemoveStatement(collection.Remove("a IN (2,3)")).AffectedItemsCount, Is.EqualTo(1)); + Assert.That(ExecuteFindStatement(collection.Find()).FetchAll().Count, Is.EqualTo(2)); + + Assert.That(ExecuteRemoveStatement(collection.Remove("a IN [3]")).AffectedItemsCount, Is.EqualTo(0)); + Assert.That(ExecuteFindStatement(collection.Find()).FetchAll().Count, Is.EqualTo(2)); + + Assert.That(ExecuteRemoveStatement(collection.Remove("1 IN c.e")).AffectedItemsCount, Is.EqualTo(2)); + Assert.That(ExecuteFindStatement(collection.Find()).FetchAll(), Is.Empty); + } + + [Test] + public void RemoveOne() + { + Collection collection = CreateCollection("test"); + var docs = new[] + { + new { _id = 1, title = "Book 1", pages = 20 }, + new { _id = 2, title = "Book 2", pages = 30 }, + new { _id = 3, title = "Book 3", pages = 40 }, + new { _id = 4, title = "Book 4", pages = 50 }, + }; + Result result = ExecuteAddStatement(collection.Add(docs)); + Assert.That(result.AffectedItemsCount, Is.EqualTo(4)); + + ExecuteAddStatement(collection.Add(new { _id = 5, title = "Book 5", pages = 60 })); + Assert.That(ExecuteFindStatement(collection.Find()).FetchAll().Count, Is.EqualTo(5)); + + // Remove sending numeric parameter. + Assert.That(collection.RemoveOne(1).AffectedItemsCount, Is.EqualTo(1)); + Assert.That(ExecuteFindStatement(collection.Find()).FetchAll().Count, Is.EqualTo(4)); + + // Remove sending string parameter. + Assert.That(collection.RemoveOne("3").AffectedItemsCount, Is.EqualTo(1)); + Assert.That(ExecuteFindStatement(collection.Find()).FetchAll().Count, Is.EqualTo(3)); + + // Remove an auto-generated id. + DbDoc document = ExecuteFindStatement(collection.Find("pages = 60")).FetchOne(); + Assert.That(collection.RemoveOne(document.Id).AffectedItemsCount, Is.EqualTo(1)); + Assert.That(ExecuteFindStatement(collection.Find()).FetchAll().Count, Is.EqualTo(2)); + + // Remove a non-existing document. + Assert.That(collection.RemoveOne(5).AffectedItemsCount, Is.EqualTo(0)); + Assert.That(ExecuteFindStatement(collection.Find()).FetchAll().Count, Is.EqualTo(2)); + + // Expected exceptions. + Assert.Throws(() => collection.RemoveOne(null)); + Assert.Throws(() => collection.RemoveOne("")); + Assert.Throws(() => collection.RemoveOne(string.Empty)); + } + + #region WL14389 + + [Test, Description("MySQLX CNET Forbid remove() with no condition-Scenario-2")] + public void ForbidRemoveWithNoCondition() + { + Collection collection = CreateCollection("test"); + var docs = new[] + { + new { _id = 1, title = "Book 1", pages = 20 }, + new { _id = 2, title = "Book 2", pages = 30 }, + new { _id = 3, title = "Book 3", pages = 40 }, + new { _id = 4, title = "Book 4", pages = 50 }, + }; + Result result = collection.Add(docs).Execute(); + Assert.That(result.AffectedItemsCount, Is.EqualTo(4)); + + result = collection.Remove("_id = 1").Execute(); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1)); + result = collection.Remove("_id = 10").Execute(); + Assert.That(result.AffectedItemsCount, Is.EqualTo(0)); + result = collection.Remove("_id = 2").Execute(); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1)); + result = collection.Remove("_id = 10").Execute(); + Assert.That(result.AffectedItemsCount, Is.EqualTo(0)); + Assert.Throws(() => collection.Remove("")); + } + + [Test, Description("Test MySQLX plugin MySQL Net 846 - Collection Unset Multiple")] + public void CollectionUnsetMultiple() + { + Collection col = CreateCollection("my_collection_1"); + + var d1 = new DbDoc(); + d1.SetValue("_id", 1); + d1.SetValue("books", "test1"); + d1.SetValue("count", 10); + + var d2 = new DbDoc(); + d2.SetValue("_id", 2); + d2.SetValue("books", "test2"); + d2.SetValue("count", 20); + + var d3 = new DbDoc(); + d3.SetValue("_id", 3); + d3.SetValue("books", "test3"); + d3.SetValue("count", 30); + + var d4 = new DbDoc(); + d4.SetValue("_id", 4); + d4.SetValue("books", "test4"); + d4.SetValue("count", 40); + + var d5 = new DbDoc(); + d5.SetValue("_id", 5); + d5.SetValue("books", "test5"); + d5.SetValue("count", 50); + + var d6 = new DbDoc(); + d6.SetValue("_id", 6); + d6.SetValue("books", "test6"); + d6.SetValue("count", 0); + + var d7 = new DbDoc(); + d7.SetValue("_id", 0); + d7.SetValue("books", "test7"); + d7.SetValue("count", 60); + + var final = col.Add(d1, d2).Add(d3).Execute(); + + var res1 = col.Find().Fields("{\"_id\":\"1\",\"books\": \"test1\" }").Fields("{\"_id\":\"2\",\"books\": \"test2\" }").Fields("{\"_id\":\"3\",\"books\": \"test3\" }").Execute().FetchAll(); + res1 = col.Find().Fields(new string[] { "_id", "books", "count" }).Execute().FetchAll(); + Assert.That(res1.Count, Is.EqualTo(3), "Matching the find count"); + Assert.That(res1[0].ToString(), Is.EqualTo(d1.ToString()), "Matching the doc string 1"); + Assert.That(res1[1].ToString(), Is.EqualTo(d2.ToString()), "Matching the doc string 2"); + Assert.That(res1[2].ToString(), Is.EqualTo(d3.ToString()), "Matching the doc string 3"); + final = col.Add(new DbDoc[] { d4, d5 }).Execute(); + var res2 = col.Find().Fields("$._id as _id,$.books as books, $.count as count").Execute().FetchAll(); + Assert.That(res2.Count, Is.EqualTo(5), "Matching the find count"); + Assert.That(res2[0].ToString(), Is.EqualTo(d1.ToString()), "Matching the doc string 1"); + Assert.That(res2[1].ToString(), Is.EqualTo(d2.ToString()), "Matching the doc string 2"); + Assert.That(res2[2].ToString(), Is.EqualTo(d3.ToString()), "Matching the doc string 3"); + Assert.That(res2[3].ToString(), Is.EqualTo(d4.ToString()), "Matching the doc string 4"); + Assert.That(res2[4].ToString(), Is.EqualTo(d5.ToString()), "Matching the doc string 5"); + final = col.Add(d6, d7).Execute(); + var res3 = col.Find().Sort("count ASC").Execute().FetchAll(); + Assert.That(res3[0].ToString(), Is.EqualTo(d6.ToString()), "Matching the doc string 7"); + Assert.That(res3[1].ToString(), Is.EqualTo(d1.ToString()), "Matching the doc string 1"); + Assert.That(res3[2].ToString(), Is.EqualTo(d2.ToString()), "Matching the doc string 2"); + Assert.That(res3[3].ToString(), Is.EqualTo(d3.ToString()), "Matching the doc string 3"); + Assert.That(res3[4].ToString(), Is.EqualTo(d4.ToString()), "Matching the doc string 4"); + Assert.That(res3[5].ToString(), Is.EqualTo(d5.ToString()), "Matching the doc string 5"); + Assert.That(res3[6].ToString(), Is.EqualTo(d7.ToString()), "Matching the doc string 6"); + var res4 = col.Find().Sort("count DESC").Execute().FetchAll(); + Assert.That(res4[0].ToString(), Is.EqualTo(d7.ToString()), "Matching the doc string 6"); + Assert.That(res4[1].ToString(), Is.EqualTo(d5.ToString()), "Matching the doc string 1"); + Assert.That(res4[2].ToString(), Is.EqualTo(d4.ToString()), "Matching the doc string 2"); + Assert.That(res4[3].ToString(), Is.EqualTo(d3.ToString()), "Matching the doc string 3"); + Assert.That(res4[4].ToString(), Is.EqualTo(d2.ToString()), "Matching the doc string 4"); + Assert.That(res4[5].ToString(), Is.EqualTo(d1.ToString()), "Matching the doc string 5"); + Assert.That(res4[6].ToString(), Is.EqualTo(d6.ToString()), "Matching the doc string 7"); + //Unset with multiple variables not supported + col.Modify("_id = 1").Unset(new string[] { "count", "books" }).Execute(); + col.Modify("_id = 1").Set("count", 10).Set("books", "test1").Execute(); + + } + + [Test, Description("Test MySQLX plugin RemovingItemUsingDbDoc")] + public void RemovingItemUsingDbDoc() + { + Collection coll = CreateCollection("test"); + DbDoc doc = new DbDoc(new { _id = 1, title = "Book 1", pages = 20 }); + Result r = coll.Add(doc).Execute(); + Assert.That((int)r.AffectedItemsCount, Is.EqualTo(1), "Match being done"); + r = coll.Remove("_id=1").Execute(); + Assert.That((int)r.AffectedItemsCount, Is.EqualTo(1), "Match being done"); + } + + #endregion WL14389 + } +} diff --git a/MySQL.Data/tests/MySqlX.Data.Tests/CrudTests/CrudGCTests.cs b/MySQL.Data/tests/MySqlX.Data.Tests/CrudTests/CrudGCTests.cs index 907e31c8b..add461b08 100644 --- a/MySQL.Data/tests/MySqlX.Data.Tests/CrudTests/CrudGCTests.cs +++ b/MySQL.Data/tests/MySqlX.Data.Tests/CrudTests/CrudGCTests.cs @@ -1,60 +1,61 @@ -// Copyright (c) 2015, 2022, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySqlX.XDevAPI; -using MySqlX.XDevAPI.Common; -using System; -using NUnit.Framework; - -namespace MySqlX.Data.Tests.ResultTests -{ - public class CrudGCTests : BaseTest - { -#if NETFRAMEWORK - [Test] - public void FetchAllNoReference() - { - Collection testColl = CreateCollection("test"); - var stmt = testColl.Add(@"{ ""_id"": 1, ""foo"": 1 }"); - stmt.Add(@"{ ""_id"": 2, ""foo"": 2 }"); - stmt.Add(@"{ ""_id"": 3, ""foo"": 3 }"); - stmt.Add(@"{ ""_id"": 4, ""foo"": 4 }"); - Result result = ExecuteAddStatement(stmt); - Assert.AreEqual(4, (int)result.AffectedItemsCount); - - var docResult = ExecuteFindStatement(testColl.Find()); - var docs = docResult.FetchAll(); - WeakReference wr = new WeakReference(docResult); - docResult = null; - GC.Collect(); - Assert.False(wr.IsAlive); - Assert.AreEqual(4, docs.Count); - } -#endif - } -} \ No newline at end of file +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySqlX.XDevAPI; +using MySqlX.XDevAPI.Common; +using System; +using NUnit.Framework; +using NUnit.Framework.Legacy; + +namespace MySqlX.Data.Tests.ResultTests +{ + public class CrudGCTests : BaseTest + { +#if NETFRAMEWORK + [Test] + public void FetchAllNoReference() + { + Collection testColl = CreateCollection("test"); + var stmt = testColl.Add(@"{ ""_id"": 1, ""foo"": 1 }"); + stmt.Add(@"{ ""_id"": 2, ""foo"": 2 }"); + stmt.Add(@"{ ""_id"": 3, ""foo"": 3 }"); + stmt.Add(@"{ ""_id"": 4, ""foo"": 4 }"); + Result result = ExecuteAddStatement(stmt); + Assert.That((int)result.AffectedItemsCount, Is.EqualTo(4)); + + var docResult = ExecuteFindStatement(testColl.Find()); + var docs = docResult.FetchAll(); + WeakReference wr = new WeakReference(docResult); + docResult = null; + GC.Collect(); + Assert.That(wr.IsAlive, Is.False); + Assert.That(docs.Count, Is.EqualTo(4)); + } +#endif + } +} diff --git a/MySQL.Data/tests/MySqlX.Data.Tests/CrudTests/DocBufferingTests.cs b/MySQL.Data/tests/MySqlX.Data.Tests/CrudTests/DocBufferingTests.cs index 5da347e2b..1913d0ea9 100644 --- a/MySQL.Data/tests/MySqlX.Data.Tests/CrudTests/DocBufferingTests.cs +++ b/MySQL.Data/tests/MySqlX.Data.Tests/CrudTests/DocBufferingTests.cs @@ -1,61 +1,62 @@ -// Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySqlX.XDevAPI; -using MySqlX.XDevAPI.Common; -using NUnit.Framework; - -namespace MySqlX.Data.Tests.CrudTests -{ - public class DocBufferingTests : BaseTest - { - [Test] - public void SmartBuffering() - { - Collection test = CreateCollection("test"); - Collection test2 = CreateCollection("test2"); - - var docs = new[] - { - new { _id = 1, title = "Book 1", pages = 20 }, - new { _id = 2, title = "Book 2", pages = 30 }, - new { _id = 3, title = "Book 3", pages = 40 }, - new { _id = 4, title = "Book 4", pages = 50 }, - }; - Result r = ExecuteAddStatement(test.Add(docs)); - Assert.AreEqual(r.Warnings.Count, r.WarningsCount); - - var docResult = ExecuteFindStatement(test.Find()); - foreach (var doc in docResult) - { - var result = ExecuteAddStatement(test2.Add(doc)); - Assert.AreEqual(1, result.AffectedItemsCount); - } - } - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySqlX.XDevAPI; +using MySqlX.XDevAPI.Common; +using NUnit.Framework; +using NUnit.Framework.Legacy; + +namespace MySqlX.Data.Tests.CrudTests +{ + public class DocBufferingTests : BaseTest + { + [Test] + public void SmartBuffering() + { + Collection test = CreateCollection("test"); + Collection test2 = CreateCollection("test2"); + + var docs = new[] + { + new { _id = 1, title = "Book 1", pages = 20 }, + new { _id = 2, title = "Book 2", pages = 30 }, + new { _id = 3, title = "Book 3", pages = 40 }, + new { _id = 4, title = "Book 4", pages = 50 }, + }; + Result r = ExecuteAddStatement(test.Add(docs)); + Assert.That(r.WarningsCount, Is.EqualTo(r.Warnings.Count)); + + var docResult = ExecuteFindStatement(test.Find()); + foreach (var doc in docResult) + { + var result = ExecuteAddStatement(test2.Add(doc)); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1)); + } + } + } +} diff --git a/MySQL.Data/tests/MySqlX.Data.Tests/CrudUpdateTests.cs b/MySQL.Data/tests/MySqlX.Data.Tests/CrudUpdateTests.cs index 213ab2273..e60869b05 100644 --- a/MySQL.Data/tests/MySqlX.Data.Tests/CrudUpdateTests.cs +++ b/MySQL.Data/tests/MySqlX.Data.Tests/CrudUpdateTests.cs @@ -1,1282 +1,1283 @@ -// Copyright (c) 2015, 2023, Oracle and/or its affiliates. -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data; -using MySql.Data.MySqlClient; -using MySqlX.XDevAPI; -using MySqlX.XDevAPI.Common; -using NUnit.Framework; -using System; -using System.Collections.Generic; - -namespace MySqlX.Data.Tests -{ - public class CrudUpdateTests : BaseTest - { - [Test] - public void SetItemInSingleDocument() - { - Collection coll = CreateCollection("test"); - Result result = ExecuteAddStatement(coll.Add(new { _id = 1, name = "Book 1" })); - Assert.AreEqual(1, result.AffectedItemsCount); - - // Set integer value. - result = ExecuteModifyStatement(coll.Modify("_id = 1").Set("pages", "20")); - Assert.AreEqual(1, result.AffectedItemsCount); - Assert.AreEqual("20", coll.GetOne(1)["pages"]); - - // Set null value. - result = ExecuteModifyStatement(coll.Modify("_id = 1").Set("pages", null)); - Assert.AreEqual(1, result.AffectedItemsCount); - Assert.Null(coll.GetOne(1)["pages"]); - - // Set existing field. - result = ExecuteModifyStatement(coll.Modify("_id = 1").Set("name", "Book 2")); - Assert.AreEqual(1, result.AffectedItemsCount); - Assert.AreEqual("Book 2", coll.GetOne(1)["name"]); - - // Set alphanumeric field. - var document = new DbDoc(); - document.SetValue("_id", 2); - document.SetValue("1a", "other"); - result = ExecuteAddStatement(coll.Add(document)); - Assert.AreEqual(1, result.AffectedItemsCount); - var insertedDocument = coll.GetOne(2); - - //result = coll.Modify("_id = 1").Set("1a", "other")); - } - - [Test] - public void ChangeItemInSingleDocument() - { - Collection coll = CreateCollection("test"); - Result result = ExecuteAddStatement(coll.Add(new { _id = 1, name = "Book 1", pages = 20 })); - Assert.AreEqual(1, result.AffectedItemsCount); - - result = ExecuteModifyStatement(coll.Modify("_id = 1").Change("name", "Book 2")); - Assert.AreEqual(1, result.AffectedItemsCount); - } - - [Test] - public void RemoveItemInSingleDocumentUsingUnset() - { - Collection coll = CreateCollection("test"); - Result result = ExecuteAddStatement(coll - .Add(new { _id = 1, name = "Book 1", pages = 20 }) - .Add(new { _id = 2, name = "Book 2", pages = 30 }) - .Add(new { _id = 3, name = "Book 3", pages = 40, author = "John", author2 = "Mary" }) - ); - Assert.AreEqual(3, result.AffectedItemsCount); - - // Unset 1 field. - result = ExecuteModifyStatement(coll.Modify("_id = 1").Unset("pages")); - Assert.AreEqual(1, result.AffectedItemsCount); - var document = ExecuteFindStatement(coll.Find("_id = 1")).FetchOne(); - Assert.AreEqual(2, document.values.Count); - - // Unset multiple fields. - result = ExecuteModifyStatement(coll.Modify("_id = 2").Unset("name", "pages")); - Assert.AreEqual(1, result.AffectedItemsCount); - document = ExecuteFindStatement(coll.Find("_id = 2")).FetchOne(); - Assert.That(document.values, Has.One.Items); - result = ExecuteModifyStatement(coll.Modify("_id = 3").Unset(null, "author", "author2")); - document = ExecuteFindStatement(coll.Find("_id = 3")).FetchOne(); - Assert.AreEqual(3, document.values.Count); - - // Unsetting nonexistent fields doesn't raise an error. - result = ExecuteModifyStatement(coll.Modify("_id = 2").Unset("otherfield")); - Assert.AreEqual(0ul, result.AffectedItemsCount); - - // Unsetting null items combined with valid values are ignored. - result = ExecuteModifyStatement(coll.Modify("_id = 3").Unset(null).Unset("name")); - Assert.AreEqual(1ul, result.AffectedItemsCount); - document = ExecuteFindStatement(coll.Find("_id = 3")).FetchOne(); - Assert.AreEqual(2, document.values.Count); - - // Unsetting single null items raises an error - var ex = Assert.Throws(() => ExecuteModifyStatement(coll.Modify("_id = 3").Unset(null))); - Assert.AreEqual("Invalid update expression list", ex.Message); - - // Unsetting empty strings raises an error. - var ex2 = Assert.Throws(() => ExecuteModifyStatement(coll.Modify("_id = 2").Unset(""))); - Assert.AreEqual(ResourcesX.DocPathNullOrEmpty, ex2.Message); - ex2 = Assert.Throws(() => ExecuteModifyStatement(coll.Modify("_id = 2").Unset(string.Empty))); - Assert.AreEqual(ResourcesX.DocPathNullOrEmpty, ex2.Message); - - // Unset with special chars. - Assert.Throws(() => ExecuteModifyStatement(coll.Modify("_id = 3").Unset(null).Unset("@*%#�"))); - Assert.Throws(() => ExecuteModifyStatement(coll.Modify("_id = 3").Unset(null).Unset("******"))); - } - - [Test] - public void SetItemAndBind() - { - Collection coll = CreateCollection("test"); - Result result = ExecuteAddStatement(coll.Add(new { _id = 1, name = "Book 1" }) - .Add(new { _id = 2, name = "Book 2" })); - Assert.AreEqual(2, result.AffectedItemsCount); - - var stmt = coll.Modify("_id = :ID"); - result = ExecuteModifyStatement(stmt.Bind("Id", 2).Set("pages", "20")); - Assert.AreEqual(1, result.AffectedItemsCount); - result = ExecuteModifyStatement(stmt.Bind("Id", 1).Set("pages", 10)); Assert.AreEqual(1, result.AffectedItemsCount); - - var docs = ExecuteFindStatement(coll.Find()).FetchAll(); - Assert.AreEqual(new DbDoc("{ \"_id\": 1, \"name\": \"Book 1\", \"pages\": 10 }").ToString(), docs[0].ToString()); - Assert.AreEqual(new DbDoc("{ \"_id\": 2, \"name\": \"Book 2\", \"pages\": \"20\" }").ToString(), docs[1].ToString()); - } - - [Test] - public void ModifyAll() - { - Collection collection = CreateCollection("test"); - var docs = new[] - { - new { _id = 1, title = "Book 1", pages = 20 }, - new { _id = 2, title = "Book 2", pages = 30 }, - }; - Result result = ExecuteAddStatement(collection.Add(docs)); - Assert.AreEqual(2, result.AffectedItemsCount); - - // Condition can't be null or empty. - string errorMessage = string.Empty; -#if !NETFRAMEWORK - errorMessage = "Parameter can't be null or empty. (Parameter 'condition')"; -#else - errorMessage = "Parameter can't be null or empty.\r\nParameter name: condition"; -#endif - Exception ex = Assert.Throws(() => ExecuteModifyStatement(collection.Modify(string.Empty))); - Assert.AreEqual(ex.Message, errorMessage); - ex = Assert.Throws(() => ExecuteModifyStatement(collection.Modify(""))); - Assert.AreEqual(ex.Message, errorMessage); - ex = Assert.Throws(() => ExecuteModifyStatement(collection.Modify(" "))); - Assert.AreEqual(ex.Message, errorMessage); - ex = Assert.Throws(() => ExecuteModifyStatement(collection.Modify(" "))); - Assert.AreEqual(ex.Message, errorMessage); - ex = Assert.Throws(() => ExecuteModifyStatement(collection.Modify(null))); - Assert.AreEqual(ex.Message, errorMessage); - - // Sending an expression that evaluates to true applies changes on all documents. - result = ExecuteModifyStatement(collection.Modify("true").Set("pages", "10")); - Assert.AreEqual(2, result.AffectedItemsCount); - } - - [Test] - public void ModifyWithLimit() - { - Collection collection = CreateCollection("test"); - var docs = new[] - { - new { _id = 1, title = "Book 1", pages = 20 }, - new { _id = 2, title = "Book 2", pages = 30 }, - }; - Result result = ExecuteAddStatement(collection.Add(docs)); - Assert.AreEqual(2, result.AffectedItemsCount); - - ExecuteModifyStatement(collection.Modify("true").Set("title", "Book X").Limit(1)); - Assert.That(ExecuteFindStatement(collection.Find("title = \"Book X\"")).FetchAll(), Has.One.Items); - - // Limit out of range. - Assert.Throws(() => ExecuteModifyStatement(collection.Modify("true").Set("pages", 10).Limit(0))); - Assert.Throws(() => ExecuteModifyStatement(collection.Modify("true").Set("pages", 10).Limit(-10))); - } - - [Test] - public void ModifyWithInOperator() - { - if (!session.InternalSession.GetServerVersion().isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher"); - - Collection collection = CreateCollection("test"); - var docs = new[] - { - new DbDoc("{ \"a\": 1, \"b\": \"foo\", \"c\": { \"d\": true, \"e\": [1,2,3] }, \"f\": [ {\"x\":5}, {\"x\":7 } ] }"), - new DbDoc("{ \"a\": 2, \"b\": \"foo2\", \"c\": { \"d\": true, \"e\": [4,5,6] }, \"f\": [ {\"x\":5}, {\"x\":8 } ] }"), - new DbDoc("{ \"a\": 1, \"b\": \"foo3\", \"c\": { \"d\": true, \"e\": [1,4,3] }, \"f\": [ {\"x\":6}, {\"x\":9 } ] }"), - }; - Result result = ExecuteAddStatement(collection.Add(docs)); - Assert.AreEqual(3, result.AffectedItemsCount); - - Assert.AreEqual(3, ExecuteModifyStatement(collection.Modify("a IN (1,2)").Set("a", 3)).AffectedItemsCount); - Assert.AreEqual(3, ExecuteFindStatement(collection.Find().Where("a = 3")).FetchAll().Count); - - Assert.AreEqual(3, ExecuteModifyStatement(collection.Modify("a IN [3]").Set("a", 1)).AffectedItemsCount); - Assert.AreEqual(3, ExecuteFindStatement(collection.Find().Where("a = 1")).FetchAll().Count); - - Assert.AreEqual(2, ExecuteModifyStatement(collection.Modify("1 IN c.e").Set("c.e", "newValue")).AffectedItemsCount); - Assert.AreEqual(2, ExecuteFindStatement(collection.Find().Where("c.e = \"newValue\"")).FetchAll().Count); - } - - [Test] - public void ReplaceOne() - { - Collection collection = CreateCollection("test"); - var docs = new[] - { - new { _id = 1, title = "Book 1", pages = 20 }, - new { _id = 2, title = "Book 2", pages = 30 }, - new { _id = 3, title = "Book 3", pages = 40 }, - new { _id = 4, title = "Book 4", pages = 50 }, - }; - Result result = ExecuteAddStatement(collection.Add(docs)); - Assert.AreEqual(4, result.AffectedItemsCount); - - // Expected exceptions. - Assert.Throws(() => collection.ReplaceOne(null, docs[1])); - Assert.Throws(() => collection.ReplaceOne("", docs[1])); - Assert.Throws(() => collection.ReplaceOne(string.Empty, docs[1])); - Assert.Throws(() => collection.ReplaceOne("1", null)); - // Replace using no matching id - Assert.Throws(() => collection.ReplaceOne(3, new DbDoc("{ \"_id\": 2, \"name\": \"John\", \"lastName\": \"Smith\" }")), - ResourcesX.ReplaceWithNoMatchingId); - - var newDoc = new { _id = 1, title = "Book 11", pages = 311 }; - - // Replace using a numeric identifier. - Assert.AreEqual(1, collection.ReplaceOne(1, newDoc).AffectedItemsCount); - DbDoc document = collection.GetOne(1); - Assert.AreEqual(1, Convert.ToInt32(document.Id)); - Assert.AreEqual("Book 11", document["title"]); - Assert.AreEqual(311, Convert.ToInt32(document["pages"])); - - // Replace using a string identifier. - Assert.AreEqual(1, collection.ReplaceOne("2", new DbDoc("{ \"name\": \"John\", \"lastName\": \"Smith\" }")).AffectedItemsCount); - document = collection.GetOne(2); - Assert.AreEqual(2, Convert.ToInt32(document.Id)); - Assert.AreEqual("John", document["name"]); - Assert.AreEqual("Smith", document["lastName"]); - - // Replace a non-existing document. - Assert.AreEqual(0, collection.ReplaceOne(5, docs[1]).AffectedItemsCount); - Assert.True(collection.GetOne(5) == null); - } - - [Test] - public void ReplaceNestedDocument() - { - var collection = CreateCollection("test"); - var docs = new DbDoc[] - { - new DbDoc(@"{ ""_id"":1, ""pages"":20, ""title"":""Book 1"", ""person"": { ""name"": ""Fred"", ""age"":45 } }" ), - new DbDoc(@"{ ""_id"": 2, ""pages"": 30,""title"" : ""Book 2"", ""person"": { ""name"": ""Peter"", ""age"": 38 } }"), - new DbDoc(@"{ ""_id"": 3, ""pages"": 40,""title"" : ""Book 3"", ""person"": { ""name"": ""Andy"", ""age"": 25 } }"), - new DbDoc(@"{ ""_id"": 4, ""pages"": 50,""title"" : ""Book 4"", ""person"": { ""name"": ""John"", ""age"": 34 } }") - }; - Assert.AreEqual(4, ExecuteAddStatement(collection.Add(docs)).AffectedItemsCount); - - DbDoc d_new = new DbDoc(@"{ ""_id"": 1, ""pages"": 20,""title"" : ""Book 1"", ""person"": { ""name"": ""Fred"", ""age"": 45 ,""State"" : ""Ohio""} }"); - Assert.AreEqual(1, collection.ReplaceOne(1, d_new).AffectedItemsCount); - DbDoc document = collection.GetOne(1); - Assert.AreEqual("Ohio", (document.values["person"] as Dictionary)["State"]); - - d_new = new DbDoc(@"{ ""_id"": 1, ""pages"": 20,""title"" : ""Book 1"", ""person"": { ""name"": ""Fred"", ""age"": 45 ,""State"" : ""Ohio"", ""newProp"": { ""a"":33 } } }"); - Assert.AreEqual(1, collection.ReplaceOne(1, d_new).AffectedItemsCount); - document = collection.GetOne(1); - Assert.AreEqual(33, ((document.values["person"] as Dictionary)["newProp"] as Dictionary)["a"]); - } - - [Test] - public void ArrayInsert() - { - Collection collection = CreateCollection("test"); - ExecuteAddStatement(collection.Add("{ \"x\":[1,2] }")); - - // x[1]=43, x[2]=2. - ExecuteModifyStatement(collection.Modify("true").ArrayInsert("x[1]", 43)); - // x[3]=44. - ExecuteModifyStatement(collection.Modify("true").ArrayInsert("x[3]", 44)); - // Since array only contains 4 items the value 46 is assigned to x[4]. - ExecuteModifyStatement(collection.Modify("true").ArrayInsert("x[5]", 46)); - // Since array only contains 5 items the value 50 is assigned to x[5]. - ExecuteModifyStatement(collection.Modify("true").ArrayInsert("x[20]", 50)); - // Assign an item from different data type. - ExecuteModifyStatement(collection.Modify("true").ArrayInsert("x[6]", "string")); - // Assign a document. - ExecuteModifyStatement(collection.Modify("true").ArrayInsert("x[7]", "{ \"name\":\"Mike\" }")); - - var result = ExecuteFindStatement(collection.Find()); - var document = result.FetchOne(); - var x = (object[])document.values["x"]; - - Assert.AreEqual(8, x.Length); - Assert.AreEqual(1, (int)x[0]); - Assert.AreEqual(43, (int)x[1]); - Assert.AreEqual(2, (int)x[2]); - Assert.AreEqual(44, (int)x[3]); - Assert.AreEqual(46, (int)x[4]); - Assert.AreEqual(50, (int)x[5]); - Assert.AreEqual("string", x[6]); - Assert.True(new DbDoc(x[7]) is DbDoc); - - // No value is inserted if the array doesn't exist. - ExecuteModifyStatement(collection.Modify("true").ArrayInsert("y[0]", 1)); - - result = ExecuteFindStatement(collection.Find()); - document = result.FetchOne(); - Assert.False(document.values.ContainsKey("y")); - - ExecuteModifyStatement(collection.Modify("true").ArrayInsert("x[0]", null)); - ExecuteModifyStatement(collection.Modify("true").ArrayInsert("x[1]", " ")); - - result = ExecuteFindStatement(collection.Find()); - document = result.FetchOne(); - x = (object[])document.values["x"]; - Assert.Null(x[0]); - Assert.AreEqual(" ", x[1]); - - // Insert an empty string fails. - var ex = Assert.Throws(() => ExecuteModifyStatement(collection.Modify("true").ArrayInsert("x[0]", ""))); - StringAssert.Contains("String can't be empty.", ex.Message); - ex = Assert.Throws(() => ExecuteModifyStatement(collection.Modify("true").ArrayInsert("x[0]", string.Empty))); - StringAssert.Contains("String can't be empty.", ex.Message); - - // Not specifying an index raises an error. - var ex2 = Assert.Throws(() => ExecuteModifyStatement(collection.Modify("true").ArrayInsert("dates", "5/1/2018"))); - Assert.AreEqual("A path expression is not a path to a cell in an array.", ex2.Message); - - var col = CreateCollection("my_collection"); - var t1 = "{\"_id\": \"1001\", \"ARR\":[1,2,3], \"ARR1\":[\"name1\",\"name2\", \"name3\"]}"; - col.Add(t1).Execute(); - col.Modify("true").ArrayInsert("ARR[0]", 4).Execute(); - col.Modify("true").ArrayInsert("ARR1[0]", "name4").Execute(); - col.Modify("true").ArrayInsert("ARR[0]", "name5").Execute(); - col.Modify("true").ArrayInsert("ARR1[0]", 5).Execute(); - col.Modify("true").ArrayInsert("ARR[0]", 6).ArrayInsert("ARR1[0]", "name6").ArrayInsert("ARR[0]", 7).ArrayInsert("ARR[0]", 8).Execute(); - col.Modify("true").ArrayInsert("ARR1[0]", null).Execute(); - col.Modify("true").ArrayInsert("ARR1[0]", " ").Execute(); - col.Modify("true").ArrayInsert("ARR1[0]", "****").Execute(); - result = ExecuteFindStatement(col.Find()); - document = result.FetchOne(); - var x2 = (object[])document.values["ARR"]; - Assert.AreEqual(8, x2.Length); - Assert.AreEqual(8, (int)x2[0]); - x2 = (object[])document.values["ARR1"]; - Assert.AreEqual("****", x2[0]); - Assert.AreEqual("name3", x2[8]); - } - - [Test] - public void ArrayAppendWithMySqlExpression() - { - Collection collection = CreateCollection("test"); - - // String containing an expression is not evaluted. - ExecuteAddStatement(collection.Add("{ \"_id\":\"123\", \"name\":\"alice\", \"email\":[ \"alice@ora.com\" ], \"dates\":\"4/1/2017\" }")); - ExecuteModifyStatement(collection.Modify("true").ArrayAppend("email", "UPPER($.name)")); - var document = collection.GetOne("123"); - Assert.AreEqual("UPPER($.name)", (document["email"] as object[])[1]); - - // Use MySqlExpression. - ExecuteAddStatement(collection.Add("{ \"_id\":\"124\", \"name\":\"alice\", \"value\":[ \"alice@ora.com\" ], \"dates\":\"4/1/2017\" }")); - ExecuteModifyStatement(collection.Modify("_id = \"124\"").ArrayAppend("value", new MySqlExpression("UPPER($.name)"))); - document = collection.GetOne("124"); - Assert.AreEqual("ALICE", (document["value"] as object[])[1]); - - // Use embedded MySqlExpression. - ExecuteAddStatement(collection.Add("{ \"_id\":\"125\", \"name\":\"alice\", \"value\":[ \"alice@ora.com\" ], \"dates\":\"4/1/2017\" }")); - ExecuteModifyStatement(collection.Modify("_id = \"125\"").ArrayAppend("value", new { expression = new MySqlExpression("UPPER($.name)") })); - document = collection.GetOne("125"); - var item = ((document["value"] as object[])[1] as Dictionary); - Assert.AreEqual("ALICE", item["expression"]); - - ExecuteAddStatement(collection.Add("{ \"_id\":\"126\", \"name\":\"alice\", \"value\":[ \"alice@ora.com\" ], \"dates\":\"4/1/2017\" }")); - ExecuteModifyStatement(collection.Modify("_id = \"126\"").ArrayAppend("value", new { expression = new MySqlExpression("UPPER($.name)"), literal = "UPPER($.name)" })); - document = collection.GetOne("126"); - item = ((document["value"] as object[])[1] as Dictionary); - Assert.AreEqual("ALICE", item["expression"]); - Assert.AreEqual("UPPER($.name)", item["literal"]); - } - - [Test] - public void ArrayAppendUsesCorrectDataTypes() - { - Collection collection = CreateCollection("test"); - ExecuteAddStatement(collection.Add("{ \"_id\":\"123\", \"email\":[ \"alice@ora.com\"], \"dates\":\"4/1/2017\" }")); - ExecuteModifyStatement(collection.Modify("true").ArrayAppend("dates", "1")); - ExecuteModifyStatement(collection.Modify("true").ArrayAppend("dates", 1)); - var document = collection.GetOne("123"); - var dates = document["dates"] as object[]; - Assert.True(dates[1] is string); - Assert.True(dates[2] is int); - } - - [Test] - public void ArrayAppend() - { - Collection collection = CreateCollection("test"); - ExecuteAddStatement(collection.Add("{ \"x\":[1,2] }")); - - // Append values of different types, null and spaces. - ExecuteModifyStatement(collection.Modify("true").ArrayAppend("x", 43)); - ExecuteModifyStatement(collection.Modify("true").ArrayAppend("x", "string")); - ExecuteModifyStatement(collection.Modify("true").ArrayAppend("x", true)); - ExecuteModifyStatement(collection.Modify("true").ArrayAppend("x", null)); - ExecuteModifyStatement(collection.Modify("true").ArrayAppend("x", " ")); - var result = ExecuteFindStatement(collection.Find()); - DbDoc document = result.FetchOne(); - var x = (object[])document.values["x"]; - - Assert.AreEqual(7, x.Length); - Assert.AreEqual(1, (int)x[0]); - Assert.AreEqual(2, (int)x[1]); - Assert.AreEqual(43, (int)x[2]); - Assert.AreEqual("string", x[3]); - Assert.AreEqual(true, x[4]); - Assert.Null(x[5]); - Assert.AreEqual(" ", x[6]); - - // No value is appended if the array doesn't exist. - ExecuteModifyStatement(collection.Modify("true").ArrayAppend("y", 45)); - - result = ExecuteFindStatement(collection.Find()); - document = result.FetchOne(); - Assert.False(document.values.ContainsKey("y")); - - var ex = Assert.Throws(() => ExecuteModifyStatement(collection.Modify("true").ArrayAppend("x", ""))); - StringAssert.Contains("String can't be empty.", ex.Message); - ex = Assert.Throws(() => ExecuteModifyStatement(collection.Modify("true").ArrayAppend("x", string.Empty))); - StringAssert.Contains("String can't be empty.", ex.Message); - - var col = CreateCollection("my_collection"); - var t1 = "{\"_id\": \"1001\", \"ARR\":[1,2,3], \"ARR1\":[\"name1\",\"name2\", \"name3\"]}"; - col.Add(t1).Execute(); - col.Modify("true").ArrayAppend("ARR", 4).Execute(); - col.Modify("true").ArrayAppend("ARR1", "name4").Execute(); - col.Modify("true").ArrayAppend("ARR", "name5").Execute(); - col.Modify("true").ArrayAppend("ARR1", 5).Execute(); - col.Modify("true").ArrayAppend("ARR", 6).ArrayAppend("ARR1", "name6").ArrayAppend("ARR", 7).ArrayAppend("ARR", 8).Execute(); - - Assert.Throws(() => ExecuteModifyStatement(col.Modify("true").ArrayAppend("ARR1", ""))); - } - - [Test] - public void ArrayInsertWithMySqlExpression() - { - Collection collection = CreateCollection("test"); - ExecuteAddStatement(collection.Add("{ \"x\":[1,2] }")); - - // String containing an expression is not evaluted. - ExecuteAddStatement(collection.Add("{ \"_id\":\"123\", \"name\":\"alice\", \"email\":[ \"alice@ora.com\" ], \"dates\":\"4/1/2017\" }")); - ExecuteModifyStatement(collection.Modify("true").ArrayInsert("email[0]", "UPPER($.name)")); - var document = collection.GetOne("123"); - Assert.AreEqual("UPPER($.name)", (document["email"] as object[])[0]); - - // Use MySqlExpression. - ExecuteAddStatement(collection.Add("{ \"_id\":\"124\", \"name\":\"alice\", \"email\":[ \"alice@ora.com\" ], \"dates\":\"4/1/2017\" }")); - ExecuteModifyStatement(collection.Modify("_id = \"124\"").ArrayInsert("email[0]", new MySqlExpression("UPPER($.name)"))); - document = collection.GetOne("124"); - Assert.AreEqual("ALICE", (document["email"] as object[])[0]); - - // Use embedded MySqlExpression. - ExecuteAddStatement(collection.Add("{ \"_id\":\"125\", \"name\":\"alice\", \"email\":[ \"alice@ora.com\" ], \"dates\":\"4/1/2017\" }")); - ExecuteModifyStatement(collection.Modify("_id = \"125\"").ArrayInsert("email[0]", new { other = new MySqlExpression("UPPER($.name)") })); - document = collection.GetOne("125"); - var item = ((document["email"] as object[])[0] as Dictionary); - Assert.AreEqual("ALICE", item["other"]); - - ExecuteAddStatement(collection.Add("{ \"_id\":\"126\", \"name\":\"alice\", \"email\":[ \"alice@ora.com\" ], \"dates\":\"4/1/2017\" }")); - ExecuteModifyStatement(collection.Modify("_id = \"126\"").ArrayInsert("email[0]", new { other = new MySqlExpression("UPPER($.name)"), literal = "UPPER($.name)" })); - document = collection.GetOne("126"); - item = ((document["email"] as object[])[0] as Dictionary); - Assert.AreEqual("ALICE", item["other"]); - Assert.AreEqual("UPPER($.name)", item["literal"]); - } - - [Test] - public void ArrayOperationsKeepDateValue() - { - Collection collection = CreateCollection("test"); - Result r = ExecuteAddStatement(collection.Add("{ \"_id\": \"123\", \"email\":[\"alice@ora.com\"], \"dates\": \"5/1/2018\" }")); - Assert.AreEqual(1ul, r.AffectedItemsCount); - - // No items are affected since dates isn't an array. - r = ExecuteModifyStatement(collection.Modify("true").ArrayInsert("dates[0]", "4/1/2018")); - Assert.AreEqual(0ul, r.AffectedItemsCount); - - // Converts a non array to an array by appending a value. - ExecuteModifyStatement(collection.Modify("true").ArrayAppend("dates", "6/1/2018")); - - // Array insert at specified index is now succesful since dates is an array. - ExecuteModifyStatement(collection.Modify("true").ArrayInsert("dates[0]", "4/1/2018")); - - DbDoc document = collection.GetOne("123"); - object[] dates = document["dates"] as object[]; - Assert.AreEqual(3, dates.Length); - Assert.AreEqual("4/1/2018", dates[0]); - Assert.AreEqual("5/1/2018", dates[1]); - Assert.AreEqual("6/1/2018", dates[2]); - } - - [Test] - public void Alphanumeric() - { - Collection collection = CreateCollection("test"); - var document = new DbDoc(); - - for (int i = 0; i < 30; i++) - { - document.SetValue("_id", i); - document.SetValue("books", "test" + i); - document.SetValue("pages", i + 10); - document.SetValue("reviewers", "reviewers" + i); - document.SetValue("person", new - { - name = "Fred" + i, - age = i - }); - document.SetValue("1address", "street" + i); - ExecuteAddStatement(collection.Add(document)); - } - - var crudresult = collection.Find("pages=10").Execute().FetchAll(); - Assert.AreEqual(1, crudresult.Count, "Count should be 1 before Unset of pages for _id=0."); - var result = collection.Modify("_id = 0").Unset("pages").Execute(); - Assert.AreEqual(1, result.AffectedItemsCount, "Affected Items Count when modify unset is used"); - crudresult = collection.Find("pages=10").Execute().FetchAll(); - Assert.AreEqual(0, crudresult.Count, "Count should be 0 after Unset of pages for _id=0"); - crudresult = collection.Find("books='test0'").Execute().FetchAll(); - Assert.AreEqual(1, crudresult.Count, "Count should be 0 after Unset of pages for _id=0"); - - result = collection.Modify("_id = 21").Unset("1address").Execute(); - Assert.AreEqual(1, result.AffectedItemsCount, "Affected Items Count when modify unset(multiple docs) is used"); - } - - [Test] - public void UnsetVariations() - { - Collection collection = CreateCollection("test"); - var document = new DbDoc("{ \"_id\":1, \"pages\":1, \"pages2\":2, \"pages3\":3, \"pages4\":{ \"internalPages\":4 } }"); - ExecuteAddStatement(collection.Add(document)); - - // Whitespace is ignored. - ExecuteModifyStatement(collection.Modify("_id = 1").Unset("pages ")); - Assert.False(collection.GetOne(1).values.ContainsKey("pages")); - ExecuteModifyStatement(collection.Modify("_id = 1").Unset(" pages2 ")); - Assert.False(collection.GetOne(1).values.ContainsKey("pages2")); - ExecuteModifyStatement(collection.Modify("_id = 1").Unset(" pages3")); - Assert.False(collection.GetOne(1).values.ContainsKey("pages3")); - ExecuteModifyStatement(collection.Modify("_id = 1").Unset(" pages4.internalPages ")); - Assert.True(collection.GetOne(1).values.ContainsKey("pages4")); - Assert.False(collection.GetOne(1).values.ContainsKey("pages4.internalPages")); - - // Error is raised with incorrect document path. - var ex = Assert.Throws(() => ExecuteModifyStatement(collection.Modify("_id = 1").Unset("pages*"))); - Assert.AreEqual("Invalid document path.", ex.Message); - ex = Assert.Throws(() => ExecuteModifyStatement(collection.Modify("_id = 1").Unset("pages!"))); - Assert.AreEqual("Invalid document path.", ex.Message); - ex = Assert.Throws(() => ExecuteModifyStatement(collection.Modify("_id = 1").Unset("pages*data"))); - Assert.AreEqual("Invalid document path.", ex.Message); - } - - #region WL14389 - - [Test, Description("Collection.Modify(condition).Unset() to accept a list of elements instead of just one.")] - public void CollectionModifyUnset() - { - List idStringList = new List(); - var col = CreateCollection("my_collection"); - var d1 = new DbDoc(); - for (int i = 0; i < 30; i++) - { - d1.SetValue("_id", i); - d1.SetValue("books", "test" + i); - d1.SetValue("pages", i + 10); - d1.SetValue("reviewers", "reviewers" + i); - d1.SetValue("person", new { name = "Fred" + i, age = i }); - d1.SetValue("1address", "street" + i); - col.Add(d1).Execute(); - } - - var crudresult = col.Find("pages=10").Execute().FetchAll(); - Assert.AreEqual(1, crudresult.Count, "Count should be 1 before Unset of pages for _id=0."); - var result = col.Modify("_id = 0").Unset("pages").Execute(); - Assert.AreEqual(1, result.AffectedItemsCount, "Affected Items Count when modify unset is used"); - crudresult = col.Find("pages=10").Execute().FetchAll(); - Assert.AreEqual(0, crudresult.Count, "Count should be 0 after Unset of pages for _id=0"); - crudresult = col.Find("books='test0'").Execute().FetchAll(); - Assert.AreEqual(1, crudresult.Count, "Count should be 0 after Unset of pages for _id=0"); - - crudresult = col.Find("pages=11").Execute().FetchAll(); - Assert.AreEqual(1, crudresult.Count, "Count of pages=11 should be 1 before Unset of pages for _id=1."); - crudresult = col.Find("reviewers='reviewers1'").Execute().FetchAll(); - Assert.AreEqual(1, crudresult.Count, "Count of reviewers1 should be 1 before Unset of pages for _id=1."); - result = col.Modify("_id = 1").Unset("pages").Unset("reviewers").Execute(); - Assert.AreEqual(1, result.AffectedItemsCount, "Affected Items Count when modify multiple unset is used"); - crudresult = col.Find("pages=11").Execute().FetchAll(); - Assert.AreEqual(0, crudresult.Count, "Count should be 0 after Unset of pages for _id=1"); - crudresult = col.Find("reviewers='reviewers1'").Execute().FetchAll(); - Assert.AreEqual(0, crudresult.Count, "Count should be 0 after Unset of pages for _id=1"); - - crudresult = col.Find("pages=21").Execute().FetchAll(); - Assert.AreEqual(1, crudresult.Count, "Count of pages=21 should be 1 before Unset of pages for _id=11."); - crudresult = col.Find("reviewers='reviewers11'").Execute().FetchAll(); - Assert.AreEqual(1, crudresult.Count, "Count of reviewers11 should be 1 before Unset of pages for _id=11."); - result = col.Modify("_id = 11").Unset(new string[] { "pages", "reviewers" }).Execute(); - Assert.AreEqual(1, result.AffectedItemsCount, "Affected Items Count when modify unset(multiple docs) is used"); - crudresult = col.Find("pages=21").Execute().FetchAll(); - Assert.AreEqual(0, crudresult.Count, "Count should be 0 after Unset of pages for _id=11"); - crudresult = col.Find("reviewers='reviewers11'").Execute().FetchAll(); - Assert.AreEqual(0, crudresult.Count, "Count should be 0 after Unset of pages for _id=11"); - - crudresult = col.Find("pages=31").Execute().FetchAll(); - Assert.AreEqual(1, crudresult.Count, "Count of pages=31 should be 1 before Unset of pages for _id=21."); - crudresult = col.Find("reviewers='reviewers21'").Execute().FetchAll(); - Assert.AreEqual(1, crudresult.Count, "Count of reviewers21 should be 1 before Unset of pages for _id=21."); - - result = col.Modify("_id = 21").Unset(" pages ").Execute(); - Assert.AreEqual(1, result.AffectedItemsCount, "Affected Items Count when modify unset(multiple docs) is used"); - //Should have failed when unset is used for fields with special characters - Assert.Throws(() => ExecuteModifyStatement(col.Modify("_id = 22").Unset("pages*"))); - //Should have failed when unset is used for non-existent fields - Assert.Throws(() => ExecuteModifyStatement(col.Modify("_id = 21").Unset("1"))); - //Should have failed when unset is used for special characters - Assert.Throws(() => ExecuteModifyStatement(col.Modify("_id = 21").Unset("@*%#^)(-+!~<>?/"))); - //Should have failed when unset is used for special characters - Assert.Throws(() => ExecuteModifyStatement(col.Modify("_id = 21").Unset("*******"))); - - crudresult = col.Find("pages=31").Execute().FetchAll(); - Assert.AreEqual(0, crudresult.Count, "Count should be 0 after Unset of pages for _id=21"); - - result = col.Modify("_id = 12").Unset(new string[] { " pages1", "reviewers1" }).Execute(); - Assert.AreEqual(0, result.AffectedItemsCount, "Affected Items Count when modify unset(invalid docs) is used"); - crudresult = col.Find("pages=22").Execute().FetchAll(); - Assert.AreEqual(1, crudresult.Count, "Count should be 1 after Unset with invalid of pages for _id=12"); - crudresult = col.Find("reviewers='reviewers12'").Execute().FetchAll(); - Assert.AreEqual(1, crudresult.Count, "Count should be 1 after Unset with invalid of pages for _id=12"); - //Testcase should have failed when unset is used with null - Assert.Throws(() => ExecuteModifyStatement(col.Modify("_id = 12").Unset(null))); - - crudresult = col.Find("pages=22").Execute().FetchAll(); - Assert.AreEqual(1, crudresult.Count, "Count should be 1 after Unset with null of pages for _id=12"); - crudresult = col.Find("reviewers='reviewers12'").Execute().FetchAll(); - Assert.AreEqual(1, crudresult.Count, "Count should be 1 after Unset with null of pages for _id=12"); - - Assert.Throws(() => ExecuteModifyStatement(col.Modify("_id = 12").Unset(""))); - - crudresult = col.Find("pages=22").Execute().FetchAll(); - Assert.AreEqual(1, crudresult.Count, "Count should be 1 after Unset with blank of pages for _id=12"); - crudresult = col.Find("reviewers='reviewers12'").Execute().FetchAll(); - Assert.AreEqual(1, crudresult.Count, "Count should be 1 after Unset with blank of pages for _id=12"); - - crudresult = col.Find("pages=22").Execute().FetchAll(); - Assert.AreEqual(1, crudresult.Count, "Count should be 1 after Unset with blank with space of pages for _id=12"); - crudresult = col.Find("reviewers='reviewers12'").Execute().FetchAll(); - Assert.AreEqual(1, crudresult.Count, "Count should be 1 after Unset with blank with space of pages for _id=12"); - - //Testcase should have failed when unset is used with blank and space - Assert.Throws(() => ExecuteModifyStatement(col.Modify("_id = 12").Unset(new string[] { "", " ", "pages" }))); - - crudresult = col.Find("pages=22").Execute().FetchAll(); - Assert.AreEqual(1, crudresult.Count); - crudresult = col.Find("reviewers='reviewers12'").Execute().FetchAll(); - Assert.AreEqual(1, crudresult.Count); - } - - [Test, Description("All Bug Fixes")] - public void ValidateValuesAfterAppendAndInserts() - { - DbDoc document = null; - Collection collection = CreateCollection("test"); - Result r = collection.Add("{ \"_id\": \"123\", \"email\": [\"alice@ora.com\"], " + - "\"dates\": \"4/1/2017\" }").Execute(); - Assert.AreEqual(1, r.AffectedItemsCount); - - collection.Modify("true").ArrayAppend("dates", "5/1/2018").Execute(); - document = collection.GetOne("123"); - object[] dates = document["dates"] as object[]; - Assert.AreEqual(2, dates.Length); - Assert.AreEqual("4/1/2017", dates[0], "Existing Date"); - Assert.AreEqual("5/1/2018", dates[1], "Appended Date"); - collection.Modify("true").ArrayInsert("dates[0]", "5/1/2059").Execute(); - document = collection.GetOne("123"); - dates = document["dates"] as object[]; - Assert.AreEqual("5/1/2059", dates[0], "Inserted Date"); - - collection = CreateCollection("test"); - r = collection.Add("{ \"_id\": \"123\", \"email\": [\"alice@ora.com\"], " + - "\"dates\": [\"4/1/2017\"] }").Execute(); - Assert.AreEqual(1, r.AffectedItemsCount); - - collection = CreateCollection("test"); - r = collection.Add("{ \"_id\": \"123\", \"email\": [\"alice@ora.com\"], " + - "\"dates\": \"4/1/2017\" }").Execute(); - Assert.AreEqual(1, r.AffectedItemsCount); - collection.Modify("true").ArrayAppend("dates", "1").Execute(); - collection.Modify("true").ArrayAppend("dates", 1).Execute(); - collection.Modify("true").ArrayAppend("dates", "3.1").Execute(); - collection.Modify("true").ArrayAppend("dates", 3.1).Execute(); - document = collection.GetOne("123"); - dates = document["dates"] as object[]; - Assert.AreEqual(5, dates.Length); - Assert.AreEqual("4/1/2017", dates[0], "Existing Date"); - Assert.AreEqual("1", dates[1], "Appended Date"); - Assert.AreEqual(1, dates[2], "Appended Date"); - Assert.AreEqual("3.1", dates[3], "Appended Date"); - Assert.AreEqual(3.1, dates[4], "Appended Date"); - - collection.Modify("true").ArrayInsert("dates[0]", "10").Execute(); - collection.Modify("true").ArrayInsert("dates[0]", 1000).Execute(); - collection.Modify("true").ArrayInsert("dates[0]", "3.1").Execute(); - collection.Modify("true").ArrayInsert("dates[0]", 22.7).Execute(); - document = collection.GetOne("123"); - dates = document["dates"] as object[]; - Assert.AreEqual("10", dates[3], "Inserted Date"); - Assert.AreEqual(1000, dates[2], "Inserted Date"); - Assert.AreEqual("3.1", dates[1], "Inserted Date"); - Assert.AreEqual(22.7, dates[0], "Inserted Date"); - - var d1 = new DbDoc(); - for (int i = 0; i < 30; i++) - { - d1.SetValue("_id", i); - d1.SetValue("books", "test" + i); - d1.SetValue("pages", i + 10); - d1.SetValue("reviewers", "reviewers" + i); - d1.SetValue("person", new - { - name = "Fred" + i, - age = i - }); - d1.SetValue("1address", "street" + i); - collection.Add(d1).Execute(); - } - Assert.Throws(() => ExecuteModifyStatement(collection.Modify("_id = 21").Unset("pages*"))); - - var docs = new[] - { - new { _id = 100, title = "Book 1", pages = 20 }, - new { _id = 200, title = "Book 2", pages = 30 }, - new { _id = 300, title = "Book 3", pages = 40 }, - new { _id = 400, title = "Book 4", pages = 50 }, - }; - r = collection.Add(docs).Execute(); - Assert.AreEqual(4, r.AffectedItemsCount, "Matching the records affected"); - var test1 = collection.Find("pages = :Pages").Bind("pAges", 90).Fields("{\"_id\":100,\"pages\": 20 }").Execute(); - Assert.IsNotNull(test1); - } - - [Test, Description("Collection.modify(condition).arrayAppend(CollectionField, ExprOrLiteral)")] - public void CollectionModifyArrayAppend() - { - - string currentYear = DateTime.Now.Year.ToString(); - DbDoc document = null; - string t1 = "{\"_id\": \"1\", \"name\": \"Alice\" }"; - var collection = CreateCollection("test"); - Result r = collection.Add(t1).Execute(); - Assert.AreEqual(1, r.AffectedItemsCount); - object[] expressions1 = new object[] { "YEAR('2000-01-01')", "MONTH('2008-02-03')", "WEEK('2008-02-20')", "DAY('2008-02-20')", "HOUR('10:05:03')", - "MINUTE('2008-02-03 10:05:03')","SECOND('10:05:03')","MICROSECOND('12:00:00.123456')","QUARTER('2008-04-01')","TIME('2003-12-31 01:02:03')","DATE('2003-12-31 01:02:03')", - "Year(CURDATE())"}; - - object[] expressions2 = new object[] { "5/1/2018",2012,"2012",-22.7,22.7,"22.7", "'large'", - "'838:59:59'" ,true,-100000000,"-10000000000","6/6/2018","9999-12-31 23:59:59","0000-00-00 00:00:00","[a,b,c]","[]"}; - object[] compare_expressions1 = new object[] { 2000, 2, 7, 20, 10, 5, 3, 123456, 2, "01:02:03.000000", "2003-12-31", currentYear }; - object[] compare_expressions2 = new object[] { "5/1/2018",2012, "2012", -22.7, 22.7, "22.7", - "'large'", "'838:59:59'", true, -100000000, "-10000000000","6/6/2018" ,"9999-12-31 23:59:59","0000-00-00 00:00:00","[a,b,c]","[]"}; - for (int k = 0; k < expressions1.Length; k++) - { - collection.Modify("true").ArrayAppend("name", "{ \"dateAndTimeValue\": " + expressions1[k] + " }").Execute(); - } - for (int k = 0; k < expressions2.Length; k++) - { - collection.Modify("true").ArrayAppend("name", "{ \"dateAndTimeValue\": \"" + expressions2[k] + "\" }").Execute(); - } - object[] actors = null; - object test = null; - Dictionary actor0 = null; - int l = 1; - for (int k = 0; k < compare_expressions1.Length; k++) - { - - document = collection.GetOne("1"); - actors = document["name"] as object[]; - actor0 = actors[l] as Dictionary; - test = actor0["dateAndTimeValue"]; - Assert.AreEqual(compare_expressions1[k].ToString(), test.ToString()); - l++; - } - for (int k = 0; k < compare_expressions2.Length; k++) - { - - document = collection.GetOne("1"); - actors = document["name"] as object[]; - actor0 = actors[l] as Dictionary; - test = actor0["dateAndTimeValue"]; - Assert.AreEqual(compare_expressions2[k].ToString(), test.ToString()); - l++; - } - - collection = CreateCollection("test"); - r = collection.Add("{ \"_id\": \"123\", \"email\": [\"alice@ora.com\"], " + - "\"dates\": [\"4/1/2017\"] }").Execute(); - Assert.AreEqual(1, r.AffectedItemsCount); - var reg_expression = new - { - test1 = new MySqlExpression("UPPER($.email)"), - test2 = new MySqlExpression("LOWER($.email)"), - test3 = new MySqlExpression("CONCAT('No', 'S', 'QL')"), - test4 = new MySqlExpression("CHAR(77, 121, 83, 81, '76')"), - test5 = new MySqlExpression("CONCAT('My', NULL, 'QL')"), - test6 = new MySqlExpression("ELT(4, 'ej', 'Heja', 'hej', 'foo')"), - test7 = new MySqlExpression("REPEAT('MySQL', 3)"), - test8 = new MySqlExpression("REVERSE('abc')"), - test9 = new MySqlExpression("RIGHT('foobarbar', 4)"), - test10 = new MySqlExpression("REPLACE('www.mysql.com', 'w', 'Ww')"), - test11 = new MySqlExpression(" HEX('abc')"), - test12 = new MySqlExpression(" BIN(12)"), - }; - object[] compare_expressions = null; - if (session.Version.isAtLeast(8, 0, 0)) - { - compare_expressions = new object[] { "[\\\"ALICE@ORA.COM\\\"]", "[\\\"alice@ora.com\\\", \\\"[\\\\\\\"alice@ora.com\\\\\\\"]\\\"]", - "NoSQL","base64:type253:TXlTUUw=",null,"foo","MySQLMySQLMySQL","cba","rbar","WwWwWw.mysql.com","616263","1100" }; - } - else - { - compare_expressions = new object[] { "[\\\"ALICE@ORA.COM\\\"]", "[\\\"alice@ora.com\\\", \\\"[\\\\\\\"alice@ora.com\\\\\\\"]\\\"]", - "NoSQL","base64:type15:TXlTUUw=",null,"foo","MySQLMySQLMySQL","cba","rbar","WwWwWw.mysql.com","616263","1100" }; - } - - var items = new List(); - items.Add(reg_expression.test1); - items.Add(reg_expression.test2); - items.Add(reg_expression.test3); - items.Add(reg_expression.test4); - items.Add(reg_expression.test5); - items.Add(reg_expression.test6); - items.Add(reg_expression.test7); - items.Add(reg_expression.test8); - items.Add(reg_expression.test9); - items.Add(reg_expression.test10); - items.Add(reg_expression.test11); - items.Add(reg_expression.test12); - int m = 1, n = 0; - foreach (var obj in items) - { - collection.Modify("true").ArrayAppend("email", obj).Execute(); - document = collection.GetOne("123"); - actors = document["email"] as object[]; - if (n == 3) - { } - else - { - Assert.AreEqual(actors[m], compare_expressions[n]); - } - - m++; n++; - } - - string json = ""; - int i = 0, j = 0, maxField = 40; - collection = CreateCollection("test"); - int maxDepth = 2; - json = "{\"_id\":\"1002\",\"XYZ\":1111"; - for (j = 0; j < maxField; j++) - { - json = json + ",\"ARR" + j + "\":["; - for (i = 0; i < maxDepth; i++) - { - json = json + i + ",["; - } - json = json + i; - for (i = maxDepth - 1; i >= 0; i--) - { - json = json + "]," + i; - } - json = json + "]"; - } - json = json + "}"; - - collection.Add(json).Execute(); - r = collection.Modify("true").ArrayAppend("ARR10", 1).ArrayAppend("ARR20", 2).ArrayAppend("ARR30", 3).Execute(); - Assert.AreEqual(1, r.AffectedItemsCount); - r = collection.Modify("true").ArrayAppend("ARR0", null).Execute(); - Assert.AreEqual(1, r.AffectedItemsCount); - r = collection.Modify("true").ArrayAppend("ARR39", null).Execute(); - Assert.AreEqual(1, r.AffectedItemsCount); - - } - - [Test, Description("MySQLX CNET Forbid modify() with no condition-Scenario-1")] - public void ForbidModifyWithNoCondition_S1() - { - - Collection collection = CreateCollection("test"); - var docs = new[] - { - new { _id = 1, title = "Book 1", pages = 20 }, - new { _id = 2, title = "Book 2", pages = 30 }, - new { _id = 3, title = "Book 3", pages = 40 }, - new { _id = 4, title = "Book 4", pages = 50 }, - }; - Result result = collection.Add(docs).Execute(); - Assert.AreEqual(4, result.AffectedItemsCount); - - // Condition can't be null or empty. - Assert.Throws(() => ExecuteModifyStatement(collection.Modify(string.Empty))); - Assert.Throws(() => ExecuteRemoveStatement(collection.Remove(""))); - Assert.Throws(() => ExecuteModifyStatement(collection.Modify(null))); - - // Sending an expression that evaluates to true applies changes on all documents. - result = collection.Modify("true").Set("pages", "10").Execute(); - Assert.AreEqual(4, result.AffectedItemsCount); - - } - - [Test, Description("MySQLX CNET Forbid modify() with no condition-Scenario-2")] - public void ForbidModifyWithNoCondition_S2() - { - - Collection collection = CreateCollection("test"); - var docs = new[] - { - new { _id = 1, title = "Book 1", pages = 20 }, - new { _id = 2, title = "Book 2", pages = 30 }, - new { _id = 3, title = "Book 3", pages = 40 }, - new { _id = 4, title = "Book 4", pages = 50 }, - }; - Result result = collection.Add(docs).Execute(); - Assert.AreEqual(4, result.AffectedItemsCount); - - // Sending an expression that evaluates to true applies changes on all documents. - //Deprecated Modify().Where() in 8.0.17 - result = collection.Modify("true").Where("false").Set("pages", "10").Execute(); - Assert.AreEqual(0, result.AffectedItemsCount); - - result = collection.Modify("true").Where("true").Set("pages", "10").Execute(); - Assert.AreEqual(4, result.AffectedItemsCount); - result = collection.Modify("false").Where("true").Set("pages", "40").Execute(); - Assert.AreEqual(4, result.AffectedItemsCount); - result = collection.Modify("false").Where("false").Set("pages", "40").Execute(); - Assert.AreEqual(0, result.AffectedItemsCount); - - // Condition can't be null or empty. - Assert.Throws(() => ExecuteModifyStatement(collection.Modify(" "))); - } - - [Test, Description("Test valid modify.patch to change element at Depth n for multiple arrays#Bug))")] - public void ModifyPatchNDepth() - { - if (!session.Version.isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher."); - string json = ""; - int i = 0, j = 0, maxField = 100; - var collection = CreateCollection("test"); - int maxDepth = 46; - json = "{\"_id\":\"1002\",\"XYZ\":1111"; - for (j = 0; j < maxField; j++) - { - json = json + ",\"ARR" + j + "\":["; - for (i = 0; i < maxDepth; i++) - { - json = json + i + ",["; - } - json = json + i; - for (i = maxDepth - 1; i >= 0; i--) - { - json = json + "]," + i; - } - json = json + "]"; - } - json = json + "}"; - - var r = collection.Modify("age = :age").Patch(json). - Bind("age", "18").Execute(); - Assert.IsNotNull(r); - } - - [Test, Description("Test valid modify.patch with condition/limit/OrderBy")] - public void ModifyPatch() - { - if (!session.Version.isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher."); - var collection = CreateCollection("test"); - var docs = new[] - { - new {_id = 1, title = "Book 1", pages = 20, age = 12}, - new {_id = 2, title = "Book 2", pages = 30,age = 18}, - new {_id = 3, title = "Book 3", pages = 40,age = 34}, - new {_id = 4, title = "Book 4", pages = 50,age = 15} - }; - var r = collection.Add(docs).Execute(); - Assert.AreEqual(4, (int)r.AffectedItemsCount, "Matching the updated record count"); - - var jsonParams = new { title = "Book 100" }; - var foundDocs = collection.Modify("age==18").Patch(jsonParams).Execute(); - Assert.AreEqual(1, (int)foundDocs.AffectedItemsCount, "Matching the record count"); - - var document = collection.GetOne("2"); - Assert.AreEqual("Book 100", document["title"]); - - jsonParams = new { title = "Book 300" }; - r = collection.Modify("age<18").Patch(jsonParams).Limit(1).Execute(); - Assert.AreEqual(1, (int)r.AffectedItemsCount, "Matching the record count"); - - document = collection.GetOne(1); - Assert.AreEqual("Book 300", document["title"]); - - var jsonParams1 = new { title = "Book 10", pages = 1000 }; - r = collection.Modify("age>30").Patch(jsonParams1).Sort("age ASC").Execute(); - Assert.AreEqual(1, (int)r.AffectedItemsCount, "Matching the record count"); - } - - [Test, Description("Test valid modify.patch with set/unset")] - public void ModifyPatchWithSetUnset() - { - if (!session.Version.isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher."); - var collection = CreateCollection("test"); - var docs = new[] - { - new {_id = 1, title = "Book 1", pages = 20, age = "12"}, - new {_id = 2, title = "Book 2", pages = 30,age = "18"}, - new {_id = 3, title = "Book 3", pages = 40,age = "34"}, - new {_id = 4, title = "Book 4", pages = 50,age = "12"} - }; - Result r = collection.Add(docs).Execute(); - Assert.AreEqual(4, r.AffectedItemsCount); - - var jsonParams = new { title = "Book 500" }; - r = collection.Modify("age = :age").Patch(jsonParams).Bind("age", "18"). - Set("pages", "5000").Execute(); - Assert.AreEqual(1, r.AffectedItemsCount); - - var document = collection.GetOne("2"); - Assert.AreEqual("5000", document["pages"].ToString()); - Assert.AreEqual("Book 500", document["title"].ToString()); - - var jsonParams1 = new { title = "Book 50000", pages = 5000 }; - r = collection.Modify("age = :age").Patch(jsonParams1).Bind("age", "18"). - Unset("pages").Execute(); - Assert.AreEqual(1, r.AffectedItemsCount, "Match being done"); - document = collection.GetOne("2"); - DbDoc test = null; - Assert.Throws(() => test = (DbDoc)document["pages"]); - Assert.AreEqual("Book 50000", document["title"]); - } - - [Test, Description("Test invalid modify.patch to attempt to change _id using modify.patch")] - public void ModifyPatchChangeId() - { - if (!session.Version.isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher."); - var collection = CreateCollection("test"); - var docs = new[] - { - new {_id = 1, title = "Book 1", pages = 20, age = 12}, - new {_id = 2, title = "Book 2", pages = 30,age = 18}, - new {_id = 3, title = "Book 3", pages = 40,age = 34}, - new {_id = 4, title = "Book 4", pages = 50,age = 12} - }; - Result r = collection.Add(docs).Execute(); - Assert.AreEqual(4, r.AffectedItemsCount); - var document = collection.GetOne("1"); - var jsonParams = new { _id = 123 }; - - r = collection.Modify("age = :age").Patch(jsonParams). - Bind("age", 18).Execute(); - Assert.AreEqual(0, r.AffectedItemsCount); - - var jsonParams2 = new { _id = 123, title = "Book 4000" }; - - r = collection.Modify("age = :age").Patch(jsonParams2). - Bind("age", 18).Execute(); - Assert.AreEqual(1, r.AffectedItemsCount); - - string jsonParams1 = "{ \"_id\": \"123\"}"; - r = collection.Modify("age = :age").Patch(jsonParams1). - Bind("age", 18).Execute(); - Assert.AreEqual(0, r.AffectedItemsCount); - - jsonParams1 = "{ \"_id\": \"123\",\"title\": \"Book 400\"}"; - r = collection.Modify("age = :age").Patch(jsonParams1). - Bind("age", 18).Execute(); - Assert.AreEqual(1, r.AffectedItemsCount); - } - - [Test, Description("Test modify.patch where the key to be modified has array, dbDoc and normal constant value and condition is matched for all.")] - public void ModifyPatchKeyWithArray() - { - if (!session.Version.isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher."); - var collection = CreateCollection("test"); - var docs1 = new[] - { - new {_id = 1, title = "Book 1", pages = 20, age = 12,name = "Morgan"}, - }; - var docs2 = - "{\"_id\": \"2\",\"age\": 12,\"name\": \"Alice\", " + - "\"address\": {\"zip\": \"12345\", \"city\": \"Los Angeles\", \"street\": \"32 Main str\"}}"; - - var docs3 = "{\"_id\": \"3\", \"age\": 12,\"name\":[\"Cynthia\"], \"ARR1\":[\"name1\",\"name2\", \"name3\"]}"; - Result r = collection.Add(docs1).Execute(); - Assert.AreEqual(1, r.AffectedItemsCount); - r = collection.Add(docs2).Execute(); - Assert.AreEqual(1, r.AffectedItemsCount); - r = collection.Add(docs3).Execute(); - Assert.AreEqual(1, r.AffectedItemsCount); - var jsonParams = new { name = "Changed" }; - r = collection.Modify("age = :age").Patch(jsonParams).Bind("age", 12).Execute(); - Assert.AreEqual(3, r.AffectedItemsCount); - } - - [Test, Description("Test that documents not matching conditions are not modified.")] - public void ModifyPatchNotMatchingConditions() - { - if (!session.Version.isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher."); - var collection = CreateCollection("test"); - var docs = new[] - { - new {_id = 1, title = "Book 1", pages = 20, age = 12}, - new {_id = 2, title = "Book 2", pages = 30,age = 18}, - new {_id = 3, title = "Book 3", pages = 40,age = 34}, - new {_id = 4, title = "Book 4", pages = 50,age = 12} - }; - Result r = collection.Add(docs).Execute(); - Assert.AreEqual(4, r.AffectedItemsCount); - var document = collection.GetOne("1"); - var jsonParams = new { title = "Book 100" }; - r = collection.Modify("age = :age").Patch(jsonParams).Bind("age", "19").Execute(); - Assert.AreEqual(0, r.AffectedItemsCount); - string jsonParams1 = "{ \"title\": \"Book 100\"}"; - r = collection.Modify("age = :age").Patch(jsonParams1).Bind("age", "28").Execute(); - Assert.AreEqual(0, r.AffectedItemsCount); - jsonParams1 = "{ \"unknownvalues\": null}"; - r = collection.Modify("age = :age").Patch(jsonParams1).Bind("age", "28").Execute(); - Assert.AreEqual(0, r.AffectedItemsCount); - } - - [Test, Description("Test modify.patch with different types of records(anonymous object,Json String,DbDoc) with same key and try to replace using a patch")] - public void ModifyPatchDifferentTypesSameKey() - { - if (!session.Version.isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher."); - var collection = CreateCollection("test"); - var docs1 = new[] - { - new {_id = 1, title = "Book 1", pages = 20, age = 12,name = "Morgan"}, - }; - var docs2 = - "{\"_id\": \"2\",\"age\": \"12\",\"name\": \"Alice\", " + - "\"address\": {\"zip\": \"12345\", \"city\": \"Los Angeles\", \"street\": \"32 Main str\"}}"; - - var docs3 = new DbDoc(@"{ ""_id"": 3, ""pages"": 20, ""age"":12,""name"":""Cynthiaa"", - ""books"": [ - {""_id"" : 10, ""title"" : ""Book 10""}, - { ""_id"" : 20, ""title"" : ""Book 20"" } - ] - }"); - Result r = collection.Add(docs1).Execute(); - Assert.AreEqual(1, r.AffectedItemsCount); - r = collection.Add(docs2).Execute(); - Assert.AreEqual(1, r.AffectedItemsCount); - r = collection.Add(docs3).Execute(); - Assert.AreEqual(1, r.AffectedItemsCount); - var jsonParams = new { name = "Changed" }; - r = collection.Modify("age = :age").Patch(jsonParams). - Bind("age", 12).Execute(); - Assert.AreEqual(2, r.AffectedItemsCount);//docs2 age is the string - } - - [Test, Description("GetOne with ExistingID and NewID with doc(Verify the Immutable feature also))")] - public void GetOneAndRemoveOne() - { - if (!session.Version.isAtLeast(5, 7, 0)) Assert.Ignore("This test is for MySql 5.7 or higher."); - var coll = CreateCollection("test"); - var docs = new[] - { - new {_id = 1, title = "Book 1", pages = 20}, - new {_id = 2, title = "Book 2", pages = 30}, - new {_id = 3, title = "Book 3", pages = 40}, - new {_id = 4, title = "Book 4", pages = 50} - }; - var r = coll.Add(docs).Execute(); - Assert.AreEqual(4, r.AffectedItemsCount); - - // Expected exceptions. - Assert.Throws(() => coll.GetOne(null)); - Assert.Throws(() => coll.GetOne("")); - Assert.Throws(() => coll.GetOne(string.Empty)); - Assert.Throws(() => coll.GetOne(" ")); - - // Get document using numeric parameter. - var document = coll.GetOne(1); - Assert.AreEqual(1, document.Id); - Assert.AreEqual("Book 1", document["title"]); - Assert.AreEqual(20, Convert.ToInt32(document["pages"])); - - // Get document using string parameter. - document = coll.GetOne("3"); - Assert.AreEqual(3, document.Id); - Assert.AreEqual("Book 3", document["title"]); - Assert.AreEqual(40, Convert.ToInt32(document["pages"])); - - // Get a non-existing document. - document = coll.GetOne(5); - Assert.AreEqual(null, document); - - coll.Add(new { _id = 5, title = "Book 5", pages = 60 }).Execute(); - Assert.AreEqual(5, coll.Find().Execute().FetchAll().Count); - // Remove sending numeric parameter. - //WL11843-Core API v1 alignment Changes - Assert.AreEqual(1, coll.RemoveOne(1).AffectedItemsCount); - Assert.AreEqual(4, coll.Find().Execute().FetchAll().Count); - - // Remove sending string parameter. - Assert.AreEqual(1, coll.RemoveOne("3").AffectedItemsCount); - Assert.AreEqual(3, coll.Find().Execute().FetchAll().Count); - - // Remove an auto-generated id. - document = coll.Find("pages = 60").Execute().FetchOne(); - Assert.AreEqual(1, coll.RemoveOne(document.Id).AffectedItemsCount); - Assert.AreEqual(2, coll.Find().Execute().FetchAll().Count); - - // Remove a non-existing document. - Assert.AreEqual(0, coll.RemoveOne(5).AffectedItemsCount); - Assert.AreEqual(2, coll.Find().Execute().FetchAll().Count); - - } - - [Test, Description("AddReplaceOne with unique id generated by SQL")] - public void AddReplaceOneUniqueId() - { - if (!session.Version.isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher."); - var collection = CreateCollection("test"); - var docs = new[] - { - new {_id = 1, name = "foo"}, - new {_id = 2, name = "bar"} - }; - var result = collection.Add(docs).Execute(); - Assert.AreEqual(2, result.AffectedItemsCount); - - // Add unique index. - session.SQL( - "ALTER TABLE test.test ADD COLUMN name VARCHAR(3) GENERATED ALWAYS AS (JSON_UNQUOTE(JSON_EXTRACT(doc, '$.name'))) VIRTUAL UNIQUE KEY NOT NULL") - .Execute(); - Assert.Throws(() => collection.AddOrReplaceOne(1, new { name = "bar" })); - Assert.Throws(() => collection.AddOrReplaceOne(1, new { _id = 3, name = "bar", age = "55" })); - } - - #endregion WL14389 - - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data; +using MySql.Data.MySqlClient; +using MySqlX.XDevAPI; +using MySqlX.XDevAPI.Common; +using NUnit.Framework; +using NUnit.Framework.Legacy; +using System; +using System.Collections.Generic; + +namespace MySqlX.Data.Tests +{ + public class CrudUpdateTests : BaseTest + { + [Test] + public void SetItemInSingleDocument() + { + Collection coll = CreateCollection("test"); + Result result = ExecuteAddStatement(coll.Add(new { _id = 1, name = "Book 1" })); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1)); + + // Set integer value. + result = ExecuteModifyStatement(coll.Modify("_id = 1").Set("pages", "20")); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1)); + Assert.That(coll.GetOne(1)["pages"], Is.EqualTo("20")); + + // Set null value. + result = ExecuteModifyStatement(coll.Modify("_id = 1").Set("pages", null)); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1)); + Assert.That(coll.GetOne(1)["pages"], Is.Null); + + // Set existing field. + result = ExecuteModifyStatement(coll.Modify("_id = 1").Set("name", "Book 2")); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1)); + Assert.That(coll.GetOne(1)["name"], Is.EqualTo("Book 2")); + + // Set alphanumeric field. + var document = new DbDoc(); + document.SetValue("_id", 2); + document.SetValue("1a", "other"); + result = ExecuteAddStatement(coll.Add(document)); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1)); + var insertedDocument = coll.GetOne(2); + + //result = coll.Modify("_id = 1").Set("1a", "other")); + } + + [Test] + public void ChangeItemInSingleDocument() + { + Collection coll = CreateCollection("test"); + Result result = ExecuteAddStatement(coll.Add(new { _id = 1, name = "Book 1", pages = 20 })); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1)); + + result = ExecuteModifyStatement(coll.Modify("_id = 1").Change("name", "Book 2")); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1)); + } + + [Test] + public void RemoveItemInSingleDocumentUsingUnset() + { + Collection coll = CreateCollection("test"); + Result result = ExecuteAddStatement(coll + .Add(new { _id = 1, name = "Book 1", pages = 20 }) + .Add(new { _id = 2, name = "Book 2", pages = 30 }) + .Add(new { _id = 3, name = "Book 3", pages = 40, author = "John", author2 = "Mary" }) + ); + Assert.That(result.AffectedItemsCount, Is.EqualTo(3)); + + // Unset 1 field. + result = ExecuteModifyStatement(coll.Modify("_id = 1").Unset("pages")); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1)); + var document = ExecuteFindStatement(coll.Find("_id = 1")).FetchOne(); + Assert.That(document.values.Count, Is.EqualTo(2)); + + // Unset multiple fields. + result = ExecuteModifyStatement(coll.Modify("_id = 2").Unset("name", "pages")); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1)); + document = ExecuteFindStatement(coll.Find("_id = 2")).FetchOne(); + Assert.That(document.values, Has.One.Items); + result = ExecuteModifyStatement(coll.Modify("_id = 3").Unset(null, "author", "author2")); + document = ExecuteFindStatement(coll.Find("_id = 3")).FetchOne(); + Assert.That(document.values.Count, Is.EqualTo(3)); + + // Unsetting nonexistent fields doesn't raise an error. + result = ExecuteModifyStatement(coll.Modify("_id = 2").Unset("otherfield")); + Assert.That(result.AffectedItemsCount, Is.EqualTo(0ul)); + + // Unsetting null items combined with valid values are ignored. + result = ExecuteModifyStatement(coll.Modify("_id = 3").Unset(null).Unset("name")); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1ul)); + document = ExecuteFindStatement(coll.Find("_id = 3")).FetchOne(); + Assert.That(document.values.Count, Is.EqualTo(2)); + + // Unsetting single null items raises an error + var ex = Assert.Throws(() => ExecuteModifyStatement(coll.Modify("_id = 3").Unset(null))); + Assert.That(ex.Message, Is.EqualTo("Invalid update expression list")); + + // Unsetting empty strings raises an error. + var ex2 = Assert.Throws(() => ExecuteModifyStatement(coll.Modify("_id = 2").Unset(""))); + Assert.That(ex2.Message, Is.EqualTo(ResourcesX.DocPathNullOrEmpty)); + ex2 = Assert.Throws(() => ExecuteModifyStatement(coll.Modify("_id = 2").Unset(string.Empty))); + Assert.That(ex2.Message, Is.EqualTo(ResourcesX.DocPathNullOrEmpty)); + + // Unset with special chars. + Assert.Throws(() => ExecuteModifyStatement(coll.Modify("_id = 3").Unset(null).Unset("@*%#�"))); + Assert.Throws(() => ExecuteModifyStatement(coll.Modify("_id = 3").Unset(null).Unset("******"))); + } + + [Test] + public void SetItemAndBind() + { + Collection coll = CreateCollection("test"); + Result result = ExecuteAddStatement(coll.Add(new { _id = 1, name = "Book 1" }) + .Add(new { _id = 2, name = "Book 2" })); + Assert.That(result.AffectedItemsCount, Is.EqualTo(2)); + + var stmt = coll.Modify("_id = :ID"); + result = ExecuteModifyStatement(stmt.Bind("Id", 2).Set("pages", "20")); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1)); + result = ExecuteModifyStatement(stmt.Bind("Id", 1).Set("pages", 10)); Assert.That(result.AffectedItemsCount, Is.EqualTo(1)); + + var docs = ExecuteFindStatement(coll.Find()).FetchAll(); + Assert.That(docs[0].ToString(), Is.EqualTo(new DbDoc("{ \"_id\": 1, \"name\": \"Book 1\", \"pages\": 10 }").ToString())); + Assert.That(docs[1].ToString(), Is.EqualTo(new DbDoc("{ \"_id\": 2, \"name\": \"Book 2\", \"pages\": \"20\" }").ToString())); + } + + [Test] + public void ModifyAll() + { + Collection collection = CreateCollection("test"); + var docs = new[] + { + new { _id = 1, title = "Book 1", pages = 20 }, + new { _id = 2, title = "Book 2", pages = 30 }, + }; + Result result = ExecuteAddStatement(collection.Add(docs)); + Assert.That(result.AffectedItemsCount, Is.EqualTo(2)); + + // Condition can't be null or empty. + string errorMessage = string.Empty; +#if !NETFRAMEWORK + errorMessage = "Parameter can't be null or empty (Parameter 'condition')"; +#else + errorMessage = "Parameter can't be null or empty\r\nParameter name: condition"; +#endif + Exception ex = Assert.Throws(() => ExecuteModifyStatement(collection.Modify(string.Empty))); + Assert.That(errorMessage, Is.EqualTo(ex.Message)); + ex = Assert.Throws(() => ExecuteModifyStatement(collection.Modify(""))); + Assert.That(errorMessage, Is.EqualTo(ex.Message)); + ex = Assert.Throws(() => ExecuteModifyStatement(collection.Modify(" "))); + Assert.That(errorMessage, Is.EqualTo(ex.Message)); + ex = Assert.Throws(() => ExecuteModifyStatement(collection.Modify(" "))); + Assert.That(errorMessage, Is.EqualTo(ex.Message)); + ex = Assert.Throws(() => ExecuteModifyStatement(collection.Modify(null))); + Assert.That(errorMessage, Is.EqualTo(ex.Message)); + + // Sending an expression that evaluates to true applies changes on all documents. + result = ExecuteModifyStatement(collection.Modify("true").Set("pages", "10")); + Assert.That(result.AffectedItemsCount, Is.EqualTo(2)); + } + + [Test] + public void ModifyWithLimit() + { + Collection collection = CreateCollection("test"); + var docs = new[] + { + new { _id = 1, title = "Book 1", pages = 20 }, + new { _id = 2, title = "Book 2", pages = 30 }, + }; + Result result = ExecuteAddStatement(collection.Add(docs)); + Assert.That(result.AffectedItemsCount, Is.EqualTo(2)); + + ExecuteModifyStatement(collection.Modify("true").Set("title", "Book X").Limit(1)); + Assert.That(ExecuteFindStatement(collection.Find("title = \"Book X\"")).FetchAll(), Has.One.Items); + + // Limit out of range. + Assert.Throws(() => ExecuteModifyStatement(collection.Modify("true").Set("pages", 10).Limit(0))); + Assert.Throws(() => ExecuteModifyStatement(collection.Modify("true").Set("pages", 10).Limit(-10))); + } + + [Test] + public void ModifyWithInOperator() + { + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); + + Collection collection = CreateCollection("test"); + var docs = new[] + { + new DbDoc("{ \"a\": 1, \"b\": \"foo\", \"c\": { \"d\": true, \"e\": [1,2,3] }, \"f\": [ {\"x\":5}, {\"x\":7 } ] }"), + new DbDoc("{ \"a\": 2, \"b\": \"foo2\", \"c\": { \"d\": true, \"e\": [4,5,6] }, \"f\": [ {\"x\":5}, {\"x\":8 } ] }"), + new DbDoc("{ \"a\": 1, \"b\": \"foo3\", \"c\": { \"d\": true, \"e\": [1,4,3] }, \"f\": [ {\"x\":6}, {\"x\":9 } ] }"), + }; + Result result = ExecuteAddStatement(collection.Add(docs)); + Assert.That(result.AffectedItemsCount, Is.EqualTo(3)); + + Assert.That(ExecuteModifyStatement(collection.Modify("a IN (1,2)").Set("a", 3)).AffectedItemsCount, Is.EqualTo(3)); + Assert.That(ExecuteFindStatement(collection.Find().Where("a = 3")).FetchAll().Count, Is.EqualTo(3)); + + Assert.That(ExecuteModifyStatement(collection.Modify("a IN [3]").Set("a", 1)).AffectedItemsCount, Is.EqualTo(3)); + Assert.That(ExecuteFindStatement(collection.Find().Where("a = 1")).FetchAll().Count, Is.EqualTo(3)); + + Assert.That(ExecuteModifyStatement(collection.Modify("1 IN c.e").Set("c.e", "newValue")).AffectedItemsCount, Is.EqualTo(2)); + Assert.That(ExecuteFindStatement(collection.Find().Where("c.e = \"newValue\"")).FetchAll().Count, Is.EqualTo(2)); + } + + [Test] + public void ReplaceOne() + { + Collection collection = CreateCollection("test"); + var docs = new[] + { + new { _id = 1, title = "Book 1", pages = 20 }, + new { _id = 2, title = "Book 2", pages = 30 }, + new { _id = 3, title = "Book 3", pages = 40 }, + new { _id = 4, title = "Book 4", pages = 50 }, + }; + Result result = ExecuteAddStatement(collection.Add(docs)); + Assert.That(result.AffectedItemsCount, Is.EqualTo(4)); + + // Expected exceptions. + Assert.Throws(() => collection.ReplaceOne(null, docs[1])); + Assert.Throws(() => collection.ReplaceOne("", docs[1])); + Assert.Throws(() => collection.ReplaceOne(string.Empty, docs[1])); + Assert.Throws(() => collection.ReplaceOne("1", null)); + // Replace using no matching id + Assert.Throws(() => collection.ReplaceOne(3, new DbDoc("{ \"_id\": 2, \"name\": \"John\", \"lastName\": \"Smith\" }")), + ResourcesX.ReplaceWithNoMatchingId); + + var newDoc = new { _id = 1, title = "Book 11", pages = 311 }; + + // Replace using a numeric identifier. + Assert.That(collection.ReplaceOne(1, newDoc).AffectedItemsCount, Is.EqualTo(1)); + DbDoc document = collection.GetOne(1); + Assert.That(Convert.ToInt32(document.Id), Is.EqualTo(1)); + Assert.That(document["title"], Is.EqualTo("Book 11")); + Assert.That(Convert.ToInt32(document["pages"]), Is.EqualTo(311)); + + // Replace using a string identifier. + Assert.That(collection.ReplaceOne("2", new DbDoc("{ \"name\": \"John\", \"lastName\": \"Smith\" }")).AffectedItemsCount, Is.EqualTo(1)); + document = collection.GetOne(2); + Assert.That(Convert.ToInt32(document.Id), Is.EqualTo(2)); + Assert.That(document["name"], Is.EqualTo("John")); + Assert.That(document["lastName"], Is.EqualTo("Smith")); + + // Replace a non-existing document. + Assert.That(collection.ReplaceOne(5, docs[1]).AffectedItemsCount, Is.EqualTo(0)); + Assert.That(collection.GetOne(5) == null); + } + + [Test] + public void ReplaceNestedDocument() + { + var collection = CreateCollection("test"); + var docs = new DbDoc[] + { + new DbDoc(@"{ ""_id"":1, ""pages"":20, ""title"":""Book 1"", ""person"": { ""name"": ""Fred"", ""age"":45 } }" ), + new DbDoc(@"{ ""_id"": 2, ""pages"": 30,""title"" : ""Book 2"", ""person"": { ""name"": ""Peter"", ""age"": 38 } }"), + new DbDoc(@"{ ""_id"": 3, ""pages"": 40,""title"" : ""Book 3"", ""person"": { ""name"": ""Andy"", ""age"": 25 } }"), + new DbDoc(@"{ ""_id"": 4, ""pages"": 50,""title"" : ""Book 4"", ""person"": { ""name"": ""John"", ""age"": 34 } }") + }; + Assert.That(ExecuteAddStatement(collection.Add(docs)).AffectedItemsCount, Is.EqualTo(4)); + + DbDoc d_new = new DbDoc(@"{ ""_id"": 1, ""pages"": 20,""title"" : ""Book 1"", ""person"": { ""name"": ""Fred"", ""age"": 45 ,""State"" : ""Ohio""} }"); + Assert.That(collection.ReplaceOne(1, d_new).AffectedItemsCount, Is.EqualTo(1)); + DbDoc document = collection.GetOne(1); + Assert.That((document.values["person"] as Dictionary)["State"], Is.EqualTo("Ohio")); + + d_new = new DbDoc(@"{ ""_id"": 1, ""pages"": 20,""title"" : ""Book 1"", ""person"": { ""name"": ""Fred"", ""age"": 45 ,""State"" : ""Ohio"", ""newProp"": { ""a"":33 } } }"); + Assert.That(collection.ReplaceOne(1, d_new).AffectedItemsCount, Is.EqualTo(1)); + document = collection.GetOne(1); + Assert.That(((document.values["person"] as Dictionary)["newProp"] as Dictionary)["a"], Is.EqualTo(33)); + } + + [Test] + public void ArrayInsert() + { + Collection collection = CreateCollection("test"); + ExecuteAddStatement(collection.Add("{ \"x\":[1,2] }")); + + // x[1]=43, x[2]=2. + ExecuteModifyStatement(collection.Modify("true").ArrayInsert("x[1]", 43)); + // x[3]=44. + ExecuteModifyStatement(collection.Modify("true").ArrayInsert("x[3]", 44)); + // Since array only contains 4 items the value 46 is assigned to x[4]. + ExecuteModifyStatement(collection.Modify("true").ArrayInsert("x[5]", 46)); + // Since array only contains 5 items the value 50 is assigned to x[5]. + ExecuteModifyStatement(collection.Modify("true").ArrayInsert("x[20]", 50)); + // Assign an item from different data type. + ExecuteModifyStatement(collection.Modify("true").ArrayInsert("x[6]", "string")); + // Assign a document. + ExecuteModifyStatement(collection.Modify("true").ArrayInsert("x[7]", "{ \"name\":\"Mike\" }")); + + var result = ExecuteFindStatement(collection.Find()); + var document = result.FetchOne(); + var x = (object[])document.values["x"]; + + Assert.That(x.Length, Is.EqualTo(8)); + Assert.That((int)x[0], Is.EqualTo(1)); + Assert.That((int)x[1], Is.EqualTo(43)); + Assert.That((int)x[2], Is.EqualTo(2)); + Assert.That((int)x[3], Is.EqualTo(44)); + Assert.That((int)x[4], Is.EqualTo(46)); + Assert.That((int)x[5], Is.EqualTo(50)); + Assert.That(x[6], Is.EqualTo("string")); + Assert.That(new DbDoc(x[7]) is DbDoc); + + // No value is inserted if the array doesn't exist. + ExecuteModifyStatement(collection.Modify("true").ArrayInsert("y[0]", 1)); + + result = ExecuteFindStatement(collection.Find()); + document = result.FetchOne(); + Assert.That(document.values.ContainsKey("y"), Is.False); + + ExecuteModifyStatement(collection.Modify("true").ArrayInsert("x[0]", null)); + ExecuteModifyStatement(collection.Modify("true").ArrayInsert("x[1]", " ")); + + result = ExecuteFindStatement(collection.Find()); + document = result.FetchOne(); + x = (object[])document.values["x"]; + Assert.That(x[0], Is.Null); + Assert.That(x[1], Is.EqualTo(" ")); + + // Insert an empty string fails. + var ex = Assert.Throws(() => ExecuteModifyStatement(collection.Modify("true").ArrayInsert("x[0]", ""))); + Assert.That(ex.Message, Does.Contain("String can't be empty")); + ex = Assert.Throws(() => ExecuteModifyStatement(collection.Modify("true").ArrayInsert("x[0]", string.Empty))); + Assert.That(ex.Message, Does.Contain("String can't be empty")); + + // Not specifying an index raises an error. + var ex2 = Assert.Throws(() => ExecuteModifyStatement(collection.Modify("true").ArrayInsert("dates", "5/1/2018"))); + Assert.That(ex2.Message, Is.EqualTo("A path expression is not a path to a cell in an array.")); + + var col = CreateCollection("my_collection"); + var t1 = "{\"_id\": \"1001\", \"ARR\":[1,2,3], \"ARR1\":[\"name1\",\"name2\", \"name3\"]}"; + col.Add(t1).Execute(); + col.Modify("true").ArrayInsert("ARR[0]", 4).Execute(); + col.Modify("true").ArrayInsert("ARR1[0]", "name4").Execute(); + col.Modify("true").ArrayInsert("ARR[0]", "name5").Execute(); + col.Modify("true").ArrayInsert("ARR1[0]", 5).Execute(); + col.Modify("true").ArrayInsert("ARR[0]", 6).ArrayInsert("ARR1[0]", "name6").ArrayInsert("ARR[0]", 7).ArrayInsert("ARR[0]", 8).Execute(); + col.Modify("true").ArrayInsert("ARR1[0]", null).Execute(); + col.Modify("true").ArrayInsert("ARR1[0]", " ").Execute(); + col.Modify("true").ArrayInsert("ARR1[0]", "****").Execute(); + result = ExecuteFindStatement(col.Find()); + document = result.FetchOne(); + var x2 = (object[])document.values["ARR"]; + Assert.That(x2.Length, Is.EqualTo(8)); + Assert.That((int)x2[0], Is.EqualTo(8)); + x2 = (object[])document.values["ARR1"]; + Assert.That(x2[0], Is.EqualTo("****")); + Assert.That(x2[8], Is.EqualTo("name3")); + } + + [Test] + public void ArrayAppendWithMySqlExpression() + { + Collection collection = CreateCollection("test"); + + // String containing an expression is not evaluted. + ExecuteAddStatement(collection.Add("{ \"_id\":\"123\", \"name\":\"alice\", \"email\":[ \"alice@ora.com\" ], \"dates\":\"4/1/2017\" }")); + ExecuteModifyStatement(collection.Modify("true").ArrayAppend("email", "UPPER($.name)")); + var document = collection.GetOne("123"); + Assert.That((document["email"] as object[])[1], Is.EqualTo("UPPER($.name)")); + + // Use MySqlExpression. + ExecuteAddStatement(collection.Add("{ \"_id\":\"124\", \"name\":\"alice\", \"value\":[ \"alice@ora.com\" ], \"dates\":\"4/1/2017\" }")); + ExecuteModifyStatement(collection.Modify("_id = \"124\"").ArrayAppend("value", new MySqlExpression("UPPER($.name)"))); + document = collection.GetOne("124"); + Assert.That((document["value"] as object[])[1], Is.EqualTo("ALICE")); + + // Use embedded MySqlExpression. + ExecuteAddStatement(collection.Add("{ \"_id\":\"125\", \"name\":\"alice\", \"value\":[ \"alice@ora.com\" ], \"dates\":\"4/1/2017\" }")); + ExecuteModifyStatement(collection.Modify("_id = \"125\"").ArrayAppend("value", new { expression = new MySqlExpression("UPPER($.name)") })); + document = collection.GetOne("125"); + var item = ((document["value"] as object[])[1] as Dictionary); + Assert.That(item["expression"], Is.EqualTo("ALICE")); + + ExecuteAddStatement(collection.Add("{ \"_id\":\"126\", \"name\":\"alice\", \"value\":[ \"alice@ora.com\" ], \"dates\":\"4/1/2017\" }")); + ExecuteModifyStatement(collection.Modify("_id = \"126\"").ArrayAppend("value", new { expression = new MySqlExpression("UPPER($.name)"), literal = "UPPER($.name)" })); + document = collection.GetOne("126"); + item = ((document["value"] as object[])[1] as Dictionary); + Assert.That(item["expression"], Is.EqualTo("ALICE")); + Assert.That(item["literal"], Is.EqualTo("UPPER($.name)")); + } + + [Test] + public void ArrayAppendUsesCorrectDataTypes() + { + Collection collection = CreateCollection("test"); + ExecuteAddStatement(collection.Add("{ \"_id\":\"123\", \"email\":[ \"alice@ora.com\"], \"dates\":\"4/1/2017\" }")); + ExecuteModifyStatement(collection.Modify("true").ArrayAppend("dates", "1")); + ExecuteModifyStatement(collection.Modify("true").ArrayAppend("dates", 1)); + var document = collection.GetOne("123"); + var dates = document["dates"] as object[]; + Assert.That(dates[1] is string); + Assert.That(dates[2] is int); + } + + [Test] + public void ArrayAppend() + { + Collection collection = CreateCollection("test"); + ExecuteAddStatement(collection.Add("{ \"x\":[1,2] }")); + + // Append values of different types, null and spaces. + ExecuteModifyStatement(collection.Modify("true").ArrayAppend("x", 43)); + ExecuteModifyStatement(collection.Modify("true").ArrayAppend("x", "string")); + ExecuteModifyStatement(collection.Modify("true").ArrayAppend("x", true)); + ExecuteModifyStatement(collection.Modify("true").ArrayAppend("x", null)); + ExecuteModifyStatement(collection.Modify("true").ArrayAppend("x", " ")); + var result = ExecuteFindStatement(collection.Find()); + DbDoc document = result.FetchOne(); + var x = (object[])document.values["x"]; + + Assert.That(x.Length, Is.EqualTo(7)); + Assert.That((int)x[0], Is.EqualTo(1)); + Assert.That((int)x[1], Is.EqualTo(2)); + Assert.That((int)x[2], Is.EqualTo(43)); + Assert.That(x[3], Is.EqualTo("string")); + Assert.That(x[4], Is.EqualTo(true)); + Assert.That(x[5], Is.Null); + Assert.That(x[6], Is.EqualTo(" ")); + + // No value is appended if the array doesn't exist. + ExecuteModifyStatement(collection.Modify("true").ArrayAppend("y", 45)); + + result = ExecuteFindStatement(collection.Find()); + document = result.FetchOne(); + Assert.That(document.values.ContainsKey("y"), Is.False); + + var ex = Assert.Throws(() => ExecuteModifyStatement(collection.Modify("true").ArrayAppend("x", ""))); + Assert.That(ex.Message, Does.Contain("String can't be empty")); + ex = Assert.Throws(() => ExecuteModifyStatement(collection.Modify("true").ArrayAppend("x", string.Empty))); + Assert.That(ex.Message, Does.Contain("String can't be empty")); + + var col = CreateCollection("my_collection"); + var t1 = "{\"_id\": \"1001\", \"ARR\":[1,2,3], \"ARR1\":[\"name1\",\"name2\", \"name3\"]}"; + col.Add(t1).Execute(); + col.Modify("true").ArrayAppend("ARR", 4).Execute(); + col.Modify("true").ArrayAppend("ARR1", "name4").Execute(); + col.Modify("true").ArrayAppend("ARR", "name5").Execute(); + col.Modify("true").ArrayAppend("ARR1", 5).Execute(); + col.Modify("true").ArrayAppend("ARR", 6).ArrayAppend("ARR1", "name6").ArrayAppend("ARR", 7).ArrayAppend("ARR", 8).Execute(); + + Assert.Throws(() => ExecuteModifyStatement(col.Modify("true").ArrayAppend("ARR1", ""))); + } + + [Test] + public void ArrayInsertWithMySqlExpression() + { + Collection collection = CreateCollection("test"); + ExecuteAddStatement(collection.Add("{ \"x\":[1,2] }")); + + // String containing an expression is not evaluted. + ExecuteAddStatement(collection.Add("{ \"_id\":\"123\", \"name\":\"alice\", \"email\":[ \"alice@ora.com\" ], \"dates\":\"4/1/2017\" }")); + ExecuteModifyStatement(collection.Modify("true").ArrayInsert("email[0]", "UPPER($.name)")); + var document = collection.GetOne("123"); + Assert.That((document["email"] as object[])[0], Is.EqualTo("UPPER($.name)")); + + // Use MySqlExpression. + ExecuteAddStatement(collection.Add("{ \"_id\":\"124\", \"name\":\"alice\", \"email\":[ \"alice@ora.com\" ], \"dates\":\"4/1/2017\" }")); + ExecuteModifyStatement(collection.Modify("_id = \"124\"").ArrayInsert("email[0]", new MySqlExpression("UPPER($.name)"))); + document = collection.GetOne("124"); + Assert.That((document["email"] as object[])[0], Is.EqualTo("ALICE")); + + // Use embedded MySqlExpression. + ExecuteAddStatement(collection.Add("{ \"_id\":\"125\", \"name\":\"alice\", \"email\":[ \"alice@ora.com\" ], \"dates\":\"4/1/2017\" }")); + ExecuteModifyStatement(collection.Modify("_id = \"125\"").ArrayInsert("email[0]", new { other = new MySqlExpression("UPPER($.name)") })); + document = collection.GetOne("125"); + var item = ((document["email"] as object[])[0] as Dictionary); + Assert.That(item["other"], Is.EqualTo("ALICE")); + + ExecuteAddStatement(collection.Add("{ \"_id\":\"126\", \"name\":\"alice\", \"email\":[ \"alice@ora.com\" ], \"dates\":\"4/1/2017\" }")); + ExecuteModifyStatement(collection.Modify("_id = \"126\"").ArrayInsert("email[0]", new { other = new MySqlExpression("UPPER($.name)"), literal = "UPPER($.name)" })); + document = collection.GetOne("126"); + item = ((document["email"] as object[])[0] as Dictionary); + Assert.That(item["other"], Is.EqualTo("ALICE")); + Assert.That(item["literal"], Is.EqualTo("UPPER($.name)")); + } + + [Test] + public void ArrayOperationsKeepDateValue() + { + Collection collection = CreateCollection("test"); + Result r = ExecuteAddStatement(collection.Add("{ \"_id\": \"123\", \"email\":[\"alice@ora.com\"], \"dates\": \"5/1/2018\" }")); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1ul)); + + // No items are affected since dates isn't an array. + r = ExecuteModifyStatement(collection.Modify("true").ArrayInsert("dates[0]", "4/1/2018")); + Assert.That(r.AffectedItemsCount, Is.EqualTo(0ul)); + + // Converts a non array to an array by appending a value. + ExecuteModifyStatement(collection.Modify("true").ArrayAppend("dates", "6/1/2018")); + + // Array insert at specified index is now succesful since dates is an array. + ExecuteModifyStatement(collection.Modify("true").ArrayInsert("dates[0]", "4/1/2018")); + + DbDoc document = collection.GetOne("123"); + object[] dates = document["dates"] as object[]; + Assert.That(dates.Length, Is.EqualTo(3)); + Assert.That(dates[0], Is.EqualTo("4/1/2018")); + Assert.That(dates[1], Is.EqualTo("5/1/2018")); + Assert.That(dates[2], Is.EqualTo("6/1/2018")); + } + + [Test] + public void Alphanumeric() + { + Collection collection = CreateCollection("test"); + var document = new DbDoc(); + + for (int i = 0; i < 30; i++) + { + document.SetValue("_id", i); + document.SetValue("books", "test" + i); + document.SetValue("pages", i + 10); + document.SetValue("reviewers", "reviewers" + i); + document.SetValue("person", new + { + name = "Fred" + i, + age = i + }); + document.SetValue("1address", "street" + i); + ExecuteAddStatement(collection.Add(document)); + } + + var crudresult = collection.Find("pages=10").Execute().FetchAll(); + Assert.That(crudresult.Count, Is.EqualTo(1), "Count should be 1 before Unset of pages for _id=0."); + var result = collection.Modify("_id = 0").Unset("pages").Execute(); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1), "Affected Items Count when modify unset is used"); + crudresult = collection.Find("pages=10").Execute().FetchAll(); + Assert.That(crudresult.Count, Is.EqualTo(0), "Count should be 0 after Unset of pages for _id=0"); + crudresult = collection.Find("books='test0'").Execute().FetchAll(); + Assert.That(crudresult.Count, Is.EqualTo(1), "Count should be 0 after Unset of pages for _id=0"); + + result = collection.Modify("_id = 21").Unset("1address").Execute(); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1), "Affected Items Count when modify unset(multiple docs) is used"); + } + + [Test] + public void UnsetVariations() + { + Collection collection = CreateCollection("test"); + var document = new DbDoc("{ \"_id\":1, \"pages\":1, \"pages2\":2, \"pages3\":3, \"pages4\":{ \"internalPages\":4 } }"); + ExecuteAddStatement(collection.Add(document)); + + // Whitespace is ignored. + ExecuteModifyStatement(collection.Modify("_id = 1").Unset("pages ")); + Assert.That(collection.GetOne(1).values.ContainsKey("pages"), Is.False); + ExecuteModifyStatement(collection.Modify("_id = 1").Unset(" pages2 ")); + Assert.That(collection.GetOne(1).values.ContainsKey("pages2"), Is.False); + ExecuteModifyStatement(collection.Modify("_id = 1").Unset(" pages3")); + Assert.That(collection.GetOne(1).values.ContainsKey("pages3"), Is.False); + ExecuteModifyStatement(collection.Modify("_id = 1").Unset(" pages4.internalPages ")); + Assert.That(collection.GetOne(1).values.ContainsKey("pages4")); + Assert.That(collection.GetOne(1).values.ContainsKey("pages4.internalPages"), Is.False); + + // Error is raised with incorrect document path. + var ex = Assert.Throws(() => ExecuteModifyStatement(collection.Modify("_id = 1").Unset("pages*"))); + Assert.That(ex.Message, Is.EqualTo("Invalid document path.")); + ex = Assert.Throws(() => ExecuteModifyStatement(collection.Modify("_id = 1").Unset("pages!"))); + Assert.That(ex.Message, Is.EqualTo("Invalid document path.")); + ex = Assert.Throws(() => ExecuteModifyStatement(collection.Modify("_id = 1").Unset("pages*data"))); + Assert.That(ex.Message, Is.EqualTo("Invalid document path.")); + } + + #region WL14389 + + [Test, Description("Collection.Modify(condition).Unset() to accept a list of elements instead of just one.")] + public void CollectionModifyUnset() + { + List idStringList = new List(); + var col = CreateCollection("my_collection"); + var d1 = new DbDoc(); + for (int i = 0; i < 30; i++) + { + d1.SetValue("_id", i); + d1.SetValue("books", "test" + i); + d1.SetValue("pages", i + 10); + d1.SetValue("reviewers", "reviewers" + i); + d1.SetValue("person", new { name = "Fred" + i, age = i }); + d1.SetValue("1address", "street" + i); + col.Add(d1).Execute(); + } + + var crudresult = col.Find("pages=10").Execute().FetchAll(); + Assert.That(crudresult.Count, Is.EqualTo(1), "Count should be 1 before Unset of pages for _id=0."); + var result = col.Modify("_id = 0").Unset("pages").Execute(); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1), "Affected Items Count when modify unset is used"); + crudresult = col.Find("pages=10").Execute().FetchAll(); + Assert.That(crudresult.Count, Is.EqualTo(0), "Count should be 0 after Unset of pages for _id=0"); + crudresult = col.Find("books='test0'").Execute().FetchAll(); + Assert.That(crudresult.Count, Is.EqualTo(1), "Count should be 0 after Unset of pages for _id=0"); + + crudresult = col.Find("pages=11").Execute().FetchAll(); + Assert.That(crudresult.Count, Is.EqualTo(1), "Count of pages=11 should be 1 before Unset of pages for _id=1."); + crudresult = col.Find("reviewers='reviewers1'").Execute().FetchAll(); + Assert.That(crudresult.Count, Is.EqualTo(1), "Count of reviewers1 should be 1 before Unset of pages for _id=1."); + result = col.Modify("_id = 1").Unset("pages").Unset("reviewers").Execute(); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1), "Affected Items Count when modify multiple unset is used"); + crudresult = col.Find("pages=11").Execute().FetchAll(); + Assert.That(crudresult.Count, Is.EqualTo(0), "Count should be 0 after Unset of pages for _id=1"); + crudresult = col.Find("reviewers='reviewers1'").Execute().FetchAll(); + Assert.That(crudresult.Count, Is.EqualTo(0), "Count should be 0 after Unset of pages for _id=1"); + + crudresult = col.Find("pages=21").Execute().FetchAll(); + Assert.That(crudresult.Count, Is.EqualTo(1), "Count of pages=21 should be 1 before Unset of pages for _id=11."); + crudresult = col.Find("reviewers='reviewers11'").Execute().FetchAll(); + Assert.That(crudresult.Count, Is.EqualTo(1), "Count of reviewers11 should be 1 before Unset of pages for _id=11."); + result = col.Modify("_id = 11").Unset(new string[] { "pages", "reviewers" }).Execute(); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1), "Affected Items Count when modify unset(multiple docs) is used"); + crudresult = col.Find("pages=21").Execute().FetchAll(); + Assert.That(crudresult.Count, Is.EqualTo(0), "Count should be 0 after Unset of pages for _id=11"); + crudresult = col.Find("reviewers='reviewers11'").Execute().FetchAll(); + Assert.That(crudresult.Count, Is.EqualTo(0), "Count should be 0 after Unset of pages for _id=11"); + + crudresult = col.Find("pages=31").Execute().FetchAll(); + Assert.That(crudresult.Count, Is.EqualTo(1), "Count of pages=31 should be 1 before Unset of pages for _id=21."); + crudresult = col.Find("reviewers='reviewers21'").Execute().FetchAll(); + Assert.That(crudresult.Count, Is.EqualTo(1), "Count of reviewers21 should be 1 before Unset of pages for _id=21."); + + result = col.Modify("_id = 21").Unset(" pages ").Execute(); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1), "Affected Items Count when modify unset(multiple docs) is used"); + //Should have failed when unset is used for fields with special characters + Assert.Throws(() => ExecuteModifyStatement(col.Modify("_id = 22").Unset("pages*"))); + //Should have failed when unset is used for non-existent fields + Assert.Throws(() => ExecuteModifyStatement(col.Modify("_id = 21").Unset("1"))); + //Should have failed when unset is used for special characters + Assert.Throws(() => ExecuteModifyStatement(col.Modify("_id = 21").Unset("@*%#^)(-+!~<>?/"))); + //Should have failed when unset is used for special characters + Assert.Throws(() => ExecuteModifyStatement(col.Modify("_id = 21").Unset("*******"))); + + crudresult = col.Find("pages=31").Execute().FetchAll(); + Assert.That(crudresult.Count, Is.EqualTo(0), "Count should be 0 after Unset of pages for _id=21"); + + result = col.Modify("_id = 12").Unset(new string[] { " pages1", "reviewers1" }).Execute(); + Assert.That(result.AffectedItemsCount, Is.EqualTo(0), "Affected Items Count when modify unset(invalid docs) is used"); + crudresult = col.Find("pages=22").Execute().FetchAll(); + Assert.That(crudresult.Count, Is.EqualTo(1), "Count should be 1 after Unset with invalid of pages for _id=12"); + crudresult = col.Find("reviewers='reviewers12'").Execute().FetchAll(); + Assert.That(crudresult.Count, Is.EqualTo(1), "Count should be 1 after Unset with invalid of pages for _id=12"); + //Testcase should have failed when unset is used with null + Assert.Throws(() => ExecuteModifyStatement(col.Modify("_id = 12").Unset(null))); + + crudresult = col.Find("pages=22").Execute().FetchAll(); + Assert.That(crudresult.Count, Is.EqualTo(1), "Count should be 1 after Unset with null of pages for _id=12"); + crudresult = col.Find("reviewers='reviewers12'").Execute().FetchAll(); + Assert.That(crudresult.Count, Is.EqualTo(1), "Count should be 1 after Unset with null of pages for _id=12"); + + Assert.Throws(() => ExecuteModifyStatement(col.Modify("_id = 12").Unset(""))); + + crudresult = col.Find("pages=22").Execute().FetchAll(); + Assert.That(crudresult.Count, Is.EqualTo(1), "Count should be 1 after Unset with blank of pages for _id=12"); + crudresult = col.Find("reviewers='reviewers12'").Execute().FetchAll(); + Assert.That(crudresult.Count, Is.EqualTo(1), "Count should be 1 after Unset with blank of pages for _id=12"); + + crudresult = col.Find("pages=22").Execute().FetchAll(); + Assert.That(crudresult.Count, Is.EqualTo(1), "Count should be 1 after Unset with blank with space of pages for _id=12"); + crudresult = col.Find("reviewers='reviewers12'").Execute().FetchAll(); + Assert.That(crudresult.Count, Is.EqualTo(1), "Count should be 1 after Unset with blank with space of pages for _id=12"); + + //Testcase should have failed when unset is used with blank and space + Assert.Throws(() => ExecuteModifyStatement(col.Modify("_id = 12").Unset(new string[] { "", " ", "pages" }))); + + crudresult = col.Find("pages=22").Execute().FetchAll(); + Assert.That(crudresult.Count, Is.EqualTo(1)); + crudresult = col.Find("reviewers='reviewers12'").Execute().FetchAll(); + Assert.That(crudresult.Count, Is.EqualTo(1)); + } + + [Test, Description("All Bug Fixes")] + public void ValidateValuesAfterAppendAndInserts() + { + DbDoc document = null; + Collection collection = CreateCollection("test"); + Result r = collection.Add("{ \"_id\": \"123\", \"email\": [\"alice@ora.com\"], " + + "\"dates\": \"4/1/2017\" }").Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); + + collection.Modify("true").ArrayAppend("dates", "5/1/2018").Execute(); + document = collection.GetOne("123"); + object[] dates = document["dates"] as object[]; + Assert.That(dates.Length, Is.EqualTo(2)); + Assert.That(dates[0], Is.EqualTo("4/1/2017"), "Existing Date"); + Assert.That(dates[1], Is.EqualTo("5/1/2018"), "Appended Date"); + collection.Modify("true").ArrayInsert("dates[0]", "5/1/2059").Execute(); + document = collection.GetOne("123"); + dates = document["dates"] as object[]; + Assert.That(dates[0], Is.EqualTo("5/1/2059"), "Inserted Date"); + + collection = CreateCollection("test"); + r = collection.Add("{ \"_id\": \"123\", \"email\": [\"alice@ora.com\"], " + + "\"dates\": [\"4/1/2017\"] }").Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); + + collection = CreateCollection("test"); + r = collection.Add("{ \"_id\": \"123\", \"email\": [\"alice@ora.com\"], " + + "\"dates\": \"4/1/2017\" }").Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); + collection.Modify("true").ArrayAppend("dates", "1").Execute(); + collection.Modify("true").ArrayAppend("dates", 1).Execute(); + collection.Modify("true").ArrayAppend("dates", "3.1").Execute(); + collection.Modify("true").ArrayAppend("dates", 3.1).Execute(); + document = collection.GetOne("123"); + dates = document["dates"] as object[]; + Assert.That(dates.Length, Is.EqualTo(5)); + Assert.That(dates[0], Is.EqualTo("4/1/2017"), "Existing Date"); + Assert.That(dates[1], Is.EqualTo("1"), "Appended Date"); + Assert.That(dates[2], Is.EqualTo(1), "Appended Date"); + Assert.That(dates[3], Is.EqualTo("3.1"), "Appended Date"); + Assert.That(dates[4], Is.EqualTo(3.1), "Appended Date"); + + collection.Modify("true").ArrayInsert("dates[0]", "10").Execute(); + collection.Modify("true").ArrayInsert("dates[0]", 1000).Execute(); + collection.Modify("true").ArrayInsert("dates[0]", "3.1").Execute(); + collection.Modify("true").ArrayInsert("dates[0]", 22.7).Execute(); + document = collection.GetOne("123"); + dates = document["dates"] as object[]; + Assert.That(dates[3], Is.EqualTo("10"), "Inserted Date"); + Assert.That(dates[2], Is.EqualTo(1000), "Inserted Date"); + Assert.That(dates[1], Is.EqualTo("3.1"), "Inserted Date"); + Assert.That(dates[0], Is.EqualTo(22.7), "Inserted Date"); + + var d1 = new DbDoc(); + for (int i = 0; i < 30; i++) + { + d1.SetValue("_id", i); + d1.SetValue("books", "test" + i); + d1.SetValue("pages", i + 10); + d1.SetValue("reviewers", "reviewers" + i); + d1.SetValue("person", new + { + name = "Fred" + i, + age = i + }); + d1.SetValue("1address", "street" + i); + collection.Add(d1).Execute(); + } + Assert.Throws(() => ExecuteModifyStatement(collection.Modify("_id = 21").Unset("pages*"))); + + var docs = new[] + { + new { _id = 100, title = "Book 1", pages = 20 }, + new { _id = 200, title = "Book 2", pages = 30 }, + new { _id = 300, title = "Book 3", pages = 40 }, + new { _id = 400, title = "Book 4", pages = 50 }, + }; + r = collection.Add(docs).Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(4), "Matching the records affected"); + var test1 = collection.Find("pages = :Pages").Bind("pAges", 90).Fields("{\"_id\":100,\"pages\": 20 }").Execute(); + Assert.That(test1, Is.Not.Null); + } + + [Test, Description("Collection.modify(condition).arrayAppend(CollectionField, ExprOrLiteral)")] + public void CollectionModifyArrayAppend() + { + + string currentYear = DateTime.Now.Year.ToString(); + DbDoc document = null; + string t1 = "{\"_id\": \"1\", \"name\": \"Alice\" }"; + var collection = CreateCollection("test"); + Result r = collection.Add(t1).Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); + object[] expressions1 = new object[] { "YEAR('2000-01-01')", "MONTH('2008-02-03')", "WEEK('2008-02-20')", "DAY('2008-02-20')", "HOUR('10:05:03')", + "MINUTE('2008-02-03 10:05:03')","SECOND('10:05:03')","MICROSECOND('12:00:00.123456')","QUARTER('2008-04-01')","TIME('2003-12-31 01:02:03')","DATE('2003-12-31 01:02:03')", + "Year(CURDATE())"}; + + object[] expressions2 = new object[] { "5/1/2018",2012,"2012",-22.7,22.7,"22.7", "'large'", + "'838:59:59'" ,true,-100000000,"-10000000000","6/6/2018","9999-12-31 23:59:59","0000-00-00 00:00:00","[a,b,c]","[]"}; + object[] compare_expressions1 = new object[] { 2000, 2, 7, 20, 10, 5, 3, 123456, 2, "01:02:03.000000", "2003-12-31", currentYear }; + object[] compare_expressions2 = new object[] { "5/1/2018",2012, "2012", -22.7, 22.7, "22.7", + "'large'", "'838:59:59'", true, -100000000, "-10000000000","6/6/2018" ,"9999-12-31 23:59:59","0000-00-00 00:00:00","[a,b,c]","[]"}; + for (int k = 0; k < expressions1.Length; k++) + { + collection.Modify("true").ArrayAppend("name", "{ \"dateAndTimeValue\": " + expressions1[k] + " }").Execute(); + } + for (int k = 0; k < expressions2.Length; k++) + { + collection.Modify("true").ArrayAppend("name", "{ \"dateAndTimeValue\": \"" + expressions2[k] + "\" }").Execute(); + } + object[] actors = null; + object test = null; + Dictionary actor0 = null; + int l = 1; + for (int k = 0; k < compare_expressions1.Length; k++) + { + + document = collection.GetOne("1"); + actors = document["name"] as object[]; + actor0 = actors[l] as Dictionary; + test = actor0["dateAndTimeValue"]; + Assert.That(test.ToString(), Is.EqualTo(compare_expressions1[k].ToString())); + l++; + } + for (int k = 0; k < compare_expressions2.Length; k++) + { + + document = collection.GetOne("1"); + actors = document["name"] as object[]; + actor0 = actors[l] as Dictionary; + test = actor0["dateAndTimeValue"]; + Assert.That(test.ToString(), Is.EqualTo(compare_expressions2[k].ToString())); + l++; + } + + collection = CreateCollection("test"); + r = collection.Add("{ \"_id\": \"123\", \"email\": [\"alice@ora.com\"], " + + "\"dates\": [\"4/1/2017\"] }").Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); + var reg_expression = new + { + test1 = new MySqlExpression("UPPER($.email)"), + test2 = new MySqlExpression("LOWER($.email)"), + test3 = new MySqlExpression("CONCAT('No', 'S', 'QL')"), + test4 = new MySqlExpression("CHAR(77, 121, 83, 81, '76')"), + test5 = new MySqlExpression("CONCAT('My', NULL, 'QL')"), + test6 = new MySqlExpression("ELT(4, 'ej', 'Heja', 'hej', 'foo')"), + test7 = new MySqlExpression("REPEAT('MySQL', 3)"), + test8 = new MySqlExpression("REVERSE('abc')"), + test9 = new MySqlExpression("RIGHT('foobarbar', 4)"), + test10 = new MySqlExpression("REPLACE('www.mysql.com', 'w', 'Ww')"), + test11 = new MySqlExpression(" HEX('abc')"), + test12 = new MySqlExpression(" BIN(12)"), + }; + object[] compare_expressions = null; + if (session.Version.isAtLeast(8, 0, 0)) + { + compare_expressions = new object[] { "[\\\"ALICE@ORA.COM\\\"]", "[\\\"alice@ora.com\\\", \\\"[\\\\\\\"alice@ora.com\\\\\\\"]\\\"]", + "NoSQL","base64:type253:TXlTUUw=",null,"foo","MySQLMySQLMySQL","cba","rbar","WwWwWw.mysql.com","616263","1100" }; + } + else + { + compare_expressions = new object[] { "[\\\"ALICE@ORA.COM\\\"]", "[\\\"alice@ora.com\\\", \\\"[\\\\\\\"alice@ora.com\\\\\\\"]\\\"]", + "NoSQL","base64:type15:TXlTUUw=",null,"foo","MySQLMySQLMySQL","cba","rbar","WwWwWw.mysql.com","616263","1100" }; + } + + var items = new List(); + items.Add(reg_expression.test1); + items.Add(reg_expression.test2); + items.Add(reg_expression.test3); + items.Add(reg_expression.test4); + items.Add(reg_expression.test5); + items.Add(reg_expression.test6); + items.Add(reg_expression.test7); + items.Add(reg_expression.test8); + items.Add(reg_expression.test9); + items.Add(reg_expression.test10); + items.Add(reg_expression.test11); + items.Add(reg_expression.test12); + int m = 1, n = 0; + foreach (var obj in items) + { + collection.Modify("true").ArrayAppend("email", obj).Execute(); + document = collection.GetOne("123"); + actors = document["email"] as object[]; + if (n == 3) + { } + else + { + Assert.That(compare_expressions[n], Is.EqualTo(actors[m])); + } + + m++; n++; + } + + string json = ""; + int i = 0, j = 0, maxField = 40; + collection = CreateCollection("test"); + int maxDepth = 2; + json = "{\"_id\":\"1002\",\"XYZ\":1111"; + for (j = 0; j < maxField; j++) + { + json = json + ",\"ARR" + j + "\":["; + for (i = 0; i < maxDepth; i++) + { + json = json + i + ",["; + } + json = json + i; + for (i = maxDepth - 1; i >= 0; i--) + { + json = json + "]," + i; + } + json = json + "]"; + } + json = json + "}"; + + collection.Add(json).Execute(); + r = collection.Modify("true").ArrayAppend("ARR10", 1).ArrayAppend("ARR20", 2).ArrayAppend("ARR30", 3).Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); + r = collection.Modify("true").ArrayAppend("ARR0", null).Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); + r = collection.Modify("true").ArrayAppend("ARR39", null).Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); + + } + + [Test, Description("MySQLX CNET Forbid modify() with no condition-Scenario-1")] + public void ForbidModifyWithNoCondition_S1() + { + + Collection collection = CreateCollection("test"); + var docs = new[] + { + new { _id = 1, title = "Book 1", pages = 20 }, + new { _id = 2, title = "Book 2", pages = 30 }, + new { _id = 3, title = "Book 3", pages = 40 }, + new { _id = 4, title = "Book 4", pages = 50 }, + }; + Result result = collection.Add(docs).Execute(); + Assert.That(result.AffectedItemsCount, Is.EqualTo(4)); + + // Condition can't be null or empty. + Assert.Throws(() => ExecuteModifyStatement(collection.Modify(string.Empty))); + Assert.Throws(() => ExecuteRemoveStatement(collection.Remove(""))); + Assert.Throws(() => ExecuteModifyStatement(collection.Modify(null))); + + // Sending an expression that evaluates to true applies changes on all documents. + result = collection.Modify("true").Set("pages", "10").Execute(); + Assert.That(result.AffectedItemsCount, Is.EqualTo(4)); + + } + + [Test, Description("MySQLX CNET Forbid modify() with no condition-Scenario-2")] + public void ForbidModifyWithNoCondition_S2() + { + + Collection collection = CreateCollection("test"); + var docs = new[] + { + new { _id = 1, title = "Book 1", pages = 20 }, + new { _id = 2, title = "Book 2", pages = 30 }, + new { _id = 3, title = "Book 3", pages = 40 }, + new { _id = 4, title = "Book 4", pages = 50 }, + }; + Result result = collection.Add(docs).Execute(); + Assert.That(result.AffectedItemsCount, Is.EqualTo(4)); + + // Sending an expression that evaluates to true applies changes on all documents. + //Deprecated Modify().Where() in 8.0.17 + result = collection.Modify("true").Where("false").Set("pages", "10").Execute(); + Assert.That(result.AffectedItemsCount, Is.EqualTo(0)); + + result = collection.Modify("true").Where("true").Set("pages", "10").Execute(); + Assert.That(result.AffectedItemsCount, Is.EqualTo(4)); + result = collection.Modify("false").Where("true").Set("pages", "40").Execute(); + Assert.That(result.AffectedItemsCount, Is.EqualTo(4)); + result = collection.Modify("false").Where("false").Set("pages", "40").Execute(); + Assert.That(result.AffectedItemsCount, Is.EqualTo(0)); + + // Condition can't be null or empty. + Assert.Throws(() => ExecuteModifyStatement(collection.Modify(" "))); + } + + [Test, Description("Test valid modify.patch to change element at Depth n for multiple arrays#Bug))")] + public void ModifyPatchNDepth() + { + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); + string json = ""; + int i = 0, j = 0, maxField = 100; + var collection = CreateCollection("test"); + int maxDepth = 46; + json = "{\"_id\":\"1002\",\"XYZ\":1111"; + for (j = 0; j < maxField; j++) + { + json = json + ",\"ARR" + j + "\":["; + for (i = 0; i < maxDepth; i++) + { + json = json + i + ",["; + } + json = json + i; + for (i = maxDepth - 1; i >= 0; i--) + { + json = json + "]," + i; + } + json = json + "]"; + } + json = json + "}"; + + var r = collection.Modify("age = :age").Patch(json). + Bind("age", "18").Execute(); + Assert.That(r, Is.Not.Null); + } + + [Test, Description("Test valid modify.patch with condition/limit/OrderBy")] + public void ModifyPatch() + { + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); + var collection = CreateCollection("test"); + var docs = new[] + { + new {_id = 1, title = "Book 1", pages = 20, age = 12}, + new {_id = 2, title = "Book 2", pages = 30,age = 18}, + new {_id = 3, title = "Book 3", pages = 40,age = 34}, + new {_id = 4, title = "Book 4", pages = 50,age = 15} + }; + var r = collection.Add(docs).Execute(); + Assert.That((int)r.AffectedItemsCount, Is.EqualTo(4), "Matching the updated record count"); + + var jsonParams = new { title = "Book 100" }; + var foundDocs = collection.Modify("age==18").Patch(jsonParams).Execute(); + Assert.That((int)foundDocs.AffectedItemsCount, Is.EqualTo(1), "Matching the record count"); + + var document = collection.GetOne("2"); + Assert.That(document["title"], Is.EqualTo("Book 100")); + + jsonParams = new { title = "Book 300" }; + r = collection.Modify("age<18").Patch(jsonParams).Limit(1).Execute(); + Assert.That((int)r.AffectedItemsCount, Is.EqualTo(1), "Matching the record count"); + + document = collection.GetOne(1); + Assert.That(document["title"], Is.EqualTo("Book 300")); + + var jsonParams1 = new { title = "Book 10", pages = 1000 }; + r = collection.Modify("age>30").Patch(jsonParams1).Sort("age ASC").Execute(); + Assert.That((int)r.AffectedItemsCount, Is.EqualTo(1), "Matching the record count"); + } + + [Test, Description("Test valid modify.patch with set/unset")] + public void ModifyPatchWithSetUnset() + { + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); + var collection = CreateCollection("test"); + var docs = new[] + { + new {_id = 1, title = "Book 1", pages = 20, age = "12"}, + new {_id = 2, title = "Book 2", pages = 30,age = "18"}, + new {_id = 3, title = "Book 3", pages = 40,age = "34"}, + new {_id = 4, title = "Book 4", pages = 50,age = "12"} + }; + Result r = collection.Add(docs).Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(4)); + + var jsonParams = new { title = "Book 500" }; + r = collection.Modify("age = :age").Patch(jsonParams).Bind("age", "18"). + Set("pages", "5000").Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); + + var document = collection.GetOne("2"); + Assert.That(document["pages"].ToString(), Is.EqualTo("5000")); + Assert.That(document["title"].ToString(), Is.EqualTo("Book 500")); + + var jsonParams1 = new { title = "Book 50000", pages = 5000 }; + r = collection.Modify("age = :age").Patch(jsonParams1).Bind("age", "18"). + Unset("pages").Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1), "Match being done"); + document = collection.GetOne("2"); + DbDoc test = null; + Assert.Throws(() => test = (DbDoc)document["pages"]); + Assert.That(document["title"], Is.EqualTo("Book 50000")); + } + + [Test, Description("Test invalid modify.patch to attempt to change _id using modify.patch")] + public void ModifyPatchChangeId() + { + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); + var collection = CreateCollection("test"); + var docs = new[] + { + new {_id = 1, title = "Book 1", pages = 20, age = 12}, + new {_id = 2, title = "Book 2", pages = 30,age = 18}, + new {_id = 3, title = "Book 3", pages = 40,age = 34}, + new {_id = 4, title = "Book 4", pages = 50,age = 12} + }; + Result r = collection.Add(docs).Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(4)); + var document = collection.GetOne("1"); + var jsonParams = new { _id = 123 }; + + r = collection.Modify("age = :age").Patch(jsonParams). + Bind("age", 18).Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(0)); + + var jsonParams2 = new { _id = 123, title = "Book 4000" }; + + r = collection.Modify("age = :age").Patch(jsonParams2). + Bind("age", 18).Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); + + string jsonParams1 = "{ \"_id\": \"123\"}"; + r = collection.Modify("age = :age").Patch(jsonParams1). + Bind("age", 18).Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(0)); + + jsonParams1 = "{ \"_id\": \"123\",\"title\": \"Book 400\"}"; + r = collection.Modify("age = :age").Patch(jsonParams1). + Bind("age", 18).Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); + } + + [Test, Description("Test modify.patch where the key to be modified has array, dbDoc and normal constant value and condition is matched for all.")] + public void ModifyPatchKeyWithArray() + { + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); + var collection = CreateCollection("test"); + var docs1 = new[] + { + new {_id = 1, title = "Book 1", pages = 20, age = 12,name = "Morgan"}, + }; + var docs2 = + "{\"_id\": \"2\",\"age\": 12,\"name\": \"Alice\", " + + "\"address\": {\"zip\": \"12345\", \"city\": \"Los Angeles\", \"street\": \"32 Main str\"}}"; + + var docs3 = "{\"_id\": \"3\", \"age\": 12,\"name\":[\"Cynthia\"], \"ARR1\":[\"name1\",\"name2\", \"name3\"]}"; + Result r = collection.Add(docs1).Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); + r = collection.Add(docs2).Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); + r = collection.Add(docs3).Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); + var jsonParams = new { name = "Changed" }; + r = collection.Modify("age = :age").Patch(jsonParams).Bind("age", 12).Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(3)); + } + + [Test, Description("Test that documents not matching conditions are not modified.")] + public void ModifyPatchNotMatchingConditions() + { + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); + var collection = CreateCollection("test"); + var docs = new[] + { + new {_id = 1, title = "Book 1", pages = 20, age = 12}, + new {_id = 2, title = "Book 2", pages = 30,age = 18}, + new {_id = 3, title = "Book 3", pages = 40,age = 34}, + new {_id = 4, title = "Book 4", pages = 50,age = 12} + }; + Result r = collection.Add(docs).Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(4)); + var document = collection.GetOne("1"); + var jsonParams = new { title = "Book 100" }; + r = collection.Modify("age = :age").Patch(jsonParams).Bind("age", "19").Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(0)); + string jsonParams1 = "{ \"title\": \"Book 100\"}"; + r = collection.Modify("age = :age").Patch(jsonParams1).Bind("age", "28").Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(0)); + jsonParams1 = "{ \"unknownvalues\": null}"; + r = collection.Modify("age = :age").Patch(jsonParams1).Bind("age", "28").Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(0)); + } + + [Test, Description("Test modify.patch with different types of records(anonymous object,Json String,DbDoc) with same key and try to replace using a patch")] + public void ModifyPatchDifferentTypesSameKey() + { + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); + var collection = CreateCollection("test"); + var docs1 = new[] + { + new {_id = 1, title = "Book 1", pages = 20, age = 12,name = "Morgan"}, + }; + var docs2 = + "{\"_id\": \"2\",\"age\": \"12\",\"name\": \"Alice\", " + + "\"address\": {\"zip\": \"12345\", \"city\": \"Los Angeles\", \"street\": \"32 Main str\"}}"; + + var docs3 = new DbDoc(@"{ ""_id"": 3, ""pages"": 20, ""age"":12,""name"":""Cynthiaa"", + ""books"": [ + {""_id"" : 10, ""title"" : ""Book 10""}, + { ""_id"" : 20, ""title"" : ""Book 20"" } + ] + }"); + Result r = collection.Add(docs1).Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); + r = collection.Add(docs2).Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); + r = collection.Add(docs3).Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); + var jsonParams = new { name = "Changed" }; + r = collection.Modify("age = :age").Patch(jsonParams). + Bind("age", 12).Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(2));//docs2 age is the string + } + + [Test, Description("GetOne with ExistingID and NewID with doc(Verify the Immutable feature also))")] + public void GetOneAndRemoveOne() + { + Assume.That(session.Version.isAtLeast(5, 7, 0), "This test is for MySql 5.7 or higher"); + var coll = CreateCollection("test"); + var docs = new[] + { + new {_id = 1, title = "Book 1", pages = 20}, + new {_id = 2, title = "Book 2", pages = 30}, + new {_id = 3, title = "Book 3", pages = 40}, + new {_id = 4, title = "Book 4", pages = 50} + }; + var r = coll.Add(docs).Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(4)); + + // Expected exceptions. + Assert.Throws(() => coll.GetOne(null)); + Assert.Throws(() => coll.GetOne("")); + Assert.Throws(() => coll.GetOne(string.Empty)); + Assert.Throws(() => coll.GetOne(" ")); + + // Get document using numeric parameter. + var document = coll.GetOne(1); + Assert.That(document.Id, Is.EqualTo(1)); + Assert.That(document["title"], Is.EqualTo("Book 1")); + Assert.That(Convert.ToInt32(document["pages"]), Is.EqualTo(20)); + + // Get document using string parameter. + document = coll.GetOne("3"); + Assert.That(document.Id, Is.EqualTo(3)); + Assert.That(document["title"], Is.EqualTo("Book 3")); + Assert.That(Convert.ToInt32(document["pages"]), Is.EqualTo(40)); + + // Get a non-existing document. + document = coll.GetOne(5); + Assert.That(document, Is.EqualTo(null)); + + coll.Add(new { _id = 5, title = "Book 5", pages = 60 }).Execute(); + Assert.That(coll.Find().Execute().FetchAll().Count, Is.EqualTo(5)); + // Remove sending numeric parameter. + //WL11843-Core API v1 alignment Changes + Assert.That(coll.RemoveOne(1).AffectedItemsCount, Is.EqualTo(1)); + Assert.That(coll.Find().Execute().FetchAll().Count, Is.EqualTo(4)); + + // Remove sending string parameter. + Assert.That(coll.RemoveOne("3").AffectedItemsCount, Is.EqualTo(1)); + Assert.That(coll.Find().Execute().FetchAll().Count, Is.EqualTo(3)); + + // Remove an auto-generated id. + document = coll.Find("pages = 60").Execute().FetchOne(); + Assert.That(coll.RemoveOne(document.Id).AffectedItemsCount, Is.EqualTo(1)); + Assert.That(coll.Find().Execute().FetchAll().Count, Is.EqualTo(2)); + + // Remove a non-existing document. + Assert.That(coll.RemoveOne(5).AffectedItemsCount, Is.EqualTo(0)); + Assert.That(coll.Find().Execute().FetchAll().Count, Is.EqualTo(2)); + + } + + [Test, Description("AddReplaceOne with unique id generated by SQL")] + public void AddReplaceOneUniqueId() + { + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); + var collection = CreateCollection("test"); + var docs = new[] + { + new {_id = 1, name = "foo"}, + new {_id = 2, name = "bar"} + }; + var result = collection.Add(docs).Execute(); + Assert.That(result.AffectedItemsCount, Is.EqualTo(2)); + + // Add unique index. + session.SQL( + "ALTER TABLE test.test ADD COLUMN name VARCHAR(3) GENERATED ALWAYS AS (JSON_UNQUOTE(JSON_EXTRACT(doc, '$.name'))) VIRTUAL UNIQUE KEY NOT NULL") + .Execute(); + Assert.Throws(() => collection.AddOrReplaceOne(1, new { name = "bar" })); + Assert.Throws(() => collection.AddOrReplaceOne(1, new { _id = 3, name = "bar", age = "55" })); + } + + #endregion WL14389 + + } +} diff --git a/MySQL.Data/tests/MySqlX.Data.Tests/CustomTypeTests.cs b/MySQL.Data/tests/MySqlX.Data.Tests/CustomTypeTests.cs index 389becd03..675529fbc 100644 --- a/MySQL.Data/tests/MySqlX.Data.Tests/CustomTypeTests.cs +++ b/MySQL.Data/tests/MySqlX.Data.Tests/CustomTypeTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2023, Oracle and/or its affiliates. +// Copyright © 2023, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -29,6 +29,7 @@ using MySqlX.XDevAPI; using MySqlX.XDevAPI.Common; using NUnit.Framework; +using NUnit.Framework.Legacy; using System; using System.Collections.Generic; using System.Threading.Tasks; @@ -85,7 +86,7 @@ private void InitCollection() Collection.Add(Data).Execute(); var count = session.SQL("SELECT COUNT(*) FROM test.test").Execute().FetchOne()[0]; - Assert.AreEqual(count, Collection.Count()); + Assert.That(Collection.Count(), Is.EqualTo(count)); } [Test] @@ -94,9 +95,9 @@ public void Find() InitCollection(); var result = Collection.Find("_id = :id").Bind("id", 1).Execute().FetchOne(); - Assert.NotNull(result); - Assert.True(typeof(CustomType).Equals(result.GetType())); - Assert.AreEqual(result.DictData["DictData1_1"].Meta, Data[1].DictData["DictData1_1"].Meta); + Assert.That(result, Is.Not.Null); + Assert.That(typeof(CustomType).Equals(result.GetType())); + Assert.That(Data[1].DictData["DictData1_1"].Meta, Is.EqualTo(result.DictData["DictData1_1"].Meta)); } [Test] @@ -105,8 +106,8 @@ public void RemoveOne() InitCollection(); var removeStmt = Collection.RemoveOne(1); - Assert.AreEqual(1, removeStmt.AffectedItemsCount); - Assert.AreEqual(19, Collection.Count()); + Assert.That(removeStmt.AffectedItemsCount, Is.EqualTo(1)); + Assert.That(Collection.Count(), Is.EqualTo(19)); } [TestCase("_id = :id","id",3)] @@ -116,8 +117,8 @@ public void Remove(string condition, string bind,object value) InitCollection(); var removeStmt = Collection.Remove(condition).Bind(bind,value).Execute(); - Assert.AreEqual(1, removeStmt.AffectedItemsCount); - Assert.AreEqual(19, Collection.Count()); + Assert.That(removeStmt.AffectedItemsCount, Is.EqualTo(1)); + Assert.That(Collection.Count(), Is.EqualTo(19)); } [Test] @@ -127,8 +128,8 @@ public void Modify() CustomType customTypeNew = new() { Date = DateTime.Now, Name = "NewDoc" }; var modifyStmt = Collection.Modify("_id = :id").Bind("id", 7).Patch(customTypeNew).Execute(); - Assert.AreEqual(1, modifyStmt.AffectedItemsCount); - Assert.AreEqual("NewDoc", Collection.GetOne(7).Name); + Assert.That(modifyStmt.AffectedItemsCount, Is.EqualTo(1)); + Assert.That(Collection.GetOne(7).Name, Is.EqualTo("NewDoc")); } [Test] @@ -138,14 +139,14 @@ public void PrepareStatement() var findStmt = Collection.Find("_id = :id and Name = :name").Bind("id", 15).Bind("name", "Name_15"); var doc = findStmt.Execute(); - Assert.AreEqual("Name_15", doc.FetchOne().Name); - Assert.False(findStmt._isPrepared); + Assert.That(doc.FetchOne().Name, Is.EqualTo("Name_15")); + Assert.That(findStmt._isPrepared, Is.False); for (int i = 0; i < Data.Length; i++) { doc = findStmt.Bind("id", i).Bind("name", $"Name_{i}").Limit(1).Execute(); - Assert.AreEqual($"Name_{i}", doc.FetchOne().Name); - Assert.True(findStmt._isPrepared || !findStmt.Session.SupportsPreparedStatements); + Assert.That(doc.FetchOne().Name, Is.EqualTo($"Name_{i}")); + Assert.That(findStmt._isPrepared || !findStmt.Session.SupportsPreparedStatements); } } @@ -181,7 +182,7 @@ public void InsertAsync() Task.WaitAll(tasksList.ToArray(), TimeSpan.FromMinutes(1)); var count = session.SQL("SELECT COUNT(*) FROM test.test").Execute().FetchOne()[0]; - Assert.AreEqual(count, Collection.Count()); + Assert.That(Collection.Count(), Is.EqualTo(count)); } } } diff --git a/MySQL.Data/tests/MySqlX.Data.Tests/DbDocTests.cs b/MySQL.Data/tests/MySqlX.Data.Tests/DbDocTests.cs index 087f0f74d..05f944bae 100644 --- a/MySQL.Data/tests/MySqlX.Data.Tests/DbDocTests.cs +++ b/MySQL.Data/tests/MySqlX.Data.Tests/DbDocTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2015, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -29,6 +29,7 @@ using MySqlX.XDevAPI; using System; using NUnit.Framework; +using NUnit.Framework.Legacy; namespace MySqlX.Data.Tests { @@ -50,7 +51,7 @@ public void SimpleConverstionToJson() ""_id"": 1, ""pages"": 20 }"; - StringAssert.AreEqualIgnoringCase(RemoveLineEndings(json), RemoveLineEndings(s)); + Assert.That(RemoveLineEndings(s), Is.EqualTo(RemoveLineEndings(json)).IgnoreCase); } [Test] @@ -60,7 +61,7 @@ public void SimpleParse() DbDoc d2 = new DbDoc(); d2.SetValue("id", 1); d2.SetValue("pages", 20); - Assert.True(d.Equals(d2)); + Assert.That(d.Equals(d2)); } [Test] @@ -73,7 +74,7 @@ public void NestedParse() d2.SetValue("id", 1); d2.SetValue("pages", 20); d2.SetValue("person", new { name = "Fred", age = 45 }); - Assert.True(d.Equals(d2)); + Assert.That(d.Equals(d2)); } [Test] @@ -111,8 +112,8 @@ public void ParseWithArray() d2.SetValue("id", 1); d2.SetValue("pages", 20); d2.SetValue("books", docs); - StringAssert.AreEqualIgnoringCase(d.ToString(), d2.ToString()); - StringAssert.AreEqualIgnoringCase(RemoveLineEndings(json), RemoveLineEndings(d2.ToString())); + Assert.That(d2.ToString(), Is.EqualTo(d.ToString()).IgnoreCase); + Assert.That(RemoveLineEndings(d2.ToString()), Is.EqualTo(RemoveLineEndings(json)).IgnoreCase); } [Test] @@ -122,7 +123,7 @@ public void ParseLongValues() DbDoc d2 = new DbDoc(); d2.SetValue("id", 1); d2.SetValue("pages", (long)int.MaxValue + 1); - Assert.True(d.Equals(d2)); + Assert.That(d.Equals(d2)); } [Test] @@ -132,7 +133,7 @@ public void ParseFloatValues() DbDoc d2 = new DbDoc(); d2.SetValue("id", 1); d2.SetValue("pi", 3.14159); - Assert.True(d.Equals(d2)); + Assert.That(d.Equals(d2)); } } } diff --git a/MySQL.Data/tests/MySqlX.Data.Tests/DnsSrvTests.cs b/MySQL.Data/tests/MySqlX.Data.Tests/DnsSrvTests.cs index 525911abf..0dfaee5e2 100644 --- a/MySQL.Data/tests/MySqlX.Data.Tests/DnsSrvTests.cs +++ b/MySQL.Data/tests/MySqlX.Data.Tests/DnsSrvTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2019, 2021, Oracle and/or its affiliates. +// Copyright © 2019, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -29,6 +29,7 @@ using MySql.Data.MySqlClient; using MySqlX.XDevAPI; using NUnit.Framework; +using NUnit.Framework.Legacy; using System; namespace MySqlX.Data.Tests @@ -38,18 +39,18 @@ namespace MySqlX.Data.Tests /// public class DnsSrvTests : BaseTest { - [TestCase("server=localhost;port=33060;dns-srv=true;", "Specifying a port number with DNS SRV lookup is not permitted.")] - [TestCase("server=localhost,10.10.10.10;dns-srv=true;", "Specifying multiple host names with DNS SRV lookup is not permitted.")] - [TestCase("host=localhost,10.10.10.10;dns-srv=TRUE;", "Specifying multiple host names with DNS SRV lookup is not permitted.")] - [TestCase("server=(address=localhost,priority=100), (address=10.10.10.10,priority=90);dns-srv=true;", "Specifying multiple host names with DNS SRV lookup is not permitted.")] - [TestCase("server=localhost;protocol=unix;Dns-Srv=true;", "Using Unix domain sockets with DNS SRV lookup is not permitted.")] - [TestCase("server=localhost;protocol=unixSocket;dns-srv=true;", "Using Unix domain sockets with DNS SRV lookup is not permitted.")] - [TestCase("server=localhost;connectionprotocol=unix;DnsSrv=true;", "Using Unix domain sockets with DNS SRV lookup is not permitted.")] + [TestCase("server=localhost;port=33060;dns-srv=true;", "Specifying a port number with DNS SRV lookup is not permitted")] + [TestCase("server=localhost,10.10.10.10;dns-srv=true;", "Specifying multiple host names with DNS SRV lookup is not permitted")] + [TestCase("host=localhost,10.10.10.10;dns-srv=TRUE;", "Specifying multiple host names with DNS SRV lookup is not permitted")] + [TestCase("server=(address=localhost,priority=100), (address=10.10.10.10,priority=90);dns-srv=true;", "Specifying multiple host names with DNS SRV lookup is not permitted")] + [TestCase("server=localhost;protocol=unix;Dns-Srv=true;", "Using Unix domain sockets with DNS SRV lookup is not permitted")] + [TestCase("server=localhost;protocol=unixSocket;dns-srv=true;", "Using Unix domain sockets with DNS SRV lookup is not permitted")] + [TestCase("server=localhost;connectionprotocol=unix;DnsSrv=true;", "Using Unix domain sockets with DNS SRV lookup is not permitted")] public void DnsSrvConnectionStringInvalidConfiguration(string connString, string exceptionMessage) { connString = connString.Replace("localhost", Host).Replace("33060", XPort); var exception = Assert.Throws(() => MySQLX.GetSession(connString)); - Assert.AreEqual(exceptionMessage, exception.Message); + Assert.That(exception.Message, Is.EqualTo(exceptionMessage)); } [TestCase("server=localhost;port=33060;dns-srv=false;uid=test;password=test;")] @@ -61,7 +62,7 @@ public void DnsSrvConnectionStringValidConfiguration(string connString) { connString = connString.Replace("localhost", Host).Replace("33060", XPort); using (var session = MySQLX.GetSession(connString)) - Assert.NotNull(session); + Assert.That(session, Is.Not.Null); } [Test] @@ -72,51 +73,51 @@ public void DnsSrvConnectionAnonymousTypeInvalidConfiguration() sb.Port = UInt32.Parse(XPort); sb.Server = Host; var exception = Assert.Throws(() => MySQLX.GetSession(sb.ConnectionString)); - Assert.AreEqual(MySql.Data.Resources.DnsSrvInvalidConnOptionPort, exception.Message); + Assert.That(exception.Message, Is.EqualTo(MySql.Data.Resources.DnsSrvInvalidConnOptionPort)); exception = Assert.Throws(() => MySQLX.GetClient(sb.ConnectionString, new { pooling = new { enabled = true } })); - Assert.AreEqual(MySql.Data.Resources.DnsSrvInvalidConnOptionPort, exception.Message); + Assert.That(exception.Message, Is.EqualTo(MySql.Data.Resources.DnsSrvInvalidConnOptionPort)); sb = new MySqlXConnectionStringBuilder(); sb.DnsSrv = true; sb.Server = $"{Host}, 10.10.10.10"; exception = Assert.Throws(() => MySQLX.GetSession(sb.ConnectionString)); - Assert.AreEqual(MySql.Data.Resources.DnsSrvInvalidConnOptionMultihost, exception.Message); + Assert.That(exception.Message, Is.EqualTo(MySql.Data.Resources.DnsSrvInvalidConnOptionMultihost)); exception = Assert.Throws(() => MySQLX.GetClient(sb.ConnectionString, new { pooling = new { enabled = true } })); - Assert.AreEqual(MySql.Data.Resources.DnsSrvInvalidConnOptionMultihost, exception.Message); + Assert.That(exception.Message, Is.EqualTo(MySql.Data.Resources.DnsSrvInvalidConnOptionMultihost)); sb = new MySqlXConnectionStringBuilder(); sb.DnsSrv = true; sb.Server = $"(address={Host},priority=100), (address=10.10.10.10,priority=90)"; exception = Assert.Throws(() => MySQLX.GetSession(sb.ConnectionString)); - Assert.AreEqual(MySql.Data.Resources.DnsSrvInvalidConnOptionMultihost, exception.Message); + Assert.That(exception.Message, Is.EqualTo(MySql.Data.Resources.DnsSrvInvalidConnOptionMultihost)); var connDataHost = new { server = $"(address={Host},priority=100), (address=10.10.10.10,priority=90)", dnssrv = true }; exception = Assert.Throws(() => MySQLX.GetClient(connDataHost, new { pooling = new { enabled = true } })); - Assert.AreEqual(MySql.Data.Resources.DnsSrvInvalidConnOptionMultihost, exception.Message); + Assert.That(exception.Message, Is.EqualTo(MySql.Data.Resources.DnsSrvInvalidConnOptionMultihost)); var connDataPort = new { server = Host, port = XPort, dnssrv = true }; exception = Assert.Throws(() => MySQLX.GetClient(connDataPort, new { pooling = new { enabled = true } })); - Assert.AreEqual(MySql.Data.Resources.DnsSrvInvalidConnOptionPort, exception.Message); + Assert.That(exception.Message, Is.EqualTo(MySql.Data.Resources.DnsSrvInvalidConnOptionPort)); var connDataUnix = new { server = Host, protocol = "unix", dnssrv = true }; exception = Assert.Throws(() => MySQLX.GetClient(connDataUnix, new { pooling = new { enabled = true } })); - Assert.AreEqual(MySql.Data.Resources.DnsSrvInvalidConnOptionUnixSocket, exception.Message); + Assert.That(exception.Message, Is.EqualTo(MySql.Data.Resources.DnsSrvInvalidConnOptionUnixSocket)); } - [TestCase("mysqlx+srv://test:test@localhost:33060", "Specifying a port number with DNS SRV lookup is not permitted.")] - [TestCase("mysqlx+srv://test:test@[192.1.10.10,localhost]", "Specifying multiple host names with DNS SRV lookup is not permitted.")] - [TestCase("mysqlx+srv://test:test@[192.1.10.10,localhost:33060]/test", "Specifying multiple host names with DNS SRV lookup is not permitted.")] - [TestCase("mysqlx+srv://test:test@[(address = server.example, priority = 50),(address = localhost:33060,priority=100)]", "Specifying multiple host names with DNS SRV lookup is not permitted.")] - [TestCase("mysqlx+srv://test:test@./tmp/mysql.sock?protocol=unix", "Using Unix domain sockets with DNS SRV lookup is not permitted.")] - [TestCase("mysqlx+srv://test:test@localhost?dns-srv=false;", "'dns-srv' cannot be set to false with DNS SRV lookup enabled.")] + [TestCase("mysqlx+srv://test:test@localhost:33060", "Specifying a port number with DNS SRV lookup is not permitted")] + [TestCase("mysqlx+srv://test:test@[192.1.10.10,localhost]", "Specifying multiple host names with DNS SRV lookup is not permitted")] + [TestCase("mysqlx+srv://test:test@[192.1.10.10,localhost:33060]/test", "Specifying multiple host names with DNS SRV lookup is not permitted")] + [TestCase("mysqlx+srv://test:test@[(address = server.example, priority = 50),(address = localhost:33060,priority=100)]", "Specifying multiple host names with DNS SRV lookup is not permitted")] + [TestCase("mysqlx+srv://test:test@./tmp/mysql.sock?protocol=unix", "Using Unix domain sockets with DNS SRV lookup is not permitted")] + [TestCase("mysqlx+srv://test:test@localhost?dns-srv=false;", "'dns-srv' cannot be set to false with DNS SRV lookup enabled")] public void DnsSrvConnectionStringUriInvalidConfiguration(string connStringUri, string exceptionMessage) { connStringUri = connStringUri.Replace("localhost", Host).Replace("33060", XPort); var exception = Assert.Throws(() => MySQLX.GetSession(connStringUri)); - Assert.AreEqual(exceptionMessage, exception.Message); + Assert.That(exception.Message, Is.EqualTo(exceptionMessage)); exception = Assert.Throws(() => MySQLX.GetClient(connStringUri, new { pooling = new { enabled = true } })); - Assert.AreEqual(exceptionMessage, exception.Message); + Assert.That(exception.Message, Is.EqualTo(exceptionMessage)); } [TestCase("mysqlx+srv://test:test@localhost")] @@ -128,7 +129,7 @@ public void DnsResolverNoHosts(string connString) { connString = connString.Replace("localhost", Host); var ex = Assert.Throws(() => MySQLX.GetSession(connString)); - Assert.AreEqual(string.Format(MySql.Data.Resources.DnsSrvNoHostsAvailable, Host), ex.Message); + Assert.That(ex.Message, Is.EqualTo(string.Format(MySql.Data.Resources.DnsSrvNoHostsAvailable, Host))); } [Test] @@ -137,8 +138,8 @@ public void DnsResolverNoHostsPooling() using (var client = MySQLX.GetClient($"mysqlx+srv://test:test@{Host}?dns-srv=true;", new { pooling = new { enabled = true } })) { var ex = Assert.Throws(() => client.GetSession()); - Assert.AreEqual(string.Format(MySql.Data.Resources.DnsSrvNoHostsAvailable, Host), ex.Message); + Assert.That(ex.Message, Is.EqualTo(string.Format(MySql.Data.Resources.DnsSrvNoHostsAvailable, Host))); } } } -} \ No newline at end of file +} diff --git a/MySQL.Data/tests/MySqlX.Data.Tests/ExprParserTests.cs b/MySQL.Data/tests/MySqlX.Data.Tests/ExprParserTests.cs index 7b7e31cf4..8553d1d55 100644 --- a/MySQL.Data/tests/MySqlX.Data.Tests/ExprParserTests.cs +++ b/MySQL.Data/tests/MySqlX.Data.Tests/ExprParserTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2015, 2022, Oracle and/or its affiliates. +// Copyright © 2015, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -34,6 +34,7 @@ using System.Collections.Generic; using System.Linq; using NUnit.Framework; +using NUnit.Framework.Legacy; namespace MySqlX.Data.Tests { @@ -97,12 +98,12 @@ private void CheckParseRoundTrip(string input, string expected) } Expr expr = new ExprParser(input).Parse(); string canonicalized = ExprUnparser.ExprToString(expr); - Assert.AreEqual(expected, canonicalized); + Assert.That(canonicalized, Is.EqualTo(expected)); // System.err.println("Canonicalized: " + canonicalized); Expr expr2 = new ExprParser(canonicalized).Parse(); string recanonicalized = ExprUnparser.ExprToString(expr2); - Assert.AreEqual(expected, recanonicalized); + Assert.That(recanonicalized, Is.EqualTo(expected)); } /** @@ -209,104 +210,104 @@ public void TestRoundTrips() public void TestExprTree() { Expr expr = new ExprParser("a like 'xyz' and $.count > 10 + 1").Parse(); - Assert.AreEqual(Expr.Types.Type.Operator, expr.Type); - Assert.AreEqual("&&", expr.Operator.Name); - Assert.AreEqual(2, expr.Operator.Param.Count); + Assert.That(expr.Type, Is.EqualTo(Expr.Types.Type.Operator)); + Assert.That(expr.Operator.Name, Is.EqualTo("&&")); + Assert.That(expr.Operator.Param.Count, Is.EqualTo(2)); // check left side of AND: (a like 'xyz') Expr andLeft = expr.Operator.Param[0]; - Assert.AreEqual(Expr.Types.Type.Operator, andLeft.Type); - Assert.AreEqual("like", andLeft.Operator.Name); - Assert.AreEqual(2, andLeft.Operator.Param.Count); + Assert.That(andLeft.Type, Is.EqualTo(Expr.Types.Type.Operator)); + Assert.That(andLeft.Operator.Name, Is.EqualTo("like")); + Assert.That(andLeft.Operator.Param.Count, Is.EqualTo(2)); Expr identA = andLeft.Operator.Param[0]; - Assert.AreEqual(Expr.Types.Type.Ident, identA.Type); - Assert.AreEqual("a", identA.Identifier.Name); + Assert.That(identA.Type, Is.EqualTo(Expr.Types.Type.Ident)); + Assert.That(identA.Identifier.Name, Is.EqualTo("a")); Expr literalXyz = andLeft.Operator.Param[1]; - Assert.AreEqual(Expr.Types.Type.Literal, literalXyz.Type); + Assert.That(literalXyz.Type, Is.EqualTo(Expr.Types.Type.Literal)); Scalar scalarXyz = literalXyz.Literal; - Assert.AreEqual(Scalar.Types.Type.VString, scalarXyz.Type); - Assert.AreEqual("xyz", scalarXyz.VString.Value.ToStringUtf8()); + Assert.That(scalarXyz.Type, Is.EqualTo(Scalar.Types.Type.VString)); + Assert.That(scalarXyz.VString.Value.ToStringUtf8(), Is.EqualTo("xyz")); // check right side of AND: ($.count > 10 + 1) Expr andRight = expr.Operator.Param[1]; - Assert.AreEqual(Expr.Types.Type.Operator, andRight.Type); - Assert.AreEqual(">", andRight.Operator.Name); - Assert.AreEqual(2, andRight.Operator.Param.Count); + Assert.That(andRight.Type, Is.EqualTo(Expr.Types.Type.Operator)); + Assert.That(andRight.Operator.Name, Is.EqualTo(">")); + Assert.That(andRight.Operator.Param.Count, Is.EqualTo(2)); Expr countDocPath = andRight.Operator.Param[0]; - Assert.AreEqual(Expr.Types.Type.Ident, countDocPath.Type); + Assert.That(countDocPath.Type, Is.EqualTo(Expr.Types.Type.Ident)); ColumnIdentifier countId = countDocPath.Identifier; - Assert.AreEqual(string.Empty, countId.Name); - Assert.AreEqual(string.Empty, countId.TableName); - Assert.AreEqual(string.Empty, countId.SchemaName); + Assert.That(countId.Name, Is.EqualTo(string.Empty)); + Assert.That(countId.TableName, Is.EqualTo(string.Empty)); + Assert.That(countId.SchemaName, Is.EqualTo(string.Empty)); Assert.That(countId.DocumentPath.Count==1); - Assert.AreEqual(DocumentPathItem.Types.Type.Member, countId.DocumentPath[0].Type); - Assert.AreEqual("count", countId.DocumentPath[0].Value); + Assert.That(countId.DocumentPath[0].Type, Is.EqualTo(DocumentPathItem.Types.Type.Member)); + Assert.That(countId.DocumentPath[0].Value, Is.EqualTo("count")); Expr addition = andRight.Operator.Param[1]; Scalar addLeftScalar = addition.Operator.Param[0].Literal; Scalar addRightScalar = addition.Operator.Param[1].Literal; - Assert.AreEqual(Expr.Types.Type.Operator, addition.Type); - Assert.AreEqual("+", addition.Operator.Name); - Assert.AreEqual(2, addition.Operator.Param.Count); - Assert.AreEqual(Expr.Types.Type.Literal, addition.Operator.Param[0].Type); - Assert.AreEqual(Expr.Types.Type.Literal, addition.Operator.Param[1].Type); - Assert.AreEqual(Scalar.Types.Type.VSint, addLeftScalar.Type); - Assert.AreEqual(Scalar.Types.Type.VSint, addRightScalar.Type); - Assert.AreEqual(10, addLeftScalar.VSignedInt); - Assert.AreEqual(1, addRightScalar.VSignedInt); + Assert.That(addition.Type, Is.EqualTo(Expr.Types.Type.Operator)); + Assert.That(addition.Operator.Name, Is.EqualTo("+")); + Assert.That(addition.Operator.Param.Count, Is.EqualTo(2)); + Assert.That(addition.Operator.Param[0].Type, Is.EqualTo(Expr.Types.Type.Literal)); + Assert.That(addition.Operator.Param[1].Type, Is.EqualTo(Expr.Types.Type.Literal)); + Assert.That(addLeftScalar.Type, Is.EqualTo(Scalar.Types.Type.VSint)); + Assert.That(addRightScalar.Type, Is.EqualTo(Scalar.Types.Type.VSint)); + Assert.That(addLeftScalar.VSignedInt, Is.EqualTo(10)); + Assert.That(addRightScalar.VSignedInt, Is.EqualTo(1)); } [Test] public void TestOrderByParserBasic() { List orderSpec = new ExprParser("a, b desc").ParseOrderSpec(); - Assert.AreEqual(2, orderSpec.Count); + Assert.That(orderSpec.Count, Is.EqualTo(2)); Order o1 = orderSpec[0]; - Assert.False(o1.HasDirection); - Assert.AreEqual("a", ExprUnparser.ExprToString(o1.Expr)); + Assert.That(o1.HasDirection, Is.False); + Assert.That(ExprUnparser.ExprToString(o1.Expr), Is.EqualTo("a")); Order o2 = orderSpec[1]; - Assert.True(o2.HasDirection); - Assert.AreEqual(Order.Types.Direction.Desc, o2.Direction); - Assert.AreEqual("b", ExprUnparser.ExprToString(o2.Expr)); + Assert.That(o2.HasDirection); + Assert.That(o2.Direction, Is.EqualTo(Order.Types.Direction.Desc)); + Assert.That(ExprUnparser.ExprToString(o2.Expr), Is.EqualTo("b")); } [Test] public void TestOrderByParserComplexExpressions() { List orderSpec = new ExprParser("field not in ('a',func('b', 2.0),'c') desc, 1-a$**[0].*, now () + $.b + c > 2 asc").ParseOrderSpec(); - Assert.AreEqual(3, orderSpec.Count); + Assert.That(orderSpec.Count, Is.EqualTo(3)); Order o1 = orderSpec[0]; - Assert.True(o1.HasDirection); - Assert.AreEqual(Order.Types.Direction.Desc, o1.Direction); - Assert.AreEqual("field not in(\"a\", func(\"b\", 2), \"c\")", ExprUnparser.ExprToString(o1.Expr)); + Assert.That(o1.HasDirection); + Assert.That(o1.Direction, Is.EqualTo(Order.Types.Direction.Desc)); + Assert.That(ExprUnparser.ExprToString(o1.Expr), Is.EqualTo("field not in(\"a\", func(\"b\", 2), \"c\")")); Order o2 = orderSpec[1]; - Assert.False(o2.HasDirection); - Assert.AreEqual("(1 - a$**[0].*)", ExprUnparser.ExprToString(o2.Expr)); + Assert.That(o2.HasDirection, Is.False); + Assert.That(ExprUnparser.ExprToString(o2.Expr), Is.EqualTo("(1 - a$**[0].*)")); Order o3 = orderSpec[2]; - Assert.True(o3.HasDirection); - Assert.AreEqual(Order.Types.Direction.Asc, o3.Direction); - Assert.AreEqual("(((now() + $.b) + c) > 2)", ExprUnparser.ExprToString(o3.Expr)); + Assert.That(o3.HasDirection); + Assert.That(o3.Direction, Is.EqualTo(Order.Types.Direction.Asc)); + Assert.That(ExprUnparser.ExprToString(o3.Expr), Is.EqualTo("(((now() + $.b) + c) > 2)")); } [Test] public void TestNamedPlaceholders() { ExprParser parser = new ExprParser("a = :a and b = :b and (c = 'x' or d = :b)"); - Assert.AreEqual("IDENT(a)", parser.tokens[0].ToString()); - Assert.AreEqual("EQ", parser.tokens[1].ToString()); + Assert.That(parser.tokens[0].ToString(), Is.EqualTo("IDENT(a)")); + Assert.That(parser.tokens[1].ToString(), Is.EqualTo("EQ")); Expr e = parser.Parse(); - Assert.AreEqual(0, parser.placeholderNameToPosition["a"]); - Assert.AreEqual(1, parser.placeholderNameToPosition["b"]); - Assert.AreEqual(2, parser.positionalPlaceholderCount); + Assert.That(parser.placeholderNameToPosition["a"], Is.EqualTo(0)); + Assert.That(parser.placeholderNameToPosition["b"], Is.EqualTo(1)); + Assert.That(parser.positionalPlaceholderCount, Is.EqualTo(2)); Expr aEqualsPlaceholder = e.Operator.Param[0].Operator.Param[0].Operator.Param[1]; - Assert.AreEqual(Expr.Types.Type.Placeholder, aEqualsPlaceholder.Type); - Assert.AreEqual((uint)0, aEqualsPlaceholder.Position); + Assert.That(aEqualsPlaceholder.Type, Is.EqualTo(Expr.Types.Type.Placeholder)); + Assert.That(aEqualsPlaceholder.Position, Is.EqualTo((uint)0)); Expr bEqualsPlaceholder = e.Operator.Param[0].Operator.Param[1].Operator.Param[1]; - Assert.AreEqual(Expr.Types.Type.Placeholder, bEqualsPlaceholder.Type); - Assert.AreEqual((uint)1, bEqualsPlaceholder.Position); + Assert.That(bEqualsPlaceholder.Type, Is.EqualTo(Expr.Types.Type.Placeholder)); + Assert.That(bEqualsPlaceholder.Position, Is.EqualTo((uint)1)); Expr dEqualsPlaceholder = e.Operator.Param[1].Operator.Param[1].Operator.Param[1]; - Assert.AreEqual(Expr.Types.Type.Placeholder, dEqualsPlaceholder.Type); - Assert.AreEqual((uint)1, dEqualsPlaceholder.Position); + Assert.That(dEqualsPlaceholder.Type, Is.EqualTo(Expr.Types.Type.Placeholder)); + Assert.That(dEqualsPlaceholder.Position, Is.EqualTo((uint)1)); } [Test] @@ -314,23 +315,23 @@ public void TestNumberedPlaceholders() { ExprParser parser = new ExprParser("a == :1 and b == :3 and (c == :2 or d == :2)"); Expr e = parser.Parse(); - Assert.AreEqual(0, parser.placeholderNameToPosition["1"]); - Assert.AreEqual(1, parser.placeholderNameToPosition["3"]); - Assert.AreEqual(2, parser.placeholderNameToPosition["2"]); - Assert.AreEqual(3, parser.positionalPlaceholderCount); + Assert.That(parser.placeholderNameToPosition["1"], Is.EqualTo(0)); + Assert.That(parser.placeholderNameToPosition["3"], Is.EqualTo(1)); + Assert.That(parser.placeholderNameToPosition["2"], Is.EqualTo(2)); + Assert.That(parser.positionalPlaceholderCount, Is.EqualTo(3)); Expr aEqualsPlaceholder = e.Operator.Param[0].Operator.Param[0].Operator.Param[1]; - Assert.AreEqual(Expr.Types.Type.Placeholder, aEqualsPlaceholder.Type); - Assert.AreEqual((uint)0, aEqualsPlaceholder.Position); + Assert.That(aEqualsPlaceholder.Type, Is.EqualTo(Expr.Types.Type.Placeholder)); + Assert.That(aEqualsPlaceholder.Position, Is.EqualTo((uint)0)); Expr bEqualsPlaceholder = e.Operator.Param[0].Operator.Param[1].Operator.Param[1]; - Assert.AreEqual(Expr.Types.Type.Placeholder, bEqualsPlaceholder.Type); - Assert.AreEqual((uint)1, bEqualsPlaceholder.Position); + Assert.That(bEqualsPlaceholder.Type, Is.EqualTo(Expr.Types.Type.Placeholder)); + Assert.That(bEqualsPlaceholder.Position, Is.EqualTo((uint)1)); Expr cEqualsPlaceholder = e.Operator.Param[1].Operator.Param[0].Operator.Param[1]; - Assert.AreEqual(Expr.Types.Type.Placeholder, cEqualsPlaceholder.Type); - Assert.AreEqual((uint)2, cEqualsPlaceholder.Position); + Assert.That(cEqualsPlaceholder.Type, Is.EqualTo(Expr.Types.Type.Placeholder)); + Assert.That(cEqualsPlaceholder.Position, Is.EqualTo((uint)2)); Expr dEqualsPlaceholder = e.Operator.Param[1].Operator.Param[1].Operator.Param[1]; - Assert.AreEqual(Expr.Types.Type.Placeholder, dEqualsPlaceholder.Type); - Assert.AreEqual((uint)2, dEqualsPlaceholder.Position); + Assert.That(dEqualsPlaceholder.Type, Is.EqualTo(Expr.Types.Type.Placeholder)); + Assert.That(dEqualsPlaceholder.Position, Is.EqualTo((uint)2)); } [Test] @@ -338,20 +339,20 @@ public void TestUnnumberedPlaceholders() { ExprParser parser = new ExprParser("a = ? and b = ? and (c = 'x' or d = ?)"); Expr e = parser.Parse(); - Assert.AreEqual(0, parser.placeholderNameToPosition["0"]); - Assert.AreEqual(1, parser.placeholderNameToPosition["1"]); - Assert.AreEqual(2, parser.placeholderNameToPosition["2"]); - Assert.AreEqual(3, parser.positionalPlaceholderCount); + Assert.That(parser.placeholderNameToPosition["0"], Is.EqualTo(0)); + Assert.That(parser.placeholderNameToPosition["1"], Is.EqualTo(1)); + Assert.That(parser.placeholderNameToPosition["2"], Is.EqualTo(2)); + Assert.That(parser.positionalPlaceholderCount, Is.EqualTo(3)); Expr aEqualsPlaceholder = e.Operator.Param[0].Operator.Param[0].Operator.Param[1]; - Assert.AreEqual(Expr.Types.Type.Placeholder, aEqualsPlaceholder.Type); - Assert.AreEqual((uint)0, aEqualsPlaceholder.Position); + Assert.That(aEqualsPlaceholder.Type, Is.EqualTo(Expr.Types.Type.Placeholder)); + Assert.That(aEqualsPlaceholder.Position, Is.EqualTo((uint)0)); Expr bEqualsPlaceholder = e.Operator.Param[0].Operator.Param[1].Operator.Param[1]; - Assert.AreEqual(Expr.Types.Type.Placeholder, bEqualsPlaceholder.Type); - Assert.AreEqual((uint)1, bEqualsPlaceholder.Position); + Assert.That(bEqualsPlaceholder.Type, Is.EqualTo(Expr.Types.Type.Placeholder)); + Assert.That(bEqualsPlaceholder.Position, Is.EqualTo((uint)1)); Expr dEqualsPlaceholder = e.Operator.Param[1].Operator.Param[1].Operator.Param[1]; - Assert.AreEqual(Expr.Types.Type.Placeholder, dEqualsPlaceholder.Type); - Assert.AreEqual((uint)2, dEqualsPlaceholder.Position); + Assert.That(dEqualsPlaceholder.Type, Is.EqualTo(Expr.Types.Type.Placeholder)); + Assert.That(dEqualsPlaceholder.Position, Is.EqualTo((uint)2)); } [Test] @@ -359,24 +360,24 @@ public void TestJsonLiteral() { Expr e = new ExprParser("{'a':1, 'b':\"a string\"}").Parse(); - Assert.AreEqual("{'a':1, 'b':\"a string\"}", ExprUnparser.ExprToString(e)); + Assert.That(ExprUnparser.ExprToString(e), Is.EqualTo("{'a':1, 'b':\"a string\"}")); - Assert.AreEqual(Expr.Types.Type.Object, e.Type); + Assert.That(e.Type, Is.EqualTo(Expr.Types.Type.Object)); Mysqlx.Expr.Object o = e.Object; - Assert.AreEqual(2, o.Fld.Count); + Assert.That(o.Fld.Count, Is.EqualTo(2)); Mysqlx.Expr.Object.Types.ObjectField of; of = o.Fld[0]; - Assert.AreEqual("a", of.Key); + Assert.That(of.Key, Is.EqualTo("a")); e = of.Value; - Assert.AreEqual(Expr.Types.Type.Literal, e.Type); - Assert.AreEqual(1, e.Literal.VSignedInt); + Assert.That(e.Type, Is.EqualTo(Expr.Types.Type.Literal)); + Assert.That(e.Literal.VSignedInt, Is.EqualTo(1)); of = o.Fld[1]; - Assert.AreEqual("b", of.Key); + Assert.That(of.Key, Is.EqualTo("b")); e = of.Value; - Assert.AreEqual(Expr.Types.Type.Literal, e.Type); - Assert.AreEqual("a string", e.Literal.VString.Value.ToStringUtf8()); + Assert.That(e.Type, Is.EqualTo(Expr.Types.Type.Literal)); + Assert.That(e.Literal.VString.Value.ToStringUtf8(), Is.EqualTo("a string")); } [Test] @@ -386,8 +387,8 @@ public void TestTrivialDocumentProjection() proj = new ExprParser("$.a as a").ParseDocumentProjection(); Assert.That(proj, Has.One.Items); - Assert.AreNotEqual(string.Empty, proj[0].Alias); - Assert.AreEqual("a", proj[0].Alias); + Assert.That(proj[0].Alias, Is.Not.EqualTo(string.Empty)); + Assert.That(proj[0].Alias, Is.EqualTo("a")); proj = new ExprParser("$.a as a, $.b as b, $.c as c").ParseDocumentProjection(); } @@ -397,26 +398,26 @@ public void TestExprAsPathDocumentProjection() { List projList = new ExprParser("$.a as b, (1 + 1) * 100 as x, 2 as j42").ParseDocumentProjection(); - Assert.AreEqual(3, projList.Count); + Assert.That(projList.Count, Is.EqualTo(3)); // check $.a as b Projection proj = projList[0]; IList paths = proj.Source.Identifier.DocumentPath; - Assert.AreEqual(1, paths.Count); - Assert.AreEqual(DocumentPathItem.Types.Type.Member, paths[0].Type); - Assert.AreEqual("a", paths[0].Value); + Assert.That(paths.Count, Is.EqualTo(1)); + Assert.That(paths[0].Type, Is.EqualTo(DocumentPathItem.Types.Type.Member)); + Assert.That(paths[0].Value, Is.EqualTo("a")); - Assert.AreEqual("b", proj.Alias); + Assert.That(proj.Alias, Is.EqualTo("b")); // check (1 + 1) * 100 as x proj = projList[1]; - Assert.AreEqual("((1 + 1) * 100)", ExprUnparser.ExprToString(proj.Source)); - Assert.AreEqual("x", proj.Alias); + Assert.That(ExprUnparser.ExprToString(proj.Source), Is.EqualTo("((1 + 1) * 100)")); + Assert.That(proj.Alias, Is.EqualTo("x")); // check 2 as j42 proj = projList[2]; - Assert.AreEqual("2", ExprUnparser.ExprToString(proj.Source)); - Assert.AreEqual("j42", proj.Alias); + Assert.That(ExprUnparser.ExprToString(proj.Source), Is.EqualTo("2")); + Assert.That(proj.Alias, Is.EqualTo("j42")); } [Test] @@ -426,7 +427,7 @@ public void TestJsonConstructorAsDocumentProjection() string projString = "{'a':'value for a', 'b':1+1, 'c'::bindvar, 'd':$.member[22], 'e':{'nested':'doc'}}"; Projection proj = new Projection(); proj.Source = new ExprParser(projString, false).Parse(); - Assert.AreEqual(Expr.Types.Type.Object, proj.Source.Type); + Assert.That(proj.Source.Type, Is.EqualTo(Expr.Types.Type.Object)); IEnumerator fields = proj.Source.Object.Fld.GetEnumerator(); string[][] array = new string[][] { @@ -439,10 +440,10 @@ public void TestJsonConstructorAsDocumentProjection() { fields.MoveNext(); Mysqlx.Expr.Object.Types.ObjectField f = fields.Current; - Assert.AreEqual(pair[0], f.Key); - Assert.AreEqual(pair[1], ExprUnparser.ExprToString(f.Value)); + Assert.That(f.Key, Is.EqualTo(pair[0])); + Assert.That(ExprUnparser.ExprToString(f.Value), Is.EqualTo(pair[1])); }); - Assert.False(fields.MoveNext()); + Assert.That(fields.MoveNext(), Is.False); } [Test] @@ -451,7 +452,7 @@ public void TestJsonExprsInDocumentProjection() // this is not a single doc as the project but multiple docs as embedded fields string projString = "{'a':1} as a, {'b':2} as b"; List projList = new ExprParser(projString).ParseDocumentProjection(); - Assert.AreEqual(2, projList.Count); + Assert.That(projList.Count, Is.EqualTo(2)); // TODO: verification of remaining elements } @@ -459,10 +460,10 @@ public void TestJsonExprsInDocumentProjection() public void TestTableInsertProjection() { Column col = new ExprParser("a").ParseTableInsertField(); - Assert.AreEqual("a", col.Name); + Assert.That(col.Name, Is.EqualTo("a")); col = new ExprParser("`double weird `` string`").ParseTableInsertField(); - Assert.AreEqual("double weird ` string", col.Name); + Assert.That(col.Name, Is.EqualTo("double weird ` string")); } [Test] @@ -470,45 +471,45 @@ public void TestTableUpdateField() { ColumnIdentifier col; col = new ExprParser("a").ParseTableUpdateField(); - Assert.AreEqual("a", col.Name); + Assert.That(col.Name, Is.EqualTo("a")); col = new ExprParser("b.c").ParseTableUpdateField(); - Assert.AreEqual("b", col.TableName); - Assert.AreEqual("c", col.Name); + Assert.That(col.TableName, Is.EqualTo("b")); + Assert.That(col.Name, Is.EqualTo("c")); col = new ExprParser("d.e$.the_path[2]").ParseTableUpdateField(); - Assert.AreEqual("d", col.TableName); - Assert.AreEqual("e", col.Name); - Assert.AreEqual(2, col.DocumentPath.Count); - Assert.AreEqual("the_path", col.DocumentPath[0].Value); - Assert.AreEqual((uint)2, col.DocumentPath[1].Index); + Assert.That(col.TableName, Is.EqualTo("d")); + Assert.That(col.Name, Is.EqualTo("e")); + Assert.That(col.DocumentPath.Count, Is.EqualTo(2)); + Assert.That(col.DocumentPath[0].Value, Is.EqualTo("the_path")); + Assert.That(col.DocumentPath[1].Index, Is.EqualTo((uint)2)); col = new ExprParser("`zzz\\``").ParseTableUpdateField(); - Assert.AreEqual("zzz`", col.Name); + Assert.That(col.Name, Is.EqualTo("zzz`")); } [Test] public void TestTrivialTableSelectProjection() { List proj = new ExprParser("a, b as c").ParseTableSelectProjection(); - Assert.AreEqual(2, proj.Count); - Assert.AreEqual("a", ExprUnparser.ExprToString(proj[0].Source)); - Assert.AreEqual(string.Empty, proj[0].Alias); - Assert.AreEqual("b", ExprUnparser.ExprToString(proj[1].Source)); - Assert.AreNotEqual(string.Empty, proj[1].Alias); - Assert.AreEqual("c", proj[1].Alias); + Assert.That(proj.Count, Is.EqualTo(2)); + Assert.That(ExprUnparser.ExprToString(proj[0].Source), Is.EqualTo("a")); + Assert.That(proj[0].Alias, Is.EqualTo(string.Empty)); + Assert.That(ExprUnparser.ExprToString(proj[1].Source), Is.EqualTo("b")); + Assert.That(proj[1].Alias, Is.Not.EqualTo(string.Empty)); + Assert.That(proj[1].Alias, Is.EqualTo("c")); } [Test] public void TestStarTableSelectProjection() { List proj = new ExprParser("*, b as c").ParseTableSelectProjection(); - Assert.AreEqual(2, proj.Count); - Assert.AreEqual("*", ExprUnparser.ExprToString(proj[0].Source)); - Assert.AreEqual(string.Empty, proj[0].Alias); - Assert.AreEqual("b", ExprUnparser.ExprToString(proj[1].Source)); - Assert.AreNotEqual(string.Empty, proj[1].Alias); - Assert.AreEqual("c", proj[1].Alias); + Assert.That(proj.Count, Is.EqualTo(2)); + Assert.That(ExprUnparser.ExprToString(proj[0].Source), Is.EqualTo("*")); + Assert.That(proj[0].Alias, Is.EqualTo(string.Empty)); + Assert.That(ExprUnparser.ExprToString(proj[1].Source), Is.EqualTo("b")); + Assert.That(proj[1].Alias, Is.Not.EqualTo(string.Empty)); + Assert.That(proj[1].Alias, Is.EqualTo("c")); } [Test] @@ -516,13 +517,13 @@ public void TestComplexTableSelectProjection() { string projectionString = "(1 + 1) * 100 as `one-o-two`, 'a is \\'a\\'' as `what is 'a'`"; List proj = new ExprParser(projectionString).ParseTableSelectProjection(); - Assert.AreEqual(2, proj.Count); + Assert.That(proj.Count, Is.EqualTo(2)); - Assert.AreEqual("((1 + 1) * 100)", ExprUnparser.ExprToString(proj[0].Source)); - Assert.AreEqual("one-o-two", proj[0].Alias); + Assert.That(ExprUnparser.ExprToString(proj[0].Source), Is.EqualTo("((1 + 1) * 100)")); + Assert.That(proj[0].Alias, Is.EqualTo("one-o-two")); - Assert.AreEqual("a is 'a'", proj[1].Source.Literal.VString.Value.ToStringUtf8()); - Assert.AreEqual("what is 'a'", proj[1].Alias); + Assert.That(proj[1].Source.Literal.VString.Value.ToStringUtf8(), Is.EqualTo("a is 'a'")); + Assert.That(proj[1].Alias, Is.EqualTo("what is 'a'")); } [Test] @@ -539,13 +540,13 @@ public void TestRandom() public void UnqualifiedDocPaths() { Expr expr = new ExprParser("1 + b[0]", false).Parse(); - Assert.AreEqual("(1 + $.b[0])", ExprUnparser.ExprToString(expr)); + Assert.That(ExprUnparser.ExprToString(expr), Is.EqualTo("(1 + $.b[0])")); expr = new ExprParser("a.*", false).Parse(); - Assert.AreEqual("$.a.*", ExprUnparser.ExprToString(expr)); + Assert.That(ExprUnparser.ExprToString(expr), Is.EqualTo("$.a.*")); expr = new ExprParser("bL . vT .*", false).Parse(); - Assert.AreEqual("$.bL.vT.*", ExprUnparser.ExprToString(expr)); + Assert.That(ExprUnparser.ExprToString(expr), Is.EqualTo("$.bL.vT.*")); expr = new ExprParser("dd ** .X", false).Parse(); - Assert.AreEqual("$.dd**.X", ExprUnparser.ExprToString(expr)); + Assert.That(ExprUnparser.ExprToString(expr), Is.EqualTo("$.dd**.X")); } [TestCase("info$.additionalinfo.hobbies", "info$.additionalinfo.hobbies", true)] @@ -559,13 +560,12 @@ public void JsonColumnPath(string exprString, string unparserString, bool isRela { if(unparserString == null) { - Assert.AreEqual($"Unable to parse query '{exprString}'", - Assert.Throws(() => new ExprParser(exprString, isRelational).Parse()).Message); + Assert.That(Assert.Throws(() => new ExprParser(exprString, isRelational).Parse()).Message, Is.EqualTo($"Unable to parse query '{exprString}'")); } else { Expr expr = new ExprParser(exprString, isRelational).Parse(); - Assert.AreEqual(unparserString, ExprUnparser.ExprToString(expr)); + Assert.That(ExprUnparser.ExprToString(expr), Is.EqualTo(unparserString)); } } } diff --git a/MySQL.Data/tests/MySqlX.Data.Tests/GenericListener.cs b/MySQL.Data/tests/MySqlX.Data.Tests/GenericListener.cs index 1d9cf00bb..b12077da7 100644 --- a/MySQL.Data/tests/MySqlX.Data.Tests/GenericListener.cs +++ b/MySQL.Data/tests/MySqlX.Data.Tests/GenericListener.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/tests/MySqlX.Data.Tests/JsonParserTests.cs b/MySQL.Data/tests/MySqlX.Data.Tests/JsonParserTests.cs index 6d37b92bf..c9ee9d1fb 100644 --- a/MySQL.Data/tests/MySqlX.Data.Tests/JsonParserTests.cs +++ b/MySQL.Data/tests/MySqlX.Data.Tests/JsonParserTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2017, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -31,6 +31,7 @@ using System; using System.Collections.Generic; using NUnit.Framework; +using NUnit.Framework.Legacy; namespace MySqlX.Data.Tests { @@ -43,21 +44,21 @@ public void ParseBooleanValue() DbDoc document = new DbDoc(@"{ ""_id"": 1, ""isDocument"": true }"); Result result = ExecuteAddStatement(collection.Add(document)); - Assert.AreEqual(1, result.AffectedItemsCount); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1)); document = collection.GetOne(1); - Assert.True(document.values.ContainsKey("isDocument")); - Assert.True((bool) document.values["isDocument"]); + Assert.That(document.values.ContainsKey("isDocument")); + Assert.That((bool) document.values["isDocument"]); document = new DbDoc(new { _id=2, isDocument=false }); result = ExecuteAddStatement(collection.Add(document)); - Assert.AreEqual(1, result.AffectedItemsCount); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1)); document = collection.GetOne(2); - Assert.True(document.values.ContainsKey("isDocument")); - Assert.False((bool) document.values["isDocument"]); + Assert.That(document.values.ContainsKey("isDocument")); + Assert.That((bool) document.values["isDocument"], Is.False); - Assert.True(ExecuteFindStatement(collection.Find("isDocument = false")).FetchAll().Count > 0); + Assert.That(ExecuteFindStatement(collection.Find("isDocument = false")).FetchAll().Count > 0); } [Test] @@ -67,11 +68,11 @@ public void ParseNullValue() DbDoc document = new DbDoc(@"{ ""isDocument"": null }"); Result result = ExecuteAddStatement(collection.Add(document)); - Assert.AreEqual(1, result.AffectedItemsCount); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1)); document = ExecuteFindStatement(collection.Find()).FetchOne(); - Assert.True(document.values.ContainsKey("isDocument")); - Assert.Null(document.values["isDocument"]); + Assert.That(document.values.ContainsKey("isDocument")); + Assert.That(document.values["isDocument"], Is.Null); } [Test] @@ -81,11 +82,11 @@ public void ParseNumberArray() DbDoc document = new DbDoc(@"{ ""id"": 1, ""list"": [1,2,3] }"); Result result = ExecuteAddStatement(collection.Add(document)); - Assert.AreEqual(1, result.AffectedItemsCount); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1)); document = ExecuteFindStatement(collection.Find()).FetchOne(); - Assert.True(document.values.ContainsKey("list")); - Assert.AreEqual(new object[] { 1, 2, 3 }, document.values["list"]); + Assert.That(document.values.ContainsKey("list")); + Assert.That(document.values["list"], Is.EqualTo(new object[] { 1, 2, 3 })); } [Test] @@ -96,11 +97,11 @@ public void ParsObjectArray() DbDoc document = new DbDoc(@"{ ""id"": 1, ""list"": [1,""a""] }"); //DbDoc document = new DbDoc(@"{ ""id"": 1, ""list"": [1,""a"",true,null] }"); Result result = ExecuteAddStatement(collection.Add(document)); - Assert.AreEqual(1, result.AffectedItemsCount); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1)); document = ExecuteFindStatement(collection.Find()).FetchOne(); - Assert.True(document.values.ContainsKey("list")); - Assert.AreEqual(new object[] { 1, "a" }, document.values["list"]); + Assert.That(document.values.ContainsKey("list")); + Assert.That(document.values["list"], Is.EqualTo(new object[] { 1, "a" })); //Assert.AreEqual(new object[] { 1, "a", true, null }, document.values["list"]); } @@ -111,13 +112,13 @@ public void ParseGroupsEmbededInArrays() //DbDoc document = new DbDoc(@"{ ""id"": 1, ""list"": [1,""a"",true,null] }"); Collection collection = CreateCollection("test"); Result result = ExecuteAddStatement(collection.Add(document)); - Assert.AreEqual(1, result.AffectedItemsCount); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1)); document = ExecuteFindStatement(collection.Find()).FetchOne(); - Assert.True(document.values.ContainsKey("list")); + Assert.That(document.values.ContainsKey("list")); var dictionary = new Dictionary(); dictionary.Add("b",1); - Assert.AreEqual(new object[] { 1, "a", dictionary }, document.values["list"]); + Assert.That(document.values["list"], Is.EqualTo(new object[] { 1, "a", dictionary })); //Assert.AreEqual(new object[] { 1, "a", true, null, dictionary }, document.values["list"]); } @@ -139,19 +140,19 @@ public void ParseWithEscapedQuotes() var document = collection.GetOne("123"); var innerEmail = ((document["email"] as object[])[1]) as Dictionary; - Assert.AreEqual("[\\\"ALICE@ORA.COM\\\"]", innerEmail["email"]); + Assert.That(innerEmail["email"], Is.EqualTo("[\\\"ALICE@ORA.COM\\\"]")); innerEmail = ((document["email"] as object[])[2]) as Dictionary; - Assert.AreEqual("ALICE@ORA.COM", innerEmail["email"]); + Assert.That(innerEmail["email"], Is.EqualTo("ALICE@ORA.COM")); ExecuteAddStatement(collection.Add("{ \"_id\": \"124\", \"email\": \"\\\"\" }")); document = collection.GetOne("124"); - Assert.AreEqual("\\\"", document["email"]); + Assert.That(document["email"], Is.EqualTo("\\\"")); var ex = Assert.Throws(() => ExecuteAddStatement(collection.Add("{ \"_id\": \"124\", \"email\": \"\"\" }"))); - Assert.AreEqual("The value provided is not a valid JSON document. Expected token ','", ex.Message); + Assert.That(ex.Message, Is.EqualTo("The value provided is not a valid JSON document. Expected token ','")); ex = Assert.Throws(() => ExecuteAddStatement(collection.Add("{ \"_id\": \"124\", \"email\": \"\\\" }"))); - Assert.AreEqual("The value provided is not a valid JSON document. Failed to find ending '\"' while reading stream.", ex.Message); + Assert.That(ex.Message, Is.EqualTo("The value provided is not a valid JSON document. Failed to find ending '\"' while reading stream.")); } } } diff --git a/MySQL.Data/tests/MySqlX.Data.Tests/MergePatch.cs b/MySQL.Data/tests/MySqlX.Data.Tests/MergePatch.cs index 26ab3a5d4..63d3093e9 100644 --- a/MySQL.Data/tests/MySqlX.Data.Tests/MergePatch.cs +++ b/MySQL.Data/tests/MySqlX.Data.Tests/MergePatch.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2017, 2021, Oracle and/or its affiliates. +// Copyright © 2017, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -32,6 +32,7 @@ using System; using System.Collections.Generic; using NUnit.Framework; +using NUnit.Framework.Legacy; namespace MySqlX.Data.Tests { @@ -133,35 +134,35 @@ public void PatchExpectedExceptions() [Test] public void SimplePatch() { - if (!session.InternalSession.GetServerVersion().isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher"); + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); Collection collection = CreateCollection("test"); Result r = ExecuteAddStatement(collection.Add("{ \"_id\": \"123\", \"email\": \"alice@ora.com\", \"startDate\": \"4/1/2017\" }")); - Assert.AreEqual(1, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); r = ExecuteAddStatement(collection.Add("{ \"_id\": \"124\", \"email\": \"jose@ora.com\", \"startDate\": \"4/1/2017\" }")); - Assert.AreEqual(1, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); ExecuteModifyStatement(collection.Modify("email = \"alice@ora.com\"").Patch("{ \"_id\": \"123\", \"email\":\"bob@ora.com\", \"startDate\":null }")); DbDoc document = collection.GetOne("123"); - Assert.AreEqual("123", document.Id); - Assert.AreEqual("bob@ora.com", document.values["email"]); - Assert.True(!document.values.ContainsKey("startDate")); + Assert.That(document.Id, Is.EqualTo("123")); + Assert.That(document.values["email"], Is.EqualTo("bob@ora.com")); + Assert.That(!document.values.ContainsKey("startDate")); document = collection.GetOne("124"); - Assert.AreEqual("124", document.Id); - Assert.AreEqual("jose@ora.com", document.values["email"]); - Assert.True(document.values.ContainsKey("startDate")); + Assert.That(document.Id, Is.EqualTo("124")); + Assert.That(document.values["email"], Is.EqualTo("jose@ora.com")); + Assert.That(document.values.ContainsKey("startDate")); } [Test] public void SimplePatchUsingMySqlExpressionClass() { - if (!session.InternalSession.GetServerVersion().isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher"); + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); Collection collection = CreateCollection("test"); Result r = ExecuteAddStatement(collection.Add("{ \"_id\": \"123\", \"email\": \"alice@ora.com\", \"startDate\": \"4/1/2017\" }")); - Assert.AreEqual(1, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); var patch = new { @@ -170,69 +171,69 @@ public void SimplePatchUsingMySqlExpressionClass() ExecuteModifyStatement(collection.Modify("true").Patch(patch)); DbDoc document = collection.GetOne("123"); - Assert.AreEqual("ALICE@ORA.COM", document.values["email"]); + Assert.That(document.values["email"], Is.EqualTo("ALICE@ORA.COM")); } [Test] public void CRUD() { - if (!session.InternalSession.GetServerVersion().isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher"); + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); Collection collection = CreateCollection("test"); Result r = ExecuteAddStatement(collection.Add(documentsAsJsonStrings)); - Assert.AreEqual(1, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); // Add field. ExecuteModifyStatement(collection.Modify("language = :lang").Patch("{ \"translations\": [\"Spanish\"] }").Bind("lang", "English")); var document = ExecuteFindStatement(collection.Find("language = :lang").Bind("lang", "English")).FetchOne(); - Assert.True(document.values.ContainsKey("translations")); + Assert.That(document.values.ContainsKey("translations")); // Update field. ExecuteModifyStatement(collection.Modify("language = :lang").Patch("{ \"translations\": [\"Spanish\", \"Italian\"] }").Bind("lang", "English")); document = ExecuteFindStatement(collection.Find("language = :lang").Bind("lang", "English")).FetchOne(); - Assert.True(document.values.ContainsKey("translations")); + Assert.That(document.values.ContainsKey("translations")); var translations = (object[])document.values["translations"]; - Assert.AreEqual("Spanish", (string)translations[0]); - Assert.AreEqual("Italian", (string)translations[1]); + Assert.That((string)translations[0], Is.EqualTo("Spanish")); + Assert.That((string)translations[1], Is.EqualTo("Italian")); // Remove field. ExecuteModifyStatement(collection.Modify("language = :lang").Patch("{ \"translations\": null }").Bind("lang", "English")); document = ExecuteFindStatement(collection.Find("language = :lang").Bind("lang", "English")).FetchOne(); - Assert.False(document.values.ContainsKey("translations")); + Assert.That(document.values.ContainsKey("translations"), Is.False); // Add field. - Assert.False(((Dictionary)document.values["additionalinfo"]).ContainsKey("musicby")); + Assert.That(((Dictionary)document.values["additionalinfo"]).ContainsKey("musicby"), Is.False); ExecuteModifyStatement(collection.Modify("additionalinfo.director.name = :director").Patch("{ \"additionalinfo\": { \"musicby\": \"Sakila D\" } }").Bind("director", "Sharice Legaspi")); document = ExecuteFindStatement(collection.Find("language = :lang").Bind("lang", "English")).FetchOne(); - Assert.True(((Dictionary)document.values["additionalinfo"]).ContainsKey("musicby")); + Assert.That(((Dictionary)document.values["additionalinfo"]).ContainsKey("musicby")); // Update field. ExecuteModifyStatement(collection.Modify("additionalinfo.director.name = :director").Patch("{ \"additionalinfo\": { \"musicby\": \"The Sakila\" } }").Bind("director", "Sharice Legaspi")); document = ExecuteFindStatement(collection.Find("language = :lang").Bind("lang", "English")).FetchOne(); - Assert.True(((Dictionary)document.values["additionalinfo"]).ContainsKey("musicby")); - Assert.AreEqual("The Sakila", ((Dictionary)document.values["additionalinfo"])["musicby"]); + Assert.That(((Dictionary)document.values["additionalinfo"]).ContainsKey("musicby")); + Assert.That(((Dictionary)document.values["additionalinfo"])["musicby"], Is.EqualTo("The Sakila")); // Remove field. ExecuteModifyStatement(collection.Modify("additionalinfo.director.name = :director").Patch("{ \"additionalinfo\": { \"musicby\": null } }").Bind("director", "Sharice Legaspi")); document = ExecuteFindStatement(collection.Find("additionalinfo.director.name = :director").Bind("director", "Sharice Legaspi")).FetchOne(); - Assert.False(((Dictionary)document.values["additionalinfo"]).ContainsKey("musicby")); + Assert.That(((Dictionary)document.values["additionalinfo"]).ContainsKey("musicby"), Is.False); // Add field. - Assert.False(((Dictionary)((Dictionary)document.values["additionalinfo"])["director"]).ContainsKey("country")); + Assert.That(((Dictionary)((Dictionary)document.values["additionalinfo"])["director"]).ContainsKey("country"), Is.False); ExecuteModifyStatement(collection.Modify("additionalinfo.director.name = :director").Patch("{ \"additionalinfo\": { \"director\": { \"country\": \"France\" } } }").Bind("director", "Sharice Legaspi")); document = ExecuteFindStatement(collection.Find("language = :lang").Bind("lang", "English")).FetchOne(); - Assert.True(((Dictionary)((Dictionary)document.values["additionalinfo"])["director"]).ContainsKey("country")); + Assert.That(((Dictionary)((Dictionary)document.values["additionalinfo"])["director"]).ContainsKey("country")); // Update field. ExecuteModifyStatement(collection.Modify("additionalinfo.director.name = :director").Patch("{ \"additionalinfo\": { \"director\": { \"country\": \"Canada\" } } }").Bind("director", "Sharice Legaspi")); document = ExecuteFindStatement(collection.Find("language = :lang").Bind("lang", "English")).FetchOne(); - Assert.True(((Dictionary)((Dictionary)document.values["additionalinfo"])["director"]).ContainsKey("country")); - Assert.AreEqual("Canada", ((Dictionary)((Dictionary)document.values["additionalinfo"])["director"])["country"]); + Assert.That(((Dictionary)((Dictionary)document.values["additionalinfo"])["director"]).ContainsKey("country")); + Assert.That(((Dictionary)((Dictionary)document.values["additionalinfo"])["director"])["country"], Is.EqualTo("Canada")); // Remove field. ExecuteModifyStatement(collection.Modify("additionalinfo.director.name = :director").Patch("{ \"additionalinfo\": { \"director\": { \"country\": null } } }").Bind("director", "Sharice Legaspi")); document = ExecuteFindStatement(collection.Find("additionalinfo.director.name = :director").Bind("director", "Sharice Legaspi")).FetchOne(); - Assert.False(((Dictionary)((Dictionary)document.values["additionalinfo"])["director"]).ContainsKey("country")); + Assert.That(((Dictionary)((Dictionary)document.values["additionalinfo"])["director"]).ContainsKey("country"), Is.False); } #endregion @@ -242,69 +243,69 @@ public void CRUD() [Test] public void ReplaceUpdateInDifferentNestingLevels() { - if (!session.InternalSession.GetServerVersion().isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher"); + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); Collection collection = CreateCollection("test"); Result r = ExecuteAddStatement(collection.Add(documentsAsDbDocs)); - Assert.AreEqual(1, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); DbDoc document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); - Assert.AreEqual("AFRICAN EGG", document["title"]); + Assert.That(document["title"], Is.EqualTo("AFRICAN EGG")); ExecuteModifyStatement(collection.Modify("_id = :id").Patch("{ \"title\": \"The African Egg\" }").Bind("id", "a6f4b93e1a264a108393524f29546a8c")); document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); - Assert.AreEqual("The African Egg", document["title"]); + Assert.That(document["title"], Is.EqualTo("The African Egg")); - Assert.AreEqual(57, ((Dictionary)((Dictionary)document.values["additionalinfo"])["director"])["age"]); + Assert.That(((Dictionary)((Dictionary)document.values["additionalinfo"])["director"])["age"], Is.EqualTo(57)); ExecuteModifyStatement(collection.Modify("additionalinfo.director.name = :director").Patch("{ \"additionalinfo\": { \"director\": { \"age\": 67 } } }").Bind("director", "Sharice Legaspi")); document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); - Assert.AreEqual(67, ((Dictionary)((Dictionary)document.values["additionalinfo"])["director"])["age"]); + Assert.That(((Dictionary)((Dictionary)document.values["additionalinfo"])["director"])["age"], Is.EqualTo(67)); ExecuteModifyStatement(collection.Modify("_id = :id").Patch("{ \"additionalinfo\": { \"director\": { \"age\": 77 } } }").Bind("id", "a6f4b93e1a264a108393524f29546a8c")); document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); - Assert.AreEqual(77, ((Dictionary)((Dictionary)document.values["additionalinfo"])["director"])["age"]); + Assert.That(((Dictionary)((Dictionary)document.values["additionalinfo"])["director"])["age"], Is.EqualTo(77)); ExecuteModifyStatement(collection.Modify("_id = :id").Patch("{ \"title\": { \"movie\": \"The African Egg\"} }").Bind("id", "a6f4b93e1a264a108393524f29546a8c")); document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); - Assert.AreEqual("The African Egg", ((Dictionary)document.values["title"])["movie"]); + Assert.That(((Dictionary)document.values["title"])["movie"], Is.EqualTo("The African Egg")); ExecuteModifyStatement(collection.Modify("_id = :id").Patch("{ \"additionalinfo\": \"No data available\" }").Bind("id", "a6f4b93e1a264a108393524f29546a8c")); document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); - Assert.AreEqual("No data available", document.values["additionalinfo"]); + Assert.That(document.values["additionalinfo"], Is.EqualTo("No data available")); } [Test] public void AddRemoveFieldInDifferentNestingLevels() { - if (!session.InternalSession.GetServerVersion().isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher"); + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); Collection collection = CreateCollection("test"); Result r = ExecuteAddStatement(collection.Add(documentsAsDbDocs)); - Assert.AreEqual(1, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); DbDoc document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); - Assert.False(document.values.ContainsKey("translations")); + Assert.That(document.values.ContainsKey("translations"), Is.False); ExecuteModifyStatement(collection.Modify("_id = :id").Patch("{ \"translations\": [\"Spanish\"] }").Bind("id", "a6f4b93e1a264a108393524f29546a8c")); document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); - Assert.True(document.values.ContainsKey("translations")); + Assert.That(document.values.ContainsKey("translations")); ExecuteModifyStatement(collection.Modify("_id = :id").Patch("{ \"translations\": null }").Bind("id", "a6f4b93e1a264a108393524f29546a8c")); document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); - Assert.False(document.values.ContainsKey("translations")); + Assert.That(document.values.ContainsKey("translations"), Is.False); - Assert.False(((Dictionary)((Dictionary)document.values["additionalinfo"])["director"]).ContainsKey("country")); + Assert.That(((Dictionary)((Dictionary)document.values["additionalinfo"])["director"]).ContainsKey("country"), Is.False); ExecuteModifyStatement(collection.Modify("additionalinfo.director.name = :director").Patch("{ \"additionalinfo\": { \"director\": { \"country\": \"France\" } } }").Bind("director", "Sharice Legaspi")); document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); - Assert.True(((Dictionary)((Dictionary)document.values["additionalinfo"])["director"]).ContainsKey("country")); + Assert.That(((Dictionary)((Dictionary)document.values["additionalinfo"])["director"]).ContainsKey("country")); ExecuteModifyStatement(collection.Modify("additionalinfo.director.name = :director").Patch("{ \"additionalinfo\": { \"director\": { \"country\": null } } }").Bind("director", "Sharice Legaspi")); document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); - Assert.False(((Dictionary)((Dictionary)document.values["additionalinfo"])["director"]).ContainsKey("country")); + Assert.That(((Dictionary)((Dictionary)document.values["additionalinfo"])["director"]).ContainsKey("country"), Is.False); - Assert.False(((Dictionary)document.values["additionalinfo"]).ContainsKey("musicby")); + Assert.That(((Dictionary)document.values["additionalinfo"]).ContainsKey("musicby"), Is.False); ExecuteModifyStatement(collection.Modify("_id = :id").Patch("{ \"additionalinfo\": { \"musicby\": \"The Sakila\" } }").Bind("id", "a6f4b93e1a264a108393524f29546a8c")); document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); - Assert.True(((Dictionary)document.values["additionalinfo"]).ContainsKey("musicby")); + Assert.That(((Dictionary)document.values["additionalinfo"]).ContainsKey("musicby")); ExecuteModifyStatement(collection.Modify("_id = :id").Patch("{ \"additionalinfo\": { \"musicby\": null } }").Bind("id", "a6f4b93e1a264a108393524f29546a8c")); document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); - Assert.False(((Dictionary)document.values["additionalinfo"]).ContainsKey("musicby")); + Assert.That(((Dictionary)document.values["additionalinfo"]).ContainsKey("musicby"), Is.False); } #endregion @@ -314,11 +315,11 @@ public void AddRemoveFieldInDifferentNestingLevels() [Test] public void CRUDMultipleFields() { - if (!session.InternalSession.GetServerVersion().isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher"); + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); Collection collection = CreateCollection("test"); Result r = ExecuteAddStatement(collection.Add(documentsAsDbDocs)); - Assert.AreEqual(1, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); DbDoc document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); @@ -326,34 +327,34 @@ public void CRUDMultipleFields() ExecuteModifyStatement(collection.Modify("_id = :id").Patch("{ \"field 1\": \"one\", \"field 2\": \"two\", \"field 3\": \"three\" }").Bind("id", "a6f4b93e1a264a108393524f29546a8c")); ExecuteModifyStatement(collection.Modify("additionalinfo.director.name = :director").Patch("{ \"additionalinfo\": { \"director\": { \"field 1\": \"one\", \"field 2\": \"two\", \"field 3\": \"three\" } } }").Bind("director", "Sharice Legaspi")); document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); - Assert.AreEqual("one", document.values["field 1"]); - Assert.AreEqual("two", document.values["field 2"]); - Assert.AreEqual("three", document.values["field 3"]); - Assert.AreEqual("one", (((Dictionary)((Dictionary)document.values["additionalinfo"])["director"]))["field 1"]); - Assert.AreEqual("two", (((Dictionary)((Dictionary)document.values["additionalinfo"])["director"]))["field 2"]); - Assert.AreEqual("three", (((Dictionary)((Dictionary)document.values["additionalinfo"])["director"]))["field 3"]); + Assert.That(document.values["field 1"], Is.EqualTo("one")); + Assert.That(document.values["field 2"], Is.EqualTo("two")); + Assert.That(document.values["field 3"], Is.EqualTo("three")); + Assert.That((((Dictionary)((Dictionary)document.values["additionalinfo"])["director"]))["field 1"], Is.EqualTo("one")); + Assert.That((((Dictionary)((Dictionary)document.values["additionalinfo"])["director"]))["field 2"], Is.EqualTo("two")); + Assert.That((((Dictionary)((Dictionary)document.values["additionalinfo"])["director"]))["field 3"], Is.EqualTo("three")); // Update/Replace fields. ExecuteModifyStatement(collection.Modify("_id = :id").Patch("{ \"field 1\": \"ONE\", \"field 2\": \"TWO\", \"field 3\": \"THREE\" }").Bind("id", "a6f4b93e1a264a108393524f29546a8c")); ExecuteModifyStatement(collection.Modify("additionalinfo.director.name = :director").Patch("{ \"additionalinfo\": { \"director\": { \"field 1\": \"ONE\", \"field 2\": \"TWO\", \"field 3\": \"THREE\" } } }").Bind("director", "Sharice Legaspi")); document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); - Assert.AreEqual("ONE", document.values["field 1"]); - Assert.AreEqual("TWO", document.values["field 2"]); - Assert.AreEqual("THREE", document.values["field 3"]); - Assert.AreEqual("ONE", (((Dictionary)((Dictionary)document.values["additionalinfo"])["director"]))["field 1"]); - Assert.AreEqual("TWO", (((Dictionary)((Dictionary)document.values["additionalinfo"])["director"]))["field 2"]); - Assert.AreEqual("THREE", (((Dictionary)((Dictionary)document.values["additionalinfo"])["director"]))["field 3"]); + Assert.That(document.values["field 1"], Is.EqualTo("ONE")); + Assert.That(document.values["field 2"], Is.EqualTo("TWO")); + Assert.That(document.values["field 3"], Is.EqualTo("THREE")); + Assert.That((((Dictionary)((Dictionary)document.values["additionalinfo"])["director"]))["field 1"], Is.EqualTo("ONE")); + Assert.That((((Dictionary)((Dictionary)document.values["additionalinfo"])["director"]))["field 2"], Is.EqualTo("TWO")); + Assert.That((((Dictionary)((Dictionary)document.values["additionalinfo"])["director"]))["field 3"], Is.EqualTo("THREE")); // Remove fields. ExecuteModifyStatement(collection.Modify("_id = :id").Patch("{ \"field 1\": null, \"field 2\": null, \"field 3\": null }").Bind("id", "a6f4b93e1a264a108393524f29546a8c")); ExecuteModifyStatement(collection.Modify("additionalinfo.director.name = :director").Patch("{ \"additionalinfo\": { \"director\": { \"field 1\": null, \"field 2\": null, \"field 3\": null } } }").Bind("director", "Sharice Legaspi")); document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); - Assert.False(document.values.ContainsKey("field 1")); - Assert.False(document.values.ContainsKey("field 2")); - Assert.False(document.values.ContainsKey("field 3")); - Assert.False((((Dictionary)((Dictionary)document.values["additionalinfo"])["director"])).ContainsKey("field 1")); - Assert.False((((Dictionary)((Dictionary)document.values["additionalinfo"])["director"])).ContainsKey("field 2")); - Assert.False((((Dictionary)((Dictionary)document.values["additionalinfo"])["director"])).ContainsKey("field 3")); + Assert.That(document.values.ContainsKey("field 1"), Is.False); + Assert.That(document.values.ContainsKey("field 2"), Is.False); + Assert.That(document.values.ContainsKey("field 3"), Is.False); + Assert.That((((Dictionary)((Dictionary)document.values["additionalinfo"])["director"])).ContainsKey("field 1"), Is.False); + Assert.That((((Dictionary)((Dictionary)document.values["additionalinfo"])["director"])).ContainsKey("field 2"), Is.False); + Assert.That((((Dictionary)((Dictionary)document.values["additionalinfo"])["director"])).ContainsKey("field 3"), Is.False); } #endregion @@ -363,131 +364,131 @@ public void CRUDMultipleFields() [Test] public void AddNewFieldUsingExpressions() { - if (!session.InternalSession.GetServerVersion().isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher"); + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); Collection collection = CreateCollection("test"); Result r = ExecuteAddStatement(collection.Add(documentsAsDbDocs)); - Assert.AreEqual(1, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); DbDoc document = ExecuteFindStatement(collection.Find()).FetchOne(); - Assert.False(((Dictionary)((object[])document.values["actors"])[0]).ContainsKey("age")); + Assert.That(((Dictionary)((object[])document.values["actors"])[0]).ContainsKey("age"), Is.False); Assert.Throws(() => ExecuteModifyStatement(collection.Modify("true").Patch("{ \"actors\": { \"age\": Year(CURDATE()) - CAST(SUBSTRING_INDEX(actors.birthdate, ' ', - 1) AS DECIMAL)) } }"))); document = ExecuteFindStatement(collection.Find()).FetchOne(); - Assert.False(document.values.ContainsKey("audio")); + Assert.That(document.values.ContainsKey("audio"), Is.False); ExecuteModifyStatement(collection.Modify("true").Patch("{ \"audio\": CONCAT($.language, ', no subtitles') }")); document = ExecuteFindStatement(collection.Find()).FetchOne(); - Assert.AreEqual("English, no subtitles", document.values["audio"]); + Assert.That(document.values["audio"], Is.EqualTo("English, no subtitles")); } [Test] public void ReplaceUpdateUsingExpressions() { - if (!session.InternalSession.GetServerVersion().isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher"); + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); Collection collection = CreateCollection("test"); Result r = ExecuteAddStatement(collection.Add(documentsAsDbDocs)); - Assert.AreEqual(1, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); DbDoc document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); - Assert.False(document.values.ContainsKey("audio")); + Assert.That(document.values.ContainsKey("audio"), Is.False); ExecuteModifyStatement(collection.Modify("true").Patch("{ \"audio\": CONCAT(UPPER($.language), ', No Subtitles') }")); document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); - Assert.AreEqual("ENGLISH, No Subtitles", document.values["audio"]); + Assert.That(document.values["audio"], Is.EqualTo("ENGLISH, No Subtitles")); } [Test] public void ReplaceUpdateIdUsingExpressions() { - if (!session.InternalSession.GetServerVersion().isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher"); + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); Collection collection = CreateCollection("test"); Result r = ExecuteAddStatement(collection.Add(documentsAsDbDocs)); - Assert.AreEqual(1, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); // Changes to the _id field are ignored. ExecuteModifyStatement(collection.Modify("_id = :id").Patch("{ \"_id\": replace(UUID(), '-', '') }").Bind("id", "a6f4b93e1a264a108393524f29546a8c")); DbDoc document = ExecuteFindStatement(collection.Find()).FetchOne(); - Assert.AreEqual("a6f4b93e1a264a108393524f29546a8c", document.Id); + Assert.That(document.Id, Is.EqualTo("a6f4b93e1a264a108393524f29546a8c")); } [Test] public void AddIdToNestedDocumentUsingExpressions() { - if (!session.InternalSession.GetServerVersion().isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher"); + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); Collection collection = CreateCollection("test"); Result r = ExecuteAddStatement(collection.Add(documentsAsDbDocs)); - Assert.AreEqual(1, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); DbDoc document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); - Assert.False(((Dictionary)document.values["additionalinfo"]).ContainsKey("_id")); + Assert.That(((Dictionary)document.values["additionalinfo"]).ContainsKey("_id"), Is.False); ExecuteModifyStatement(collection.Modify("_id = :id").Patch("{ \"additionalinfo\": { \"_id\": replace(UUID(), '-', '') } }").Bind("id", "a6f4b93e1a264a108393524f29546a8c")); document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); - Assert.True(((Dictionary)document.values["additionalinfo"]).ContainsKey("_id")); + Assert.That(((Dictionary)document.values["additionalinfo"]).ContainsKey("_id")); } [Test] public void AddNullFieldUsingExpressions() { - if (!session.InternalSession.GetServerVersion().isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher"); + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); Collection collection = CreateCollection("test"); Result r = ExecuteAddStatement(collection.Add(documentsAsDbDocs)); - Assert.AreEqual(1, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); DbDoc document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); - Assert.False(((Dictionary)document.values["additionalinfo"]).ContainsKey("releasedate")); + Assert.That(((Dictionary)document.values["additionalinfo"]).ContainsKey("releasedate"), Is.False); Exception ex = Assert.Throws(() => ExecuteModifyStatement(collection.Modify("_id = :id").Patch("{ \"releasedate\": DATE_ADD('2006-04-00',INTERVAL 1 DAY) }").Bind("id", "a6f4b93e1a264a108393524f29546a8c"))); - Assert.AreEqual("Invalid data for update operation on document collection table", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Invalid data for update operation on document collection table")); } [Test] public void ReplaceUpdateNullFieldReturnedFromExpression() { - if (!session.InternalSession.GetServerVersion().isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher"); + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); Collection collection = CreateCollection("test"); Result r = ExecuteAddStatement(collection.Add(documentsAsDbDocs)); - Assert.AreEqual(1, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); DbDoc document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); - Assert.AreEqual("AFRICAN EGG", document.values["title"]); + Assert.That(document.values["title"], Is.EqualTo("AFRICAN EGG")); ExecuteModifyStatement(collection.Modify("_id = :id").Patch("{ \"title\": concat('my ', NULL, ' title') }").Bind("id", "a6f4b93e1a264a108393524f29546a8c")); document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); - Assert.False(document.values.ContainsKey("title")); + Assert.That(document.values.ContainsKey("title"), Is.False); } [Test] public void AddNewFieldReturnedFromExpression() { - if (!session.InternalSession.GetServerVersion().isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher"); + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); Collection collection = CreateCollection("test"); Result r = ExecuteAddStatement(collection.Add(documentsAsDbDocs)); - Assert.AreEqual(1, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); DbDoc document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); - Assert.False(document.values.ContainsKey("docfield")); + Assert.That(document.values.ContainsKey("docfield"), Is.False); ExecuteModifyStatement(collection.Modify("_id = :id").Patch("{ \"docfield\": JSON_OBJECT('field 1', 1, 'field 2', 'two') }").Bind("id", "a6f4b93e1a264a108393524f29546a8c")); document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); - Assert.True(document.values.ContainsKey("docfield")); + Assert.That(document.values.ContainsKey("docfield")); } [Test] public void ReplaceUpdateFieldWithDocumentReturnedFromExpression() { - if (!session.InternalSession.GetServerVersion().isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher"); + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); Collection collection = CreateCollection("test"); Result r = ExecuteAddStatement(collection.Add(documentsAsDbDocs)); - Assert.AreEqual(1, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); DbDoc document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); - Assert.AreEqual("Science fiction", document.values["genre"]); + Assert.That(document.values["genre"], Is.EqualTo("Science fiction")); ExecuteModifyStatement(collection.Modify("_id = :id").Patch("{ \"genre\": JSON_OBJECT('name', 'Science Fiction') }").Bind("id", "a6f4b93e1a264a108393524f29546a8c")); document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); - Assert.AreEqual("Science Fiction", ((Dictionary)document.values["genre"])["name"]); + Assert.That(((Dictionary)document.values["genre"])["name"], Is.EqualTo("Science Fiction")); } #endregion @@ -497,117 +498,117 @@ public void ReplaceUpdateFieldWithDocumentReturnedFromExpression() [Test] public void ReplaceUpdateId() { - if (!session.InternalSession.GetServerVersion().isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher"); + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); Collection collection = CreateCollection("test"); Result r = ExecuteAddStatement(collection.Add(documentsAsDbDocs)); - Assert.AreEqual(1, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); // Changes to the _id field are ignored. ExecuteModifyStatement(collection.Modify("_id = :id").Patch("{ \"_id\": \"b5f4b93e1a264a108393524f29546a9d\" }").Bind("id", "a6f4b93e1a264a108393524f29546a8c")); DbDoc document = ExecuteFindStatement(collection.Find()).FetchOne(); - Assert.AreEqual("a6f4b93e1a264a108393524f29546a8c", document.Id); + Assert.That(document.Id, Is.EqualTo("a6f4b93e1a264a108393524f29546a8c")); } [Test] public void AddIdToNestedDocument() { - if (!session.InternalSession.GetServerVersion().isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher"); + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); Collection collection = CreateCollection("test"); Result r = ExecuteAddStatement(collection.Add(documentsAsDbDocs)); - Assert.AreEqual(1, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); // Add id to nested document is allowed. DbDoc document = ExecuteFindStatement(collection.Find()).FetchOne(); var field = (Dictionary)document.values["additionalinfo"]; - Assert.AreEqual(3, field.Count); - Assert.False(field.ContainsKey("_id")); + Assert.That(field.Count, Is.EqualTo(3)); + Assert.That(field.ContainsKey("_id"), Is.False); ExecuteModifyStatement(collection.Modify("_id = :id").Patch("{ \"additionalinfo\": { \"_id\": \"b5f4b93e1a264a108393524f29546a9d\" } }").Bind("id", "a6f4b93e1a264a108393524f29546a8c")); document = ExecuteFindStatement(collection.Find()).FetchOne(); field = (Dictionary)document.values["additionalinfo"]; - Assert.AreEqual(4, field.Count); - Assert.True(field.ContainsKey("_id")); - Assert.AreEqual("b5f4b93e1a264a108393524f29546a9d", field["_id"]); + Assert.That(field.Count, Is.EqualTo(4)); + Assert.That(field.ContainsKey("_id")); + Assert.That(field["_id"], Is.EqualTo("b5f4b93e1a264a108393524f29546a9d")); } [Test] public void SetNullToId() { - if (!session.InternalSession.GetServerVersion().isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher"); + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); Collection collection = CreateCollection("test"); Result r = ExecuteAddStatement(collection.Add(documentsAsJsonStrings)); - Assert.AreEqual(1, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); // Changes to the _id field are ignored. ExecuteModifyStatement(collection.Modify("true").Patch("{ \"_id\": NULL }")); - Assert.AreEqual("a6f4b93e1a264a108393524f29546a8c", ExecuteFindStatement(collection.Find()).FetchOne().Id); + Assert.That(ExecuteFindStatement(collection.Find()).FetchOne().Id, Is.EqualTo("a6f4b93e1a264a108393524f29546a8c")); } [Test] public void AddNullFields() { - if (!session.InternalSession.GetServerVersion().isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher"); + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); Collection collection = CreateCollection("test"); Result r = ExecuteAddStatement(collection.Add(documentsAsJsonStrings)); - Assert.AreEqual(1, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); ExecuteModifyStatement(collection.Modify("true").Patch("{ \"nullfield\": NULL }")); - Assert.False(ExecuteFindStatement(collection.Find()).FetchOne().values.ContainsKey("nullfield")); + Assert.That(ExecuteFindStatement(collection.Find()).FetchOne().values.ContainsKey("nullfield"), Is.False); ExecuteModifyStatement(collection.Modify("true").Patch("{ \"nullfield\": [NULL, NULL] }")); DbDoc document = ExecuteFindStatement(collection.Find()).FetchOne(); - Assert.True(document.values.ContainsKey("nullfield")); + Assert.That(document.values.ContainsKey("nullfield")); var nullArray = (object[])document.values["nullfield"]; - Assert.Null(nullArray[0]); - Assert.Null(nullArray[1]); + Assert.That(nullArray[0], Is.Null); + Assert.That(nullArray[1], Is.Null); ExecuteModifyStatement(collection.Modify("true").Patch("{ \"nullfield\": { \"nested\": NULL } }")); document = ExecuteFindStatement(collection.Find()).FetchOne(); - Assert.True(ExecuteFindStatement(collection.Find()).FetchOne().values.ContainsKey("nullfield")); - Assert.True(((Dictionary)document.values["nullfield"]).Count == 0); + Assert.That(ExecuteFindStatement(collection.Find()).FetchOne().values.ContainsKey("nullfield")); + Assert.That(((Dictionary)document.values["nullfield"]).Count == 0); ExecuteModifyStatement(collection.Modify("true").Patch("{ \"nullfield\": { \"nested\": [NULL, NULL] } }")); document = ExecuteFindStatement(collection.Find()).FetchOne(); var nestedNullArray = (object[])((Dictionary)document.values["nullfield"])["nested"]; - Assert.Null(nestedNullArray[0]); - Assert.Null(nestedNullArray[1]); + Assert.That(nestedNullArray[0], Is.Null); + Assert.That(nestedNullArray[1], Is.Null); } [Test] public void AddNestedNullFields() { - if (!session.InternalSession.GetServerVersion().isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher"); + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); Collection collection = CreateCollection("test"); Result r = ExecuteAddStatement(collection.Add(documentsAsJsonStrings)); - Assert.AreEqual(1, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); ExecuteModifyStatement(collection.Modify("true").Patch("{ \"additionalinfo\": { \"nullfield\": NULL } }")); - Assert.False(((Dictionary)ExecuteFindStatement(collection.Find()).FetchOne().values["additionalinfo"]).ContainsKey("nullfield")); + Assert.That(((Dictionary)ExecuteFindStatement(collection.Find()).FetchOne().values["additionalinfo"]).ContainsKey("nullfield"), Is.False); ExecuteModifyStatement(collection.Modify("true").Patch("{ \"additionalinfo\": { \"nullfield\": [NULL, NULL] } }")); DbDoc document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); var nestedNullArray = (object[])((Dictionary)document.values["additionalinfo"])["nullfield"]; - Assert.Null(nestedNullArray[0]); - Assert.Null(nestedNullArray[1]); + Assert.That(nestedNullArray[0], Is.Null); + Assert.That(nestedNullArray[1], Is.Null); ExecuteModifyStatement(collection.Modify("true").Patch("{ \"additionalinfo\": { \"nullfield\": { \"nested\": NULL } } }")); document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); - Assert.False(((Dictionary)((Dictionary)document.values["additionalinfo"])["nullfield"]).ContainsKey("nullfield")); + Assert.That(((Dictionary)((Dictionary)document.values["additionalinfo"])["nullfield"]).ContainsKey("nullfield"), Is.False); ExecuteModifyStatement(collection.Modify("true").Patch("{ \"additionalinfo\": { \"nullfield\": { \"nested\": [NULL, NULL] } } }")); document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); nestedNullArray = (object[])((Dictionary)((Dictionary)document.values["additionalinfo"])["nullfield"])["nested"]; - Assert.Null(nestedNullArray[0]); - Assert.Null(nestedNullArray[1]); + Assert.That(nestedNullArray[0], Is.Null); + Assert.That(nestedNullArray[1], Is.Null); ExecuteModifyStatement(collection.Modify("true").Patch("{ \"additionalinfo\": { \"nullfield\": { \"nested\": JSON_OBJECT('field', null) } } }")); document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); var nestedObject = (Dictionary)((Dictionary)((Dictionary)document.values["additionalinfo"])["nullfield"])["nested"]; - CollectionAssert.IsEmpty(nestedObject); + Assert.That(nestedObject, Is.Empty); } #endregion @@ -617,32 +618,32 @@ public void GetDocumentProperties() { Collection collection = CreateCollection("test"); Result r = ExecuteAddStatement(collection.Add(documentsAsDbDocs)); - Assert.AreEqual(1, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); // Get root string properties. DbDoc document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); - Assert.AreEqual("a6f4b93e1a264a108393524f29546a8c", document.Id); - Assert.AreEqual("AFRICAN EGG", document["title"]); - Assert.AreEqual("G", document["rating"]); + Assert.That(document.Id, Is.EqualTo("a6f4b93e1a264a108393524f29546a8c")); + Assert.That(document["title"], Is.EqualTo("AFRICAN EGG")); + Assert.That(document["rating"], Is.EqualTo("G")); // Get root numeric properties. - Assert.AreEqual(2006, document["releaseyear"]); - Assert.AreEqual(130, document["duration"]); + Assert.That(document["releaseyear"], Is.EqualTo(2006)); + Assert.That(document["duration"], Is.EqualTo(130)); // Get root array. object[] actors = document["actors"] as object[]; - Assert.True(actors.Length == 3); + Assert.That(actors.Length == 3); Dictionary actor1 = actors[1] as Dictionary; - Assert.AreEqual("VAL BOLGER", actor1["name"]); + Assert.That(actor1["name"], Is.EqualTo("VAL BOLGER")); // Get nested string properies. - Assert.AreEqual("Sharice Legaspi", document["additionalinfo.director.name"]); - Assert.AreEqual(57, document["additionalinfo.director.age"]); - Assert.AreEqual("Italy", document["additionalinfo.director.birthplace.country"]); + Assert.That(document["additionalinfo.director.name"], Is.EqualTo("Sharice Legaspi")); + Assert.That(document["additionalinfo.director.age"], Is.EqualTo(57)); + Assert.That(document["additionalinfo.director.birthplace.country"], Is.EqualTo("Italy")); // Get nested array. object[] awards = document["additionalinfo.director.awards"] as object[]; - Assert.True(awards.Length == 2); + Assert.That(awards.Length == 2); } [Test] @@ -651,51 +652,51 @@ public void PatchUsingDateAndTimeFunctions() string t1 = "{\"_id\": \"1\", \"name\": \"Alice\" }"; Collection collection = CreateCollection("test"); Result r = ExecuteAddStatement(collection.Add(t1)); - Assert.AreEqual(1, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); ExecuteModifyStatement(collection.Modify("_id = :id").Patch("{ \"dateAndTimeValue\": YEAR('2000-01-01') }").Bind("id", "1")); DbDoc document = collection.GetOne("1"); - Assert.AreEqual(2000, document["dateAndTimeValue"]); + Assert.That(document["dateAndTimeValue"], Is.EqualTo(2000)); ExecuteModifyStatement(collection.Modify("_id = :id").Patch("{ \"dateAndTimeValue\": MONTH('2008-02-03') }").Bind("id", "1")); document = collection.GetOne("1"); - Assert.AreEqual(2, document["dateAndTimeValue"]); + Assert.That(document["dateAndTimeValue"], Is.EqualTo(2)); ExecuteModifyStatement(collection.Modify("_id = :id").Patch("{ \"dateAndTimeValue\": WEEK('2008-02-20') }").Bind("id", "1")); document = collection.GetOne("1"); - Assert.AreEqual(7, document["dateAndTimeValue"]); + Assert.That(document["dateAndTimeValue"], Is.EqualTo(7)); ExecuteModifyStatement(collection.Modify("_id = :id").Patch("{ \"dateAndTimeValue\": DAY('2008-02-20') }").Bind("id", "1")); document = collection.GetOne("1"); - Assert.AreEqual(20, document["dateAndTimeValue"]); + Assert.That(document["dateAndTimeValue"], Is.EqualTo(20)); ExecuteModifyStatement(collection.Modify("_id = :id").Patch("{ \"dateAndTimeValue\": HOUR('10:05:03') }").Bind("id", "1")); document = collection.GetOne("1"); - Assert.AreEqual(10, document["dateAndTimeValue"]); + Assert.That(document["dateAndTimeValue"], Is.EqualTo(10)); ExecuteModifyStatement(collection.Modify("_id = :id").Patch("{ \"dateAndTimeValue\": MINUTE('2008-02-03 10:05:03') }").Bind("id", "1")); document = collection.GetOne("1"); - Assert.AreEqual(5, document["dateAndTimeValue"]); + Assert.That(document["dateAndTimeValue"], Is.EqualTo(5)); ExecuteModifyStatement(collection.Modify("_id = :id").Patch("{ \"dateAndTimeValue\": SECOND('10:05:03') }").Bind("id", "1")); document = collection.GetOne("1"); - Assert.AreEqual(3, document["dateAndTimeValue"]); + Assert.That(document["dateAndTimeValue"], Is.EqualTo(3)); ExecuteModifyStatement(collection.Modify("_id = :id").Patch("{ \"dateAndTimeValue\": MICROSECOND('12:00:00.123456') }").Bind("id", "1")); document = collection.GetOne("1"); - Assert.AreEqual(123456, document["dateAndTimeValue"]); + Assert.That(document["dateAndTimeValue"], Is.EqualTo(123456)); ExecuteModifyStatement(collection.Modify("_id = :id").Patch("{ \"dateAndTimeValue\": QUARTER('2008-04-01') }").Bind("id", "1")); document = collection.GetOne("1"); - Assert.AreEqual(2, document["dateAndTimeValue"]); + Assert.That(document["dateAndTimeValue"], Is.EqualTo(2)); ExecuteModifyStatement(collection.Modify("_id = :id").Patch("{ \"dateAndTimeValue\": TIME('2003-12-31 01:02:03') }").Bind("id", "1")); document = collection.GetOne("1"); - Assert.AreEqual("01:02:03.000000", document["dateAndTimeValue"]); + Assert.That(document["dateAndTimeValue"], Is.EqualTo("01:02:03.000000")); ExecuteModifyStatement(collection.Modify("_id = :id").Patch("{ \"dateAndTimeValue\": DATE('2003-12-31 01:02:03') }").Bind("id", "1")); document = collection.GetOne("1"); - Assert.AreEqual("2003-12-31", document["dateAndTimeValue"]); + Assert.That(document["dateAndTimeValue"], Is.EqualTo("2003-12-31")); } [Test] @@ -704,19 +705,19 @@ public void PatchUsingOtherKnownFunctions() string t1 = "{\"_id\": \"1\", \"name\": \"Alice\" }"; Collection collection = CreateCollection("test"); Result r = ExecuteAddStatement(collection.Add(t1)); - Assert.AreEqual(1, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); ExecuteModifyStatement(collection.Modify("_id = :id").Patch("{ \"otherValue\": CHAR(77, 121, 83, 81, '76') }").Bind("id", "1")); DbDoc document = collection.GetOne("1"); - Assert.AreEqual("base64:type15:TXlTUUw=", document["otherValue"]); + Assert.That(document["otherValue"], Is.EqualTo("base64:type15:TXlTUUw=")); ExecuteModifyStatement(collection.Modify("_id = :id").Patch("{ \"otherValue\": HEX('abc') }").Bind("id", "1")); document = collection.GetOne("1"); - Assert.AreEqual("616263", document["otherValue"]); + Assert.That(document["otherValue"], Is.EqualTo("616263")); ExecuteModifyStatement(collection.Modify("_id = :id").Patch("{ \"otherValue\": BIN(12) }").Bind("id", "1")); document = collection.GetOne("1"); - Assert.AreEqual("1100", document["otherValue"]); + Assert.That(document["otherValue"], Is.EqualTo("1100")); } #region WL14389 @@ -725,7 +726,7 @@ public void PatchUsingOtherKnownFunctions() public void ModifyPatchMultipleRecords_S1() { - if (!session.Version.isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher."); + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); var collection = CreateCollection("test"); var docs = new[] { @@ -735,61 +736,61 @@ public void ModifyPatchMultipleRecords_S1() new {_id = 4, title = "Book 4", pages = 50,age = "12"} }; Result r = collection.Add(docs).Execute(); - Assert.AreEqual(4, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(4)); var document = collection.GetOne("1"); var jsonParams = new { title = "Book 100" }; r = collection.Modify("age = :age").Patch(jsonParams). Bind("age", "12").Execute();//Multiple Records - Assert.AreEqual(2, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(2)); string jsonParams1 = "{ \"title\": \"Book 400\"}"; r = collection.Modify("age = :age").Patch(jsonParams1). Bind("age", "18").Execute(); - Assert.AreEqual(1, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); document = collection.GetOne("1"); - Assert.AreEqual("Book 100", document["title"]); + Assert.That(document["title"], Is.EqualTo("Book 100")); document = collection.GetOne("4"); - Assert.AreEqual("Book 100", document["title"]); + Assert.That(document["title"], Is.EqualTo("Book 100")); document = collection.GetOne("2"); - Assert.AreEqual("Book 400", document["title"]); + Assert.That(document["title"], Is.EqualTo("Book 400")); string splName = "A*b"; jsonParams1 = "{\"data1\":\"" + splName + "\"}"; r = collection.Modify("age = :age").Patch(jsonParams1). Bind("age", "18").Execute(); - Assert.AreEqual(1, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); document = collection.GetOne("2"); - Assert.AreEqual(splName, document["data1"]); + Assert.That(document["data1"], Is.EqualTo(splName)); splName = "A/b"; jsonParams1 = "{\"data1\":\"" + splName + "\"}"; r = collection.Modify("age = :age").Patch(jsonParams1). Bind("age", "18").Execute(); - Assert.AreEqual(1, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); document = collection.GetOne("2"); - Assert.AreEqual(splName, document["data1"]); + Assert.That(document["data1"], Is.EqualTo(splName)); splName = "A&b!c@d#e$f%g^h&i(j)k-l+m=0_p~q`r}s{t][.,?/><"; jsonParams1 = "{\"data1\":\"" + splName + "\"}"; r = collection.Modify("age = :age").Patch(jsonParams1). Bind("age", "18").Execute(); - Assert.AreEqual(1, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); document = collection.GetOne("2"); - Assert.AreEqual(splName, document["data1"]); + Assert.That(document["data1"], Is.EqualTo(splName)); //Large Key Length string myString = new string('*', 65535); jsonParams1 = "{\"data1\":\"" + myString + "\"}"; r = collection.Modify("age = :age").Patch(jsonParams1). Bind("age", "18").Execute(); - Assert.AreEqual(1, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); document = collection.GetOne("2"); - Assert.AreEqual(myString, document["data1"]); + Assert.That(document["data1"], Is.EqualTo(myString)); collection = CreateCollection("test"); r = collection.Add(documentsAsJsonStrings).Execute(); - Assert.AreEqual(1, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); r = collection.Add(documentAsJsonString2).Execute(); - Assert.AreEqual(1, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); collection.Modify("_id = :id").Patch("{ \"field 1\": \"one\", \"field 2\": \"two\", \"field 3\": \"three\" }"). @@ -806,26 +807,20 @@ public void ModifyPatchMultipleRecords_S1() "\"one\", \"field2 12\": \"two\", \"field3 13\": \"three\" } } }"). Bind("director", "Steven Spielberg").Execute(); document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); - Assert.AreEqual("one", document["field 1"]); - Assert.AreEqual("two", document["field 2"]); - Assert.AreEqual("three", document["field 3"]); - Assert.AreEqual("one", - (((Dictionary)((Dictionary)document["additionalinfo"])["director"]))["field1 11"]); - Assert.AreEqual("two", - (((Dictionary)((Dictionary)document["additionalinfo"])["director"]))["field2 12"]); - Assert.AreEqual("three", - (((Dictionary)((Dictionary)document["additionalinfo"])["director"]))["field3 13"]); + Assert.That(document["field 1"], Is.EqualTo("one")); + Assert.That(document["field 2"], Is.EqualTo("two")); + Assert.That(document["field 3"], Is.EqualTo("three")); + Assert.That((((Dictionary)((Dictionary)document["additionalinfo"])["director"]))["field1 11"], Is.EqualTo("one")); + Assert.That((((Dictionary)((Dictionary)document["additionalinfo"])["director"]))["field2 12"], Is.EqualTo("two")); + Assert.That((((Dictionary)((Dictionary)document["additionalinfo"])["director"]))["field3 13"], Is.EqualTo("three")); document = collection.GetOne("123456789asdferdfghhghjh12334"); - Assert.AreEqual("one", document["field 1"]); - Assert.AreEqual("two", document["field 2"]); - Assert.AreEqual("three", document["field 3"]); - Assert.AreEqual("one", - (((Dictionary)((Dictionary)document["additionalinfo"])["director"]))["field1 11"]); - Assert.AreEqual("two", - (((Dictionary)((Dictionary)document["additionalinfo"])["director"]))["field2 12"]); - Assert.AreEqual("three", - (((Dictionary)((Dictionary)document["additionalinfo"])["director"]))["field3 13"]); + Assert.That(document["field 1"], Is.EqualTo("one")); + Assert.That(document["field 2"], Is.EqualTo("two")); + Assert.That(document["field 3"], Is.EqualTo("three")); + Assert.That((((Dictionary)((Dictionary)document["additionalinfo"])["director"]))["field1 11"], Is.EqualTo("one")); + Assert.That((((Dictionary)((Dictionary)document["additionalinfo"])["director"]))["field2 12"], Is.EqualTo("two")); + Assert.That((((Dictionary)((Dictionary)document["additionalinfo"])["director"]))["field3 13"], Is.EqualTo("three")); collection.Modify("language = :language"). Patch("{ \"additionalinfo\": { \"director\": { \"test1\": " + @@ -836,25 +831,19 @@ public void ModifyPatchMultipleRecords_S1() Bind("language", "English").Execute(); //Multiple Records document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); - Assert.AreEqual("check1", document["field 1"]); - Assert.AreEqual("check2", document["field 2"]); - Assert.AreEqual("check3", document["field 3"]); - Assert.AreEqual("one", - (((Dictionary)((Dictionary)document["additionalinfo"])["director"]))["test1"]); - Assert.AreEqual("two", - (((Dictionary)((Dictionary)document["additionalinfo"])["director"]))["test2"]); - Assert.AreEqual("three", - (((Dictionary)((Dictionary)document["additionalinfo"])["director"]))["test3"]); + Assert.That(document["field 1"], Is.EqualTo("check1")); + Assert.That(document["field 2"], Is.EqualTo("check2")); + Assert.That(document["field 3"], Is.EqualTo("check3")); + Assert.That((((Dictionary)((Dictionary)document["additionalinfo"])["director"]))["test1"], Is.EqualTo("one")); + Assert.That((((Dictionary)((Dictionary)document["additionalinfo"])["director"]))["test2"], Is.EqualTo("two")); + Assert.That((((Dictionary)((Dictionary)document["additionalinfo"])["director"]))["test3"], Is.EqualTo("three")); document = collection.GetOne("123456789asdferdfghhghjh12334"); - Assert.AreEqual("check1", document["field 1"]); - Assert.AreEqual("check2", document["field 2"]); - Assert.AreEqual("check3", document["field 3"]); - Assert.AreEqual("one", - (((Dictionary)((Dictionary)document["additionalinfo"])["director"]))["test1"]); - Assert.AreEqual("two", - (((Dictionary)((Dictionary)document["additionalinfo"])["director"]))["test2"]); - Assert.AreEqual("three", - (((Dictionary)((Dictionary)document["additionalinfo"])["director"]))["test3"]); + Assert.That(document["field 1"], Is.EqualTo("check1")); + Assert.That(document["field 2"], Is.EqualTo("check2")); + Assert.That(document["field 3"], Is.EqualTo("check3")); + Assert.That((((Dictionary)((Dictionary)document["additionalinfo"])["director"]))["test1"], Is.EqualTo("one")); + Assert.That((((Dictionary)((Dictionary)document["additionalinfo"])["director"]))["test2"], Is.EqualTo("two")); + Assert.That((((Dictionary)((Dictionary)document["additionalinfo"])["director"]))["test3"], Is.EqualTo("three")); collection = CreateCollection("test"); var data2 = new DbDoc(@"{ ""_id"": -1, ""pages"": 20, @@ -864,13 +853,13 @@ public void ModifyPatchMultipleRecords_S1() ] }"); r = collection.Add(data2).Execute(); - Assert.AreEqual(1, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); document = collection.GetOne("-1"); - Assert.AreEqual("20", document["pages"].ToString()); + Assert.That(document["pages"].ToString(), Is.EqualTo("20")); collection.Modify("_id = :id").Patch("{ \"pages\": \"200\" }"). Bind("id", -1).Execute(); document = collection.GetOne("-1"); - Assert.AreEqual("200", document["pages"]); + Assert.That(document["pages"], Is.EqualTo("200")); data2 = new DbDoc(@"{ ""_id"": 1, ""pages"": 20, ""books"": [ {""_id"" : 10, ""title"" : ""Book 10""}, @@ -883,10 +872,10 @@ public void ModifyPatchMultipleRecords_S1() Bind("id", "1").Execute(); document = collection.GetOne("1"); object[] books = document["books"] as object[]; - Assert.AreEqual(1, books.Length); + Assert.That(books.Length, Is.EqualTo(1)); Dictionary book1 = books[0] as Dictionary; - Assert.AreEqual("11", book1["_id"]); - Assert.AreEqual("Ganges", book1["title"]); + Assert.That(book1["_id"], Is.EqualTo("11")); + Assert.That(book1["title"], Is.EqualTo("Ganges")); var t1 = "{\"_id\": \"1\", \"name\": \"Alice\", \"address\": [{\"zip\": \"12345\", \"city\": \"Los Angeles\", \"street\": \"32 Main str\"}]}"; var t2 = @@ -897,65 +886,65 @@ public void ModifyPatchMultipleRecords_S1() collection = CreateCollection("test"); r = collection.Add(t1).Execute(); - Assert.AreEqual(1, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); r = collection.Add(t2).Execute(); //update the name and zip code of match collection.Modify("_id = :id").Patch("{\"name\": \"Joe\", \"address\": [{\"zip\":\"91234\"}]}").Bind("id", "1").Execute(); document = collection.GetOne("1"); - Assert.AreEqual("Joe", document["name"]); + Assert.That(document["name"], Is.EqualTo("Joe")); object[] address = document["address"] as object[]; - Assert.AreEqual(1, address.Length); + Assert.That(address.Length, Is.EqualTo(1)); Dictionary address1 = address[0] as Dictionary; - Assert.AreEqual("91234", address1["zip"]); + Assert.That(address1["zip"], Is.EqualTo("91234")); collection = CreateCollection("test"); r = collection.Add(t1).Execute(); - Assert.AreEqual(1, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); r = collection.Add(t2).Execute(); - Assert.AreEqual(1, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); r = collection.Add(t3).Execute(); - Assert.AreEqual(1, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); collection.Modify("_id = :id").Patch("{\"name\": \"Joe\", \"address\": [{\"zip1\":\"91234\"},{\"zip2\":\"10000\"}]}"). Bind("id", "3").Execute(); document = collection.GetOne("3"); - Assert.AreEqual("Joe", document["name"]); + Assert.That(document["name"], Is.EqualTo("Joe")); address = document["address"] as object[]; - Assert.AreEqual(2, address.Length); + Assert.That(address.Length, Is.EqualTo(2)); address1 = address[0] as Dictionary; - Assert.AreEqual("91234", address1["zip1"]); + Assert.That(address1["zip1"], Is.EqualTo("91234")); address1 = address[1] as Dictionary; - Assert.AreEqual("10000", address1["zip2"]); + Assert.That(address1["zip2"], Is.EqualTo("10000")); collection = CreateCollection("test"); var t = "{\"_id\": \"id1004\", \"age\": 1, \"misc\": 1.2, \"name\": { \"last\": \"ABCDEF3\", \"first\": \"ABCDEF1\", \"middle\": { \"middle1\": \"ABCDEF21\", \"middle2\": \"ABCDEF22\"}}}"; r = collection.Add(t).Execute(); collection.Modify("_id = :id").Patch("{\"name\":{\"middle\":{\"middle1\": {\"middle11\" : \"ABCDEF211\", \"middle12\" : \"ABCDEF212\", \"middle13\" : \"ABCDEF213\"}}}}").Bind("id", "id1004").Execute(); document = collection.GetOne("id1004"); - Assert.AreEqual("ABCDEF211", document["name.middle.middle1.middle11"]); - Assert.AreEqual("ABCDEF212", document["name.middle.middle1.middle12"]); - Assert.AreEqual("ABCDEF213", document["name.middle.middle1.middle13"]); + Assert.That(document["name.middle.middle1.middle11"], Is.EqualTo("ABCDEF211")); + Assert.That(document["name.middle.middle1.middle12"], Is.EqualTo("ABCDEF212")); + Assert.That(document["name.middle.middle1.middle13"], Is.EqualTo("ABCDEF213")); t1 = "{\"_id\": \"1001\", \"ARR\":[1,2,3], \"ARR1\":[\"name1\",\"name2\", \"name3\"]}"; t2 = "{\"_id\": \"1002\", \"ARR\":[1,1,2], \"ARR1\":[\"name1\",\"name2\", \"name3\"]}"; t3 = "{\"_id\": \"1003\", \"ARR\":[1,4,5], \"ARR1\":[\"name1\",\"name2\", \"name3\"]}"; collection = CreateCollection("test"); r = collection.Add(t1).Execute(); - Assert.AreEqual(1, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); r = collection.Add(t2).Execute(); - Assert.AreEqual(1, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); r = collection.Add(t3).Execute(); - Assert.AreEqual(1, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); collection.Modify("_id = :_id"). Patch("{\"ARR\":[6,8,3],\"ARR1\":[\"changed name1\",\"changed name2\", \"changed name3\"]}"). Bind("_id", "1001").Execute(); document = collection.GetOne("1001"); object[] arr = document["ARR1"] as object[]; - Assert.AreEqual(3, arr.Length); + Assert.That(arr.Length, Is.EqualTo(3)); int j = 1; for (int i = 0; i < arr.Length; i++) { - Assert.AreEqual("changed name" + j, arr[i]); + Assert.That(arr[i], Is.EqualTo("changed name" + j)); j++; } @@ -969,41 +958,41 @@ public void ModifyPatchMultipleRecords_S1() collection = CreateCollection("test"); r = collection.Add(t1).Execute(); - Assert.AreEqual(1, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); r = collection.Add(t2).Execute(); - Assert.AreEqual(1, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); r = collection.Add(t3).Execute(); - Assert.AreEqual(1, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); collection.Modify("_id = :id"). Patch("{\"address\": null, \"zip\": $.address.zip, \"street\": $.address.street, \"city\": upper($.address.city)}").Bind("id", "1"). Execute(); document = collection.GetOne("1"); - Assert.AreEqual("Alice", document["name"]); - Assert.AreEqual("32 Main str", document["street"]); - Assert.AreEqual("LOS ANGELES", document["city"]); - Assert.AreEqual("12345", document["zip"]); + Assert.That(document["name"], Is.EqualTo("Alice")); + Assert.That(document["street"], Is.EqualTo("32 Main str")); + Assert.That(document["city"], Is.EqualTo("LOS ANGELES")); + Assert.That(document["zip"], Is.EqualTo("12345")); t1 = "{\"_id\": \"1\", \"name\": \"Alice\", \"address\": {\"test\":{\"zip\": \"12345\", " + "\"city\": \"Los Angeles\", \"street\": \"32 Main str\"}}}"; collection = CreateCollection("test"); r = collection.Add(t1).Execute(); - Assert.AreEqual(1, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); collection.Modify("_id = :id"). Patch("{\"address\":{\"test\": null,\"zip\":$.address.test.zip,\"city\": lower($.address.test.city)}}").Bind("id", "1"). Execute(); document = collection.GetOne("1"); - Assert.AreEqual("Alice", document["name"]); - Assert.AreEqual("los angeles", document["address.city"]); - Assert.AreEqual("12345", document["address.zip"]); + Assert.That(document["name"], Is.EqualTo("Alice")); + Assert.That(document["address.city"], Is.EqualTo("los angeles")); + Assert.That(document["address.zip"], Is.EqualTo("12345")); } [Test, Description("Test valid modify.patch to change element at Depth 5 for multiple arrays))")] public void ModifyInNestedObjects() { - if (!session.Version.isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher."); + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); string json = ""; int i = 0, j = 0, k = 0, l = 0, m = 0, n = 0, maxFld = 10; var collection = CreateCollection("test"); @@ -1087,7 +1076,7 @@ public void ModifyInNestedObjects() var document1 = collection.GetOne("1002"); var test = "ARR" + i; object[] arr1 = document1[test] as object[]; - Assert.AreEqual(3, arr1.Length); + Assert.That(arr1.Length, Is.EqualTo(3)); i = 0; j = 0; for (i = 0; i < arr1.Length; i++) @@ -1096,65 +1085,65 @@ public void ModifyInNestedObjects() if (i == 1) { object[] arr2 = arr1[1] as object[]; - Assert.AreEqual(3, arr2.Length); + Assert.That(arr2.Length, Is.EqualTo(3)); for (j = 0; j < arr2.Length; j++) { if (j == 1) { object[] arr3 = arr2[1] as object[]; - Assert.AreEqual(3, arr3.Length); + Assert.That(arr3.Length, Is.EqualTo(3)); for (k = 0; k < arr3.Length; k++) { if (k == 1) { object[] arr4 = arr3[1] as object[]; - Assert.AreEqual(3, arr4.Length); + Assert.That(arr4.Length, Is.EqualTo(3)); for (l = 0; l < arr4.Length; l++) { if (l == 1) { object[] arr5 = arr4[1] as object[]; - Assert.AreEqual(3, arr5.Length); + Assert.That(arr5.Length, Is.EqualTo(3)); for (m = 0; m < arr5.Length; m++) { if (m == 1) { object[] arr6 = arr5[1] as object[]; - Assert.AreEqual(1, arr6.Length); + Assert.That(arr6.Length, Is.EqualTo(1)); if (arr6.Length == 1) - Assert.AreEqual(4, arr6[0]); + Assert.That(arr6[0], Is.EqualTo(4)); } else - Assert.AreEqual(5, arr5[m]); + Assert.That(arr5[m], Is.EqualTo(5)); if (m == 2) break; } } else - Assert.AreEqual(6, arr4[l]); + Assert.That(arr4[l], Is.EqualTo(6)); if (l == 2) break; } } else - Assert.AreEqual(7, arr3[k]); + Assert.That(arr3[k], Is.EqualTo(7)); if (k == 2) break; } } if (j == 0 || j == 2) - Assert.AreEqual(8, arr2[j]); + Assert.That(arr2[j], Is.EqualTo(8)); if (j == 2) break; } } else - Assert.AreEqual(9, arr1[i]); + Assert.That(arr1[i], Is.EqualTo(9)); if (i == 2) break; } @@ -1179,7 +1168,7 @@ public void ModifyInNestedObjects() { var test = "ARR" + i; object[] arr1 = document[test] as object[]; - Assert.AreEqual(3, arr1.Length); + Assert.That(arr1.Length, Is.EqualTo(3)); i = 0; j = 0; for (i = 0; i < arr1.Length; i++) @@ -1188,65 +1177,65 @@ public void ModifyInNestedObjects() if (i == 1) { object[] arr2 = arr1[1] as object[]; - Assert.AreEqual(3, arr2.Length); + Assert.That(arr2.Length, Is.EqualTo(3)); for (j = 0; j < arr2.Length; j++) { if (j == 1) { object[] arr3 = arr2[1] as object[]; - Assert.AreEqual(3, arr3.Length); + Assert.That(arr3.Length, Is.EqualTo(3)); for (k = 0; k < arr3.Length; k++) { if (k == 1) { object[] arr4 = arr3[1] as object[]; - Assert.AreEqual(3, arr4.Length); + Assert.That(arr4.Length, Is.EqualTo(3)); for (l = 0; l < arr4.Length; l++) { if (l == 1) { object[] arr5 = arr4[1] as object[]; - Assert.AreEqual(3, arr5.Length); + Assert.That(arr5.Length, Is.EqualTo(3)); for (m = 0; m < arr5.Length; m++) { if (m == 1) { object[] arr6 = arr5[1] as object[]; - Assert.AreEqual(1, arr6.Length); + Assert.That(arr6.Length, Is.EqualTo(1)); if (arr6.Length == 1) - Assert.AreEqual(4, arr6[0]); + Assert.That(arr6[0], Is.EqualTo(4)); } else - Assert.AreEqual(5, arr5[m]); + Assert.That(arr5[m], Is.EqualTo(5)); if (m == 2) break; } } else - Assert.AreEqual(6, arr4[l]); + Assert.That(arr4[l], Is.EqualTo(6)); if (l == 2) break; } } else - Assert.AreEqual(7, arr3[k]); + Assert.That(arr3[k], Is.EqualTo(7)); if (k == 2) break; } } if (j == 0 || j == 2) - Assert.AreEqual(8, arr2[j]); + Assert.That(arr2[j], Is.EqualTo(8)); if (j == 2) break; } } else - Assert.AreEqual(9, arr1[i]); + Assert.That(arr1[i], Is.EqualTo(9)); if (i == 2) break; } @@ -1258,71 +1247,71 @@ public void ModifyInNestedObjects() listDocs.Add(new DbDoc(documentAsJsonString2)); collection = CreateCollection("test"); Result r = collection.Add(listDocs.ToArray()).Execute(); - Assert.AreEqual(2, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(2)); document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); - Assert.AreEqual("AFRICAN EGG", document["title"]); + Assert.That(document["title"], Is.EqualTo("AFRICAN EGG")); // Modify Using ID and Patch Title collection.Modify("_id = :id").Patch("{ \"title\": \"The African Egg\" }"). Bind("id", "a6f4b93e1a264a108393524f29546a8c").Execute(); document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); - Assert.AreEqual("The African Egg", document["title"]); + Assert.That(document["title"], Is.EqualTo("The African Egg")); - Assert.AreEqual(57, ((Dictionary)((Dictionary)document["additionalinfo"])["director"])["age"]); + Assert.That(((Dictionary)((Dictionary)document["additionalinfo"])["director"])["age"], Is.EqualTo(57)); // Modify Using additionalinfo.director.name = :director and Patch Age 67 collection.Modify("additionalinfo.director.name = :director"). Patch("{ \"additionalinfo\": { \"director\": { \"age\": 67 } } }"). Bind("director", "Sharice Legaspi").Execute(); document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); - Assert.AreEqual(67, ((Dictionary)((Dictionary)document["additionalinfo"])["director"])["age"]); + Assert.That(((Dictionary)((Dictionary)document["additionalinfo"])["director"])["age"], Is.EqualTo(67)); // Modify Using _id=:id and Patch Age 77 collection.Modify("_id = :id"). Patch("{ \"additionalinfo\": { \"director\": { \"age\": 77 } } }"). Bind("id", "a6f4b93e1a264a108393524f29546a8c").Execute(); document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); - Assert.AreEqual(77, ((Dictionary)((Dictionary)document["additionalinfo"])["director"])["age"]); + Assert.That(((Dictionary)((Dictionary)document["additionalinfo"])["director"])["age"], Is.EqualTo(77)); // Modify Using _id=:id and Patch contains movie title collection.Modify("_id = :id"). Patch("{ \"title\": { \"movie\": \"The African Egg\"} }"). Bind("id", "a6f4b93e1a264a108393524f29546a8c").Execute(); document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); - Assert.AreEqual("The African Egg", ((Dictionary)document["title"])["movie"]); + Assert.That(((Dictionary)document["title"])["movie"], Is.EqualTo("The African Egg")); // Modify Using _id=:id and Patch additionalinfo Birthplace director country countryActual collection.Modify("_id = :id"). Patch("{ \"additionalinfo\": { \"director\": { \"birthplace\": { \"country\": { \"countryActual\": \"India\" } } } } }"). Bind("id", "123456789asdferdfghhghjh12334").Execute(); document = collection.GetOne("123456789asdferdfghhghjh12334"); - Assert.AreEqual("India", document["additionalinfo.director.birthplace.country.countryActual"]); + Assert.That(document["additionalinfo.director.birthplace.country.countryActual"], Is.EqualTo("India")); // Modify Using _id=:id and Patch additionalinfo Birthplace director country countryActual" collection.Modify("_id = :id"). Patch("{ \"additionalinfo\": { \"director\": { \"birthplace\": { \"country\": { \"city\": \"NewDelhi\",\"countryActual\": \"India\" } } } } }"). Bind("id", "123456789asdferdfghhghjh12334").Execute(); document = collection.GetOne("123456789asdferdfghhghjh12334"); - Assert.AreEqual("India", document["additionalinfo.director.birthplace.country.countryActual"]); - Assert.AreEqual("NewDelhi", document["additionalinfo.director.birthplace.country.city"]); + Assert.That(document["additionalinfo.director.birthplace.country.countryActual"], Is.EqualTo("India")); + Assert.That(document["additionalinfo.director.birthplace.country.city"], Is.EqualTo("NewDelhi")); // Modify Using _id=:id and Patch additionalinfo Birthplace director country to replace an array collection.Modify("_id = :id"). Patch("{ \"additionalinfo\": { \"director\": { \"birthplace\": { \"country\": \"India\" } } } }"). Bind("id", "123456789asdferdfghhghjh12334").Execute(); document = collection.GetOne("123456789asdferdfghhghjh12334"); - Assert.AreEqual("India", document["additionalinfo.director.birthplace.country"]); + Assert.That(document["additionalinfo.director.birthplace.country"], Is.EqualTo("India")); // Modify Using _id=:id and Patch additionalinfo writers to replace an array collection.Modify("_id = :id"). Patch("{ \"additionalinfo\": { \"writers\": \"Jeoff Archer\" } }"). Bind("id", "123456789asdferdfghhghjh12334").Execute(); document = collection.GetOne("123456789asdferdfghhghjh12334"); - Assert.AreEqual("Jeoff Archer", document["additionalinfo.writers"]); + Assert.That(document["additionalinfo.writers"], Is.EqualTo("Jeoff Archer")); //Reset the docs collection = CreateCollection("test"); r = collection.Add(listDocs.ToArray()).Execute(); - Assert.AreEqual(2, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(2)); // Modify Using _id=:id and Patch contains blank collection.Modify("_id = :id").Patch("{ \"additionalinfo\": \"\" }"). @@ -1335,13 +1324,13 @@ public void ModifyInNestedObjects() [Test, Description("Test valid modify.patch to add/remove fields at Depth for multiple arrays.))")] public void ModifyPatchAtDepthMultipleArrays_S1() { - if (!session.Version.isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher."); + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); Collection collection = CreateCollection("test"); List listDocs = new List(); listDocs.Add(documentsAsDbDocs[0]); listDocs.Add(new DbDoc(documentAsJsonString2)); Result r = collection.Add(listDocs.ToArray()).Execute(); - Assert.AreEqual(2, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(2)); object[] path = null; DbDoc document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); Assert.Throws(() => path = document["translations"] as object[]); @@ -1351,7 +1340,7 @@ public void ModifyPatchAtDepthMultipleArrays_S1() Bind("id", "a6f4b93e1a264a108393524f29546a8c").Execute(); document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); path = document["translations"] as object[]; - Assert.AreEqual("Spanish", path[0], + Assert.That(path[0], Is.EqualTo("Spanish"), "Verify transalations field is present or not"); collection.Modify("_id = :id"). Patch("{ \"translations\": null }"). @@ -1364,7 +1353,7 @@ public void ModifyPatchAtDepthMultipleArrays_S1() Patch("{ \"additionalinfo\": { \"director\": { \"mobile\": \"9876543210\" } } }"). Bind("age", 57).Execute(); document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); - Assert.AreEqual("9876543210", document["additionalinfo.director.mobile"], + Assert.That(document["additionalinfo.director.mobile"], Is.EqualTo("9876543210"), "Verify mobile field is present or not"); collection.Modify("additionalinfo.director.name = :director"). Patch("{ \"additionalinfo\": { \"director\": { \"mobile\": null } } }"). @@ -1377,7 +1366,7 @@ public void ModifyPatchAtDepthMultipleArrays_S1() Patch("{ \"additionalinfo\": { \"musicby\": \"The Sakila\" } }"). Bind("id", "a6f4b93e1a264a108393524f29546a8c").Execute(); document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); - Assert.AreEqual("The Sakila", document["additionalinfo.musicby"], + Assert.That(document["additionalinfo.musicby"], Is.EqualTo("The Sakila"), "Verify musicby field is present or not"); collection.Modify("_id = :id").Patch("{ \"additionalinfo\": { \"musicby\": null } }"). Bind("id", "a6f4b93e1a264a108393524f29546a8c").Execute(); @@ -1389,7 +1378,7 @@ public void ModifyPatchAtDepthMultipleArrays_S1() Patch("{\"additionalinfo\": { \"director\": { \"awards\": { \"genre\": \"Action\" } } } }"). Bind("id", "a6f4b93e1a264a108393524f29546a8c").Execute(); document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); - Assert.AreEqual("Action", document["additionalinfo.director.awards.genre"], + Assert.That(document["additionalinfo.director.awards.genre"], Is.EqualTo("Action"), "Verify musicby field is present or not"); collection.Modify("_id = :id"). Patch("{\"additionalinfo\": { \"director\": { \"awards\": { \"genre\": null } } } }"). @@ -1402,12 +1391,12 @@ public void ModifyPatchAtDepthMultipleArrays_S1() [Test, Description("Test valid modify.patch to use expr to change existing keys in document))")] public void ModifyPatchAtDepthMultipleArrays_S2() { - if (!session.Version.isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher."); + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); DbDoc document = null; Collection collection = CreateCollection("test"); Result r = collection.Add("{ \"_id\": \"123\", \"email\": \"alice@ora.com\", " + "\"startDate\": \"4/1/2017\" }").Execute(); - Assert.AreEqual(1, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); var patch1 = new { email = new MySqlExpression("UPPER($.email)") @@ -1459,16 +1448,16 @@ public void ModifyPatchAtDepthMultipleArrays_S2() collection.Modify("true").Patch(patch1).Execute(); document = collection.GetOne("123"); - Assert.AreEqual("ALICE@ORA.COM", document["email"]); + Assert.That(document["email"], Is.EqualTo("ALICE@ORA.COM")); collection.Modify("true").Patch(patch2).Execute(); document = collection.GetOne("123"); - Assert.AreEqual("alice@ora.com", document["email"]); + Assert.That(document["email"], Is.EqualTo("alice@ora.com")); collection.Modify("true").Patch(patch3).Execute(); document = collection.GetOne("123"); - Assert.AreEqual("NoSQL", document["email"]); + Assert.That(document["email"], Is.EqualTo("NoSQL")); collection.Modify("true").Patch(patch4).Execute(); document = collection.GetOne("123"); - Assert.AreEqual("base64:type15:TXlTUUw=", document["email"]); + Assert.That(document["email"], Is.EqualTo("base64:type15:TXlTUUw=")); collection.Modify("true").Patch(patch5).Execute(); document = collection.GetOne("123"); DbDoc test = null; @@ -1479,84 +1468,84 @@ public void ModifyPatchAtDepthMultipleArrays_S2() "\"startDate\": \"4/1/2017\" }").Execute(); collection.Modify("true").Patch(patch6).Execute(); document = collection.GetOne("123"); - Assert.AreEqual("foo", document["email"]); + Assert.That(document["email"], Is.EqualTo("foo")); collection.Modify("true").Patch(patch7).Execute(); document = collection.GetOne("123"); - Assert.AreEqual("MySQLMySQLMySQL", document["email"]); + Assert.That(document["email"], Is.EqualTo("MySQLMySQLMySQL")); collection.Modify("true").Patch(patch8).Execute(); document = collection.GetOne("123"); - Assert.AreEqual("cba", document["email"]); + Assert.That(document["email"], Is.EqualTo("cba")); collection.Modify("true").Patch(patch9).Execute(); document = collection.GetOne("123"); - Assert.AreEqual("rbar", document["email"]); + Assert.That(document["email"], Is.EqualTo("rbar")); collection.Modify("true").Patch(patch10).Execute(); document = collection.GetOne("123"); - Assert.AreEqual("WwWwWw.mysql.com", document["email"]); + Assert.That(document["email"], Is.EqualTo("WwWwWw.mysql.com")); collection.Modify("true").Patch(patch11).Execute(); document = collection.GetOne("123"); - Assert.AreEqual("616263", document["email"]); + Assert.That(document["email"], Is.EqualTo("616263")); collection.Modify("true").Patch(patch12).Execute(); document = collection.GetOne("123"); - Assert.AreEqual("1100", document["email"]); + Assert.That(document["email"], Is.EqualTo("1100")); string t1 = "{\"_id\": \"1\", \"name\": \"Alice\" }"; collection = CreateCollection("test"); r = collection.Add(t1).Execute(); - Assert.AreEqual(1, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); collection.Modify("_id = :id").Patch("{ \"dateAndTimeValue\": YEAR('2000-01-01') }").Bind("id", "1").Execute(); document = collection.GetOne("1"); - Assert.AreEqual(2000, document["dateAndTimeValue"]); + Assert.That(document["dateAndTimeValue"], Is.EqualTo(2000)); collection.Modify("_id = :id").Patch("{ \"dateAndTimeValue\": MONTH('2008-02-03') }").Bind("id", "1").Execute(); document = collection.GetOne("1"); - Assert.AreEqual(2, document["dateAndTimeValue"]); + Assert.That(document["dateAndTimeValue"], Is.EqualTo(2)); collection.Modify("_id = :id").Patch("{ \"dateAndTimeValue\": WEEK('2008-02-20') }").Bind("id", "1").Execute(); document = collection.GetOne("1"); - Assert.AreEqual(7, document["dateAndTimeValue"]); + Assert.That(document["dateAndTimeValue"], Is.EqualTo(7)); collection.Modify("_id = :id").Patch("{ \"dateAndTimeValue\": DAY('2008-02-20') }").Bind("id", "1").Execute(); document = collection.GetOne("1"); - Assert.AreEqual(20, document["dateAndTimeValue"]); + Assert.That(document["dateAndTimeValue"], Is.EqualTo(20)); collection.Modify("_id = :id").Patch("{ \"dateAndTimeValue\": HOUR('10:05:03') }").Bind("id", "1").Execute(); document = collection.GetOne("1"); - Assert.AreEqual(10, document["dateAndTimeValue"]); + Assert.That(document["dateAndTimeValue"], Is.EqualTo(10)); collection.Modify("_id = :id").Patch("{ \"dateAndTimeValue\": MINUTE('2008-02-03 10:05:03') }").Bind("id", "1").Execute(); document = collection.GetOne("1"); - Assert.AreEqual(5, document["dateAndTimeValue"]); + Assert.That(document["dateAndTimeValue"], Is.EqualTo(5)); collection.Modify("_id = :id").Patch("{ \"dateAndTimeValue\": SECOND('10:05:03') }").Bind("id", "1").Execute(); document = collection.GetOne("1"); - Assert.AreEqual(3, document["dateAndTimeValue"]); + Assert.That(document["dateAndTimeValue"], Is.EqualTo(3)); collection.Modify("_id = :id").Patch("{ \"dateAndTimeValue\": MICROSECOND('12:00:00.123456') }").Bind("id", "1").Execute(); document = collection.GetOne("1"); - Assert.AreEqual(123456, document["dateAndTimeValue"]); + Assert.That(document["dateAndTimeValue"], Is.EqualTo(123456)); collection.Modify("_id = :id").Patch("{ \"dateAndTimeValue\": QUARTER('2008-04-01') }").Bind("id", "1").Execute(); document = collection.GetOne("1"); - Assert.AreEqual(2, document["dateAndTimeValue"]); + Assert.That(document["dateAndTimeValue"], Is.EqualTo(2)); collection.Modify("_id = :id").Patch("{ \"dateAndTimeValue\": TIME('2003-12-31 01:02:03') }").Bind("id", "1").Execute(); document = collection.GetOne("1"); - Assert.AreEqual("01:02:03.000000", document["dateAndTimeValue"]); + Assert.That(document["dateAndTimeValue"], Is.EqualTo("01:02:03.000000")); collection.Modify("_id = :id").Patch("{ \"dateAndTimeValue\": DATE('2003-12-31 01:02:03') }").Bind("id", "1").Execute(); document = collection.GetOne("1"); - Assert.AreEqual("2003-12-31", document["dateAndTimeValue"]); + Assert.That(document["dateAndTimeValue"], Is.EqualTo("2003-12-31")); List listDocs = new List(); listDocs.Add(documentsAsDbDocs[0]); listDocs.Add(new DbDoc(documentAsJsonString2)); r = collection.Add(listDocs.ToArray()).Execute(); - Assert.AreEqual(2, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(2)); document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); object[] actors = document["actors"] as object[]; - Assert.AreEqual(3, actors.Length); + Assert.That(actors.Length, Is.EqualTo(3)); Dictionary actor0 = actors[0] as Dictionary; Assert.Throws(() => test = (DbDoc)actor0["age"]); @@ -1566,52 +1555,52 @@ public void ModifyPatchAtDepthMultipleArrays_S2() "\"DOB\": \"19 Mar 1982\", \"citizen\": \"USA\"}}}"; collection = CreateCollection("test"); r = collection.Add(t1).Execute(); - Assert.AreEqual(1, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); collection.Modify("_id = :id"). Patch("{\"details\":{\"personal\": null,\"mobile\":$.details.personal.mobile,\"yearofbirth\":" + "CAST(SUBSTRING_INDEX($.details.personal.DOB, ' ', -1) AS DECIMAL)}}").Bind("id", "1"). Execute(); document = collection.GetOne("1"); - Assert.AreEqual("Alice", document["name"]); - Assert.AreEqual("9876543210", document["details.mobile"]); - Assert.AreEqual("1982", document["details.yearofbirth"].ToString()); + Assert.That(document["name"], Is.EqualTo("Alice")); + Assert.That(document["details.mobile"], Is.EqualTo("9876543210")); + Assert.That(document["details.yearofbirth"].ToString(), Is.EqualTo("1982")); collection = CreateCollection("test"); r = collection.Add(t1).Execute(); - Assert.AreEqual(1, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); collection.Modify("_id = :id"). Patch("{\"details\":{\"personal\": null,\"mobile\":$.details.personal.mobile,\"currentyear\":" + "CURDATE()}}").Bind("id", "1"). Execute(); document = collection.GetOne("1"); - Assert.AreEqual("Alice", document["name"]); - Assert.AreEqual("9876543210", document["details.mobile"]); - Assert.AreEqual(document["details.currentyear"].ToString(), document["details.currentyear"].ToString(), "Matching the current date"); + Assert.That(document["name"], Is.EqualTo("Alice")); + Assert.That(document["details.mobile"], Is.EqualTo("9876543210")); + Assert.That(document["details.currentyear"].ToString(), Is.EqualTo(document["details.currentyear"].ToString()), "Matching the current date"); collection = CreateCollection("test"); r = collection.Add(t1).Execute(); - Assert.AreEqual(1, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); collection.Modify("_id = :id"). Patch("{\"details\":{\"personal\": null,\"mobile\":$.details.personal.mobile,\"currentyear\":" + "Year(CURDATE())}}").Bind("id", "1"). Execute(); document = collection.GetOne("1"); - Assert.AreEqual("Alice", document["name"]); - Assert.AreEqual("9876543210", document["details.mobile"]); - Assert.AreEqual(document["details.currentyear"].ToString(), document["details.currentyear"].ToString()); + Assert.That(document["name"], Is.EqualTo("Alice")); + Assert.That(document["details.mobile"], Is.EqualTo("9876543210")); + Assert.That(document["details.currentyear"].ToString(), Is.EqualTo(document["details.currentyear"].ToString())); collection = CreateCollection("test"); r = collection.Add(t1).Execute(); - Assert.AreEqual(1, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); collection.Modify("_id = :id"). Patch("{\"details\":{\"personal\": null,\"mobile\":$.details.personal.mobile,\"currentage\":" + "Year(CURDATE()) - CAST(SUBSTRING_INDEX($.details.personal.DOB, ' ', -1) AS DECIMAL)}}").Bind("id", "1"). Execute(); document = collection.GetOne("1"); - Assert.AreEqual("Alice", document["name"]); - Assert.AreEqual("9876543210", document["details.mobile"]); - Assert.AreEqual(document["details.currentage"].ToString(), document["details.currentage"].ToString()); + Assert.That(document["name"], Is.EqualTo("Alice")); + Assert.That(document["details.mobile"], Is.EqualTo("9876543210")); + Assert.That(document["details.currentage"].ToString(), Is.EqualTo(document["details.currentage"].ToString())); collection = CreateCollection("test"); r = collection.Add(listDocs.ToArray()).Execute(); - Assert.AreEqual(2, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(2)); document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); // Get root array. Assert.Throws(() => test = (DbDoc)document["audio"]); @@ -1619,41 +1608,41 @@ public void ModifyPatchAtDepthMultipleArrays_S2() collection.Modify("true"). Patch("{ \"audio\": CONCAT($.language, ', no subtitles') }").Execute(); document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); - Assert.AreEqual("English, no subtitles", document["audio"]); + Assert.That(document["audio"], Is.EqualTo("English, no subtitles")); collection = CreateCollection("test"); r = collection.Add(listDocs.ToArray()).Execute(); - Assert.AreEqual(2, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(2)); document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); Assert.Throws(() => test = (DbDoc)document["audio"]); collection.Modify("true").Patch("{ \"audio\": CONCAT(UPPER($.language), ', No Subtitles') }").Execute(); document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); - Assert.AreEqual("ENGLISH, No Subtitles", document["audio"]); + Assert.That(document["audio"], Is.EqualTo("ENGLISH, No Subtitles")); collection = CreateCollection("test"); r = collection.Add(listDocs.ToArray()).Execute(); - Assert.AreEqual(2, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(2)); collection.Modify("_id = :id").Patch("{ \"_id\": replace(UUID(), '-', '') }"). Bind("id", "a6f4b93e1a264a108393524f29546a8c").Execute(); document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); - Assert.AreEqual("a6f4b93e1a264a108393524f29546a8c", document.Id); + Assert.That(document.Id, Is.EqualTo("a6f4b93e1a264a108393524f29546a8c")); collection = CreateCollection("test"); r = collection.Add(listDocs.ToArray()).Execute(); - Assert.AreEqual(2, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(2)); Assert.Throws(() => test = (DbDoc)document["additionalinfo._id"]); document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); collection.Modify("_id = :id").Patch("{ \"additionalinfo\": { \"_id\": replace(UUID(), '-', '') } }"). Bind("id", "a6f4b93e1a264a108393524f29546a8c").Execute(); document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); - Assert.True(((Dictionary)document["additionalinfo"])["_id"] != null); + Assert.That(((Dictionary)document["additionalinfo"])["_id"] != null); collection = CreateCollection("test"); r = collection.Add(listDocs.ToArray()).Execute(); - Assert.AreEqual(2, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(2)); document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); Assert.Throws(() => test = (DbDoc)document["additionalinfo.releasedate"]); @@ -1666,15 +1655,15 @@ public void ModifyPatchAtDepthMultipleArrays_S2() } catch (MySqlException ex) { - Assert.AreEqual("Invalid data for update operation on document collection table", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Invalid data for update operation on document collection table")); } collection = CreateCollection("test"); r = collection.Add(listDocs.ToArray()).Execute(); - Assert.AreEqual(2, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(2)); document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); - Assert.AreEqual("AFRICAN EGG", document["title"]); + Assert.That(document["title"], Is.EqualTo("AFRICAN EGG")); collection.Modify("_id = :id").Patch("{ \"title\": concat('my ', NULL, ' title') }"). Bind("id", "a6f4b93e1a264a108393524f29546a8c").Execute(); document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); @@ -1682,7 +1671,7 @@ public void ModifyPatchAtDepthMultipleArrays_S2() collection = CreateCollection("test"); r = collection.Add(listDocs.ToArray()).Execute(); - Assert.AreEqual(2, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(2)); document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); Assert.Throws(() => test = (DbDoc)document["docfield"]); @@ -1692,26 +1681,26 @@ public void ModifyPatchAtDepthMultipleArrays_S2() document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); object docField = document["docfield"] as object; - Assert.True(docField != null); + Assert.That(docField != null); collection = CreateCollection("test"); r = collection.Add(listDocs.ToArray()).Execute(); - Assert.AreEqual(2, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(2)); document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); - Assert.AreEqual("Science fiction", document["genre"]); + Assert.That(document["genre"], Is.EqualTo("Science fiction")); collection.Modify("_id = :id").Patch("{ \"genre\": JSON_OBJECT('name', 'Science Fiction') }"). Bind("id", "a6f4b93e1a264a108393524f29546a8c").Execute(); document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); - Assert.AreEqual("Science Fiction", ((Dictionary)document["genre"])["name"]); + Assert.That(((Dictionary)document["genre"])["name"], Is.EqualTo("Science Fiction")); } [Test, Description("Test invalid modify.patch to attempt to use invalid string (non JSON string/empty/NULL) as patch string.))")] public void ModifyPatchInvalidString() { - if (!session.Version.isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher."); + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); var collection = CreateCollection("test"); var docs = new[] { @@ -1721,7 +1710,7 @@ public void ModifyPatchInvalidString() new {_id = 4, title = "Book 4", pages = 50,age = 12} }; Result r = collection.Add(docs).Execute(); - Assert.AreEqual(4, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(4)); var document = collection.GetOne("1"); var jsonParams = "invalidJsonString"; Assert.Throws(() => ExecuteModifyStatement(collection.Modify("age = :age").Patch(jsonParams).Bind("age", "12"))); @@ -1742,14 +1731,14 @@ public void ModifyPatchInvalidString() r = collection.Add(documentsAsJsonStrings).Execute(); - Assert.AreEqual(1, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); collection.Modify("true").Patch("{ \"_id\": NULL }").Execute(); - Assert.AreEqual("1", collection.Find().Execute().FetchOne().Id.ToString()); + Assert.That(collection.Find().Execute().FetchOne().Id.ToString(), Is.EqualTo("1")); collection = CreateCollection("test"); r = collection.Add(documentsAsJsonStrings).Execute(); - Assert.AreEqual(1, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); collection.Modify("true").Patch("{ \"nullfield\": NULL }").Execute(); DbDoc test = null; @@ -1758,18 +1747,18 @@ public void ModifyPatchInvalidString() collection.Modify("true").Patch("{ \"nullfield\": [NULL, NULL] }").Execute(); document = collection.Find().Execute().FetchOne(); var nullArray = (object[])document["nullfield"]; - Assert.AreEqual(null, nullArray[0]); - Assert.AreEqual(null, nullArray[1]); + Assert.That(nullArray[0], Is.EqualTo(null)); + Assert.That(nullArray[1], Is.EqualTo(null)); collection.Modify("true").Patch("{ \"nullfield\": { \"nested\": NULL } }").Execute(); document = collection.Find().Execute().FetchOne(); - Assert.AreEqual(true, ((Dictionary)document["nullfield"]).Count == 0); + Assert.That(((Dictionary)document["nullfield"]).Count == 0, Is.EqualTo(true)); collection.Modify("true").Patch("{ \"nullfield\": { \"nested\": [NULL, NULL] } }").Execute(); document = collection.Find().Execute().FetchOne(); var nestedNullArray = (object[])((Dictionary)document["nullfield"])["nested"]; - Assert.AreEqual(null, nestedNullArray[0]); - Assert.AreEqual(null, nestedNullArray[1]); + Assert.That(nestedNullArray[0], Is.EqualTo(null)); + Assert.That(nestedNullArray[1], Is.EqualTo(null)); collection.Modify("true").Patch("{ \"additionalinfo\": { \"nullfield\": NULL } }").Execute(); Dictionary test2 = null; @@ -1778,20 +1767,20 @@ public void ModifyPatchInvalidString() collection.Modify("true").Patch("{ \"additionalinfo\": { \"nullfield\": [NULL, NULL] } }").Execute(); document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); nestedNullArray = (object[])((Dictionary)document["additionalinfo"])["nullfield"]; - Assert.AreEqual(null, nestedNullArray[0]); - Assert.AreEqual(null, nestedNullArray[1]); + Assert.That(nestedNullArray[0], Is.EqualTo(null)); + Assert.That(nestedNullArray[1], Is.EqualTo(null)); collection.Modify("true").Patch("{ \"additionalinfo\": { \"nullfield\": { \"nested\": [NULL, NULL] } } }").Execute(); document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); nestedNullArray = (object[])((((Dictionary)((Dictionary)document["additionalinfo"])["nullfield"]))["nested"]); - Assert.AreEqual(null, nestedNullArray[0]); - Assert.AreEqual(null, nestedNullArray[1]); + Assert.That(nestedNullArray[0], Is.EqualTo(null)); + Assert.That(nestedNullArray[1], Is.EqualTo(null)); collection.Modify("true").Patch("{ \"additionalinfo\": { \"nullfield\": { \"nested\": JSON_OBJECT('field', null) } } }").Execute(); document = collection.GetOne("a6f4b93e1a264a108393524f29546a8c"); var nestedObject = (Dictionary)((Dictionary)((Dictionary)document["additionalinfo.nullfield.nested"])); - Assert.AreEqual(0, nestedObject.Count); + Assert.That(nestedObject.Count, Is.EqualTo(0)); } #endregion WL14389 diff --git a/MySQL.Data/tests/MySqlX.Data.Tests/MockServer.cs b/MySQL.Data/tests/MySqlX.Data.Tests/MockServer.cs new file mode 100644 index 000000000..d600576b6 --- /dev/null +++ b/MySQL.Data/tests/MySqlX.Data.Tests/MockServer.cs @@ -0,0 +1,138 @@ +// Copyright © 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using System; +using System.Net; +using System.Net.Sockets; +using System.Threading; +using System.Threading.Tasks; + +namespace MySqlX.Data.Tests +{ + public class MockServer + { + private TcpListener listener; + + private int _port; + + private IPAddress _address; + + private ManualResetEvent _stopserver = new ManualResetEvent(false); + + private CancellationTokenSource cts; + + private bool _usetimeout; + + public int Port + { + get => _port; + set => _port = value; + } + + public IPAddress Address + { + get => _address; + set => _address = value; + } + + public MockServer(bool usetimeout) + { + GetMockServerInfo(); + _stopserver.Reset(); + _usetimeout = usetimeout; + cts = new CancellationTokenSource(TimeSpan.FromSeconds(12)); + } + + public void GetMockServerInfo() + { + TcpListener loopback = new TcpListener(IPAddress.Loopback, 0); + loopback.Start(); + _port = ((IPEndPoint)loopback.LocalEndpoint).Port; + loopback.Stop(); + _address = Dns.GetHostEntry("localhost").AddressList[0]; + } + + public void StopServer() + { + _stopserver.Set(); + } + public void DisposeListener() + { + if (listener != null) + { + listener.Stop(); + } + } + + public async Task ServerWorker(CancellationToken ct) + { + await Task.Run(() => + { + IPEndPoint endpoint = new IPEndPoint(IPAddress.Loopback, Port); + listener = new(endpoint); + + try + { + listener.Start(); + while (!_stopserver.WaitOne(1)) + { + listener.BeginAcceptSocket(new AsyncCallback(beginConnection), null); + } + } + catch (Exception) + { + } + finally + { + listener.Stop(); + } + }, ct).ConfigureAwait(false); + } + + public void StartServer() + { + ServerWorker(cts.Token).ConfigureAwait(false); + } + + private void beginConnection(IAsyncResult iar) + { + try + { + Socket client = listener.EndAcceptSocket(iar); + if (_usetimeout) + { + Task.Delay(500).Wait(); + client.Close(); + } + } + catch (Exception) + { + } + } + } +} \ No newline at end of file diff --git a/MySQL.Data/tests/MySqlX.Data.Tests/MySqlX.Data.Tests.csproj b/MySQL.Data/tests/MySqlX.Data.Tests/MySqlX.Data.Tests.csproj index e4f19faa7..0835199a7 100644 --- a/MySQL.Data/tests/MySqlX.Data.Tests/MySqlX.Data.Tests.csproj +++ b/MySQL.Data/tests/MySqlX.Data.Tests/MySqlX.Data.Tests.csproj @@ -3,17 +3,17 @@ MySql.Data.Tests MySql.Data.Tests Class Library - Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. - 8.2.0 + Copyright © 2016, 2025, Oracle and/or its affiliates. + 9.4.0 Oracle Oracle MySql.Data.Tests - net8.0;net7.0;net6.0;net462;net48; + net9.0;net8.0; MySqlx.Data.Tests MySql;.NET Connector;MySql Connector/NET;netcore;.Net Core;MySql Conector/Net Core;coreclr;C/NET;C/Net Core http://www.mysql.com/common/logos/logo-mysql-170x115.png http://dev.mysql.com/downloads/ - GPL-2.0-only + GPL-2.0-only WITH Universal-FOSS-exception-1.0 true false false @@ -28,6 +28,14 @@ latest + + $(TargetFrameworks);net10.0 + + + + net462;net48;$(TargetFrameworks) + + @@ -62,10 +70,9 @@ - - - - + + + diff --git a/MySQL.Data/tests/MySqlX.Data.Tests/PerformanceTests.cs b/MySQL.Data/tests/MySqlX.Data.Tests/PerformanceTests.cs index a5fc6c523..b35491dff 100644 --- a/MySQL.Data/tests/MySqlX.Data.Tests/PerformanceTests.cs +++ b/MySQL.Data/tests/MySqlX.Data.Tests/PerformanceTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2018, 2021, Oracle and/or its affiliates. +// Copyright © 2018, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySQL.Data/tests/MySqlX.Data.Tests/PreparedStatementsTests.cs b/MySQL.Data/tests/MySqlX.Data.Tests/PreparedStatementsTests.cs index f6e5fc910..c33e85059 100644 --- a/MySQL.Data/tests/MySqlX.Data.Tests/PreparedStatementsTests.cs +++ b/MySQL.Data/tests/MySqlX.Data.Tests/PreparedStatementsTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2018, 2023, Oracle and/or its affiliates. +// Copyright © 2018, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -33,6 +33,7 @@ using MySqlX.XDevAPI.CRUD; using MySqlX.XDevAPI.Relational; using NUnit.Framework; +using NUnit.Framework.Legacy; using System; using System.Collections.Generic; using System.Threading.Tasks; @@ -65,7 +66,7 @@ private void InitCollection() { Collection coll = CreateCollection(_collectionName); Result r = ExecuteAddStatement(coll.Add(_docs)); - Assert.AreEqual(4, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(4)); } public void InitTable() @@ -100,11 +101,11 @@ private void ValidatePreparedStatements(int count, ulong executions, string sqlT $"WHERE {condition}"; var preparedStatements = ExecuteSQL(sql).FetchAll(); - Assert.AreEqual(count, preparedStatements.Count); + Assert.That(preparedStatements.Count, Is.EqualTo(count)); if (count > 0) { - StringAssert.AreEqualIgnoringCase(sqlText, preparedStatements[0]["SQL_TEXT"].ToString()); - Assert.AreEqual(executions, preparedStatements[0]["COUNT_EXECUTE"]); + Assert.That(preparedStatements[0]["SQL_TEXT"].ToString(), Is.EqualTo(sqlText).IgnoreCase); + Assert.That(preparedStatements[0]["COUNT_EXECUTE"], Is.EqualTo(executions)); } } @@ -123,15 +124,15 @@ public void Find() Collection coll = GetCollection(); var findStmt = coll.Find("_id = :id and pages = :pages").Bind("id", 1).Bind("pages", 20); var doc = ExecuteFindStatement(findStmt); - Assert.AreEqual("Book 1", doc.FetchAll()[0]["title"].ToString()); - Assert.False(findStmt._isPrepared); + Assert.That(doc.FetchAll()[0]["title"].ToString(), Is.EqualTo("Book 1")); + Assert.That(findStmt._isPrepared, Is.False); ValidatePreparedStatements(0, 0, null); for (int i = 1; i <= _docs.Length; i++) { doc = ExecuteFindStatement(findStmt.Bind("id", i).Bind("pages", i * 10 + 10).Limit(1)); - Assert.AreEqual($"Book {i}", doc.FetchAll()[0]["title"].ToString()); - Assert.True(findStmt._isPrepared || !findStmt.Session.SupportsPreparedStatements); + Assert.That(doc.FetchAll()[0]["title"].ToString(), Is.EqualTo($"Book {i}")); + Assert.That(findStmt._isPrepared || !findStmt.Session.SupportsPreparedStatements); } ValidatePreparedStatements(1, 4, @@ -146,13 +147,13 @@ public void FindWithChanges() var findStmt = coll.Find("_id = 1"); var foundDoc = ExecuteFindStatement(findStmt); - Assert.AreEqual("Book 1", foundDoc.FetchAll()[0]["title"].ToString()); - Assert.False(findStmt._isPrepared); + Assert.That(foundDoc.FetchAll()[0]["title"].ToString(), Is.EqualTo("Book 1")); + Assert.That(findStmt._isPrepared, Is.False); ValidatePreparedStatements(0, 0, null); foundDoc = ExecuteFindStatement(findStmt.Limit(1)); - Assert.AreEqual("Book 1", foundDoc.FetchAll()[0]["title"].ToString()); - Assert.True(findStmt._isPrepared || !findStmt.Session.SupportsPreparedStatements); + Assert.That(foundDoc.FetchAll()[0]["title"].ToString(), Is.EqualTo("Book 1")); + Assert.That(findStmt._isPrepared || !findStmt.Session.SupportsPreparedStatements); ValidatePreparedStatements(1, 1, $"SELECT doc FROM `{schemaName}`.`{_collectionName}` WHERE (JSON_UNQUOTE(JSON_EXTRACT(doc,'$._id')) = 1) LIMIT ?, ?"); @@ -160,8 +161,8 @@ public void FindWithChanges() for (int i = 1; i <= _docs.Length; i++) { var foundDoc2 = ExecuteFindStatement(findStmt.Where($"_id = {i}")); - Assert.AreEqual($"Book {i}", foundDoc2.FetchAll()[0]["title"].ToString()); - Assert.False(findStmt._isPrepared); + Assert.That(foundDoc2.FetchAll()[0]["title"].ToString(), Is.EqualTo($"Book {i}")); + Assert.That(findStmt._isPrepared, Is.False); } ValidatePreparedStatements(0, 0, null); @@ -181,13 +182,13 @@ public void DeallocatePreparedStatmentsWhenClosingSession() var findStmt = coll.Find($"_id = 1"); var foundDoc = ExecuteFindStatement(findStmt); - Assert.AreEqual("Book 1", foundDoc.FetchAll()[0]["title"].ToString()); - Assert.False(findStmt._isPrepared); + Assert.That(foundDoc.FetchAll()[0]["title"].ToString(), Is.EqualTo("Book 1")); + Assert.That(findStmt._isPrepared, Is.False); ValidatePreparedStatements(0, 0, null, threadId); foundDoc = ExecuteFindStatement(findStmt.Limit(1)); - Assert.AreEqual("Book 1", foundDoc.FetchAll()[0]["title"].ToString()); - Assert.True(findStmt._isPrepared || !findStmt.Session.SupportsPreparedStatements); + Assert.That(foundDoc.FetchAll()[0]["title"].ToString(), Is.EqualTo("Book 1")); + Assert.That(findStmt._isPrepared || !findStmt.Session.SupportsPreparedStatements); if (findStmt.Session.SupportsPreparedStatements) { @@ -207,15 +208,15 @@ public void Select() Table table = GetTable(); var selectStmt = table.Select().Where("id = :id").Bind("id", 1); RowResult row = ExecuteSelectStatement(selectStmt); - Assert.AreEqual(_allRows[0][1], row.FetchAll()[0]["name"].ToString()); - Assert.False(selectStmt._isPrepared); + Assert.That(row.FetchAll()[0]["name"].ToString(), Is.EqualTo(_allRows[0][1])); + Assert.That(selectStmt._isPrepared, Is.False); ValidatePreparedStatements(0, 0, null); for (int i = 0; i < _allRows.Length; i++) { row = ExecuteSelectStatement(selectStmt.Bind("id", i + 1).Limit(1)); - Assert.AreEqual(_allRows[i][1], row.FetchAll()[0]["name"].ToString()); - Assert.True(selectStmt._isPrepared || !selectStmt.Session.SupportsPreparedStatements); + Assert.That(row.FetchAll()[0]["name"].ToString(), Is.EqualTo(_allRows[i][1])); + Assert.That(selectStmt._isPrepared || !selectStmt.Session.SupportsPreparedStatements); } ValidatePreparedStatements(1, 3, @@ -230,13 +231,13 @@ public void SelectWithChanges() var selectStmt = table.Select().Where("id = 1"); RowResult row = ExecuteSelectStatement(selectStmt); - Assert.AreEqual(_allRows[0][1], row.FetchAll()[0]["name"].ToString()); - Assert.False(selectStmt._isPrepared); + Assert.That(row.FetchAll()[0]["name"].ToString(), Is.EqualTo(_allRows[0][1])); + Assert.That(selectStmt._isPrepared, Is.False); ValidatePreparedStatements(0, 0, null); row = ExecuteSelectStatement(selectStmt.Limit(1)); - Assert.AreEqual(_allRows[0][1], row.FetchAll()[0]["name"].ToString()); - Assert.True(selectStmt._isPrepared || !selectStmt.Session.SupportsPreparedStatements); + Assert.That(row.FetchAll()[0]["name"].ToString(), Is.EqualTo(_allRows[0][1])); + Assert.That(selectStmt._isPrepared || !selectStmt.Session.SupportsPreparedStatements); ValidatePreparedStatements(1, 1, $"SELECT * FROM `{schemaName}`.`{_tableName}` WHERE (`id` = 1) LIMIT ?, ?"); @@ -244,8 +245,8 @@ public void SelectWithChanges() for (int i = 2; i <= _allRows.Length; i++) { row = ExecuteSelectStatement(selectStmt.Where($"id = {i}")); - Assert.AreEqual(_allRows[i - 1][1], row.FetchAll()[0]["name"].ToString()); - Assert.False(selectStmt._isPrepared); + Assert.That(row.FetchAll()[0]["name"].ToString(), Is.EqualTo(_allRows[i - 1][1])); + Assert.That(selectStmt._isPrepared, Is.False); } ValidatePreparedStatements(0, 0, null); @@ -258,15 +259,15 @@ public void Modify() Collection coll = GetCollection(); var modifyStmt = coll.Modify("_id = :id").Set("title", "Magazine 1").Bind("id", 1); Result result = ExecuteModifyStatement(modifyStmt); - Assert.AreEqual(1ul, result.AffectedItemsCount); - Assert.False(modifyStmt._isPrepared); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1ul)); + Assert.That(modifyStmt._isPrepared, Is.False); ValidatePreparedStatements(0, 0, null); for (int i = 2; i <= _docs.Length; i++) { result = ExecuteModifyStatement(modifyStmt.Bind("id", i).Limit(1)); - Assert.AreEqual(1ul, result.AffectedItemsCount); - Assert.True(modifyStmt._isPrepared || !modifyStmt.Session.SupportsPreparedStatements); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1ul)); + Assert.That(modifyStmt._isPrepared || !modifyStmt.Session.SupportsPreparedStatements); } ValidatePreparedStatements(1, 3, @@ -280,21 +281,21 @@ public void ModifyWithChanges() Collection coll = GetCollection(); var modifyStmt = coll.Modify("_id = :id").Set("title", "CONCAT('Magazine ', id)").Bind("id", 1); Result result = ExecuteModifyStatement(modifyStmt); - Assert.AreEqual(1ul, result.AffectedItemsCount); - Assert.False(modifyStmt._isPrepared); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1ul)); + Assert.That(modifyStmt._isPrepared, Is.False); ValidatePreparedStatements(0, 0, null); result = ExecuteModifyStatement(modifyStmt.Bind("id", 2).Limit(1)); - Assert.AreEqual(1ul, result.AffectedItemsCount); - Assert.True(modifyStmt._isPrepared || !modifyStmt.Session.SupportsPreparedStatements); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1ul)); + Assert.That(modifyStmt._isPrepared || !modifyStmt.Session.SupportsPreparedStatements); ValidatePreparedStatements(1, 1, $"UPDATE `{schemaName}`.`{_collectionName}` SET doc=JSON_SET(JSON_SET(doc,'$.title','CONCAT(\\'Magazine \\', id)'),'$._id',JSON_EXTRACT(`doc`,'$._id')) WHERE (JSON_EXTRACT(doc,'$._id') = ?) LIMIT ?"); for (int i = 3; i <= _docs.Length; i++) { result = ExecuteModifyStatement(modifyStmt.Set("title", $"Magazine {i}").Bind("id", i)); - Assert.AreEqual(1ul, result.AffectedItemsCount); - Assert.False(modifyStmt._isPrepared); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1ul)); + Assert.That(modifyStmt._isPrepared, Is.False); } ValidatePreparedStatements(0, 0, null); @@ -307,15 +308,15 @@ public void Update() Table table = GetTable(); var updateStmt = table.Update().Where("id = :id").Set("name", "Magazine").Bind("id", 1); Result result = ExecuteUpdateStatement(updateStmt); - Assert.AreEqual(1ul, result.AffectedItemsCount); - Assert.False(updateStmt._isPrepared); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1ul)); + Assert.That(updateStmt._isPrepared, Is.False); ValidatePreparedStatements(0, 0, null); for (int i = 2; i <= _allRows.Length; i++) { result = ExecuteUpdateStatement(updateStmt.Bind("id", i).Limit(1)); - Assert.AreEqual(1ul, result.AffectedItemsCount); - Assert.True(updateStmt._isPrepared || !updateStmt.Session.SupportsPreparedStatements); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1ul)); + Assert.That(updateStmt._isPrepared || !updateStmt.Session.SupportsPreparedStatements); } ValidatePreparedStatements(1, 2, @@ -329,21 +330,21 @@ public void UpdateWithChanges() Table table = GetTable(); var updateStmt = table.Update().Where("id = :id").Set("name", "CONCAT('Magazine ', id)").Bind("id", 1); Result result = ExecuteUpdateStatement(updateStmt); - Assert.AreEqual(1ul, result.AffectedItemsCount); - Assert.False(updateStmt._isPrepared); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1ul)); + Assert.That(updateStmt._isPrepared, Is.False); ValidatePreparedStatements(0, 0, null); result = ExecuteUpdateStatement(updateStmt.Bind("id", 2).Limit(1)); - Assert.AreEqual(1ul, result.AffectedItemsCount); - Assert.True(updateStmt._isPrepared || !updateStmt.Session.SupportsPreparedStatements); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1ul)); + Assert.That(updateStmt._isPrepared || !updateStmt.Session.SupportsPreparedStatements); ValidatePreparedStatements(1, 1, $"UPDATE `{schemaName}`.`{_tableName}` SET `name`=CONCAT('Magazine ',`id`) WHERE (`id` = ?) LIMIT ?"); for (int i = 3; i <= _allRows.Length; i++) { result = ExecuteUpdateStatement(updateStmt.Set("name", $"Magazine {i}").Bind("id", i)); - Assert.AreEqual(1ul, result.AffectedItemsCount); - Assert.False(updateStmt._isPrepared); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1ul)); + Assert.That(updateStmt._isPrepared, Is.False); } ValidatePreparedStatements(0, 0, null); @@ -356,15 +357,15 @@ public void Remove() Collection coll = GetCollection(); var removeStmt = coll.Remove("_id = :id").Bind("id", 1); Result result = ExecuteRemoveStatement(removeStmt); - Assert.AreEqual(1ul, result.AffectedItemsCount); - Assert.False(removeStmt._isPrepared); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1ul)); + Assert.That(removeStmt._isPrepared, Is.False); ValidatePreparedStatements(0, 0, null); for (int i = 2; i <= _docs.Length; i++) { result = ExecuteRemoveStatement(removeStmt.Bind("id", i).Limit(1)); - Assert.AreEqual(1ul, result.AffectedItemsCount); - Assert.True(removeStmt._isPrepared || !removeStmt.Session.SupportsPreparedStatements); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1ul)); + Assert.That(removeStmt._isPrepared || !removeStmt.Session.SupportsPreparedStatements); } ValidatePreparedStatements(1, 3, @@ -378,21 +379,21 @@ public void RemoveWithChanges() Collection coll = GetCollection(); var removeStmt = coll.Remove("_id = :id").Bind("id", 1); Result result = ExecuteRemoveStatement(removeStmt); - Assert.AreEqual(1ul, result.AffectedItemsCount); - Assert.False(removeStmt._isPrepared); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1ul)); + Assert.That(removeStmt._isPrepared, Is.False); ValidatePreparedStatements(0, 0, null); result = ExecuteRemoveStatement(removeStmt.Bind("id", 2).Limit(1)); - Assert.AreEqual(1ul, result.AffectedItemsCount); - Assert.True(removeStmt._isPrepared || !removeStmt.Session.SupportsPreparedStatements); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1ul)); + Assert.That(removeStmt._isPrepared || !removeStmt.Session.SupportsPreparedStatements); ValidatePreparedStatements(1, 1, $"DELETE FROM `{schemaName}`.`{_collectionName}` WHERE (JSON_EXTRACT(doc,'$._id') = ?) LIMIT ?"); for (int i = 3; i <= _docs.Length; i++) { result = ExecuteRemoveStatement(removeStmt.Where($"_id = {i}")); - Assert.AreEqual(1ul, result.AffectedItemsCount); - Assert.False(removeStmt._isPrepared); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1ul)); + Assert.That(removeStmt._isPrepared, Is.False); } ValidatePreparedStatements(0, 0, null); @@ -405,15 +406,15 @@ public void Delete() Table table = GetTable(); var deleteStmt = table.Delete().Where("id = :id").Bind("id", 1); Result result = ExecuteDeleteStatement(deleteStmt); - Assert.AreEqual(1ul, result.AffectedItemsCount); - Assert.False(deleteStmt._isPrepared); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1ul)); + Assert.That(deleteStmt._isPrepared, Is.False); ValidatePreparedStatements(0, 0, null); for (int i = 2; i <= _allRows.Length; i++) { result = ExecuteDeleteStatement(deleteStmt.Bind("id", i).Limit(1)); - Assert.AreEqual(1ul, result.AffectedItemsCount); - Assert.True(deleteStmt._isPrepared || !deleteStmt.Session.SupportsPreparedStatements); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1ul)); + Assert.That(deleteStmt._isPrepared || !deleteStmt.Session.SupportsPreparedStatements); } ValidatePreparedStatements(1, 2, @@ -427,21 +428,21 @@ public void DeleteWithChanges() Table table = GetTable(); var deleteStmt = table.Delete().Where("id = :id").Bind("id", 1); Result result = ExecuteDeleteStatement(deleteStmt); - Assert.AreEqual(1ul, result.AffectedItemsCount); - Assert.False(deleteStmt._isPrepared); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1ul)); + Assert.That(deleteStmt._isPrepared, Is.False); ValidatePreparedStatements(0, 0, null); result = ExecuteDeleteStatement(deleteStmt.Bind("id", 2).Limit(1)); - Assert.AreEqual(1ul, result.AffectedItemsCount); - Assert.True(deleteStmt._isPrepared || !deleteStmt.Session.SupportsPreparedStatements); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1ul)); + Assert.That(deleteStmt._isPrepared || !deleteStmt.Session.SupportsPreparedStatements); ValidatePreparedStatements(1, 1, $"DELETE FROM `{schemaName}`.`{_tableName}` WHERE (`id` = ?) LIMIT ?"); for (int i = 3; i <= _allRows.Length; i++) { result = ExecuteDeleteStatement(deleteStmt.Where($"id = {i}")); - Assert.AreEqual(1ul, result.AffectedItemsCount); - Assert.False(deleteStmt._isPrepared); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1ul)); + Assert.That(deleteStmt._isPrepared, Is.False); } ValidatePreparedStatements(0, 0, null); @@ -457,20 +458,20 @@ public void MaxPreparedStmtCount() ((Session)coll.Session).SQL("SET GLOBAL max_prepared_stmt_count=0").Execute(); var findStmt = coll.Find("_id = :id and pages = :pages").Bind("id", 1).Bind("pages", 20); var doc = ExecuteFindStatement(findStmt); - Assert.AreEqual("Book 1", doc.FetchAll()[0]["title"].ToString()); - Assert.False(findStmt._isPrepared); - Assert.True(findStmt.Session.SupportsPreparedStatements); + Assert.That(doc.FetchAll()[0]["title"].ToString(), Is.EqualTo("Book 1")); + Assert.That(findStmt._isPrepared, Is.False); + Assert.That(findStmt.Session.SupportsPreparedStatements); ValidatePreparedStatements(0, 0, null); doc = ExecuteFindStatement(findStmt.Bind("id", 2).Bind("pages", 30).Limit(1)); - Assert.AreEqual($"Book 2", doc.FetchAll()[0]["title"].ToString()); - Assert.False(findStmt._isPrepared); - Assert.False(findStmt.Session.SupportsPreparedStatements); + Assert.That(doc.FetchAll()[0]["title"].ToString(), Is.EqualTo($"Book 2")); + Assert.That(findStmt._isPrepared, Is.False); + Assert.That(findStmt.Session.SupportsPreparedStatements, Is.False); doc = ExecuteFindStatement(findStmt.Bind("id", 3).Bind("pages", 40).Limit(1)); - Assert.AreEqual($"Book 3", doc.FetchAll()[0]["title"].ToString()); - Assert.False(findStmt._isPrepared); - Assert.False(findStmt.Session.SupportsPreparedStatements); + Assert.That(doc.FetchAll()[0]["title"].ToString(), Is.EqualTo($"Book 3")); + Assert.That(findStmt._isPrepared, Is.False); + Assert.That(findStmt.Session.SupportsPreparedStatements, Is.False); } finally { @@ -488,34 +489,34 @@ public void LimitAndOffset() var findStmt = coll.Find("pages >= :lower AND pages <= :upper").Bind("lower", 20).Bind("upper", 20); var result = ExecuteFindStatement(findStmt).FetchAll(); Assert.That(result, Has.One.Items); - Assert.AreEqual("Book 1", result[0]["title"].ToString()); - Assert.False(findStmt._isPrepared); + Assert.That(result[0]["title"].ToString(), Is.EqualTo("Book 1")); + Assert.That(findStmt._isPrepared, Is.False); ValidatePreparedStatements(0, 0, null); // second execution adding limit (prepared statement) result = ExecuteFindStatement(findStmt.Bind("lower", 0).Bind("upper", 100).Limit(1)).FetchAll(); Assert.That(result, Has.One.Items); - Assert.AreEqual($"Book 1", result[0]["title"].ToString()); - Assert.True(findStmt._isPrepared); + Assert.That(result[0]["title"].ToString(), Is.EqualTo($"Book 1")); + Assert.That(findStmt._isPrepared); ValidatePreparedStatements(1, 1, $"SELECT doc FROM `{schemaName}`.`{_collectionName}` WHERE ((JSON_EXTRACT(doc,'$.pages') >= ?) AND (JSON_EXTRACT(doc,'$.pages') <= ?)) LIMIT ?, ?"); // new execution using a different limit and offset (prepared statement) result = ExecuteFindStatement(findStmt.Bind("lower", 0).Bind("upper", 100).Limit(2).Offset(1)).FetchAll(); - Assert.AreEqual(2, result.Count); - Assert.AreEqual($"Book 2", result[0]["title"].ToString()); - Assert.AreEqual($"Book 3", result[1]["title"].ToString()); - Assert.True(findStmt._isPrepared || !findStmt.Session.SupportsPreparedStatements); + Assert.That(result.Count, Is.EqualTo(2)); + Assert.That(result[0]["title"].ToString(), Is.EqualTo($"Book 2")); + Assert.That(result[1]["title"].ToString(), Is.EqualTo($"Book 3")); + Assert.That(findStmt._isPrepared || !findStmt.Session.SupportsPreparedStatements); ValidatePreparedStatements(1, 2, $"SELECT doc FROM `{schemaName}`.`{_collectionName}` WHERE ((JSON_EXTRACT(doc,'$.pages') >= ?) AND (JSON_EXTRACT(doc,'$.pages') <= ?)) LIMIT ?, ?"); // execution without limit and offset but persisting previous values (prepared statement) result = ExecuteFindStatement(findStmt.Bind("lower", 0).Bind("upper", 100)).FetchAll(); - Assert.AreEqual(2, result.Count); - Assert.True(findStmt._isPrepared); + Assert.That(result.Count, Is.EqualTo(2)); + Assert.That(findStmt._isPrepared); ValidatePreparedStatements(1, 3, $"SELECT doc FROM `{schemaName}`.`{_collectionName}` WHERE ((JSON_EXTRACT(doc,'$.pages') >= ?) AND (JSON_EXTRACT(doc,'$.pages') <= ?)) LIMIT ?, ?"); @@ -543,16 +544,16 @@ public void ConnectionPoolingTest() { var row = res0.FetchOne(); connectionID1 = row[0].ToString(); - Assert.IsNotEmpty(connectionID1); + Assert.That(connectionID1, Is.Not.Empty); } var findStmt = col.Find("_id = :id and pages = :pages").Bind("id", 1).Bind("pages", 20); var doc = ExecuteFindStatement(findStmt); - Assert.AreEqual("Book 1", doc.FetchAll()[0]["title"].ToString()); + Assert.That(doc.FetchAll()[0]["title"].ToString(), Is.EqualTo("Book 1")); ValidatePreparedStatements(0, 0, null); for (int i = 1; i < _docs.Length; i++) { doc = ExecuteFindStatement(findStmt.Bind("id", i).Bind("pages", i * 10 + 10).Limit(1)); - Assert.AreEqual($"Book {i}", doc.FetchAll()[0]["title"].ToString()); + Assert.That(doc.FetchAll()[0]["title"].ToString(), Is.EqualTo($"Book {i}")); } ValidatePreparedStatements(1, 3, $"SELECT doc FROM `{schemaName}`.`{_collectionName}` WHERE ((JSON_UNQUOTE(JSON_EXTRACT(doc,'$._id')) = ?) AND (JSON_EXTRACT(doc,'$.pages') = ?)) LIMIT ?, ?"); @@ -564,18 +565,18 @@ public void ConnectionPoolingTest() { var row = res0.FetchOne(); connectionID1 = row[0].ToString(); - Assert.IsNotEmpty(connectionID1); + Assert.That(connectionID1, Is.Not.Empty); } s = session2.GetSchema(schemaName); col = s.GetCollection(_collectionName); findStmt = col.Find("_id = :id and pages = :pages").Bind("id", 1).Bind("pages", 20); doc = ExecuteFindStatement(findStmt); - Assert.AreEqual("Book 1", doc.FetchAll()[0]["title"].ToString()); + Assert.That(doc.FetchAll()[0]["title"].ToString(), Is.EqualTo("Book 1")); ValidatePreparedStatements(0, 0, null, connectionID1); for (int i = 1; i < _docs.Length; i++) { doc = ExecuteFindStatement(findStmt.Bind("id", i).Bind("pages", i * 10 + 10).Limit(1)); - Assert.AreEqual($"Book {i}", doc.FetchAll()[0]["title"].ToString()); + Assert.That(doc.FetchAll()[0]["title"].ToString(), Is.EqualTo($"Book {i}")); } ValidatePreparedStatements(1, 3, $"SELECT doc FROM `{schemaName}`.`{_collectionName}` WHERE ((JSON_UNQUOTE(JSON_EXTRACT(doc,'$._id')) = ?) AND (JSON_EXTRACT(doc,'$.pages') = ?)) LIMIT ?, ?"); @@ -587,18 +588,18 @@ public void ConnectionPoolingTest() { var row = res0.FetchOne(); connectionID1 = row[0].ToString(); - Assert.IsNotEmpty(connectionID1); + Assert.That(connectionID1, Is.Not.Empty); } s = session2.GetSchema(schemaName); col = s.GetCollection(_collectionName); findStmt = col.Find("_id = :id and pages = :pages").Bind("id", 1).Bind("pages", 20); doc = ExecuteFindStatement(findStmt); - Assert.AreEqual("Book 1", doc.FetchAll()[0]["title"].ToString()); + Assert.That(doc.FetchAll()[0]["title"].ToString(), Is.EqualTo("Book 1")); ValidatePreparedStatements(0, 0, null, connectionID1); for (int i = 1; i < _docs.Length; i++) { doc = ExecuteFindStatement(findStmt.Bind("id", i).Bind("pages", i * 10 + 10).Limit(1)); - Assert.AreEqual($"Book {i}", doc.FetchAll()[0]["title"].ToString()); + Assert.That(doc.FetchAll()[0]["title"].ToString(), Is.EqualTo($"Book {i}")); } ValidatePreparedStatements(1, 3, $"SELECT doc FROM `{schemaName}`.`{_collectionName}` WHERE ((JSON_UNQUOTE(JSON_EXTRACT(doc,'$._id')) = ?) AND (JSON_EXTRACT(doc,'$.pages') = ?)) LIMIT ?, ?"); @@ -610,7 +611,7 @@ public void ConnectionPoolingTest() [Test, Description("Deallocate PreparedStatments When Closing Session Load-100 times")] public void DeallocatePreparedStatmentsWhenClosingSessionLoad() { - if (!Platform.IsWindows()) Assert.Ignore("Check for Linux OS"); + Assume.That(Platform.IsWindows(), "Check for Linux OS"); InitCollection(); string threadId; @@ -624,13 +625,13 @@ public void DeallocatePreparedStatmentsWhenClosingSessionLoad() Collection coll = mySession.GetSchema(schemaName).GetCollection(_collectionName); var findStmt = coll.Find("_id = :id and pages = :pages").Bind("id", 1).Bind("pages", 20); var doc = ExecuteFindStatement(findStmt); - Assert.AreEqual("Book 1", doc.FetchAll()[0]["title"].ToString()); + Assert.That(doc.FetchAll()[0]["title"].ToString(), Is.EqualTo("Book 1")); ValidatePreparedStatements(0, 0, null, threadId); for (int i = 1; i <= _docs.Length; i++) { doc = ExecuteFindStatement(findStmt.Bind("id", i).Bind("pages", i * 10 + 10).Limit(1)); - Assert.AreEqual($"Book {i}", doc.FetchAll()[0]["title"].ToString()); + Assert.That(doc.FetchAll()[0]["title"].ToString(), Is.EqualTo($"Book {i}")); } ValidatePreparedStatements(1, 4, $"SELECT doc FROM `{schemaName}`.`{_collectionName}` WHERE ((JSON_UNQUOTE(JSON_EXTRACT(doc,'$._id')) = ?) AND (JSON_EXTRACT(doc,'$.pages') = ?)) LIMIT ?, ?", threadId); @@ -658,23 +659,23 @@ public void DeallocatePreparedStatmentsWhenClosingSessionParallel() var findStmt1 = coll1.Find("_id = :id and pages = :pages").Bind("id", 1).Bind("pages", 20); var findStmt2 = coll2.Find("_id = :id and pages = :pages").Bind("id", 1).Bind("pages", 20); var doc1 = ExecuteFindStatement(findStmt1); - Assert.AreEqual("Book 1", doc1.FetchAll()[0]["title"].ToString()); + Assert.That(doc1.FetchAll()[0]["title"].ToString(), Is.EqualTo("Book 1")); ValidatePreparedStatements(0, 0, null, threadId1); var doc2 = ExecuteFindStatement(findStmt2); - Assert.AreEqual("Book 1", doc2.FetchAll()[0]["title"].ToString()); + Assert.That(doc2.FetchAll()[0]["title"].ToString(), Is.EqualTo("Book 1")); ValidatePreparedStatements(0, 0, null, threadId2); for (int i = 1; i <= _docs.Length; i++) { doc1 = ExecuteFindStatement(findStmt1.Bind("id", i).Bind("pages", i * 10 + 10).Limit(1)); - Assert.AreEqual($"Book {i}", doc1.FetchAll()[0]["title"].ToString()); + Assert.That(doc1.FetchAll()[0]["title"].ToString(), Is.EqualTo($"Book {i}")); } for (int i = 1; i <= _docs.Length; i++) { doc2 = ExecuteFindStatement(findStmt2.Bind("id", i).Bind("pages", i * 10 + 10).Limit(1)); - Assert.AreEqual($"Book {i}", doc2.FetchAll()[0]["title"].ToString()); + Assert.That(doc2.FetchAll()[0]["title"].ToString(), Is.EqualTo($"Book {i}")); } ValidatePreparedStatements(1, 4, @@ -693,21 +694,21 @@ public void MaxPreparedStmtCountAsOne() { Collection coll = CreateCollection("testGlobal"); Result r = ExecuteAddStatement(coll.Add(_docs)); - Assert.AreEqual(4, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo(4)); try { ((Session)coll.Session).SQL("SET GLOBAL max_prepared_stmt_count=1").Execute(); var findStmt = coll.Find("_id = :id and pages = :pages").Bind("id", 1).Bind("pages", 20); var doc = ExecuteFindStatement(findStmt); - Assert.AreEqual("Book 1", doc.FetchAll()[0]["title"].ToString()); + Assert.That(doc.FetchAll()[0]["title"].ToString(), Is.EqualTo("Book 1")); ValidatePreparedStatements(0, 0, null); for (int i = 1; i <= _docs.Length; i++) { doc = ExecuteFindStatement(findStmt.Bind("id", i).Bind("pages", i * 10 + 10).Limit(1)); - Assert.AreEqual($"Book {i}", doc.FetchAll()[0]["title"].ToString()); + Assert.That(doc.FetchAll()[0]["title"].ToString(), Is.EqualTo($"Book {i}")); } ValidatePreparedStatements(1, 4, $"SELECT doc FROM `{schemaName}`.`testGlobal` WHERE ((JSON_EXTRACT(doc,'$._id') = ?) AND (JSON_EXTRACT(doc,'$.pages') = ?)) LIMIT ?, ?"); @@ -746,13 +747,13 @@ public void PSMultipleFindAsync() var findStmt = coll.Find("age = 1"); tasksList.Add(findStmt.ExecuteAsync().ContinueWith((findResult) => { - Assert.AreEqual(1, findResult.Result.FetchAll()[0]["age"]); + Assert.That(findResult.Result.FetchAll()[0]["age"], Is.EqualTo(1)); })); tasksList.Add(findStmt.ExecuteAsync().ContinueWith((findResult) => { - Assert.AreEqual(1, findResult.Result.FetchAll()[0]["age"]); + Assert.That(findResult.Result.FetchAll()[0]["age"], Is.EqualTo(1)); })); - Assert.AreEqual(true, Task.WaitAll(tasksList.ToArray(), TimeSpan.FromMinutes(2)), "WaitAll timeout"); + Assert.That(Task.WaitAll(tasksList.ToArray(), TimeSpan.FromMinutes(2)), Is.EqualTo(true), "WaitAll timeout"); ValidatePreparedStatements(1, 1, $"SELECT doc FROM `test`.`test` WHERE (JSON_EXTRACT(doc,'$.age') = 1)"); } @@ -765,7 +766,7 @@ public void FindRemoveWithString() { InitCollection(); Collection coll = GetCollection(); - Assert.AreEqual(4, coll.Count()); + Assert.That(coll.Count(), Is.EqualTo(4)); var findStmt = coll.Find("_id = :id and pages = :pages").Bind("id", "1").Bind("pages", 20); var doc = ExecuteFindStatement(findStmt); findStmt = coll.Find("_id = :id and pages = :pages").Bind("id", "2").Bind("pages", 30); @@ -777,11 +778,11 @@ public void FindRemoveWithString() } findStmt = coll.Find("_id = :id").Bind("id", "4"); var docCount = ExecuteFindStatement(findStmt).FetchAll(); - Assert.AreEqual(1, docCount.Count, "There should be a record"); - Assert.AreEqual("Book 4", docCount[0]["title"].ToString()); + Assert.That(docCount.Count, Is.EqualTo(1), "There should be a record"); + Assert.That(docCount[0]["title"].ToString(), Is.EqualTo("Book 4")); findStmt = coll.Find("_id = :id").Bind("id", "1"); docCount = ExecuteFindStatement(findStmt).FetchAll(); - Assert.AreEqual(0, docCount.Count, "There should not be any records"); + Assert.That(docCount.Count, Is.EqualTo(0), "There should not be any records"); } /// @@ -805,7 +806,7 @@ public void StatementWithOffset() new { _id = 8, name = "tommy h", age =31,profit = 3000} }; var r = coll.Add(docs1).Execute(); - Assert.AreEqual((ulong)8, r.AffectedItemsCount); + Assert.That(r.AffectedItemsCount, Is.EqualTo((ulong)8)); var findStmt = coll.Find().Fields("_id as ID", "name as Name", "age as Age", "profit as Profit").GroupBy("age"). GroupBy("profit").Sort("profit ASC").Limit(3); @@ -880,7 +881,7 @@ public void SessionSqlStatementFail() [Test, Description("DELETE WHERE THROWS PARSE EXCEPTION WITH IN OPERATOR FOR ARRAY")] public void DeleteParseException() { - if (!session.Version.isAtLeast(8, 0, 16)) Assert.Ignore("This test is for MySql 8.0.16 or higher."); + Assume.That(session.Version.isAtLeast(8, 0, 16), "This test is for MySql 8.0.16 or higher"); var tableName = "newtable"; Session session1 = null; Client client1 = null; diff --git a/MySQL.Data/tests/MySqlX.Data.Tests/Properties/AssemblyInfo.cs b/MySQL.Data/tests/MySqlX.Data.Tests/Properties/AssemblyInfo.cs index abfe68df2..20a236993 100644 --- a/MySQL.Data/tests/MySqlX.Data.Tests/Properties/AssemblyInfo.cs +++ b/MySQL.Data/tests/MySqlX.Data.Tests/Properties/AssemblyInfo.cs @@ -1,16 +1,16 @@ -// Copyright © 2015, 2019, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2015, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -38,7 +38,7 @@ [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("MySQL Connector/NET")] -[assembly: AssemblyCopyright("Copyright © 2016, 2020, Oracle and/or its affiliates. All rights reserved.")] +[assembly: AssemblyCopyright("Copyright © 2016, 2025, Oracle and/or its affiliates.")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] @@ -52,4 +52,4 @@ #if !DEBUG [assembly: AssemblyKeyName("ConnectorNet")] -#endif \ No newline at end of file +#endif diff --git a/MySQL.Data/tests/MySqlX.Data.Tests/Properties/CreateUsers.sql b/MySQL.Data/tests/MySqlX.Data.Tests/Properties/CreateUsers.sql index 4edcb388b..8c0ea0906 100644 --- a/MySQL.Data/tests/MySqlX.Data.Tests/Properties/CreateUsers.sql +++ b/MySQL.Data/tests/MySqlX.Data.Tests/Properties/CreateUsers.sql @@ -1,14 +1,12 @@ DROP USER IF EXISTS 'test'; DROP USER IF EXISTS 'testNoPass'; DROP USER IF EXISTS 'testSha2'; -DROP USER IF EXISTS 'testNative'; DROP USER IF EXISTS 'testAnyhost'; CREATE USER 'test'@'%' identified by 'test'; GRANT ALL PRIVILEGES ON *.* TO 'test'@'%'; CREATE USER 'testNoPass'@'%'; CREATE USER 'testSha2'@'%' identified with caching_sha2_password by 'mysql'; GRANT ALL PRIVILEGES ON *.* TO 'testSha2'@'%'; -CREATE USER 'testNative'@'%' identified with mysql_native_password by 'test'; CREATE USER 'testAnyhost'@'%' identified by 'test'; GRANT ALL PRIVILEGES ON *.* TO 'testAnyhost'@'%'; FLUSH PRIVILEGES; \ No newline at end of file diff --git a/MySQL.Data/tests/MySqlX.Data.Tests/RelationalTests/ColumnMetadataTests.cs b/MySQL.Data/tests/MySqlX.Data.Tests/RelationalTests/ColumnMetadataTests.cs index de92ca359..aae0a3684 100644 --- a/MySQL.Data/tests/MySqlX.Data.Tests/RelationalTests/ColumnMetadataTests.cs +++ b/MySQL.Data/tests/MySqlX.Data.Tests/RelationalTests/ColumnMetadataTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2016, 2021, Oracle and/or its affiliates. +// Copyright © 2016, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -30,6 +30,7 @@ using MySql.Data.MySqlClient.X.XDevAPI.Common; using MySqlX.XDevAPI.Relational; using NUnit.Framework; +using NUnit.Framework.Legacy; namespace MySqlX.Data.Tests.RelationalTests { @@ -45,46 +46,46 @@ public void ColumnMetadata() RowResult r = ExecuteSelectStatement(GetSession().GetSchema(schemaName).GetTable("test").Select("1 + 1 as a", "b", "c")); var rows = r.FetchAll(); - Assert.AreEqual(3, r.Columns.Count); - Assert.AreEqual("def", r.Columns[0].DatabaseName); - Assert.Null(r.Columns[0].SchemaName); - Assert.Null(r.Columns[0].TableName); - Assert.Null(r.Columns[0].TableLabel); - Assert.Null(r.Columns[0].ColumnName); - Assert.AreEqual("a", r.Columns[0].ColumnLabel); - Assert.AreEqual(ColumnType.Tinyint, r.Columns[0].Type); - Assert.AreEqual(3u, r.Columns[0].Length); - Assert.AreEqual(0u, r.Columns[0].FractionalDigits); - Assert.True(r.Columns[0].IsNumberSigned); - Assert.Null(r.Columns[0].CharacterSetName); - Assert.Null(r.Columns[0].CollationName); - Assert.False(r.Columns[0].IsPadded); + Assert.That(r.Columns.Count, Is.EqualTo(3)); + Assert.That(r.Columns[0].DatabaseName, Is.EqualTo("def")); + Assert.That(r.Columns[0].SchemaName, Is.Null); + Assert.That(r.Columns[0].TableName, Is.Null); + Assert.That(r.Columns[0].TableLabel, Is.Null); + Assert.That(r.Columns[0].ColumnName, Is.Null); + Assert.That(r.Columns[0].ColumnLabel, Is.EqualTo("a")); + Assert.That(r.Columns[0].Type, Is.EqualTo(ColumnType.Tinyint)); + Assert.That(r.Columns[0].Length, Is.EqualTo(3u)); + Assert.That(r.Columns[0].FractionalDigits, Is.EqualTo(0u)); + Assert.That(r.Columns[0].IsNumberSigned); + Assert.That(r.Columns[0].CharacterSetName, Is.Null); + Assert.That(r.Columns[0].CollationName, Is.Null); + Assert.That(r.Columns[0].IsPadded, Is.False); - Assert.AreEqual(schemaName, r.Columns[1].SchemaName); - Assert.AreEqual("test", r.Columns[1].TableName); - Assert.AreEqual("test", r.Columns[1].TableLabel); - Assert.AreEqual("b", r.Columns[1].ColumnName); - Assert.AreEqual("b", r.Columns[1].ColumnLabel); - Assert.AreEqual(ColumnType.String, r.Columns[1].Type); - Assert.AreEqual(255u, r.Columns[1].Length); - Assert.AreEqual(0u, r.Columns[1].FractionalDigits); - Assert.False(r.Columns[1].IsNumberSigned); - Assert.AreEqual("utf8mb4", r.Columns[1].CharacterSetName); - Assert.AreEqual("utf8mb4_0900_ai_ci", r.Columns[1].CollationName); - Assert.False(r.Columns[1].IsPadded); + Assert.That(r.Columns[1].SchemaName, Is.EqualTo(schemaName)); + Assert.That(r.Columns[1].TableName, Is.EqualTo("test")); + Assert.That(r.Columns[1].TableLabel, Is.EqualTo("test")); + Assert.That(r.Columns[1].ColumnName, Is.EqualTo("b")); + Assert.That(r.Columns[1].ColumnLabel, Is.EqualTo("b")); + Assert.That(r.Columns[1].Type, Is.EqualTo(ColumnType.String)); + Assert.That(r.Columns[1].Length, Is.EqualTo(255u)); + Assert.That(r.Columns[1].FractionalDigits, Is.EqualTo(0u)); + Assert.That(r.Columns[1].IsNumberSigned, Is.False); + Assert.That(r.Columns[1].CharacterSetName, Is.EqualTo("utf8mb4")); + Assert.That(r.Columns[1].CollationName, Is.EqualTo("utf8mb4_0900_ai_ci")); + Assert.That(r.Columns[1].IsPadded, Is.False); - Assert.AreEqual(schemaName, r.Columns[2].SchemaName); - Assert.AreEqual("test", r.Columns[2].TableName); - Assert.AreEqual("test", r.Columns[2].TableLabel); - Assert.AreEqual("c", r.Columns[2].ColumnName); - Assert.AreEqual("c", r.Columns[2].ColumnLabel); - Assert.AreEqual(ColumnType.String, r.Columns[2].Type); - Assert.AreEqual(20u, r.Columns[2].Length); - Assert.AreEqual(0u, r.Columns[2].FractionalDigits); - Assert.False(r.Columns[2].IsNumberSigned); - Assert.AreEqual("utf8mb4", r.Columns[2].CharacterSetName); - Assert.AreEqual("utf8mb4_0900_ai_ci", r.Columns[2].CollationName); - Assert.False(r.Columns[2].IsPadded); + Assert.That(r.Columns[2].SchemaName, Is.EqualTo(schemaName)); + Assert.That(r.Columns[2].TableName, Is.EqualTo("test")); + Assert.That(r.Columns[2].TableLabel, Is.EqualTo("test")); + Assert.That(r.Columns[2].ColumnName, Is.EqualTo("c")); + Assert.That(r.Columns[2].ColumnLabel, Is.EqualTo("c")); + Assert.That(r.Columns[2].Type, Is.EqualTo(ColumnType.String)); + Assert.That(r.Columns[2].Length, Is.EqualTo(20u)); + Assert.That(r.Columns[2].FractionalDigits, Is.EqualTo(0u)); + Assert.That(r.Columns[2].IsNumberSigned, Is.False); + Assert.That(r.Columns[2].CharacterSetName, Is.EqualTo("utf8mb4")); + Assert.That(r.Columns[2].CollationName, Is.EqualTo("utf8mb4_0900_ai_ci")); + Assert.That(r.Columns[2].IsPadded, Is.False); //Assert.AreEqual("Δ", rows[0][2]); } @@ -100,26 +101,26 @@ public void SchemaDefaultCharset() RowResult r = ExecuteSelectStatement(GetSession().GetSchema(schemaName).GetTable("test").Select("b")); var rows = r.FetchAll(); - Assert.AreEqual(schemaName, r.Columns[0].SchemaName); - Assert.AreEqual("test", r.Columns[0].TableName); - Assert.AreEqual("test", r.Columns[0].TableLabel); - Assert.AreEqual("b", r.Columns[0].ColumnName); - Assert.AreEqual("b", r.Columns[0].ColumnLabel); - Assert.AreEqual(ColumnType.String, r.Columns[0].Type); - Assert.AreEqual(0u, r.Columns[0].FractionalDigits); - Assert.AreEqual(false, r.Columns[0].IsNumberSigned); - Assert.AreEqual(defaultValues[0][0], r.Columns[0].CharacterSetName); - Assert.AreEqual(defaultValues[0][1], r.Columns[0].CollationName); - Assert.AreEqual(false, r.Columns[0].IsPadded); - Assert.AreEqual("CAR", rows[0][0]); + Assert.That(r.Columns[0].SchemaName, Is.EqualTo(schemaName)); + Assert.That(r.Columns[0].TableName, Is.EqualTo("test")); + Assert.That(r.Columns[0].TableLabel, Is.EqualTo("test")); + Assert.That(r.Columns[0].ColumnName, Is.EqualTo("b")); + Assert.That(r.Columns[0].ColumnLabel, Is.EqualTo("b")); + Assert.That(r.Columns[0].Type, Is.EqualTo(ColumnType.String)); + Assert.That(r.Columns[0].FractionalDigits, Is.EqualTo(0u)); + Assert.That(r.Columns[0].IsNumberSigned, Is.EqualTo(false)); + Assert.That(r.Columns[0].CharacterSetName, Is.EqualTo(defaultValues[0][0])); + Assert.That(r.Columns[0].CollationName, Is.EqualTo(defaultValues[0][1])); + Assert.That(r.Columns[0].IsPadded, Is.EqualTo(false)); + Assert.That(rows[0][0], Is.EqualTo("CAR")); using (var connection = new MySqlConnection(ConnectionStringRoot)) { connection.Open(); if (connection.driver.Version.isAtLeast(8, 0, 1)) - Assert.AreEqual(1020u, r.Columns[0].Length); + Assert.That(r.Columns[0].Length, Is.EqualTo(1020u)); else - Assert.AreEqual(255u, r.Columns[0].Length); + Assert.That(r.Columns[0].Length, Is.EqualTo(255u)); } } @@ -129,11 +130,11 @@ public void ColumnNames() ExecuteSQL("CREATE TABLE test(columnA VARCHAR(255), columnB INT, columnX BIT)"); RowResult r = ExecuteSelectStatement(GetSession().GetSchema(schemaName).GetTable("test").Select()); - Assert.AreEqual(3, r.ColumnCount); - Assert.AreEqual(r.Columns.Count, r.ColumnCount); - Assert.AreEqual("columnA", r.ColumnNames[0]); - Assert.AreEqual("columnB", r.ColumnNames[1]); - Assert.AreEqual("columnX", r.ColumnNames[2]); + Assert.That(r.ColumnCount, Is.EqualTo(3)); + Assert.That(r.ColumnCount, Is.EqualTo(r.Columns.Count)); + Assert.That(r.ColumnNames[0], Is.EqualTo("columnA")); + Assert.That(r.ColumnNames[1], Is.EqualTo("columnB")); + Assert.That(r.ColumnNames[2], Is.EqualTo("columnX")); } [Test] @@ -146,19 +147,19 @@ public void TableDefaultCharset() RowResult r = ExecuteSelectStatement(GetSession().GetSchema(schemaName).GetTable("test").Select("b")); var rows = r.FetchAll(); - Assert.AreEqual(schemaName, r.Columns[0].SchemaName); - Assert.AreEqual("test", r.Columns[0].TableName); - Assert.AreEqual("test", r.Columns[0].TableLabel); - Assert.AreEqual("b", r.Columns[0].ColumnName); - Assert.AreEqual("b", r.Columns[0].ColumnLabel); - Assert.AreEqual(ColumnType.String, r.Columns[0].Type); - Assert.AreEqual(255u, r.Columns[0].Length); - Assert.AreEqual(0u, r.Columns[0].FractionalDigits); - Assert.False(r.Columns[0].IsNumberSigned); - Assert.AreEqual("utf8mb4", r.Columns[0].CharacterSetName); - Assert.AreEqual("utf8mb4_0900_ai_ci", r.Columns[0].CollationName); - Assert.False(r.Columns[0].IsPadded); - Assert.AreEqual("Δ", rows[0][0]); + Assert.That(r.Columns[0].SchemaName, Is.EqualTo(schemaName)); + Assert.That(r.Columns[0].TableName, Is.EqualTo("test")); + Assert.That(r.Columns[0].TableLabel, Is.EqualTo("test")); + Assert.That(r.Columns[0].ColumnName, Is.EqualTo("b")); + Assert.That(r.Columns[0].ColumnLabel, Is.EqualTo("b")); + Assert.That(r.Columns[0].Type, Is.EqualTo(ColumnType.String)); + Assert.That(r.Columns[0].Length, Is.EqualTo(255u)); + Assert.That(r.Columns[0].FractionalDigits, Is.EqualTo(0u)); + Assert.That(r.Columns[0].IsNumberSigned, Is.False); + Assert.That(r.Columns[0].CharacterSetName, Is.EqualTo("utf8mb4")); + Assert.That(r.Columns[0].CollationName, Is.EqualTo("utf8mb4_0900_ai_ci")); + Assert.That(r.Columns[0].IsPadded, Is.False); + Assert.That(rows[0][0], Is.EqualTo("Δ")); } } } diff --git a/MySQL.Data/tests/MySqlX.Data.Tests/RelationalTests/DataTypeTests.cs b/MySQL.Data/tests/MySqlX.Data.Tests/RelationalTests/DataTypeTests.cs index 0790d1b50..b13a25a79 100644 --- a/MySQL.Data/tests/MySqlX.Data.Tests/RelationalTests/DataTypeTests.cs +++ b/MySQL.Data/tests/MySqlX.Data.Tests/RelationalTests/DataTypeTests.cs @@ -1,313 +1,313 @@ -// Copyright (c) 2015, 2022, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data.MySqlClient; -using MySql.Data.MySqlClient.X.XDevAPI.Common; -using MySqlX.XDevAPI.Relational; -using NUnit.Framework; -using System; - -namespace MySqlX.Data.Tests.RelationalTests -{ - public class DataTypeTests : BaseTest - { - [TearDown] - public void TearDown() => ExecuteSQL("DROP TABLE IF EXISTS test"); - - [Test] - public void Float() - { - ExecuteSQL("CREATE TABLE test(rvalue FLOAT(14,8))"); - ExecuteSQL("INSERT INTO test VALUES(23.4), (14.8), (11.9)"); - - RowResult r = ExecuteSelectStatement(GetSession().GetSchema("test").GetTable("test").Select("rvalue")); - var rows = r.FetchAll(); - Assert.That(r.Columns, Has.One.Items); - Assert.AreEqual(typeof(float), r.Columns[0].ClrType); - Assert.AreEqual(14, (int)r.Columns[0].Length); - Assert.AreEqual(8, (int)r.Columns[0].FractionalDigits); - Assert.AreEqual(ColumnType.Float, r.Columns[0].Type); - Assert.AreEqual(3, rows.Count); - Assert.AreEqual(23.4f, (float)rows[0][0]); - Assert.AreEqual(14.8f, rows[1][0]); - Assert.AreEqual(11.9f, rows[2][0]); - } - - [Test] - public void Double() - { - ExecuteSQL("CREATE TABLE test(rvalue DOUBLE(12,4))"); - ExecuteSQL("INSERT INTO test VALUES(23.4), (14.8), (11.9)"); - - RowResult r = ExecuteSelectStatement(GetSession().GetSchema("test").GetTable("test").Select("rvalue")); - var rows = r.FetchAll(); - Assert.That(r.Columns, Has.One.Items); - Assert.AreEqual(typeof(double), r.Columns[0].ClrType); - Assert.AreEqual(ColumnType.Double, r.Columns[0].Type); - Assert.AreEqual(12, (int)r.Columns[0].Length); - Assert.AreEqual(4, (int)r.Columns[0].FractionalDigits); - Assert.AreEqual(3, rows.Count); - Assert.AreEqual(23.4, rows[0][0]); - Assert.AreEqual(14.8, rows[1][0]); - Assert.AreEqual(11.9, rows[2][0]); - } - - [Test] - public void Set() - { - ExecuteSQL("CREATE TABLE test(rvalue SET('A','B','C','D'))"); - ExecuteSQL("INSERT INTO test VALUES('A'), ('B,A'), ('B')"); - - RowResult r = ExecuteSelectStatement(GetSession().GetSchema("test").GetTable("test").Select("rvalue")); - var rows = r.FetchAll(); - Assert.That(r.Columns, Has.One.Items); - Assert.AreEqual(typeof(string), r.Columns[0].ClrType); - Assert.AreEqual(ColumnType.Set, r.Columns[0].Type); - Assert.AreEqual(3, rows.Count); - Assert.AreEqual("A", rows[0][0]); - Assert.AreEqual("A,B", rows[1][0]); - Assert.AreEqual("B", rows[2][0]); - } - - [Test] - public void Enum() - { - ExecuteSQL("CREATE TABLE test(rvalue Enum('Alpha','Beta','C','D'))"); - ExecuteSQL("INSERT INTO test VALUES('Alpha'), ('Beta'), ('C')"); - - RowResult r = ExecuteSelectStatement(GetSession().GetSchema("test").GetTable("test").Select("rvalue")); - var rows = r.FetchAll(); - Assert.That(r.Columns, Has.One.Items); - Assert.AreEqual(typeof(string), r.Columns[0].ClrType); - Assert.AreEqual(ColumnType.Enum, r.Columns[0].Type); - Assert.AreEqual(3, rows.Count); - Assert.AreEqual("Alpha", rows[0][0]); - Assert.AreEqual("Beta", rows[1][0]); - Assert.AreEqual("C", rows[2][0]); - } - - [Test] - public void SignedIntegers() - { - ExecuteSQL("CREATE TABLE test(tinyCol TINYINT, smallCol SMALLINT, mediumCol MEDIUMINT, intCol INT, bigCol BIGINT)"); - ExecuteSQL("INSERT INTO test VALUES(127, 32767, 8388607, 2147483647, 9223372036854775807)"); - ExecuteSQL("INSERT INTO test VALUES(-128, -32768, -8388608, -2147483648, -9223372036854775808)"); - - RowResult r = ExecuteSelectStatement(GetSession().GetSchema("test").GetTable("test").Select()); - var rows = r.FetchAll(); - Assert.AreEqual(5, r.Columns.Count); - Assert.AreEqual(typeof(sbyte), r.Columns[0].ClrType); - Assert.AreEqual(ColumnType.Tinyint, r.Columns[0].Type); - Assert.AreEqual((sbyte)127, rows[0][0]); - Assert.AreEqual((sbyte)-128, rows[1][0]); - Assert.AreEqual(typeof(Int16), r.Columns[1].ClrType); - Assert.AreEqual(ColumnType.Smallint, r.Columns[1].Type); - Assert.AreEqual((short)32767, rows[0][1]); - Assert.AreEqual((short)-32768, rows[1][1]); - Assert.AreEqual(typeof(Int32), r.Columns[2].ClrType); - Assert.AreEqual(ColumnType.Mediumint, r.Columns[2].Type); - Assert.AreEqual(8388607, rows[0][2]); - Assert.AreEqual(-8388608, rows[1][2]); - Assert.AreEqual(typeof(Int32), r.Columns[3].ClrType); - Assert.AreEqual(ColumnType.Int, r.Columns[3].Type); - Assert.AreEqual(2147483647, rows[0][3]); - Assert.AreEqual(-2147483648, rows[1][3]); - Assert.AreEqual(typeof(Int64), r.Columns[4].ClrType); - Assert.AreEqual(ColumnType.Bigint, r.Columns[4].Type); - Assert.AreEqual((long)9223372036854775807, rows[0][4]); - Assert.AreEqual((long)-9223372036854775808, rows[1][4]); - } - - [Test] - public void UnsignedIntegers() - { - ExecuteSQL("CREATE TABLE test(tinyCol TINYINT UNSIGNED, smallCol SMALLINT UNSIGNED, mediumCol MEDIUMINT UNSIGNED, intCol INT UNSIGNED, bigCol BIGINT UNSIGNED)"); - ExecuteSQL("INSERT INTO test VALUES(255, 65535, 16777215, 4294967295, 18446744073709551615)"); - - RowResult r = ExecuteSelectStatement(GetSession().GetSchema("test").GetTable("test").Select()); - var rows = r.FetchAll(); - Assert.AreEqual(5, r.Columns.Count); - Assert.AreEqual(typeof(byte), r.Columns[0].ClrType); - Assert.AreEqual(ColumnType.Tinyint, r.Columns[0].Type); - Assert.AreEqual((byte)255, rows[0][0]); - Assert.AreEqual(typeof(UInt16), r.Columns[1].ClrType); - Assert.AreEqual(ColumnType.Smallint, r.Columns[1].Type); - Assert.AreEqual((ushort)65535, rows[0][1]); - Assert.AreEqual(typeof(UInt32), r.Columns[2].ClrType); - Assert.AreEqual(ColumnType.Mediumint, r.Columns[2].Type); - Assert.AreEqual((uint)16777215, rows[0][2]); - Assert.AreEqual(typeof(UInt32), r.Columns[3].ClrType); - Assert.AreEqual(ColumnType.Int, r.Columns[3].Type); - Assert.AreEqual((uint)4294967295, rows[0][3]); - Assert.AreEqual(typeof(UInt64), r.Columns[4].ClrType); - Assert.AreEqual(ColumnType.Bigint, r.Columns[4].Type); - Assert.AreEqual((ulong)18446744073709551615, rows[0][4]); - } - - [Test] - public void Bit() - { - ExecuteSQL("CREATE TABLE test(bitCol BIT(8))"); - ExecuteSQL("INSERT INTO test VALUES(b'1111111')"); - - RowResult r = ExecuteSelectStatement(GetSession().GetSchema("test").GetTable("test").Select()); - var rows = r.FetchAll(); - Assert.That(r.Columns, Has.One.Items); - Assert.AreEqual(typeof(UInt64), r.Columns[0].ClrType); - Assert.AreEqual(ColumnType.Bit, r.Columns[0].Type); - Assert.AreEqual((ulong)127, rows[0][0]); - } - - [Test] - public void Decimal() - { - ExecuteSQL("CREATE TABLE test(decCol1 DECIMAL(20,9))"); - ExecuteSQL("INSERT INTO test VALUES(-1.23), (-12.345), (5), (43)"); - ExecuteSQL("INSERT INTO test VALUES(14523.2887238), (-8947.8923784)"); - - RowResult r = ExecuteSelectStatement(GetSession().GetSchema("test").GetTable("test").Select()); - var rows = r.FetchAll(); - Assert.That(r.Columns, Has.One.Items); - Assert.AreEqual(typeof(decimal), r.Columns[0].ClrType); - Assert.AreEqual(ColumnType.Decimal, r.Columns[0].Type); - Assert.AreEqual(-1.23m, rows[0][0]); - Assert.AreEqual(-12.345m, rows[1][0]); - Assert.AreEqual(5m, rows[2][0]); - Assert.AreEqual(43m, rows[3][0]); - Assert.AreEqual(14523.2887238m, rows[4][0]); - Assert.AreEqual(-8947.8923784m, rows[5][0]); - } - - [Test] - public void Json() - { - ExecuteSQL("CREATE TABLE test(jdoc JSON)"); - ExecuteSQL("INSERT INTO test VALUES('{ \"id\": 1, \"name\": \"John\" }')"); - ExecuteSQL("INSERT INTO test VALUES('[ \"a\", 1, \"b\", 2 ]')"); - - RowResult r = ExecuteSelectStatement(GetSession().GetSchema("test").GetTable("test").Select()); - var rows = r.FetchAll(); - Assert.That(r.Columns, Has.One.Items); - Assert.AreEqual(typeof(string), r.Columns[0].ClrType); - Assert.AreEqual(ColumnType.Json, r.Columns[0].Type); - Assert.AreEqual("{\"id\": 1, \"name\": \"John\"}", rows[0][0]); - Assert.AreEqual("[\"a\", 1, \"b\", 2]", rows[1][0]); - } - - [Test] - public void Strings() - { - ExecuteSQL("CREATE TABLE test(name VARCHAR(255) COLLATE cp932_japanese_ci)"); - ExecuteSQL("INSERT INTO test VALUES('表')"); - - RowResult r = ExecuteSelectStatement(GetSession().GetSchema("test").GetTable("test").Select()); - var rows = r.FetchAll(); - Assert.That(r.Columns, Has.One.Items); - Assert.AreEqual(typeof(string), r.Columns[0].ClrType); - Assert.AreEqual(ColumnType.String, r.Columns[0].Type); - Assert.AreEqual("表", rows[0][0]); - } - - [Test] - [Ignore("Fix for 8.0.13")] - public void UnsingedZeroFill() - { - ExecuteSQL("CREATE TABLE test(id INT ZEROFILL)"); - ExecuteSQL("INSERT INTO test VALUES(100)"); - - RowResult r = ExecuteSelectStatement(GetSession().GetSchema("test").GetTable("test").Select()); - var rows = r.FetchAll(); - Assert.That(r.Columns, Has.One.Items); - Assert.AreEqual(typeof(UInt32), r.Columns[0].ClrType); - Assert.AreEqual(ColumnType.Int, r.Columns[0].Type); - Assert.False(r.Columns[0].IsNumberSigned); - Assert.True(r.Columns[0].IsPadded); - Assert.AreEqual("0000000100", rows[0][0].ToString()); - } - - [Test] - public void Bytes() - { - ExecuteSQL("CREATE TABLE test(name VARCHAR(255) BINARY)"); - ExecuteSQL("INSERT INTO test VALUES('John')"); - - RowResult r = ExecuteSelectStatement(GetSession().GetSchema("test").GetTable("test").Select()); - var rows = r.FetchAll(); - Assert.That(r.Columns, Has.One.Items); - Assert.AreEqual(typeof(string), r.Columns[0].ClrType); - Assert.AreEqual(ColumnType.String, r.Columns[0].Type); - Assert.AreEqual("John", rows[0][0]); - } - - [Test] - public void BytesUsingCollation() - { - ExecuteSQL("CREATE TABLE test(name VARCHAR(255) COLLATE utf8_bin)"); - ExecuteSQL("INSERT INTO test VALUES('Mark')"); - - RowResult r = ExecuteSelectStatement(GetSession().GetSchema("test").GetTable("test").Select()); - var rows = r.FetchAll(); - Assert.That(r.Columns, Has.One.Items); - Assert.AreEqual(typeof(string), r.Columns[0].ClrType); - Assert.AreEqual(ColumnType.String, r.Columns[0].Type); - Assert.AreEqual("Mark", rows[0][0]); - } - - [Test] - public void Geometry() - { - ExecuteSQL("CREATE TABLE test(line GEOMETRY)"); - ExecuteSQL("INSERT INTO test VALUES(ST_GeomFromText('LINESTRING(0 0, 10 10, 20 25, 50 60)'))"); - - RowResult r = ExecuteSelectStatement(GetSession().GetSchema("test").GetTable("test").Select()); - var rows = r.FetchAll(); - Assert.That(r.Columns, Has.One.Items); - Assert.AreEqual(typeof(byte[]), r.Columns[0].ClrType); - Assert.AreEqual(ColumnType.Geometry, r.Columns[0].Type); - Assert.AreEqual("0000000001020000000400000000000000000000000000000000000000000000000000244000000000000024400000000000003440000000000000394000000000000049400000000000004E40", - BitConverter.ToString((byte[])rows[0][0]).Replace("-", "")); - } - - [Test] - public void BlobTypes() - { - ExecuteSQL("CREATE TABLE test(a BLOB, b TEXT)"); - ExecuteSQL("INSERT INTO test VALUES('Car', 'Plane')"); - - RowResult r = ExecuteSelectStatement(GetSession().GetSchema(schemaName).GetTable("test").Select()); - var rows = r.FetchAll(); - Assert.AreEqual(2, r.Columns.Count); - Assert.AreEqual(typeof(byte[]), r.Columns[0].ClrType); - Assert.AreEqual(typeof(string), r.Columns[1].ClrType); - Assert.AreEqual(ColumnType.Bytes, r.Columns[0].Type); - Assert.AreEqual(ColumnType.String, r.Columns[1].Type); - Assert.AreEqual(CharSetMap.GetEncoding(r.Columns[0].CharacterSetName).GetBytes("Car"), rows[0][0]); - Assert.AreEqual("Plane", rows[0][1]); - } - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data.MySqlClient; +using MySql.Data.MySqlClient.X.XDevAPI.Common; +using MySqlX.XDevAPI.Relational; +using NUnit.Framework; +using NUnit.Framework.Legacy; +using System; + +namespace MySqlX.Data.Tests.RelationalTests +{ + public class DataTypeTests : BaseTest + { + [TearDown] + public void TearDown() => ExecuteSQL("DROP TABLE IF EXISTS test"); + + [Test] + public void Float() + { + ExecuteSQL("CREATE TABLE test(rvalue FLOAT(14,8))"); + ExecuteSQL("INSERT INTO test VALUES(23.4), (14.8), (11.9)"); + + RowResult r = ExecuteSelectStatement(GetSession().GetSchema("test").GetTable("test").Select("rvalue")); + var rows = r.FetchAll(); + Assert.That(r.Columns, Has.One.Items); + Assert.That(r.Columns[0].ClrType, Is.EqualTo(typeof(float))); + Assert.That((int)r.Columns[0].Length, Is.EqualTo(14)); + Assert.That((int)r.Columns[0].FractionalDigits, Is.EqualTo(8)); + Assert.That(r.Columns[0].Type, Is.EqualTo(ColumnType.Float)); + Assert.That(rows.Count, Is.EqualTo(3)); + Assert.That((float)rows[0][0], Is.EqualTo(23.4f)); + Assert.That(rows[1][0], Is.EqualTo(14.8f)); + Assert.That(rows[2][0], Is.EqualTo(11.9f)); + } + + [Test] + public void Double() + { + ExecuteSQL("CREATE TABLE test(rvalue DOUBLE(12,4))"); + ExecuteSQL("INSERT INTO test VALUES(23.4), (14.8), (11.9)"); + + RowResult r = ExecuteSelectStatement(GetSession().GetSchema("test").GetTable("test").Select("rvalue")); + var rows = r.FetchAll(); + Assert.That(r.Columns, Has.One.Items); + Assert.That(r.Columns[0].ClrType, Is.EqualTo(typeof(double))); + Assert.That(r.Columns[0].Type, Is.EqualTo(ColumnType.Double)); + Assert.That((int)r.Columns[0].Length, Is.EqualTo(12)); + Assert.That((int)r.Columns[0].FractionalDigits, Is.EqualTo(4)); + Assert.That(rows.Count, Is.EqualTo(3)); + Assert.That(rows[0][0], Is.EqualTo(23.4)); + Assert.That(rows[1][0], Is.EqualTo(14.8)); + Assert.That(rows[2][0], Is.EqualTo(11.9)); + } + + [Test] + public void Set() + { + ExecuteSQL("CREATE TABLE test(rvalue SET('A','B','C','D'))"); + ExecuteSQL("INSERT INTO test VALUES('A'), ('B,A'), ('B')"); + + RowResult r = ExecuteSelectStatement(GetSession().GetSchema("test").GetTable("test").Select("rvalue")); + var rows = r.FetchAll(); + Assert.That(r.Columns, Has.One.Items); + Assert.That(r.Columns[0].ClrType, Is.EqualTo(typeof(string))); + Assert.That(r.Columns[0].Type, Is.EqualTo(ColumnType.Set)); + Assert.That(rows.Count, Is.EqualTo(3)); + Assert.That(rows[0][0], Is.EqualTo("A")); + Assert.That(rows[1][0], Is.EqualTo("A,B")); + Assert.That(rows[2][0], Is.EqualTo("B")); + } + + [Test] + public void Enum() + { + ExecuteSQL("CREATE TABLE test(rvalue Enum('Alpha','Beta','C','D'))"); + ExecuteSQL("INSERT INTO test VALUES('Alpha'), ('Beta'), ('C')"); + + RowResult r = ExecuteSelectStatement(GetSession().GetSchema("test").GetTable("test").Select("rvalue")); + var rows = r.FetchAll(); + Assert.That(r.Columns, Has.One.Items); + Assert.That(r.Columns[0].ClrType, Is.EqualTo(typeof(string))); + Assert.That(r.Columns[0].Type, Is.EqualTo(ColumnType.Enum)); + Assert.That(rows.Count, Is.EqualTo(3)); + Assert.That(rows[0][0], Is.EqualTo("Alpha")); + Assert.That(rows[1][0], Is.EqualTo("Beta")); + Assert.That(rows[2][0], Is.EqualTo("C")); + } + + [Test] + public void SignedIntegers() + { + ExecuteSQL("CREATE TABLE test(tinyCol TINYINT, smallCol SMALLINT, mediumCol MEDIUMINT, intCol INT, bigCol BIGINT)"); + ExecuteSQL("INSERT INTO test VALUES(127, 32767, 8388607, 2147483647, 9223372036854775807)"); + ExecuteSQL("INSERT INTO test VALUES(-128, -32768, -8388608, -2147483648, -9223372036854775808)"); + + RowResult r = ExecuteSelectStatement(GetSession().GetSchema("test").GetTable("test").Select()); + var rows = r.FetchAll(); + Assert.That(r.Columns.Count, Is.EqualTo(5)); + Assert.That(r.Columns[0].ClrType, Is.EqualTo(typeof(sbyte))); + Assert.That(r.Columns[0].Type, Is.EqualTo(ColumnType.Tinyint)); + Assert.That(rows[0][0], Is.EqualTo((sbyte)127)); + Assert.That(rows[1][0], Is.EqualTo((sbyte)-128)); + Assert.That(r.Columns[1].ClrType, Is.EqualTo(typeof(Int16))); + Assert.That(r.Columns[1].Type, Is.EqualTo(ColumnType.Smallint)); + Assert.That(rows[0][1], Is.EqualTo((short)32767)); + Assert.That(rows[1][1], Is.EqualTo((short)-32768)); + Assert.That(r.Columns[2].ClrType, Is.EqualTo(typeof(Int32))); + Assert.That(r.Columns[2].Type, Is.EqualTo(ColumnType.Mediumint)); + Assert.That(rows[0][2], Is.EqualTo(8388607)); + Assert.That(rows[1][2], Is.EqualTo(-8388608)); + Assert.That(r.Columns[3].ClrType, Is.EqualTo(typeof(Int32))); + Assert.That(r.Columns[3].Type, Is.EqualTo(ColumnType.Int)); + Assert.That(rows[0][3], Is.EqualTo(2147483647)); + Assert.That(rows[1][3], Is.EqualTo(-2147483648)); + Assert.That(r.Columns[4].ClrType, Is.EqualTo(typeof(Int64))); + Assert.That(r.Columns[4].Type, Is.EqualTo(ColumnType.Bigint)); + Assert.That(rows[0][4], Is.EqualTo((long)9223372036854775807)); + Assert.That(rows[1][4], Is.EqualTo((long)-9223372036854775808)); + } + + [Test] + public void UnsignedIntegers() + { + ExecuteSQL("CREATE TABLE test(tinyCol TINYINT UNSIGNED, smallCol SMALLINT UNSIGNED, mediumCol MEDIUMINT UNSIGNED, intCol INT UNSIGNED, bigCol BIGINT UNSIGNED)"); + ExecuteSQL("INSERT INTO test VALUES(255, 65535, 16777215, 4294967295, 18446744073709551615)"); + + RowResult r = ExecuteSelectStatement(GetSession().GetSchema("test").GetTable("test").Select()); + var rows = r.FetchAll(); + Assert.That(r.Columns.Count, Is.EqualTo(5)); + Assert.That(r.Columns[0].ClrType, Is.EqualTo(typeof(byte))); + Assert.That(r.Columns[0].Type, Is.EqualTo(ColumnType.Tinyint)); + Assert.That(rows[0][0], Is.EqualTo((byte)255)); + Assert.That(r.Columns[1].ClrType, Is.EqualTo(typeof(UInt16))); + Assert.That(r.Columns[1].Type, Is.EqualTo(ColumnType.Smallint)); + Assert.That(rows[0][1], Is.EqualTo((ushort)65535)); + Assert.That(r.Columns[2].ClrType, Is.EqualTo(typeof(UInt32))); + Assert.That(r.Columns[2].Type, Is.EqualTo(ColumnType.Mediumint)); + Assert.That(rows[0][2], Is.EqualTo((uint)16777215)); + Assert.That(r.Columns[3].ClrType, Is.EqualTo(typeof(UInt32))); + Assert.That(r.Columns[3].Type, Is.EqualTo(ColumnType.Int)); + Assert.That(rows[0][3], Is.EqualTo((uint)4294967295)); + Assert.That(r.Columns[4].ClrType, Is.EqualTo(typeof(UInt64))); + Assert.That(r.Columns[4].Type, Is.EqualTo(ColumnType.Bigint)); + Assert.That(rows[0][4], Is.EqualTo((ulong)18446744073709551615)); + } + + [Test] + public void Bit() + { + ExecuteSQL("CREATE TABLE test(bitCol BIT(8))"); + ExecuteSQL("INSERT INTO test VALUES(b'1111111')"); + + RowResult r = ExecuteSelectStatement(GetSession().GetSchema("test").GetTable("test").Select()); + var rows = r.FetchAll(); + Assert.That(r.Columns, Has.One.Items); + Assert.That(r.Columns[0].ClrType, Is.EqualTo(typeof(UInt64))); + Assert.That(r.Columns[0].Type, Is.EqualTo(ColumnType.Bit)); + Assert.That(rows[0][0], Is.EqualTo((ulong)127)); + } + + [Test] + public void Decimal() + { + ExecuteSQL("CREATE TABLE test(decCol1 DECIMAL(20,9))"); + ExecuteSQL("INSERT INTO test VALUES(-1.23), (-12.345), (5), (43)"); + ExecuteSQL("INSERT INTO test VALUES(14523.2887238), (-8947.8923784)"); + + RowResult r = ExecuteSelectStatement(GetSession().GetSchema("test").GetTable("test").Select()); + var rows = r.FetchAll(); + Assert.That(r.Columns, Has.One.Items); + Assert.That(r.Columns[0].ClrType, Is.EqualTo(typeof(decimal))); + Assert.That(r.Columns[0].Type, Is.EqualTo(ColumnType.Decimal)); + Assert.That(rows[0][0], Is.EqualTo(-1.23m)); + Assert.That(rows[1][0], Is.EqualTo(-12.345m)); + Assert.That(rows[2][0], Is.EqualTo(5m)); + Assert.That(rows[3][0], Is.EqualTo(43m)); + Assert.That(rows[4][0], Is.EqualTo(14523.2887238m)); + Assert.That(rows[5][0], Is.EqualTo(-8947.8923784m)); + } + + [Test] + public void Json() + { + ExecuteSQL("CREATE TABLE test(jdoc JSON)"); + ExecuteSQL("INSERT INTO test VALUES('{ \"id\": 1, \"name\": \"John\" }')"); + ExecuteSQL("INSERT INTO test VALUES('[ \"a\", 1, \"b\", 2 ]')"); + + RowResult r = ExecuteSelectStatement(GetSession().GetSchema("test").GetTable("test").Select()); + var rows = r.FetchAll(); + Assert.That(r.Columns, Has.One.Items); + Assert.That(r.Columns[0].ClrType, Is.EqualTo(typeof(string))); + Assert.That(r.Columns[0].Type, Is.EqualTo(ColumnType.Json)); + Assert.That(rows[0][0], Is.EqualTo("{\"id\": 1, \"name\": \"John\"}")); + Assert.That(rows[1][0], Is.EqualTo("[\"a\", 1, \"b\", 2]")); + } + + [Test] + public void Strings() + { + ExecuteSQL("CREATE TABLE test(name VARCHAR(255) COLLATE cp932_japanese_ci)"); + ExecuteSQL("INSERT INTO test VALUES('表')"); + + RowResult r = ExecuteSelectStatement(GetSession().GetSchema("test").GetTable("test").Select()); + var rows = r.FetchAll(); + Assert.That(r.Columns, Has.One.Items); + Assert.That(r.Columns[0].ClrType, Is.EqualTo(typeof(string))); + Assert.That(r.Columns[0].Type, Is.EqualTo(ColumnType.String)); + Assert.That(rows[0][0], Is.EqualTo("表")); + } + + [Test] + [Ignore("Fix for 8.0.13")] + public void UnsingedZeroFill() + { + ExecuteSQL("CREATE TABLE test(id INT ZEROFILL)"); + ExecuteSQL("INSERT INTO test VALUES(100)"); + + RowResult r = ExecuteSelectStatement(GetSession().GetSchema("test").GetTable("test").Select()); + var rows = r.FetchAll(); + Assert.That(r.Columns, Has.One.Items); + Assert.That(r.Columns[0].ClrType, Is.EqualTo(typeof(UInt32))); + Assert.That(r.Columns[0].Type, Is.EqualTo(ColumnType.Int)); + Assert.That(r.Columns[0].IsNumberSigned, Is.False); + Assert.That(r.Columns[0].IsPadded); + Assert.That(rows[0][0].ToString(), Is.EqualTo("0000000100")); + } + + [Test] + public void Bytes() + { + ExecuteSQL("CREATE TABLE test(name VARCHAR(255) BINARY)"); + ExecuteSQL("INSERT INTO test VALUES('John')"); + + RowResult r = ExecuteSelectStatement(GetSession().GetSchema("test").GetTable("test").Select()); + var rows = r.FetchAll(); + Assert.That(r.Columns, Has.One.Items); + Assert.That(r.Columns[0].ClrType, Is.EqualTo(typeof(string))); + Assert.That(r.Columns[0].Type, Is.EqualTo(ColumnType.String)); + Assert.That(rows[0][0], Is.EqualTo("John")); + } + + [Test] + public void BytesUsingCollation() + { + ExecuteSQL("CREATE TABLE test(name VARCHAR(255) COLLATE utf8_bin)"); + ExecuteSQL("INSERT INTO test VALUES('Mark')"); + + RowResult r = ExecuteSelectStatement(GetSession().GetSchema("test").GetTable("test").Select()); + var rows = r.FetchAll(); + Assert.That(r.Columns, Has.One.Items); + Assert.That(r.Columns[0].ClrType, Is.EqualTo(typeof(string))); + Assert.That(r.Columns[0].Type, Is.EqualTo(ColumnType.String)); + Assert.That(rows[0][0], Is.EqualTo("Mark")); + } + + [Test] + public void Geometry() + { + ExecuteSQL("CREATE TABLE test(line GEOMETRY)"); + ExecuteSQL("INSERT INTO test VALUES(ST_GeomFromText('LINESTRING(0 0, 10 10, 20 25, 50 60)'))"); + + RowResult r = ExecuteSelectStatement(GetSession().GetSchema("test").GetTable("test").Select()); + var rows = r.FetchAll(); + Assert.That(r.Columns, Has.One.Items); + Assert.That(r.Columns[0].ClrType, Is.EqualTo(typeof(byte[]))); + Assert.That(r.Columns[0].Type, Is.EqualTo(ColumnType.Geometry)); + Assert.That(BitConverter.ToString((byte[])rows[0][0]).Replace("-", ""), Is.EqualTo("0000000001020000000400000000000000000000000000000000000000000000000000244000000000000024400000000000003440000000000000394000000000000049400000000000004E40")); + } + + [Test] + public void BlobTypes() + { + ExecuteSQL("CREATE TABLE test(a BLOB, b TEXT)"); + ExecuteSQL("INSERT INTO test VALUES('Car', 'Plane')"); + + RowResult r = ExecuteSelectStatement(GetSession().GetSchema(schemaName).GetTable("test").Select()); + var rows = r.FetchAll(); + Assert.That(r.Columns.Count, Is.EqualTo(2)); + Assert.That(r.Columns[0].ClrType, Is.EqualTo(typeof(byte[]))); + Assert.That(r.Columns[1].ClrType, Is.EqualTo(typeof(string))); + Assert.That(r.Columns[0].Type, Is.EqualTo(ColumnType.Bytes)); + Assert.That(r.Columns[1].Type, Is.EqualTo(ColumnType.String)); + Assert.That(rows[0][0], Is.EqualTo(CharSetMap.GetEncoding(r.Columns[0].CharacterSetName).GetBytes("Car"))); + Assert.That(rows[0][1], Is.EqualTo("Plane")); + } + } +} diff --git a/MySQL.Data/tests/MySqlX.Data.Tests/RelationalTests/DateTimeTests.cs b/MySQL.Data/tests/MySqlX.Data.Tests/RelationalTests/DateTimeTests.cs index 0c36e116b..fdd9ca112 100644 --- a/MySQL.Data/tests/MySqlX.Data.Tests/RelationalTests/DateTimeTests.cs +++ b/MySQL.Data/tests/MySqlX.Data.Tests/RelationalTests/DateTimeTests.cs @@ -1,126 +1,127 @@ -// Copyright (c) 2015, 2021, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data.MySqlClient.X.XDevAPI.Common; -using MySqlX.XDevAPI.Relational; -using NUnit.Framework; -using System; - -namespace MySqlX.Data.Tests.RelationalTests -{ - public class DateTimeTests : BaseTest - { - [TearDown] - public void TearDown() => ExecuteSQL("DROP TABLE IF EXISTS test"); - [Test] - public void DateTime() - { - ExecuteSQL("CREATE TABLE test.test(DT DATETIME)"); - ExecuteSQL("INSERT INTO test.test VALUES('2001-02-03 04:05:06')"); - - RowResult r = ExecuteSelectStatement(GetSession().GetSchema("test").GetTable("test").Select("dt")); - var rows = r.FetchAll(); - Assert.That(r.Columns, Has.One.Items); - Assert.AreEqual(typeof(DateTime), r.Columns[0].ClrType); - Assert.AreEqual(ColumnType.DateTime, r.Columns[0].Type); - Assert.That(rows, Has.One.Items); - DateTime dt = (DateTime)rows[0]["dt"]; - DateTime test = new DateTime(2001, 2, 3, 4, 5, 6); - Assert.AreEqual(test, dt); - } - - [Test] - public void Date() - { - ExecuteSQL("CREATE TABLE test.test(DT DATE)"); - ExecuteSQL("INSERT INTO test.test VALUES('2001-02-03')"); - - RowResult r = ExecuteSelectStatement(GetSession().GetSchema("test").GetTable("test").Select("dt")); - var rows = r.FetchAll(); - Assert.That(r.Columns, Has.One.Items); - Assert.AreEqual(typeof(DateTime), r.Columns[0].ClrType); - Assert.AreEqual(ColumnType.Date, r.Columns[0].Type); - Assert.That(rows, Has.One.Items); - DateTime dt = (DateTime)rows[0]["dt"]; - DateTime test = new DateTime(2001, 2, 3); - Assert.AreEqual(test, dt); - } - - [Test] - public void Timestamp() - { - ExecuteSQL("CREATE TABLE test.test(DT TIMESTAMP)"); - ExecuteSQL("INSERT INTO test.test VALUES('2001-02-03')"); - - RowResult r = ExecuteSelectStatement(GetSession().GetSchema("test").GetTable("test").Select("dt")); - var rows = r.FetchAll(); - Assert.That(r.Columns, Has.One.Items); - Assert.AreEqual(typeof(DateTime), r.Columns[0].ClrType); - //TODO: this should support timestamp - Assert.AreEqual(ColumnType.Timestamp, r.Columns[0].Type); - Assert.That(rows, Has.One.Items); - DateTime dt = (DateTime)rows[0]["dt"]; - DateTime test = new DateTime(2001, 2, 3); - Assert.AreEqual(test, dt); - } - - [Test] - public void Time() - { - ExecuteSQL("CREATE TABLE test.test(DT TIME)"); - ExecuteSQL("INSERT INTO test.test VALUES('01:02:03')"); - - RowResult r = ExecuteSelectStatement(GetSession().GetSchema("test").GetTable("test").Select("dt")); - var rows = r.FetchAll(); - Assert.That(r.Columns, Has.One.Items); - Assert.AreEqual(typeof(TimeSpan), r.Columns[0].ClrType); - Assert.AreEqual(ColumnType.Time, r.Columns[0].Type); - Assert.That(rows, Has.One.Items); - TimeSpan t = (TimeSpan)rows[0]["dt"]; - TimeSpan test = new TimeSpan(1, 2, 3); - Assert.AreEqual(test, t); - } - - [Test] - public void NegativeTime() - { - ExecuteSQL("CREATE TABLE test.test(DT TIME)"); - ExecuteSQL("INSERT INTO test.test VALUES('-01:02:03')"); - - RowResult r = ExecuteSelectStatement(GetSession().GetSchema("test").GetTable("test").Select("dt")); - var rows = r.FetchAll(); - Assert.That(r.Columns, Has.One.Items); - Assert.AreEqual(typeof(TimeSpan), r.Columns[0].ClrType); - Assert.AreEqual(ColumnType.Time, r.Columns[0].Type); - Assert.That(rows, Has.One.Items); - TimeSpan t = (TimeSpan)rows[0]["dt"]; - TimeSpan test = new TimeSpan(-1, 2, 3); - Assert.AreEqual(test, t); - } - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data.MySqlClient.X.XDevAPI.Common; +using MySqlX.XDevAPI.Relational; +using NUnit.Framework; +using NUnit.Framework.Legacy; +using System; + +namespace MySqlX.Data.Tests.RelationalTests +{ + public class DateTimeTests : BaseTest + { + [TearDown] + public void TearDown() => ExecuteSQL("DROP TABLE IF EXISTS test"); + [Test] + public void DateTime() + { + ExecuteSQL("CREATE TABLE test.test(DT DATETIME)"); + ExecuteSQL("INSERT INTO test.test VALUES('2001-02-03 04:05:06')"); + + RowResult r = ExecuteSelectStatement(GetSession().GetSchema("test").GetTable("test").Select("dt")); + var rows = r.FetchAll(); + Assert.That(r.Columns, Has.One.Items); + Assert.That(r.Columns[0].ClrType, Is.EqualTo(typeof(DateTime))); + Assert.That(r.Columns[0].Type, Is.EqualTo(ColumnType.DateTime)); + Assert.That(rows, Has.One.Items); + DateTime dt = (DateTime)rows[0]["dt"]; + DateTime test = new DateTime(2001, 2, 3, 4, 5, 6); + Assert.That(dt, Is.EqualTo(test)); + } + + [Test] + public void Date() + { + ExecuteSQL("CREATE TABLE test.test(DT DATE)"); + ExecuteSQL("INSERT INTO test.test VALUES('2001-02-03')"); + + RowResult r = ExecuteSelectStatement(GetSession().GetSchema("test").GetTable("test").Select("dt")); + var rows = r.FetchAll(); + Assert.That(r.Columns, Has.One.Items); + Assert.That(r.Columns[0].ClrType, Is.EqualTo(typeof(DateTime))); + Assert.That(r.Columns[0].Type, Is.EqualTo(ColumnType.Date)); + Assert.That(rows, Has.One.Items); + DateTime dt = (DateTime)rows[0]["dt"]; + DateTime test = new DateTime(2001, 2, 3); + Assert.That(dt, Is.EqualTo(test)); + } + + [Test] + public void Timestamp() + { + ExecuteSQL("CREATE TABLE test.test(DT TIMESTAMP)"); + ExecuteSQL("INSERT INTO test.test VALUES('2001-02-03')"); + + RowResult r = ExecuteSelectStatement(GetSession().GetSchema("test").GetTable("test").Select("dt")); + var rows = r.FetchAll(); + Assert.That(r.Columns, Has.One.Items); + Assert.That(r.Columns[0].ClrType, Is.EqualTo(typeof(DateTime))); + //TODO: this should support timestamp + Assert.That(r.Columns[0].Type, Is.EqualTo(ColumnType.Timestamp)); + Assert.That(rows, Has.One.Items); + DateTime dt = (DateTime)rows[0]["dt"]; + DateTime test = new DateTime(2001, 2, 3); + Assert.That(dt, Is.EqualTo(test)); + } + + [Test] + public void Time() + { + ExecuteSQL("CREATE TABLE test.test(DT TIME)"); + ExecuteSQL("INSERT INTO test.test VALUES('01:02:03')"); + + RowResult r = ExecuteSelectStatement(GetSession().GetSchema("test").GetTable("test").Select("dt")); + var rows = r.FetchAll(); + Assert.That(r.Columns, Has.One.Items); + Assert.That(r.Columns[0].ClrType, Is.EqualTo(typeof(TimeSpan))); + Assert.That(r.Columns[0].Type, Is.EqualTo(ColumnType.Time)); + Assert.That(rows, Has.One.Items); + TimeSpan t = (TimeSpan)rows[0]["dt"]; + TimeSpan test = new TimeSpan(1, 2, 3); + Assert.That(t, Is.EqualTo(test)); + } + + [Test] + public void NegativeTime() + { + ExecuteSQL("CREATE TABLE test.test(DT TIME)"); + ExecuteSQL("INSERT INTO test.test VALUES('-01:02:03')"); + + RowResult r = ExecuteSelectStatement(GetSession().GetSchema("test").GetTable("test").Select("dt")); + var rows = r.FetchAll(); + Assert.That(r.Columns, Has.One.Items); + Assert.That(r.Columns[0].ClrType, Is.EqualTo(typeof(TimeSpan))); + Assert.That(r.Columns[0].Type, Is.EqualTo(ColumnType.Time)); + Assert.That(rows, Has.One.Items); + TimeSpan t = (TimeSpan)rows[0]["dt"]; + TimeSpan test = new TimeSpan(-1, 2, 3); + Assert.That(t, Is.EqualTo(test)); + } + } +} diff --git a/MySQL.Data/tests/MySqlX.Data.Tests/RelationalTests/RelationalGCTests.cs b/MySQL.Data/tests/MySqlX.Data.Tests/RelationalTests/RelationalGCTests.cs index bb6735a3a..553f9ec47 100644 --- a/MySQL.Data/tests/MySqlX.Data.Tests/RelationalTests/RelationalGCTests.cs +++ b/MySQL.Data/tests/MySqlX.Data.Tests/RelationalTests/RelationalGCTests.cs @@ -1,57 +1,58 @@ -// Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySqlX.XDevAPI.Relational; -using System; -using NUnit.Framework; - -namespace MySqlX.Data.Tests.ResultTests -{ - public class RelationalGCTests : BaseTest - { -#if NETFRAMEWORK - [Test] - public void FetchAllNoReference() - { - ExecuteSQL("CREATE TABLE test(name VARCHAR(40), age INT)"); - Table table = testSchema.GetTable("test"); - - ExecuteInsertStatement(table.Insert("name", "age").Values("Henry", "22").Values("Patric", 30)); - var result = ExecuteSelectStatement(table.Select()); - var rows = result.FetchAll(); - WeakReference wr = new WeakReference(result); - result = null; - GC.Collect(); - Assert.False(wr.IsAlive); - Assert.AreEqual(2, rows.Count); - Assert.AreEqual(22, rows[0]["age"]); - Assert.AreEqual("Patric", rows[1]["name"]); - } -#endif - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySqlX.XDevAPI.Relational; +using System; +using NUnit.Framework; +using NUnit.Framework.Legacy; + +namespace MySqlX.Data.Tests.ResultTests +{ + public class RelationalGCTests : BaseTest + { +#if NETFRAMEWORK + [Test] + public void FetchAllNoReference() + { + ExecuteSQL("CREATE TABLE test(name VARCHAR(40), age INT)"); + Table table = testSchema.GetTable("test"); + + ExecuteInsertStatement(table.Insert("name", "age").Values("Henry", "22").Values("Patric", 30)); + var result = ExecuteSelectStatement(table.Select()); + var rows = result.FetchAll(); + WeakReference wr = new WeakReference(result); + result = null; + GC.Collect(); + Assert.That(wr.IsAlive, Is.False); + Assert.That(rows.Count, Is.EqualTo(2)); + Assert.That(rows[0]["age"], Is.EqualTo(22)); + Assert.That(rows[1]["name"], Is.EqualTo("Patric")); + } +#endif + } +} diff --git a/MySQL.Data/tests/MySqlX.Data.Tests/RelationalTests/RowBufferingTests.cs b/MySQL.Data/tests/MySqlX.Data.Tests/RelationalTests/RowBufferingTests.cs index 22b2bf019..f0d8790a6 100644 --- a/MySQL.Data/tests/MySqlX.Data.Tests/RelationalTests/RowBufferingTests.cs +++ b/MySQL.Data/tests/MySqlX.Data.Tests/RelationalTests/RowBufferingTests.cs @@ -1,56 +1,57 @@ -// Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySqlX.XDevAPI.Relational; -using NUnit.Framework; - -namespace MySqlX.Data.Tests.RelationalTests -{ - public class RowBufferingTests : BaseTest - { - [Test] - public void SmartBuffering() - { - ExecuteSQL("CREATE TABLE test1(id INT)"); - ExecuteSQL("INSERT INTO test1 VALUES (1),(2),(3),(4)"); - ExecuteSQL("CREATE TABLE test2(id INT, val INT)"); - ExecuteSQL("INSERT INTO test2 VALUES (1,0)"); - - var rowResult = ExecuteSelectStatement(testSchema.GetTable("test1").Select("id")); - Assert.AreEqual(0, rowResult.IndexOf("id")); - foreach (var row in rowResult) - { - var result = ExecuteUpdateStatement(testSchema.GetTable("test2").Update().Where("id=1").Set("val", row["id"])); - Assert.AreEqual(1, result.AffectedItemsCount); - } - - Row valRow = ExecuteSelectStatement(testSchema.GetTable("test2").Select("val")).FetchOne(); - Assert.AreEqual(4, valRow[0]); - } - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySqlX.XDevAPI.Relational; +using NUnit.Framework; +using NUnit.Framework.Legacy; + +namespace MySqlX.Data.Tests.RelationalTests +{ + public class RowBufferingTests : BaseTest + { + [Test] + public void SmartBuffering() + { + ExecuteSQL("CREATE TABLE test1(id INT)"); + ExecuteSQL("INSERT INTO test1 VALUES (1),(2),(3),(4)"); + ExecuteSQL("CREATE TABLE test2(id INT, val INT)"); + ExecuteSQL("INSERT INTO test2 VALUES (1,0)"); + + var rowResult = ExecuteSelectStatement(testSchema.GetTable("test1").Select("id")); + Assert.That(rowResult.IndexOf("id"), Is.EqualTo(0)); + foreach (var row in rowResult) + { + var result = ExecuteUpdateStatement(testSchema.GetTable("test2").Update().Where("id=1").Set("val", row["id"])); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1)); + } + + Row valRow = ExecuteSelectStatement(testSchema.GetTable("test2").Select("val")).FetchOne(); + Assert.That(valRow[0], Is.EqualTo(4)); + } + } +} diff --git a/MySQL.Data/tests/MySqlX.Data.Tests/RelationalTests/SqlTests.cs b/MySQL.Data/tests/MySqlX.Data.Tests/RelationalTests/SqlTests.cs index f63954835..3ebe3e995 100644 --- a/MySQL.Data/tests/MySqlX.Data.Tests/RelationalTests/SqlTests.cs +++ b/MySQL.Data/tests/MySqlX.Data.Tests/RelationalTests/SqlTests.cs @@ -1,1065 +1,1066 @@ -// Copyright (c) 2015, 2021, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using Google.Protobuf; -using MySql.Data.Common; -using MySql.Data.MySqlClient; -using MySqlX.XDevAPI; -using MySqlX.XDevAPI.Relational; -using NUnit.Framework; -using System.Collections.Generic; - -namespace MySqlX.Data.Tests.RelationalTests -{ - public class SqlTests : BaseTest - { - [TearDown] - public void TearDown() - { - ExecuteSQL("DROP TABLE IF EXISTS test"); - } - - [Test] - public void ReturnSimpleScalar() - { - ExecuteSQL("DROP TABLE IF EXISTS test.test"); - ExecuteSQL("CREATE TABLE test.test(id INT)"); - ExecuteSQL("INSERT INTO test.test VALUES (1)"); - using (var ss = MySQLX.GetSession(ConnectionString)) - { - SqlResult r = ss.SQL("SELECT * FROM test.test").Execute(); - Assert.True(r.Next()); - Assert.AreEqual(1, r[0]); - Assert.False(r.NextResult()); - } - - } - - [Test] - public void ExecuteStoredProcedure() - { - ExecuteSQL("CREATE PROCEDURE `my_proc` () BEGIN SELECT 5; END"); - - Session session = GetSession(true); - var result = ExecuteSQLStatement(session.SQL("CALL my_proc()")); - Assert.True(result.HasData); - var row = result.FetchOne(); - Assert.NotNull(row); - Assert.AreEqual((sbyte)5, row[0]); - Assert.False(result.Next()); - Assert.Null(result.FetchOne()); - Assert.False(result.NextResult()); - } - - [Test] - public void ExecuteStoredProcedureMultipleResults() - { - ExecuteSQL("drop procedure if exists my_proc"); - ExecuteSQL("CREATE PROCEDURE `my_proc` () BEGIN SELECT 5; SELECT 'A'; SELECT 5 * 2; END"); - - Session session = GetSession(true); - var result = ExecuteSQLStatement(session.SQL("CALL my_proc()")); - Assert.True(result.HasData); - var row = result.FetchOne(); - Assert.NotNull(row); - Assert.AreEqual((sbyte)5, row[0]); - Assert.False(result.Next()); - Assert.Null(result.FetchOne()); - - Assert.True(result.NextResult()); - row = result.FetchOne(); - Assert.NotNull(row); - Assert.AreEqual("A", row[0]); - Assert.False(result.Next()); - Assert.Null(result.FetchOne()); - - Assert.True(result.NextResult()); - row = result.FetchOne(); - Assert.NotNull(row); - Assert.AreEqual((sbyte)10, row[0]); - Assert.False(result.Next()); - Assert.Null(result.FetchOne()); - - Assert.False(result.NextResult()); - } - - [Test] - public void Bind() - { - ExecuteSQL("drop table if exists test.test"); - ExecuteSQL("CREATE TABLE test.test(id INT, letter varchar(1))"); - for (int i = 1; i <= 10; i++) - ExecuteSQLStatement(GetSession(true).SQL("INSERT INTO test.test VALUES (?, ?), (?, ?)") - .Bind(i, ((char)('@' + i)).ToString()) - .Bind(++i, ((char)('@' + i)).ToString())); - - SqlResult result = ExecuteSQLStatement(GetSession(true).SQL("select * from test.test where id=?").Bind(5)); - Assert.True(result.Next()); - Assert.That(result.Rows, Has.One.Items); - Assert.AreEqual(5, result[0]); - Assert.AreEqual("E", result[1]); - } - - [Test] - public void BindNull() - { - ExecuteSQL("drop table if exists test.test"); - ExecuteSQL("CREATE TABLE test.test(id INT, letter varchar(1))"); - - var session = GetSession(true); - var result = ExecuteSQLStatement(session.SQL("INSERT INTO test.test VALUES(1, ?), (2, 'B');").Bind(null)); - Assert.AreEqual(2ul, result.AffectedItemsCount); - - var sqlResult = ExecuteSQLStatement(session.SQL("SELECT * FROM test.test WHERE letter is ?").Bind(null)).FetchAll(); - Assert.That(sqlResult, Has.One.Items); - Assert.AreEqual(1, sqlResult[0][0]); - Assert.Null(sqlResult[0][1]); - } - - [Test] - public void Alias() - { - var session = GetSession(true); - var stmt = ExecuteSQLStatement(session.SQL("SELECT 1 AS UNO")); - var result = stmt.FetchAll(); - Assert.AreEqual("UNO", stmt.Columns[0].ColumnLabel); - } - - #region WL14389 - - [Test, Description("call after failed procedure")] - public void ProcedureWithNoTable() - { - ExecuteSQL("create procedure newproc (in p1 int,in p2 char(20)) begin select 1; select 'XXX' from notab; end;"); - - var session = MySQLX.GetSession(ConnectionString + ";database=test;"); - - - var sqlRes = session.SQL("call newproc(?, ?)").Bind(10).Bind("X").Execute(); - var ex = Assert.Throws(() => session.SQL("drop procedure if exists newproc ").Execute()); - StringAssert.AreEqualIgnoringCase("Table 'test.notab' doesn't exist", ex.Message); - } - - [Test, Description("Stored Procedure Table Positive using Session")] - public void TablePositiveSession() - { - MySqlXConnectionStringBuilder sb = new MySqlXConnectionStringBuilder(ConnectionString); - var connectionStringObject = new { connection = "server=" + sb.Server + ";user=" + sb.UserID + ";port=" + sb.Port + ";password=" + sb.Password + ";sslmode=" + MySqlSslMode.Required + ";" }; - using (Session sessionPlain = MySQLX.GetSession(connectionStringObject.connection)) - { - sessionPlain.SQL("DROP DATABASE IF EXISTS DBName").Execute(); - sessionPlain.SQL("CREATE DATABASE DBName").Execute(); - sessionPlain.SQL("USE DBName").Execute(); - sessionPlain.SQL("CREATE TABLE address" + - "(address_number INT NOT NULL AUTO_INCREMENT, " + - "building_name VARCHAR(100) NOT NULL, " + - "district VARCHAR(100) NOT NULL, PRIMARY KEY (address_number)" + ");").Execute(); - sessionPlain.SQL("INSERT INTO address" + - "(address_number,building_name,district)" + - " VALUES " + - "(1573,'MySQL','BGL');").Execute(); - string procI = "CREATE PROCEDURE my_add_one_procedure " + - " (IN address_id INT) " + - "BEGIN " + - "select * from address as a where a.address_number = address_id;" + - "END;"; - sessionPlain.SQL(procI).Execute(); - var res = sessionPlain.SQL("CALL my_add_one_procedure(1573);").Execute(); - if (res.HasData) - { - var row = res.FetchOne(); - if (row != null) - { - do - { - if (row[0] != null) - Assert.IsNotNull(row[0].ToString()); - - if (row[1] != null) - Assert.IsNotNull(row[1].ToString()); - - if (row[2] != null) - Assert.IsNotNull(row[2].ToString()); - - } while (res.Next()); while (res.NextResult()) ; - } - } - sessionPlain.SQL("DROP DATABASE DBName").Execute(); - } - } - - [Test, Description("Stored Procedure Table-StringBuilder and Session")] - public void StoredProcTablePositiveStringBuilderSession() - { - if (!Platform.IsWindows()) Assert.Ignore("This test is for Windows OS only"); - - MySqlXConnectionStringBuilder sb = new MySqlXConnectionStringBuilder(ConnectionString); - var connectionStringObject = new { connection = "server=" + sb.Server + ";user=" + sb.UserID + ";port=" + sb.Port + ";password=" + sb.Password }; - - using (MySqlConnection mysql = new MySqlConnection(ConnectionStringRoot)) - { - mysql.Open(); - System.Text.StringBuilder sql = new System.Text.StringBuilder(); - sql.AppendLine("DROP DATABASE IF EXISTS DBName"); - MySqlScript script = new MySqlScript(mysql, sql.ToString()); - script.Execute(); - sql = new System.Text.StringBuilder(); - sql.AppendLine("CREATE DATABASE DBName"); - script = new MySqlScript(mysql, sql.ToString()); - script.Execute(); - sql = new System.Text.StringBuilder(); - sql.AppendLine("USE DBName"); - script = new MySqlScript(mysql, sql.ToString()); - script.Execute(); - sql = new System.Text.StringBuilder(); - sql.AppendLine("CREATE TABLE address" + - "(address_number INT NOT NULL AUTO_INCREMENT, " + - "building_name VARCHAR(100) NOT NULL, " + - "district VARCHAR(100) NOT NULL, PRIMARY KEY (address_number)" + ");" - ); - script = new MySqlScript(mysql, sql.ToString()); - script.Execute(); - sql = new System.Text.StringBuilder(); - sql.AppendLine("INSERT INTO address" + - "(address_number,building_name,district)" + - " VALUES " + - "(1573,'MySQL','BGL');"); - script = new MySqlScript(mysql, sql.ToString()); - script.Execute(); - sql = new System.Text.StringBuilder(); - sql.AppendLine("INSERT INTO address" + - "(address_number,building_name,district)" + - " VALUES " + - "(1,'MySQLTest1','BGLTest1');"); - script = new MySqlScript(mysql, sql.ToString()); - script.Execute(); - sql = new System.Text.StringBuilder(); - sql.AppendLine("INSERT INTO address" + - "(address_number,building_name,district)" + - " VALUES " + - "(2,'MySQLTest2','BGLTest2');"); - script = new MySqlScript(mysql, sql.ToString()); - script.Execute(); - sql = new System.Text.StringBuilder(); - sql.AppendLine("DELIMITER //"); - sql.AppendLine("CREATE PROCEDURE my_add_one_procedure " + - " (IN address_id INT) " + - "BEGIN " + - "select * from address as a where a.address_number = address_id;" + - "END//"); - script = new MySqlScript(mysql, sql.ToString()); - script.Execute(); - sql = new System.Text.StringBuilder(); - sql.AppendLine("DELIMITER ;"); - script = new MySqlScript(mysql, sql.ToString()); - script.Execute(); - } - - using (Session sessionPlain = MySQLX.GetSession(connectionStringObject.connection)) - { - sessionPlain.SQL("USE DBName").Execute(); - var res = sessionPlain.SQL("CALL my_add_one_procedure(1573);").Execute(); - if (res.HasData) - { - var row = res.FetchOne(); - if (row != null) - { - do - { - if (row[0] != null) - Assert.IsNotNull(row[0].ToString()); - - if (row[1] != null) - Assert.IsNotNull(row[1].ToString()); - - if (row[2] != null) - Assert.IsNotNull(row[2].ToString()); - - } while (res.Next()); while (res.NextResult()) ; - } - } - sessionPlain.SQL("DROP PROCEDURE my_add_one_procedure;").Execute(); - sessionPlain.SQL("DROP TABLE address;").Execute(); - sessionPlain.SQL("DROP DATABASE DBName;").Execute(); - } - } - - [Test, Description("Stored Procedure Table-Negative(procedure returns null)")] - public void StoredProcReturnsNull() - { - if (!Platform.IsWindows()) Assert.Ignore("This test is for Windows OS only"); - - MySqlConnection mysql = new MySqlConnection(ConnectionStringRoot); - mysql.Open(); - System.Text.StringBuilder sql = new System.Text.StringBuilder(); - sql.AppendLine("DROP DATABASE IF EXISTS DBName"); - MySqlScript script = new MySqlScript(mysql, sql.ToString()); - script.Execute(); - sql = new System.Text.StringBuilder(); - sql.AppendLine("CREATE DATABASE DBName"); - script = new MySqlScript(mysql, sql.ToString()); - script.Execute(); - sql = new System.Text.StringBuilder(); - sql.AppendLine("USE DBName"); - script = new MySqlScript(mysql, sql.ToString()); - script.Execute(); - sql = new System.Text.StringBuilder(); - sql.AppendLine("CREATE TABLE address" + - "(address_number INT NOT NULL AUTO_INCREMENT, " + - "building_name VARCHAR(100) NOT NULL, " + - "district VARCHAR(100) NOT NULL, PRIMARY KEY (address_number)" + ");" - ); - script = new MySqlScript(mysql, sql.ToString()); - script.Execute(); - sql = new System.Text.StringBuilder(); - sql.AppendLine("INSERT INTO address" + - "(address_number,building_name,district)" + - " VALUES " + - "(1573,'MySQL','BGL');"); - script = new MySqlScript(mysql, sql.ToString()); - script.Execute(); - sql = new System.Text.StringBuilder(); - sql.AppendLine("INSERT INTO address" + - "(address_number,building_name,district)" + - " VALUES " + - "(1,'MySQLTest1','BGLTest1');"); - script = new MySqlScript(mysql, sql.ToString()); - script.Execute(); - sql = new System.Text.StringBuilder(); - sql.AppendLine("INSERT INTO address" + - "(address_number,building_name,district)" + - " VALUES " + - "(2,'MySQLTest2','BGLTest2');"); - script = new MySqlScript(mysql, sql.ToString()); - script.Execute(); - sql = new System.Text.StringBuilder(); - sql.AppendLine("DELIMITER //"); - sql.AppendLine("CREATE PROCEDURE my_add_one_procedure " + - " (IN address_id INT) " + - "BEGIN " + - "select * from address as a where a.address_number = address_id;" + - "END//"); - script = new MySqlScript(mysql, sql.ToString()); - script.Execute(); - sql = new System.Text.StringBuilder(); - sql.AppendLine("DELIMITER ;"); - script = new MySqlScript(mysql, sql.ToString()); - script.Execute(); - - MySqlXConnectionStringBuilder sb = new MySqlXConnectionStringBuilder(ConnectionString); - var connectionStringObject = new { connection = "server=" + sb.Server + ";user=" + sb.UserID + ";port=" + sb.Port + ";password=" + sb.Password + ";sslmode=" + MySqlSslMode.Required + ";" }; - using (Session sessionPlain = MySQLX.GetSession(connectionStringObject.connection)) - { - sessionPlain.SQL("USE DBName").Execute(); - - var res = sessionPlain.SQL("CALL my_add_one_procedure(1000);").Execute(); - if (res.HasData) - { - var row = res.FetchOne(); - Assert.IsNull(row); - } - res.Next(); - res.NextResult(); - } - } - - //SQLTests - [Test, Description("Bind Support for Session SQL Numeric Datatypes- integer,JSON,tinyint,smallint,mediumint,bigint,float,double,decimal")] - public void BindSupportSessionSQLNumericDatatypes() - { - if (!session.Version.isAtLeast(5, 7, 0)) Assert.Ignore("This test is for MySql 5.7 or higher"); - var connectionString = ConnectionString + ";sslmode=" + MySqlSslMode.Required; - SqlResult myResult; - Row row; - - //integer - using (Session sessionTest = MySQLX.GetSession(connectionString)) - { - sessionTest.SQL("DROP DATABASE IF EXISTS DBName ").Execute(); - sessionTest.SQL("CREATE DATABASE IF NOT EXISTS DBName").Execute(); - sessionTest.SQL("USE DBName").Execute(); - sessionTest.SQL("CREATE PROCEDURE my_add_one_procedure " + - " (INOUT incr_param INT) " + - "BEGIN " + - " SET incr_param = incr_param + 1;" + - "END;").Execute(); - //Uncomment once Bind is implemented in 7.0.2 - sessionTest.SQL("SET @my_var = ?;").Bind(10).Execute(); - sessionTest.SQL("CALL my_add_one_procedure(@my_var);").Execute(); - sessionTest.SQL("DROP PROCEDURE my_add_one_procedure;").Execute(); - // Use a SQL query to get the result - myResult = sessionTest.SQL("SELECT @my_var").Execute(); - // Gets the row and prints the first column - row = myResult.FetchOne(); - Assert.IsNotNull(row[0].ToString()); - sessionTest.SQL("DROP DATABASE DBName").Execute(); - } - - //JSON - using (var sessionTest = MySQLX.GetSession(connectionString)) - { - sessionTest.SQL("CREATE DATABASE IF NOT EXISTS DBName").Execute(); - sessionTest.SQL("USE DBName").Execute(); - sessionTest.SQL("CREATE PROCEDURE my_add_one_procedure " + - " (INOUT incr_param Json) " + - "BEGIN " + - " SET incr_param = incr_param;" + - "END;").Execute(); - //Uncomment once Bind is implemented in 7.0.2 - var jsonParams = "{ \"pages1\" : 30, \"pages2\" : 40 }"; - sessionTest.SQL("SET @my_var = ?;").Bind(jsonParams).Execute(); - sessionTest.SQL("CALL my_add_one_procedure(@my_var);").Execute(); - sessionTest.SQL("DROP PROCEDURE my_add_one_procedure;").Execute(); - // Use a SQL query to get the result - myResult = sessionTest.SQL("SELECT @my_var").Execute(); - // Gets the row and prints the first column - row = myResult.FetchOne(); - Assert.IsNotNull(row[0].ToString()); - sessionTest.SQL("DROP DATABASE DBName").Execute(); - } - - //TINYINT - using (var sessionTest = MySQLX.GetSession(connectionString)) - { - sessionTest.SQL("CREATE DATABASE IF NOT EXISTS DBName").Execute(); - sessionTest.SQL("USE DBName").Execute(); - sessionTest.SQL("CREATE PROCEDURE my_add_one_procedure " + - " (INOUT incr_param TINYINT) " + - "BEGIN " + - " SET incr_param = incr_param + 1;" + - "END;").Execute(); - //Uncomment once Bind is implemented in 7.0.2 - sessionTest.SQL("SET @my_var = ?;").Bind(1).Execute(); - sessionTest.SQL("CALL my_add_one_procedure(@my_var);").Execute(); - sessionTest.SQL("DROP PROCEDURE my_add_one_procedure;").Execute(); - // Use a SQL query to get the result - myResult = sessionTest.SQL("SELECT @my_var").Execute(); - // Gets the row and prints the first column - row = myResult.FetchOne(); - Assert.IsNotNull(row[0].ToString()); - sessionTest.SQL("DROP DATABASE DBName").Execute(); - } - - //SMALLINT - using (var sessionTest = MySQLX.GetSession(connectionString)) - { - sessionTest.SQL("CREATE DATABASE IF NOT EXISTS DBName").Execute(); - sessionTest.SQL("USE DBName").Execute(); - sessionTest.SQL("CREATE PROCEDURE my_add_one_procedure " + - " (INOUT incr_param SMALLINT) " + - "BEGIN " + - " SET incr_param = incr_param + 1;" + - "END;").Execute(); - //Uncomment once Bind is implemented in 7.0.2 - sessionTest.SQL("SET @my_var = ?;").Bind(11111).Execute(); - sessionTest.SQL("CALL my_add_one_procedure(@my_var);").Execute(); - sessionTest.SQL("DROP PROCEDURE my_add_one_procedure;").Execute(); - // Use a SQL query to get the result - myResult = sessionTest.SQL("SELECT @my_var").Execute(); - // Gets the row and prints the first column - row = myResult.FetchOne(); - Assert.IsNotNull(row[0].ToString()); - sessionTest.SQL("DROP DATABASE DBName").Execute(); - } - - //MEDIUMINT - using (var sessionTest = MySQLX.GetSession(connectionString)) - { - sessionTest.SQL("CREATE DATABASE IF NOT EXISTS DBName").Execute(); - sessionTest.SQL("USE DBName").Execute(); - sessionTest.SQL("CREATE PROCEDURE my_add_one_procedure " + - " (INOUT incr_param MEDIUMINT) " + - "BEGIN " + - " SET incr_param = incr_param + 1;" + - "END;").Execute(); - //Uncomment once Bind is implemented in 7.0.2 - sessionTest.SQL("SET @my_var = ?;").Bind(1111).Execute(); - sessionTest.SQL("CALL my_add_one_procedure(@my_var);").Execute(); - sessionTest.SQL("DROP PROCEDURE my_add_one_procedure;").Execute(); - // Use a SQL query to get the result - myResult = sessionTest.SQL("SELECT @my_var").Execute(); - // Gets the row and prints the first column - row = myResult.FetchOne(); - Assert.IsNotNull(row[0].ToString()); - sessionTest.SQL("DROP DATABASE DBName").Execute(); - } - - //FLOATMD - using (var sessionTest = MySQLX.GetSession(connectionString)) - { - sessionTest.SQL("CREATE DATABASE IF NOT EXISTS DBName").Execute(); - sessionTest.SQL("USE DBName").Execute(); - sessionTest.SQL("CREATE PROCEDURE my_add_one_procedure " + - " (INOUT incr_param FLOAT(10,2)) " + - "BEGIN " + - " SET incr_param = incr_param + 1;" + - "END;").Execute(); - //Uncomment once Bind is implemented in 7.0.2 - sessionTest.SQL("SET @my_var = ?;").Bind(100.2).Execute(); - sessionTest.SQL("CALL my_add_one_procedure(@my_var);").Execute(); - sessionTest.SQL("DROP PROCEDURE my_add_one_procedure;").Execute(); - // Use a SQL query to get the result - myResult = sessionTest.SQL("SELECT @my_var").Execute(); - // Gets the row and prints the first column - row = myResult.FetchOne(); - Assert.IsNotNull(row[0].ToString()); - sessionTest.SQL("DROP DATABASE DBName").Execute(); - } - - //DOUBLEMD - using (var sessionTest = MySQLX.GetSession(connectionString)) - { - sessionTest.SQL("CREATE DATABASE IF NOT EXISTS DBName").Execute(); - sessionTest.SQL("USE DBName").Execute(); - sessionTest.SQL("CREATE PROCEDURE my_add_one_procedure " + - " (INOUT incr_param DOUBLE(10,2)) " + - "BEGIN " + - " SET incr_param = incr_param + 1;" + - "END;").Execute(); - //Uncomment once Bind is implemented in 7.0.2 - sessionTest.SQL("SET @my_var = ?;").Bind(1000.2).Execute(); - sessionTest.SQL("CALL my_add_one_procedure(@my_var);").Execute(); - sessionTest.SQL("DROP PROCEDURE my_add_one_procedure;").Execute(); - // Use a SQL query to get the result - myResult = sessionTest.SQL("SELECT @my_var").Execute(); - // Gets the row and prints the first column - row = myResult.FetchOne(); - Assert.IsNotNull(row[0].ToString()); - sessionTest.SQL("DROP DATABASE DBName").Execute(); - } - - //DECIMALMD - using (var sessionTest = MySQLX.GetSession(connectionString)) - { - sessionTest.SQL("CREATE DATABASE IF NOT EXISTS DBName").Execute(); - sessionTest.SQL("USE DBName").Execute(); - sessionTest.SQL("CREATE PROCEDURE my_add_one_procedure " + - " (INOUT incr_param DECIMAL(10,2)) " + - "BEGIN " + - " SET incr_param = incr_param + 1;" + - "END;").Execute(); - //Uncomment once Bind is implemented in 7.0.2 - sessionTest.SQL("SET @my_var = ?;").Bind(10000.2).Execute(); - sessionTest.SQL("CALL my_add_one_procedure(@my_var);").Execute(); - sessionTest.SQL("DROP PROCEDURE my_add_one_procedure;").Execute(); - // Use a SQL query to get the result - myResult = sessionTest.SQL("SELECT @my_var").Execute(); - // Gets the row and prints the first column - row = myResult.FetchOne(); - Assert.IsNotNull(row[0].ToString()); - sessionTest.SQL("DROP DATABASE DBName").Execute(); - } - } - - - [Test, Description("Bind Support for Session SQL DateTime Types- date,datetime,timestamp,time,year(M)")] - public void BindSupportSessionSQLDateTimetypes() - { - if (!session.Version.isAtLeast(5, 7, 0)) Assert.Ignore("This test is for MySql 5.7 or higher"); - //DATE - string connectionString = ConnectionString + ";sslmode=" + MySqlSslMode.Required; - SqlResult myResult; - Row row; - - using (Session sessionTest = MySQLX.GetSession(connectionString)) - { - sessionTest.SQL("DROP DATABASE IF EXISTS DBName ").Execute(); - sessionTest.SQL("CREATE DATABASE IF NOT EXISTS DBName").Execute(); - sessionTest.SQL("USE DBName").Execute(); - sessionTest.SQL("CREATE PROCEDURE my_add_one_procedure " + - " (INOUT incr_param DATE) " + - "BEGIN " + - " SET incr_param = incr_param ;" + - "END;").Execute(); - //Uncomment once Bind is implemented in 7.0.2 - sessionTest.SQL("SET @my_var = ?;").Bind("1973-12-30").Execute(); - sessionTest.SQL("CALL my_add_one_procedure(@my_var);").Execute(); - sessionTest.SQL("DROP PROCEDURE my_add_one_procedure;").Execute(); - // Use a SQL query to get the result - myResult = sessionTest.SQL("SELECT @my_var").Execute(); - // Gets the row and prints the first column - row = myResult.FetchOne(); - Assert.IsNotNull(row[0].ToString()); - sessionTest.SQL("DROP DATABASE DBName").Execute(); - } - - //DATETIME - using (Session sessionTest = MySQLX.GetSession(connectionString)) - { - sessionTest.SQL("CREATE DATABASE IF NOT EXISTS DBName").Execute(); - sessionTest.SQL("USE DBName").Execute(); - sessionTest.SQL("CREATE PROCEDURE my_add_one_procedure " + - " (INOUT incr_param DATETIME) " + - "BEGIN " + - " SET incr_param = incr_param ;" + - "END;").Execute(); - //Uncomment once Bind is implemented in 7.0.2 - sessionTest.SQL("SET @my_var = ?;").Bind("1981-04-10 15:30:00").Execute(); - sessionTest.SQL("CALL my_add_one_procedure(@my_var);").Execute(); - sessionTest.SQL("DROP PROCEDURE my_add_one_procedure;").Execute(); - // Use a SQL query to get the result - myResult = sessionTest.SQL("SELECT @my_var").Execute(); - // Gets the row and prints the first column - row = myResult.FetchOne(); - Assert.IsNotNull(row[0].ToString()); - sessionTest.SQL("DROP DATABASE DBName").Execute(); - } - - //TIMESTAMP - using (Session sessionTest = MySQLX.GetSession(connectionString)) - { - sessionTest.SQL("CREATE DATABASE IF NOT EXISTS DBName").Execute(); - sessionTest.SQL("USE DBName").Execute(); - sessionTest.SQL("CREATE PROCEDURE my_add_one_procedure " + - " (INOUT incr_param TIMESTAMP) " + - "BEGIN " + - " SET incr_param = incr_param ;" + - "END;").Execute(); - //Uncomment once Bind is implemented in 7.0.2 - sessionTest.SQL("SET @my_var = ?;").Bind("20160316153000").Execute(); - sessionTest.SQL("CALL my_add_one_procedure(@my_var);").Execute(); - sessionTest.SQL("DROP PROCEDURE my_add_one_procedure;").Execute(); - // Use a SQL query to get the result - myResult = sessionTest.SQL("SELECT @my_var").Execute(); - // Gets the row and prints the first column - row = myResult.FetchOne(); - Assert.IsNotNull(row[0].ToString()); - sessionTest.SQL("DROP DATABASE DBName").Execute(); - } - - //TIME - using (Session sessionTest = MySQLX.GetSession(connectionString)) - { - sessionTest.SQL("CREATE DATABASE IF NOT EXISTS DBName").Execute(); - sessionTest.SQL("USE DBName").Execute(); - sessionTest.SQL("CREATE PROCEDURE my_add_one_procedure " + - " (INOUT incr_param TIME) " + - "BEGIN " + - " SET incr_param = incr_param ;" + - "END;").Execute(); - //Uncomment once Bind is implemented in 7.0.2 - sessionTest.SQL("SET @my_var = ?;").Bind("12:00:00").Execute(); - sessionTest.SQL("CALL my_add_one_procedure(@my_var);").Execute(); - sessionTest.SQL("DROP PROCEDURE my_add_one_procedure;").Execute(); - // Use a SQL query to get the result - myResult = sessionTest.SQL("SELECT @my_var").Execute(); - // Gets the row and prints the first column - row = myResult.FetchOne(); - Assert.IsNotNull(row[0].ToString()); - sessionTest.SQL("DROP DATABASE DBName").Execute(); - } - - //YEAR - using (Session sessionTest = MySQLX.GetSession(connectionString)) - { - sessionTest.SQL("CREATE DATABASE IF NOT EXISTS DBName").Execute(); - sessionTest.SQL("USE DBName").Execute(); - sessionTest.SQL("CREATE PROCEDURE my_add_one_procedure " + - " (INOUT incr_param YEAR(4)) " + - "BEGIN " + - " SET incr_param = incr_param ;" + - "END;").Execute(); - //Uncomment once Bind is implemented in 7.0.2 - sessionTest.SQL("SET @my_var = ?;").Bind("2111").Execute(); - sessionTest.SQL("CALL my_add_one_procedure(@my_var);").Execute(); - sessionTest.SQL("DROP PROCEDURE my_add_one_procedure;").Execute(); - // Use a SQL query to get the result - myResult = sessionTest.SQL("SELECT @my_var").Execute(); - // Gets the row and prints the first column - row = myResult.FetchOne(); - Assert.IsNotNull(row[0].ToString()); - sessionTest.SQL("DROP DATABASE DBName").Execute(); - } - } - - - [Test, Description("Bind Support for Session SQL String Types- CHAR(M),VARCHAR(M),BLOB,TINYBLOB,MEDIUMBLOB,LONGBLOB,ENUM")] - public void BindSupportSessionSQLStringtypes() - { - if (!session.Version.isAtLeast(5, 7, 0)) Assert.Ignore("This test is for MySql 5.7 or higher"); - //CHAR(20) - string connectionString = ConnectionString + ";sslmode=" + MySqlSslMode.Required; - SqlResult myResult; - Row row; - - using (Session sessionTest = MySQLX.GetSession(connectionString)) - { - sessionTest.SQL("DROP DATABASE IF EXISTS DBName ").Execute(); - sessionTest.SQL("CREATE DATABASE IF NOT EXISTS DBName").Execute(); - sessionTest.SQL("USE DBName").Execute(); - sessionTest.SQL("CREATE PROCEDURE my_add_one_procedure " + - " (INOUT incr_param CHAR(20)) " + - "BEGIN " + - " SET incr_param = incr_param;" + - "END;").Execute(); - //Uncomment once Bind is implemented in 7.0.2 - sessionTest.SQL("SET @my_var = ?;").Bind("ABCDEFGHIJABCDEFGHIJ").Execute(); - sessionTest.SQL("CALL my_add_one_procedure(@my_var);").Execute(); - sessionTest.SQL("DROP PROCEDURE my_add_one_procedure;").Execute(); - // Use a SQL query to get the result - myResult = sessionTest.SQL("SELECT @my_var").Execute(); - // Gets the row and prints the first column - row = myResult.FetchOne(); - Assert.IsNotNull(row[0].ToString()); - sessionTest.SQL("DROP DATABASE DBName").Execute(); - } - - //VARCHAR(20) - using (Session sessionTest = MySQLX.GetSession(connectionString)) - { - sessionTest.SQL("CREATE DATABASE IF NOT EXISTS DBName").Execute(); - sessionTest.SQL("USE DBName").Execute(); - sessionTest.SQL("CREATE PROCEDURE my_add_one_procedure " + - " (INOUT incr_param VARCHAR(20)) " + - "BEGIN " + - " SET incr_param = incr_param;" + - "END;").Execute(); - //Uncomment once Bind is implemented in 7.0.2 - sessionTest.SQL("SET @my_var = ?;").Bind("ABCDEFGHIJABCDEFGHIJ").Execute(); - sessionTest.SQL("CALL my_add_one_procedure(@my_var);").Execute(); - sessionTest.SQL("DROP PROCEDURE my_add_one_procedure;").Execute(); - // Use a SQL query to get the result - myResult = sessionTest.SQL("SELECT @my_var").Execute(); - // Gets the row and prints the first column - row = myResult.FetchOne(); - Assert.IsNotNull(row[0].ToString()); - sessionTest.SQL("DROP DATABASE DBName").Execute(); - } - - //BLOB - using (Session sessionTest = MySQLX.GetSession(connectionString)) - { - sessionTest.SQL("CREATE DATABASE IF NOT EXISTS DBName").Execute(); - sessionTest.SQL("USE DBName").Execute(); - sessionTest.SQL("CREATE PROCEDURE my_add_one_procedure " + - " (INOUT incr_param BLOB) " + - "BEGIN " + - " SET incr_param = incr_param ;" + - "END;").Execute(); - //Uncomment once Bind is implemented in 7.0.2 - sessionTest.SQL("SET @my_var = ?;").Bind(19731230153000).Execute(); - sessionTest.SQL("CALL my_add_one_procedure(@my_var);").Execute(); - sessionTest.SQL("DROP PROCEDURE my_add_one_procedure;").Execute(); - // Use a SQL query to get the result - myResult = sessionTest.SQL("SELECT @my_var").Execute(); - // Gets the row and prints the first column - row = myResult.FetchOne(); - Assert.IsNotNull(row[0].ToString()); - sessionTest.SQL("DROP DATABASE DBName").Execute(); - } - - //TINYBLOB - using (Session sessionTest = MySQLX.GetSession(connectionString)) - { - sessionTest.SQL("CREATE DATABASE IF NOT EXISTS DBName").Execute(); - sessionTest.SQL("USE DBName").Execute(); - sessionTest.SQL("CREATE PROCEDURE my_add_one_procedure " + - " (INOUT incr_param TINYBLOB) " + - "BEGIN " + - " SET incr_param = incr_param ;" + - "END;").Execute(); - //Uncomment once Bind is implemented in 7.0.2 - sessionTest.SQL("SET @my_var = ?;").Bind("12:00:00").Execute(); - sessionTest.SQL("CALL my_add_one_procedure(@my_var);").Execute(); - sessionTest.SQL("DROP PROCEDURE my_add_one_procedure;").Execute(); - // Use a SQL query to get the result - myResult = sessionTest.SQL("SELECT @my_var").Execute(); - // Gets the row and prints the first column - row = myResult.FetchOne(); - Assert.IsNotNull(row[0].ToString()); - sessionTest.SQL("DROP DATABASE DBName").Execute(); - } - - //MEDIUMBLOB - using (Session sessionTest = MySQLX.GetSession(connectionString)) - { - sessionTest.SQL("CREATE DATABASE IF NOT EXISTS DBName").Execute(); - sessionTest.SQL("USE DBName").Execute(); - sessionTest.SQL("CREATE PROCEDURE my_add_one_procedure " + - " (INOUT incr_param MEDIUMBLOB) " + - "BEGIN " + - " SET incr_param = incr_param ;" + - "END;").Execute(); - //Uncomment once Bind is implemented in 7.0.2 - sessionTest.SQL("SET @my_var = ?;").Bind(2111).Execute(); - sessionTest.SQL("CALL my_add_one_procedure(@my_var);").Execute(); - sessionTest.SQL("DROP PROCEDURE my_add_one_procedure;").Execute(); - // Use a SQL query to get the result - myResult = sessionTest.SQL("SELECT @my_var").Execute(); - // Gets the row and prints the first column - row = myResult.FetchOne(); - Assert.IsNotNull(row[0].ToString()); - sessionTest.SQL("DROP DATABASE DBName").Execute(); - } - - //LONGBLOB - using (Session sessionTest = MySQLX.GetSession(connectionString)) - { - sessionTest.SQL("CREATE DATABASE IF NOT EXISTS DBName").Execute(); - sessionTest.SQL("USE DBName").Execute(); - sessionTest.SQL("CREATE PROCEDURE my_add_one_procedure " + - " (INOUT incr_param LONGBLOB) " + - "BEGIN " + - " SET incr_param = incr_param ;" + - "END;").Execute(); - //Uncomment once Bind is implemented in 7.0.2 - sessionTest.SQL("SET @my_var = ?;").Bind(111232).Execute(); - sessionTest.SQL("CALL my_add_one_procedure(@my_var);").Execute(); - sessionTest.SQL("DROP PROCEDURE my_add_one_procedure;").Execute(); - // Use a SQL query to get the result - myResult = sessionTest.SQL("SELECT @my_var").Execute(); - // Gets the row and prints the first column - row = myResult.FetchOne(); - Assert.IsNotNull(row[0].ToString()); - sessionTest.SQL("DROP DATABASE DBName").Execute(); - } - - //ENUM - using (Session sessionTest = MySQLX.GetSession(connectionString)) - { - sessionTest.SQL("CREATE DATABASE IF NOT EXISTS DBName").Execute(); - sessionTest.SQL("USE DBName").Execute(); - sessionTest.SQL("CREATE PROCEDURE my_add_one_procedure " + - " (INOUT incr_param ENUM('x-small', 'small', 'medium', 'large', 'x-large')) " + - "BEGIN " + - " SET incr_param = incr_param ;" + - "END;").Execute(); - //Uncomment once Bind is implemented in 7.0.2 - sessionTest.SQL("SET @my_var = ?;").Bind("large").Execute(); - sessionTest.SQL("CALL my_add_one_procedure(@my_var);").Execute(); - sessionTest.SQL("DROP PROCEDURE my_add_one_procedure;").Execute(); - // Use a SQL query to get the result - myResult = sessionTest.SQL("SELECT @my_var").Execute(); - // Gets the row and prints the first column - row = myResult.FetchOne(); - Assert.IsNotNull(row[0].ToString()); - sessionTest.SQL("DROP DATABASE DBName").Execute(); - } - } - - [Test, Description("Bind Support for Session SQL Negative Tests-Null")] - public void BindSupportSessionSQLNegativeTest1() - { - if (!session.Version.isAtLeast(5, 7, 0)) Assert.Ignore("This test is for MySql 5.7 or higher"); - SqlResult myResult = null; - - //integer - string connectionString = ConnectionString + ";sslmode=" + MySqlSslMode.Required; - Session sessionTest = MySQLX.GetSession(connectionString); - sessionTest.SQL("DROP DATABASE IF EXISTS DBName ").Execute(); - sessionTest.SQL("CREATE DATABASE IF NOT EXISTS DBName").Execute(); - sessionTest.SQL("USE DBName").Execute(); - sessionTest.SQL("CREATE PROCEDURE my_add_one_procedure " + - " (INOUT incr_param INT) " + - "BEGIN " + - " SET incr_param = incr_param+1;" + - "END;").Execute(); - - sessionTest.SQL("SET @my_var = ?;").Bind(null).Execute(); - sessionTest.SQL("CALL my_add_one_procedure(@my_var);").Execute(); - sessionTest.SQL("DROP PROCEDURE my_add_one_procedure;").Execute(); - // Use a SQL query to get the result - myResult = sessionTest.SQL("SELECT @my_var").Execute(); - - Assert.Throws(() => myResult.FetchOne()); - sessionTest.SQL("DROP DATABASE DBName").Execute(); - sessionTest.Close(); - sessionTest.Dispose(); - } - - [Test, Description("Bind Support for Session SQL Negative Tests-Bind Chaining Tests")] - public void BindSupportSessionSQLNegativeTest2() - { - if (!session.Version.isAtLeast(5, 7, 0)) Assert.Ignore("This test is for MySql 5.7 or higher"); - - //integer - string connectionString = ConnectionString + ";sslmode=" + MySqlSslMode.Required; - Session sessionTest = MySQLX.GetSession(connectionString); - sessionTest.SQL("DROP DATABASE IF EXISTS DBName ").Execute(); - sessionTest.SQL("CREATE DATABASE IF NOT EXISTS DBName").Execute(); - sessionTest.SQL("USE DBName").Execute(); - sessionTest.SQL("CREATE PROCEDURE my_add_one_procedure " + - " (INOUT incr_param INT) " + - "BEGIN " + - " SET incr_param = incr_param + 1;" + - "END;").Execute(); - sessionTest.SQL("CREATE TABLE DBName.test(id INT, letter varchar(1))").Execute(); - - for (int i = 1; i <= 100; i++) - - session.SQL("INSERT INTO DBName.test VALUES (?, ?), (?, ?)") - .Bind(1, "a") - .Bind(2, "b") - .Execute(); - - SqlResult result = session.SQL("select * from DBName.test where id=?").Bind(5).Execute(); - - //Uncomment once Bind is implemented in 7.0.2 - Assert.Throws(() => session.SQL("SET @my_var = ?;").Bind(1).Bind(2).Execute()); - sessionTest.SQL("DROP DATABASE DBName").Execute(); - sessionTest.Close(); - sessionTest.Dispose(); - - } - - // Aditional Tests - [Test, Description("Test MySQLX plugin MySQL mixed scenario")] - public void MixedChainedCommands() - { - if (!session.Version.isAtLeast(5, 7, 0)) Assert.Ignore("This test is for MySql 5.7 or higher"); - ExecuteSQL("Drop table if exists test"); - ExecuteSQL("CREATE TABLE test(c1 float(14,8),c2 double GENERATED ALWAYS AS (c1*101/102) Stored COMMENT 'First Gen Col')"); - ExecuteSQL("INSERT INTO test(c1) VALUES (22.7)"); - ExecuteSQL("INSERT INTO test(c1) VALUES (-100000.38984)"); - ExecuteSQL("INSERT INTO test(c1) VALUES (0)"); - - RowResult r = session.GetSchema("test").GetTable("test").Select("c1").Execute(); - var rows = r.FetchAll(); - Assert.AreEqual(1, r.Columns.Count, "Matching"); - Assert.AreEqual(typeof(float).ToString(), r.Columns[0].ClrType.ToString(), "Matching"); - Assert.AreEqual(MySqlDbType.Float.ToString(), r.Columns[0].Type.ToString(), "Matching"); - Assert.AreEqual(14, (int)r.Columns[0].Length, "Matching"); - Assert.AreEqual(8, (int)r.Columns[0].FractionalDigits, "Matching"); - Assert.AreEqual(3, rows.Count, "Matching"); - Assert.AreEqual(22.7f, (float)rows[0][0], "Matching"); - Assert.AreEqual(-100000.38984f, (float)rows[1][0], "Matching"); - Assert.AreEqual(0f, (float)rows[2][0], "Matching"); - } - - [Test, Description("Test MySQLX plugin MySQL Date Time Bug")] - public void DateTimeCheck() - { - if (!session.Version.isAtLeast(5, 7, 0)) Assert.Ignore("This test is for MySql 5.7 or higher"); - ExecuteSQL("CREATE TABLE test.test1212(dt DATETIME(6))"); - ExecuteSQL("INSERT INTO test.test1212 VALUES('2015-10-21 18:01:00.12345678')"); - - RowResult r = session.GetSchema("test").GetTable("test1212").Select("dt").Execute(); - var rows = r.FetchAll(); - Assert.AreEqual(1, r.Columns.Count, "Matching Coulumn Count"); - - } - - [Test, Description("Test MySQLX plugin MySQL Datetime JSON")] - public void DateTimeJSON() - { - if (!session.Version.isAtLeast(5, 7, 0)) Assert.Ignore("This test is for MySql 5.7 or higher"); - ExecuteSQL("DROP TABLE IF EXISTS test.test"); - ExecuteSQL("CREATE TABLE test.test(Id int NOT NULL PRIMARY KEY, jsoncolumn JSON)"); - ExecuteSQL(@"INSERT INTO test.test VALUES(100000,' { ""name"" : ""bob"",""Date"": ""2015-10-09"",""Time"": ""12:18:29.000000"",""DateTimeOfRegistration"": ""2015-10-09 12:18:29.000000"",""age"":12} ')"); - RowResult r = session.GetSchema("test").GetTable("test").Select("jsoncolumn").Execute(); - var rows = r.FetchAll(); - Assert.AreEqual(1, r.Columns.Count, "Matching"); - } - - [Test, Description("Test MySQLX plugin JSON Variant")] - public void JSONVariant() - { - if (!Platform.IsWindows()) Assert.Ignore("This test is for Windows OS only"); - if (!session.Version.isAtLeast(5, 7, 0)) Assert.Ignore("This test is for MySql 5.7 or higher"); - ExecuteSQL("DROP TABLE IF EXISTS Test"); - ExecuteSQL("CREATE TABLE test (Id int NOT NULL PRIMARY KEY, jsoncolumn JSON)"); - ExecuteSQL("INSERT INTO test VALUES (1, '[1]')"); - ExecuteSQL(@"INSERT INTO test VALUES (2, '[""a"", {""b"": [true, false]}, [10, 20]]')"); - ExecuteSQL(@"INSERT INTO test VALUES (3, '{""id"":1,""name"":""test""}')"); - var r = ExecuteSQL(@"SELECT JSON_EXTRACT('{""id"": 1, ""name"": ""test""}','$.name')").FetchOne(); - Assert.AreEqual("\"test\"", r[0]); - } - - [Test, Description("Test MySQLX plugin big int as PK")] - public void BigIntasPK() - { - if (!Platform.IsWindows()) Assert.Ignore("This test is for Windows OS only"); - if (!session.Version.isAtLeast(5, 7, 0)) Assert.Ignore("This test is for MySql 5.7 or higher"); - - ExecuteSQL("DROP TABLE IF EXISTS Test"); - ExecuteSQL("CREATE TABLE test (Id bigint NOT NULL PRIMARY KEY, jsoncolumn JSON)"); - var res = ExecuteSQL("INSERT INTO test VALUES (934157136952, '[1]')"); - Assert.AreEqual(1, res.AffectedItemsCount); - res = ExecuteSQL(@"INSERT INTO test VALUES (9223372036854775807, '[""a"", {""b"": [true, false]}, [10, 20]]')"); - Assert.AreEqual(1, res.AffectedItemsCount); - Assert.Throws(() => ExecuteSQL("INSERT INTO test VALUES ('str1', '[1]')")); - } - - [Test, Description("Test MySQLX plugin tiny int as PK")] - public void TinyIntasPK() - { - if (!Platform.IsWindows()) Assert.Ignore("This test is for Windows OS only"); - if (!session.Version.isAtLeast(5, 7, 0)) Assert.Ignore("This test is for MySql 5.7 or higher"); - - using (var ss = MySQLX.GetSession(ConnectionString)) - { - ss.SQL("DROP TABLE IF EXISTS test.test").Execute(); - ss.SQL("CREATE TABLE test.test (Id tinyint NOT NULL PRIMARY KEY, jsoncolumn JSON)").Execute(); - var res = ss.SQL("INSERT INTO test.test VALUES (1, '[1]')").Execute(); - Assert.AreEqual(1, res.AffectedItemsCount); - res = ss.SQL(@"INSERT INTO test.test VALUES (2, '[""a"", {""b"": [true, false]}, [10, 20]]')").Execute(); - Assert.AreEqual(1, res.AffectedItemsCount); - Assert.Throws(() => ss.SQL("INSERT INTO test.test VALUES ('str1', '[1]')").Execute()); - } - } - - [Test, Description("Test MySQLX plugin small int as PK")] - public void SmallIntasPK() - { - if (!Platform.IsWindows()) Assert.Ignore("This test is for Windows OS only"); - if (!session.Version.isAtLeast(5, 7, 0)) Assert.Ignore("This test is for MySql 5.7 or higher"); - - using (var ss = MySQLX.GetSession(ConnectionString)) - { - ss.SQL("DROP TABLE IF EXISTS test.test").Execute(); - ss.SQL("CREATE TABLE test.test (Id smallint NOT NULL PRIMARY KEY, jsoncolumn JSON)").Execute(); - var res = ss.SQL("INSERT INTO test.test VALUES (99, '[1]')").Execute(); - Assert.AreEqual(1, res.AffectedItemsCount); - res = ss.SQL(@"INSERT INTO test.test VALUES (1, '[""a"", {""b"": [true, false]}, [10, 20]]')").Execute(); - Assert.AreEqual(1, res.AffectedItemsCount); - Assert.Throws(() => ss.SQL("INSERT INTO test.test VALUES ('str1', '[1]')").Execute()); - ss.SQL("DROP TABLE IF EXISTS test.test"); - } - } - - [Test, Description("MySQL sample data insertion and viewing")] - public void DataValidation() - { - ExecuteSQL("DROP TABLE IF EXISTS TEST"); - ExecuteSQL("CREATE TABLE TEST(name VARCHAR(20),id INT NOT NULL,sports VARCHAR(20))"); - ExecuteSQL("INSERT INTO TEST(name,id,sports) VALUES ('Federer',1,'Tennis')"); - ExecuteSQL("INSERT INTO TEST(name,id,sports) VALUES ('Ronaldo',2,'Soccer')"); - ExecuteSQL("INSERT INTO TEST(name,id,sports) VALUES ('Messi',3,'Soccer')"); - var expecteddataValue = new List { "Federer", "Ronaldo", "Messi" }; - using (SqlResult result = ExecuteSQLStatement(session.SQL("SELECT name FROM TEST;"))) - { - while (result.Next()) - { - Assert.That(result.Rows, Has.Exactly(3).Items); - Assert.True(expecteddataValue.Contains(result[0].ToString())); - } - } - } - #endregion - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using Google.Protobuf; +using MySql.Data.Common; +using MySql.Data.MySqlClient; +using MySqlX.XDevAPI; +using MySqlX.XDevAPI.Relational; +using NUnit.Framework; +using NUnit.Framework.Legacy; +using System.Collections.Generic; + +namespace MySqlX.Data.Tests.RelationalTests +{ + public class SqlTests : BaseTest + { + [TearDown] + public void TearDown() + { + ExecuteSQL("DROP TABLE IF EXISTS test"); + } + + [Test] + public void ReturnSimpleScalar() + { + ExecuteSQL("DROP TABLE IF EXISTS test.test"); + ExecuteSQL("CREATE TABLE test.test(id INT)"); + ExecuteSQL("INSERT INTO test.test VALUES (1)"); + using (var ss = MySQLX.GetSession(ConnectionString)) + { + SqlResult r = ss.SQL("SELECT * FROM test.test").Execute(); + Assert.That(r.Next()); + Assert.That(r[0], Is.EqualTo(1)); + Assert.That(r.NextResult(), Is.False); + } + + } + + [Test] + public void ExecuteStoredProcedure() + { + ExecuteSQL("CREATE PROCEDURE `my_proc` () BEGIN SELECT 5; END"); + + Session session = GetSession(true); + var result = ExecuteSQLStatement(session.SQL("CALL my_proc()")); + Assert.That(result.HasData); + var row = result.FetchOne(); + Assert.That(row, Is.Not.Null); + Assert.That(row[0], Is.EqualTo((sbyte)5)); + Assert.That(result.Next(), Is.False); + Assert.That(result.FetchOne(), Is.Null); + Assert.That(result.NextResult(), Is.False); + } + + [Test] + public void ExecuteStoredProcedureMultipleResults() + { + ExecuteSQL("drop procedure if exists my_proc"); + ExecuteSQL("CREATE PROCEDURE `my_proc` () BEGIN SELECT 5; SELECT 'A'; SELECT 5 * 2; END"); + + Session session = GetSession(true); + var result = ExecuteSQLStatement(session.SQL("CALL my_proc()")); + Assert.That(result.HasData); + var row = result.FetchOne(); + Assert.That(row, Is.Not.Null); + Assert.That(row[0], Is.EqualTo((sbyte)5)); + Assert.That(result.Next(), Is.False); + Assert.That(result.FetchOne(), Is.Null); + + Assert.That(result.NextResult()); + row = result.FetchOne(); + Assert.That(row, Is.Not.Null); + Assert.That(row[0], Is.EqualTo("A")); + Assert.That(result.Next(), Is.False); + Assert.That(result.FetchOne(), Is.Null); + + Assert.That(result.NextResult()); + row = result.FetchOne(); + Assert.That(row, Is.Not.Null); + Assert.That(row[0], Is.EqualTo((sbyte)10)); + Assert.That(result.Next(), Is.False); + Assert.That(result.FetchOne(), Is.Null); + + Assert.That(result.NextResult(), Is.False); + } + + [Test] + public void Bind() + { + ExecuteSQL("drop table if exists test.test"); + ExecuteSQL("CREATE TABLE test.test(id INT, letter varchar(1))"); + for (int i = 1; i <= 10; i++) + ExecuteSQLStatement(GetSession(true).SQL("INSERT INTO test.test VALUES (?, ?), (?, ?)") + .Bind(i, ((char)('@' + i)).ToString()) + .Bind(++i, ((char)('@' + i)).ToString())); + + SqlResult result = ExecuteSQLStatement(GetSession(true).SQL("select * from test.test where id=?").Bind(5)); + Assert.That(result.Next()); + Assert.That(result.Rows, Has.One.Items); + Assert.That(result[0], Is.EqualTo(5)); + Assert.That(result[1], Is.EqualTo("E")); + } + + [Test] + public void BindNull() + { + ExecuteSQL("drop table if exists test.test"); + ExecuteSQL("CREATE TABLE test.test(id INT, letter varchar(1))"); + + var session = GetSession(true); + var result = ExecuteSQLStatement(session.SQL("INSERT INTO test.test VALUES(1, ?), (2, 'B');").Bind(null)); + Assert.That(result.AffectedItemsCount, Is.EqualTo(2ul)); + + var sqlResult = ExecuteSQLStatement(session.SQL("SELECT * FROM test.test WHERE letter is ?").Bind(null)).FetchAll(); + Assert.That(sqlResult, Has.One.Items); + Assert.That(sqlResult[0][0], Is.EqualTo(1)); + Assert.That(sqlResult[0][1], Is.Null); + } + + [Test] + public void Alias() + { + var session = GetSession(true); + var stmt = ExecuteSQLStatement(session.SQL("SELECT 1 AS UNO")); + var result = stmt.FetchAll(); + Assert.That(stmt.Columns[0].ColumnLabel, Is.EqualTo("UNO")); + } + + #region WL14389 + + [Test, Description("call after failed procedure")] + public void ProcedureWithNoTable() + { + ExecuteSQL("create procedure newproc (in p1 int,in p2 char(20)) begin select 1; select 'XXX' from notab; end;"); + + var session = MySQLX.GetSession(ConnectionString + ";database=test;"); + + + var sqlRes = session.SQL("call newproc(?, ?)").Bind(10).Bind("X").Execute(); + var ex = Assert.Throws(() => session.SQL("drop procedure if exists newproc ").Execute()); + Assert.That(ex.Message, Is.EqualTo("Table 'test.notab' doesn't exist").IgnoreCase); + } + + [Test, Description("Stored Procedure Table Positive using Session")] + public void TablePositiveSession() + { + MySqlXConnectionStringBuilder sb = new MySqlXConnectionStringBuilder(ConnectionString); + var connectionStringObject = new { connection = "server=" + sb.Server + ";user=" + sb.UserID + ";port=" + sb.Port + ";password=" + sb.Password + ";sslmode=" + MySqlSslMode.Required + ";" }; + using (Session sessionPlain = MySQLX.GetSession(connectionStringObject.connection)) + { + sessionPlain.SQL("DROP DATABASE IF EXISTS DBName").Execute(); + sessionPlain.SQL("CREATE DATABASE DBName").Execute(); + sessionPlain.SQL("USE DBName").Execute(); + sessionPlain.SQL("CREATE TABLE address" + + "(address_number INT NOT NULL AUTO_INCREMENT, " + + "building_name VARCHAR(100) NOT NULL, " + + "district VARCHAR(100) NOT NULL, PRIMARY KEY (address_number)" + ");").Execute(); + sessionPlain.SQL("INSERT INTO address" + + "(address_number,building_name,district)" + + " VALUES " + + "(1573,'MySQL','BGL');").Execute(); + string procI = "CREATE PROCEDURE my_add_one_procedure " + + " (IN address_id INT) " + + "BEGIN " + + "select * from address as a where a.address_number = address_id;" + + "END;"; + sessionPlain.SQL(procI).Execute(); + var res = sessionPlain.SQL("CALL my_add_one_procedure(1573);").Execute(); + if (res.HasData) + { + var row = res.FetchOne(); + if (row != null) + { + do + { + if (row[0] != null) + Assert.That(row[0].ToString(), Is.Not.Null); + + if (row[1] != null) + Assert.That(row[1].ToString(), Is.Not.Null); + + if (row[2] != null) + Assert.That(row[2].ToString(), Is.Not.Null); + + } while (res.Next()); while (res.NextResult()) ; + } + } + sessionPlain.SQL("DROP DATABASE DBName").Execute(); + } + } + + [Test, Description("Stored Procedure Table-StringBuilder and Session")] + public void StoredProcTablePositiveStringBuilderSession() + { + Assume.That(Platform.IsWindows(), "This test is only for Windows OS."); + + MySqlXConnectionStringBuilder sb = new MySqlXConnectionStringBuilder(ConnectionString); + var connectionStringObject = new { connection = "server=" + sb.Server + ";user=" + sb.UserID + ";port=" + sb.Port + ";password=" + sb.Password }; + + using (MySqlConnection mysql = new MySqlConnection(ConnectionStringRoot)) + { + mysql.Open(); + System.Text.StringBuilder sql = new System.Text.StringBuilder(); + sql.AppendLine("DROP DATABASE IF EXISTS DBName"); + MySqlScript script = new MySqlScript(mysql, sql.ToString()); + script.Execute(); + sql = new System.Text.StringBuilder(); + sql.AppendLine("CREATE DATABASE DBName"); + script = new MySqlScript(mysql, sql.ToString()); + script.Execute(); + sql = new System.Text.StringBuilder(); + sql.AppendLine("USE DBName"); + script = new MySqlScript(mysql, sql.ToString()); + script.Execute(); + sql = new System.Text.StringBuilder(); + sql.AppendLine("CREATE TABLE address" + + "(address_number INT NOT NULL AUTO_INCREMENT, " + + "building_name VARCHAR(100) NOT NULL, " + + "district VARCHAR(100) NOT NULL, PRIMARY KEY (address_number)" + ");" + ); + script = new MySqlScript(mysql, sql.ToString()); + script.Execute(); + sql = new System.Text.StringBuilder(); + sql.AppendLine("INSERT INTO address" + + "(address_number,building_name,district)" + + " VALUES " + + "(1573,'MySQL','BGL');"); + script = new MySqlScript(mysql, sql.ToString()); + script.Execute(); + sql = new System.Text.StringBuilder(); + sql.AppendLine("INSERT INTO address" + + "(address_number,building_name,district)" + + " VALUES " + + "(1,'MySQLTest1','BGLTest1');"); + script = new MySqlScript(mysql, sql.ToString()); + script.Execute(); + sql = new System.Text.StringBuilder(); + sql.AppendLine("INSERT INTO address" + + "(address_number,building_name,district)" + + " VALUES " + + "(2,'MySQLTest2','BGLTest2');"); + script = new MySqlScript(mysql, sql.ToString()); + script.Execute(); + sql = new System.Text.StringBuilder(); + sql.AppendLine("DELIMITER //"); + sql.AppendLine("CREATE PROCEDURE my_add_one_procedure " + + " (IN address_id INT) " + + "BEGIN " + + "select * from address as a where a.address_number = address_id;" + + "END//"); + script = new MySqlScript(mysql, sql.ToString()); + script.Execute(); + sql = new System.Text.StringBuilder(); + sql.AppendLine("DELIMITER ;"); + script = new MySqlScript(mysql, sql.ToString()); + script.Execute(); + } + + using (Session sessionPlain = MySQLX.GetSession(connectionStringObject.connection)) + { + sessionPlain.SQL("USE DBName").Execute(); + var res = sessionPlain.SQL("CALL my_add_one_procedure(1573);").Execute(); + if (res.HasData) + { + var row = res.FetchOne(); + if (row != null) + { + do + { + if (row[0] != null) + Assert.That(row[0].ToString(), Is.Not.Null); + + if (row[1] != null) + Assert.That(row[1].ToString(), Is.Not.Null); + + if (row[2] != null) + Assert.That(row[2].ToString(), Is.Not.Null); + + } while (res.Next()); while (res.NextResult()) ; + } + } + sessionPlain.SQL("DROP PROCEDURE my_add_one_procedure;").Execute(); + sessionPlain.SQL("DROP TABLE address;").Execute(); + sessionPlain.SQL("DROP DATABASE DBName;").Execute(); + } + } + + [Test, Description("Stored Procedure Table-Negative(procedure returns null)")] + public void StoredProcReturnsNull() + { + Assume.That(Platform.IsWindows(), "This test is only for Windows OS."); + + MySqlConnection mysql = new MySqlConnection(ConnectionStringRoot); + mysql.Open(); + System.Text.StringBuilder sql = new System.Text.StringBuilder(); + sql.AppendLine("DROP DATABASE IF EXISTS DBName"); + MySqlScript script = new MySqlScript(mysql, sql.ToString()); + script.Execute(); + sql = new System.Text.StringBuilder(); + sql.AppendLine("CREATE DATABASE DBName"); + script = new MySqlScript(mysql, sql.ToString()); + script.Execute(); + sql = new System.Text.StringBuilder(); + sql.AppendLine("USE DBName"); + script = new MySqlScript(mysql, sql.ToString()); + script.Execute(); + sql = new System.Text.StringBuilder(); + sql.AppendLine("CREATE TABLE address" + + "(address_number INT NOT NULL AUTO_INCREMENT, " + + "building_name VARCHAR(100) NOT NULL, " + + "district VARCHAR(100) NOT NULL, PRIMARY KEY (address_number)" + ");" + ); + script = new MySqlScript(mysql, sql.ToString()); + script.Execute(); + sql = new System.Text.StringBuilder(); + sql.AppendLine("INSERT INTO address" + + "(address_number,building_name,district)" + + " VALUES " + + "(1573,'MySQL','BGL');"); + script = new MySqlScript(mysql, sql.ToString()); + script.Execute(); + sql = new System.Text.StringBuilder(); + sql.AppendLine("INSERT INTO address" + + "(address_number,building_name,district)" + + " VALUES " + + "(1,'MySQLTest1','BGLTest1');"); + script = new MySqlScript(mysql, sql.ToString()); + script.Execute(); + sql = new System.Text.StringBuilder(); + sql.AppendLine("INSERT INTO address" + + "(address_number,building_name,district)" + + " VALUES " + + "(2,'MySQLTest2','BGLTest2');"); + script = new MySqlScript(mysql, sql.ToString()); + script.Execute(); + sql = new System.Text.StringBuilder(); + sql.AppendLine("DELIMITER //"); + sql.AppendLine("CREATE PROCEDURE my_add_one_procedure " + + " (IN address_id INT) " + + "BEGIN " + + "select * from address as a where a.address_number = address_id;" + + "END//"); + script = new MySqlScript(mysql, sql.ToString()); + script.Execute(); + sql = new System.Text.StringBuilder(); + sql.AppendLine("DELIMITER ;"); + script = new MySqlScript(mysql, sql.ToString()); + script.Execute(); + + MySqlXConnectionStringBuilder sb = new MySqlXConnectionStringBuilder(ConnectionString); + var connectionStringObject = new { connection = "server=" + sb.Server + ";user=" + sb.UserID + ";port=" + sb.Port + ";password=" + sb.Password + ";sslmode=" + MySqlSslMode.Required + ";" }; + using (Session sessionPlain = MySQLX.GetSession(connectionStringObject.connection)) + { + sessionPlain.SQL("USE DBName").Execute(); + + var res = sessionPlain.SQL("CALL my_add_one_procedure(1000);").Execute(); + if (res.HasData) + { + var row = res.FetchOne(); + Assert.That(row, Is.Null); + } + res.Next(); + res.NextResult(); + } + } + + //SQLTests + [Test, Description("Bind Support for Session SQL Numeric Datatypes- integer,JSON,tinyint,smallint,mediumint,bigint,float,double,decimal")] + public void BindSupportSessionSQLNumericDatatypes() + { + Assume.That(session.Version.isAtLeast(5, 7, 0), "This test is for MySql 5.7 or higher"); + var connectionString = ConnectionString + ";sslmode=" + MySqlSslMode.Required; + SqlResult myResult; + Row row; + + //integer + using (Session sessionTest = MySQLX.GetSession(connectionString)) + { + sessionTest.SQL("DROP DATABASE IF EXISTS DBName ").Execute(); + sessionTest.SQL("CREATE DATABASE IF NOT EXISTS DBName").Execute(); + sessionTest.SQL("USE DBName").Execute(); + sessionTest.SQL("CREATE PROCEDURE my_add_one_procedure " + + " (INOUT incr_param INT) " + + "BEGIN " + + " SET incr_param = incr_param + 1;" + + "END;").Execute(); + //Uncomment once Bind is implemented in 7.0.2 + sessionTest.SQL("SET @my_var = ?;").Bind(10).Execute(); + sessionTest.SQL("CALL my_add_one_procedure(@my_var);").Execute(); + sessionTest.SQL("DROP PROCEDURE my_add_one_procedure;").Execute(); + // Use a SQL query to get the result + myResult = sessionTest.SQL("SELECT @my_var").Execute(); + // Gets the row and prints the first column + row = myResult.FetchOne(); + Assert.That(row[0].ToString(), Is.Not.Null); + sessionTest.SQL("DROP DATABASE DBName").Execute(); + } + + //JSON + using (var sessionTest = MySQLX.GetSession(connectionString)) + { + sessionTest.SQL("CREATE DATABASE IF NOT EXISTS DBName").Execute(); + sessionTest.SQL("USE DBName").Execute(); + sessionTest.SQL("CREATE PROCEDURE my_add_one_procedure " + + " (INOUT incr_param Json) " + + "BEGIN " + + " SET incr_param = incr_param;" + + "END;").Execute(); + //Uncomment once Bind is implemented in 7.0.2 + var jsonParams = "{ \"pages1\" : 30, \"pages2\" : 40 }"; + sessionTest.SQL("SET @my_var = ?;").Bind(jsonParams).Execute(); + sessionTest.SQL("CALL my_add_one_procedure(@my_var);").Execute(); + sessionTest.SQL("DROP PROCEDURE my_add_one_procedure;").Execute(); + // Use a SQL query to get the result + myResult = sessionTest.SQL("SELECT @my_var").Execute(); + // Gets the row and prints the first column + row = myResult.FetchOne(); + Assert.That(row[0].ToString(), Is.Not.Null); + sessionTest.SQL("DROP DATABASE DBName").Execute(); + } + + //TINYINT + using (var sessionTest = MySQLX.GetSession(connectionString)) + { + sessionTest.SQL("CREATE DATABASE IF NOT EXISTS DBName").Execute(); + sessionTest.SQL("USE DBName").Execute(); + sessionTest.SQL("CREATE PROCEDURE my_add_one_procedure " + + " (INOUT incr_param TINYINT) " + + "BEGIN " + + " SET incr_param = incr_param + 1;" + + "END;").Execute(); + //Uncomment once Bind is implemented in 7.0.2 + sessionTest.SQL("SET @my_var = ?;").Bind(1).Execute(); + sessionTest.SQL("CALL my_add_one_procedure(@my_var);").Execute(); + sessionTest.SQL("DROP PROCEDURE my_add_one_procedure;").Execute(); + // Use a SQL query to get the result + myResult = sessionTest.SQL("SELECT @my_var").Execute(); + // Gets the row and prints the first column + row = myResult.FetchOne(); + Assert.That(row[0].ToString(), Is.Not.Null); + sessionTest.SQL("DROP DATABASE DBName").Execute(); + } + + //SMALLINT + using (var sessionTest = MySQLX.GetSession(connectionString)) + { + sessionTest.SQL("CREATE DATABASE IF NOT EXISTS DBName").Execute(); + sessionTest.SQL("USE DBName").Execute(); + sessionTest.SQL("CREATE PROCEDURE my_add_one_procedure " + + " (INOUT incr_param SMALLINT) " + + "BEGIN " + + " SET incr_param = incr_param + 1;" + + "END;").Execute(); + //Uncomment once Bind is implemented in 7.0.2 + sessionTest.SQL("SET @my_var = ?;").Bind(11111).Execute(); + sessionTest.SQL("CALL my_add_one_procedure(@my_var);").Execute(); + sessionTest.SQL("DROP PROCEDURE my_add_one_procedure;").Execute(); + // Use a SQL query to get the result + myResult = sessionTest.SQL("SELECT @my_var").Execute(); + // Gets the row and prints the first column + row = myResult.FetchOne(); + Assert.That(row[0].ToString(), Is.Not.Null); + sessionTest.SQL("DROP DATABASE DBName").Execute(); + } + + //MEDIUMINT + using (var sessionTest = MySQLX.GetSession(connectionString)) + { + sessionTest.SQL("CREATE DATABASE IF NOT EXISTS DBName").Execute(); + sessionTest.SQL("USE DBName").Execute(); + sessionTest.SQL("CREATE PROCEDURE my_add_one_procedure " + + " (INOUT incr_param MEDIUMINT) " + + "BEGIN " + + " SET incr_param = incr_param + 1;" + + "END;").Execute(); + //Uncomment once Bind is implemented in 7.0.2 + sessionTest.SQL("SET @my_var = ?;").Bind(1111).Execute(); + sessionTest.SQL("CALL my_add_one_procedure(@my_var);").Execute(); + sessionTest.SQL("DROP PROCEDURE my_add_one_procedure;").Execute(); + // Use a SQL query to get the result + myResult = sessionTest.SQL("SELECT @my_var").Execute(); + // Gets the row and prints the first column + row = myResult.FetchOne(); + Assert.That(row[0].ToString(), Is.Not.Null); + sessionTest.SQL("DROP DATABASE DBName").Execute(); + } + + //FLOATMD + using (var sessionTest = MySQLX.GetSession(connectionString)) + { + sessionTest.SQL("CREATE DATABASE IF NOT EXISTS DBName").Execute(); + sessionTest.SQL("USE DBName").Execute(); + sessionTest.SQL("CREATE PROCEDURE my_add_one_procedure " + + " (INOUT incr_param FLOAT(10,2)) " + + "BEGIN " + + " SET incr_param = incr_param + 1;" + + "END;").Execute(); + //Uncomment once Bind is implemented in 7.0.2 + sessionTest.SQL("SET @my_var = ?;").Bind(100.2).Execute(); + sessionTest.SQL("CALL my_add_one_procedure(@my_var);").Execute(); + sessionTest.SQL("DROP PROCEDURE my_add_one_procedure;").Execute(); + // Use a SQL query to get the result + myResult = sessionTest.SQL("SELECT @my_var").Execute(); + // Gets the row and prints the first column + row = myResult.FetchOne(); + Assert.That(row[0].ToString(), Is.Not.Null); + sessionTest.SQL("DROP DATABASE DBName").Execute(); + } + + //DOUBLEMD + using (var sessionTest = MySQLX.GetSession(connectionString)) + { + sessionTest.SQL("CREATE DATABASE IF NOT EXISTS DBName").Execute(); + sessionTest.SQL("USE DBName").Execute(); + sessionTest.SQL("CREATE PROCEDURE my_add_one_procedure " + + " (INOUT incr_param DOUBLE(10,2)) " + + "BEGIN " + + " SET incr_param = incr_param + 1;" + + "END;").Execute(); + //Uncomment once Bind is implemented in 7.0.2 + sessionTest.SQL("SET @my_var = ?;").Bind(1000.2).Execute(); + sessionTest.SQL("CALL my_add_one_procedure(@my_var);").Execute(); + sessionTest.SQL("DROP PROCEDURE my_add_one_procedure;").Execute(); + // Use a SQL query to get the result + myResult = sessionTest.SQL("SELECT @my_var").Execute(); + // Gets the row and prints the first column + row = myResult.FetchOne(); + Assert.That(row[0].ToString(), Is.Not.Null); + sessionTest.SQL("DROP DATABASE DBName").Execute(); + } + + //DECIMALMD + using (var sessionTest = MySQLX.GetSession(connectionString)) + { + sessionTest.SQL("CREATE DATABASE IF NOT EXISTS DBName").Execute(); + sessionTest.SQL("USE DBName").Execute(); + sessionTest.SQL("CREATE PROCEDURE my_add_one_procedure " + + " (INOUT incr_param DECIMAL(10,2)) " + + "BEGIN " + + " SET incr_param = incr_param + 1;" + + "END;").Execute(); + //Uncomment once Bind is implemented in 7.0.2 + sessionTest.SQL("SET @my_var = ?;").Bind(10000.2).Execute(); + sessionTest.SQL("CALL my_add_one_procedure(@my_var);").Execute(); + sessionTest.SQL("DROP PROCEDURE my_add_one_procedure;").Execute(); + // Use a SQL query to get the result + myResult = sessionTest.SQL("SELECT @my_var").Execute(); + // Gets the row and prints the first column + row = myResult.FetchOne(); + Assert.That(row[0].ToString(), Is.Not.Null); + sessionTest.SQL("DROP DATABASE DBName").Execute(); + } + } + + + [Test, Description("Bind Support for Session SQL DateTime Types- date,datetime,timestamp,time,year(M)")] + public void BindSupportSessionSQLDateTimetypes() + { + Assume.That(session.Version.isAtLeast(5, 7, 0), "This test is for MySql 5.7 or higher"); + //DATE + string connectionString = ConnectionString + ";sslmode=" + MySqlSslMode.Required; + SqlResult myResult; + Row row; + + using (Session sessionTest = MySQLX.GetSession(connectionString)) + { + sessionTest.SQL("DROP DATABASE IF EXISTS DBName ").Execute(); + sessionTest.SQL("CREATE DATABASE IF NOT EXISTS DBName").Execute(); + sessionTest.SQL("USE DBName").Execute(); + sessionTest.SQL("CREATE PROCEDURE my_add_one_procedure " + + " (INOUT incr_param DATE) " + + "BEGIN " + + " SET incr_param = incr_param ;" + + "END;").Execute(); + //Uncomment once Bind is implemented in 7.0.2 + sessionTest.SQL("SET @my_var = ?;").Bind("1973-12-30").Execute(); + sessionTest.SQL("CALL my_add_one_procedure(@my_var);").Execute(); + sessionTest.SQL("DROP PROCEDURE my_add_one_procedure;").Execute(); + // Use a SQL query to get the result + myResult = sessionTest.SQL("SELECT @my_var").Execute(); + // Gets the row and prints the first column + row = myResult.FetchOne(); + Assert.That(row[0].ToString(), Is.Not.Null); + sessionTest.SQL("DROP DATABASE DBName").Execute(); + } + + //DATETIME + using (Session sessionTest = MySQLX.GetSession(connectionString)) + { + sessionTest.SQL("CREATE DATABASE IF NOT EXISTS DBName").Execute(); + sessionTest.SQL("USE DBName").Execute(); + sessionTest.SQL("CREATE PROCEDURE my_add_one_procedure " + + " (INOUT incr_param DATETIME) " + + "BEGIN " + + " SET incr_param = incr_param ;" + + "END;").Execute(); + //Uncomment once Bind is implemented in 7.0.2 + sessionTest.SQL("SET @my_var = ?;").Bind("1981-04-10 15:30:00").Execute(); + sessionTest.SQL("CALL my_add_one_procedure(@my_var);").Execute(); + sessionTest.SQL("DROP PROCEDURE my_add_one_procedure;").Execute(); + // Use a SQL query to get the result + myResult = sessionTest.SQL("SELECT @my_var").Execute(); + // Gets the row and prints the first column + row = myResult.FetchOne(); + Assert.That(row[0].ToString(), Is.Not.Null); + sessionTest.SQL("DROP DATABASE DBName").Execute(); + } + + //TIMESTAMP + using (Session sessionTest = MySQLX.GetSession(connectionString)) + { + sessionTest.SQL("CREATE DATABASE IF NOT EXISTS DBName").Execute(); + sessionTest.SQL("USE DBName").Execute(); + sessionTest.SQL("CREATE PROCEDURE my_add_one_procedure " + + " (INOUT incr_param TIMESTAMP) " + + "BEGIN " + + " SET incr_param = incr_param ;" + + "END;").Execute(); + //Uncomment once Bind is implemented in 7.0.2 + sessionTest.SQL("SET @my_var = ?;").Bind("20160316153000").Execute(); + sessionTest.SQL("CALL my_add_one_procedure(@my_var);").Execute(); + sessionTest.SQL("DROP PROCEDURE my_add_one_procedure;").Execute(); + // Use a SQL query to get the result + myResult = sessionTest.SQL("SELECT @my_var").Execute(); + // Gets the row and prints the first column + row = myResult.FetchOne(); + Assert.That(row[0].ToString(), Is.Not.Null); + sessionTest.SQL("DROP DATABASE DBName").Execute(); + } + + //TIME + using (Session sessionTest = MySQLX.GetSession(connectionString)) + { + sessionTest.SQL("CREATE DATABASE IF NOT EXISTS DBName").Execute(); + sessionTest.SQL("USE DBName").Execute(); + sessionTest.SQL("CREATE PROCEDURE my_add_one_procedure " + + " (INOUT incr_param TIME) " + + "BEGIN " + + " SET incr_param = incr_param ;" + + "END;").Execute(); + //Uncomment once Bind is implemented in 7.0.2 + sessionTest.SQL("SET @my_var = ?;").Bind("12:00:00").Execute(); + sessionTest.SQL("CALL my_add_one_procedure(@my_var);").Execute(); + sessionTest.SQL("DROP PROCEDURE my_add_one_procedure;").Execute(); + // Use a SQL query to get the result + myResult = sessionTest.SQL("SELECT @my_var").Execute(); + // Gets the row and prints the first column + row = myResult.FetchOne(); + Assert.That(row[0].ToString(), Is.Not.Null); + sessionTest.SQL("DROP DATABASE DBName").Execute(); + } + + //YEAR + using (Session sessionTest = MySQLX.GetSession(connectionString)) + { + sessionTest.SQL("CREATE DATABASE IF NOT EXISTS DBName").Execute(); + sessionTest.SQL("USE DBName").Execute(); + sessionTest.SQL("CREATE PROCEDURE my_add_one_procedure " + + " (INOUT incr_param YEAR(4)) " + + "BEGIN " + + " SET incr_param = incr_param ;" + + "END;").Execute(); + //Uncomment once Bind is implemented in 7.0.2 + sessionTest.SQL("SET @my_var = ?;").Bind("2111").Execute(); + sessionTest.SQL("CALL my_add_one_procedure(@my_var);").Execute(); + sessionTest.SQL("DROP PROCEDURE my_add_one_procedure;").Execute(); + // Use a SQL query to get the result + myResult = sessionTest.SQL("SELECT @my_var").Execute(); + // Gets the row and prints the first column + row = myResult.FetchOne(); + Assert.That(row[0].ToString(), Is.Not.Null); + sessionTest.SQL("DROP DATABASE DBName").Execute(); + } + } + + + [Test, Description("Bind Support for Session SQL String Types- CHAR(M),VARCHAR(M),BLOB,TINYBLOB,MEDIUMBLOB,LONGBLOB,ENUM")] + public void BindSupportSessionSQLStringtypes() + { + Assume.That(session.Version.isAtLeast(5, 7, 0), "This test is for MySql 5.7 or higher"); + //CHAR(20) + string connectionString = ConnectionString + ";sslmode=" + MySqlSslMode.Required; + SqlResult myResult; + Row row; + + using (Session sessionTest = MySQLX.GetSession(connectionString)) + { + sessionTest.SQL("DROP DATABASE IF EXISTS DBName ").Execute(); + sessionTest.SQL("CREATE DATABASE IF NOT EXISTS DBName").Execute(); + sessionTest.SQL("USE DBName").Execute(); + sessionTest.SQL("CREATE PROCEDURE my_add_one_procedure " + + " (INOUT incr_param CHAR(20)) " + + "BEGIN " + + " SET incr_param = incr_param;" + + "END;").Execute(); + //Uncomment once Bind is implemented in 7.0.2 + sessionTest.SQL("SET @my_var = ?;").Bind("ABCDEFGHIJABCDEFGHIJ").Execute(); + sessionTest.SQL("CALL my_add_one_procedure(@my_var);").Execute(); + sessionTest.SQL("DROP PROCEDURE my_add_one_procedure;").Execute(); + // Use a SQL query to get the result + myResult = sessionTest.SQL("SELECT @my_var").Execute(); + // Gets the row and prints the first column + row = myResult.FetchOne(); + Assert.That(row[0].ToString(), Is.Not.Null); + sessionTest.SQL("DROP DATABASE DBName").Execute(); + } + + //VARCHAR(20) + using (Session sessionTest = MySQLX.GetSession(connectionString)) + { + sessionTest.SQL("CREATE DATABASE IF NOT EXISTS DBName").Execute(); + sessionTest.SQL("USE DBName").Execute(); + sessionTest.SQL("CREATE PROCEDURE my_add_one_procedure " + + " (INOUT incr_param VARCHAR(20)) " + + "BEGIN " + + " SET incr_param = incr_param;" + + "END;").Execute(); + //Uncomment once Bind is implemented in 7.0.2 + sessionTest.SQL("SET @my_var = ?;").Bind("ABCDEFGHIJABCDEFGHIJ").Execute(); + sessionTest.SQL("CALL my_add_one_procedure(@my_var);").Execute(); + sessionTest.SQL("DROP PROCEDURE my_add_one_procedure;").Execute(); + // Use a SQL query to get the result + myResult = sessionTest.SQL("SELECT @my_var").Execute(); + // Gets the row and prints the first column + row = myResult.FetchOne(); + Assert.That(row[0].ToString(), Is.Not.Null); + sessionTest.SQL("DROP DATABASE DBName").Execute(); + } + + //BLOB + using (Session sessionTest = MySQLX.GetSession(connectionString)) + { + sessionTest.SQL("CREATE DATABASE IF NOT EXISTS DBName").Execute(); + sessionTest.SQL("USE DBName").Execute(); + sessionTest.SQL("CREATE PROCEDURE my_add_one_procedure " + + " (INOUT incr_param BLOB) " + + "BEGIN " + + " SET incr_param = incr_param ;" + + "END;").Execute(); + //Uncomment once Bind is implemented in 7.0.2 + sessionTest.SQL("SET @my_var = ?;").Bind(19731230153000).Execute(); + sessionTest.SQL("CALL my_add_one_procedure(@my_var);").Execute(); + sessionTest.SQL("DROP PROCEDURE my_add_one_procedure;").Execute(); + // Use a SQL query to get the result + myResult = sessionTest.SQL("SELECT @my_var").Execute(); + // Gets the row and prints the first column + row = myResult.FetchOne(); + Assert.That(row[0].ToString(), Is.Not.Null); + sessionTest.SQL("DROP DATABASE DBName").Execute(); + } + + //TINYBLOB + using (Session sessionTest = MySQLX.GetSession(connectionString)) + { + sessionTest.SQL("CREATE DATABASE IF NOT EXISTS DBName").Execute(); + sessionTest.SQL("USE DBName").Execute(); + sessionTest.SQL("CREATE PROCEDURE my_add_one_procedure " + + " (INOUT incr_param TINYBLOB) " + + "BEGIN " + + " SET incr_param = incr_param ;" + + "END;").Execute(); + //Uncomment once Bind is implemented in 7.0.2 + sessionTest.SQL("SET @my_var = ?;").Bind("12:00:00").Execute(); + sessionTest.SQL("CALL my_add_one_procedure(@my_var);").Execute(); + sessionTest.SQL("DROP PROCEDURE my_add_one_procedure;").Execute(); + // Use a SQL query to get the result + myResult = sessionTest.SQL("SELECT @my_var").Execute(); + // Gets the row and prints the first column + row = myResult.FetchOne(); + Assert.That(row[0].ToString(), Is.Not.Null); + sessionTest.SQL("DROP DATABASE DBName").Execute(); + } + + //MEDIUMBLOB + using (Session sessionTest = MySQLX.GetSession(connectionString)) + { + sessionTest.SQL("CREATE DATABASE IF NOT EXISTS DBName").Execute(); + sessionTest.SQL("USE DBName").Execute(); + sessionTest.SQL("CREATE PROCEDURE my_add_one_procedure " + + " (INOUT incr_param MEDIUMBLOB) " + + "BEGIN " + + " SET incr_param = incr_param ;" + + "END;").Execute(); + //Uncomment once Bind is implemented in 7.0.2 + sessionTest.SQL("SET @my_var = ?;").Bind(2111).Execute(); + sessionTest.SQL("CALL my_add_one_procedure(@my_var);").Execute(); + sessionTest.SQL("DROP PROCEDURE my_add_one_procedure;").Execute(); + // Use a SQL query to get the result + myResult = sessionTest.SQL("SELECT @my_var").Execute(); + // Gets the row and prints the first column + row = myResult.FetchOne(); + Assert.That(row[0].ToString(), Is.Not.Null); + sessionTest.SQL("DROP DATABASE DBName").Execute(); + } + + //LONGBLOB + using (Session sessionTest = MySQLX.GetSession(connectionString)) + { + sessionTest.SQL("CREATE DATABASE IF NOT EXISTS DBName").Execute(); + sessionTest.SQL("USE DBName").Execute(); + sessionTest.SQL("CREATE PROCEDURE my_add_one_procedure " + + " (INOUT incr_param LONGBLOB) " + + "BEGIN " + + " SET incr_param = incr_param ;" + + "END;").Execute(); + //Uncomment once Bind is implemented in 7.0.2 + sessionTest.SQL("SET @my_var = ?;").Bind(111232).Execute(); + sessionTest.SQL("CALL my_add_one_procedure(@my_var);").Execute(); + sessionTest.SQL("DROP PROCEDURE my_add_one_procedure;").Execute(); + // Use a SQL query to get the result + myResult = sessionTest.SQL("SELECT @my_var").Execute(); + // Gets the row and prints the first column + row = myResult.FetchOne(); + Assert.That(row[0].ToString(), Is.Not.Null); + sessionTest.SQL("DROP DATABASE DBName").Execute(); + } + + //ENUM + using (Session sessionTest = MySQLX.GetSession(connectionString)) + { + sessionTest.SQL("CREATE DATABASE IF NOT EXISTS DBName").Execute(); + sessionTest.SQL("USE DBName").Execute(); + sessionTest.SQL("CREATE PROCEDURE my_add_one_procedure " + + " (INOUT incr_param ENUM('x-small', 'small', 'medium', 'large', 'x-large')) " + + "BEGIN " + + " SET incr_param = incr_param ;" + + "END;").Execute(); + //Uncomment once Bind is implemented in 7.0.2 + sessionTest.SQL("SET @my_var = ?;").Bind("large").Execute(); + sessionTest.SQL("CALL my_add_one_procedure(@my_var);").Execute(); + sessionTest.SQL("DROP PROCEDURE my_add_one_procedure;").Execute(); + // Use a SQL query to get the result + myResult = sessionTest.SQL("SELECT @my_var").Execute(); + // Gets the row and prints the first column + row = myResult.FetchOne(); + Assert.That(row[0].ToString(), Is.Not.Null); + sessionTest.SQL("DROP DATABASE DBName").Execute(); + } + } + + [Test, Description("Bind Support for Session SQL Negative Tests-Null")] + public void BindSupportSessionSQLNegativeTest1() + { + Assume.That(session.Version.isAtLeast(5, 7, 0), "This test is for MySql 5.7 or higher"); + SqlResult myResult = null; + + //integer + string connectionString = ConnectionString + ";sslmode=" + MySqlSslMode.Required; + Session sessionTest = MySQLX.GetSession(connectionString); + sessionTest.SQL("DROP DATABASE IF EXISTS DBName ").Execute(); + sessionTest.SQL("CREATE DATABASE IF NOT EXISTS DBName").Execute(); + sessionTest.SQL("USE DBName").Execute(); + sessionTest.SQL("CREATE PROCEDURE my_add_one_procedure " + + " (INOUT incr_param INT) " + + "BEGIN " + + " SET incr_param = incr_param+1;" + + "END;").Execute(); + + sessionTest.SQL("SET @my_var = ?;").Bind(null).Execute(); + sessionTest.SQL("CALL my_add_one_procedure(@my_var);").Execute(); + sessionTest.SQL("DROP PROCEDURE my_add_one_procedure;").Execute(); + // Use a SQL query to get the result + myResult = sessionTest.SQL("SELECT @my_var").Execute(); + + Assert.Throws(() => myResult.FetchOne()); + sessionTest.SQL("DROP DATABASE DBName").Execute(); + sessionTest.Close(); + sessionTest.Dispose(); + } + + [Test, Description("Bind Support for Session SQL Negative Tests-Bind Chaining Tests")] + public void BindSupportSessionSQLNegativeTest2() + { + Assume.That(session.Version.isAtLeast(5, 7, 0), "This test is for MySql 5.7 or higher"); + + //integer + string connectionString = ConnectionString + ";sslmode=" + MySqlSslMode.Required; + Session sessionTest = MySQLX.GetSession(connectionString); + sessionTest.SQL("DROP DATABASE IF EXISTS DBName ").Execute(); + sessionTest.SQL("CREATE DATABASE IF NOT EXISTS DBName").Execute(); + sessionTest.SQL("USE DBName").Execute(); + sessionTest.SQL("CREATE PROCEDURE my_add_one_procedure " + + " (INOUT incr_param INT) " + + "BEGIN " + + " SET incr_param = incr_param + 1;" + + "END;").Execute(); + sessionTest.SQL("CREATE TABLE DBName.test(id INT, letter varchar(1))").Execute(); + + for (int i = 1; i <= 100; i++) + + session.SQL("INSERT INTO DBName.test VALUES (?, ?), (?, ?)") + .Bind(1, "a") + .Bind(2, "b") + .Execute(); + + SqlResult result = session.SQL("select * from DBName.test where id=?").Bind(5).Execute(); + + //Uncomment once Bind is implemented in 7.0.2 + Assert.Throws(() => session.SQL("SET @my_var = ?;").Bind(1).Bind(2).Execute()); + sessionTest.SQL("DROP DATABASE DBName").Execute(); + sessionTest.Close(); + sessionTest.Dispose(); + + } + + // Aditional Tests + [Test, Description("Test MySQLX plugin MySQL mixed scenario")] + public void MixedChainedCommands() + { + Assume.That(session.Version.isAtLeast(5, 7, 0), "This test is for MySql 5.7 or higher"); + ExecuteSQL("Drop table if exists test"); + ExecuteSQL("CREATE TABLE test(c1 float(14,8),c2 double GENERATED ALWAYS AS (c1*101/102) Stored COMMENT 'First Gen Col')"); + ExecuteSQL("INSERT INTO test(c1) VALUES (22.7)"); + ExecuteSQL("INSERT INTO test(c1) VALUES (-100000.38984)"); + ExecuteSQL("INSERT INTO test(c1) VALUES (0)"); + + RowResult r = session.GetSchema("test").GetTable("test").Select("c1").Execute(); + var rows = r.FetchAll(); + Assert.That(r.Columns.Count, Is.EqualTo(1), "Matching"); + Assert.That(r.Columns[0].ClrType.ToString(), Is.EqualTo(typeof(float).ToString()), "Matching"); + Assert.That(r.Columns[0].Type.ToString(), Is.EqualTo(MySqlDbType.Float.ToString()), "Matching"); + Assert.That((int)r.Columns[0].Length, Is.EqualTo(14), "Matching"); + Assert.That((int)r.Columns[0].FractionalDigits, Is.EqualTo(8), "Matching"); + Assert.That(rows.Count, Is.EqualTo(3), "Matching"); + Assert.That((float)rows[0][0], Is.EqualTo(22.7f), "Matching"); + Assert.That((float)rows[1][0], Is.EqualTo(-100000.38984f), "Matching"); + Assert.That((float)rows[2][0], Is.EqualTo(0f), "Matching"); + } + + [Test, Description("Test MySQLX plugin MySQL Date Time Bug")] + public void DateTimeCheck() + { + Assume.That(session.Version.isAtLeast(5, 7, 0), "This test is for MySql 5.7 or higher"); + ExecuteSQL("CREATE TABLE test.test1212(dt DATETIME(6))"); + ExecuteSQL("INSERT INTO test.test1212 VALUES('2015-10-21 18:01:00.12345678')"); + + RowResult r = session.GetSchema("test").GetTable("test1212").Select("dt").Execute(); + var rows = r.FetchAll(); + Assert.That(r.Columns.Count, Is.EqualTo(1), "Matching Coulumn Count"); + + } + + [Test, Description("Test MySQLX plugin MySQL Datetime JSON")] + public void DateTimeJSON() + { + Assume.That(session.Version.isAtLeast(5, 7, 0), "This test is for MySql 5.7 or higher"); + ExecuteSQL("DROP TABLE IF EXISTS test.test"); + ExecuteSQL("CREATE TABLE test.test(Id int NOT NULL PRIMARY KEY, jsoncolumn JSON)"); + ExecuteSQL(@"INSERT INTO test.test VALUES(100000,' { ""name"" : ""bob"",""Date"": ""2015-10-09"",""Time"": ""12:18:29.000000"",""DateTimeOfRegistration"": ""2015-10-09 12:18:29.000000"",""age"":12} ')"); + RowResult r = session.GetSchema("test").GetTable("test").Select("jsoncolumn").Execute(); + var rows = r.FetchAll(); + Assert.That(r.Columns.Count, Is.EqualTo(1), "Matching"); + } + + [Test, Description("Test MySQLX plugin JSON Variant")] + public void JSONVariant() + { + Assume.That(Platform.IsWindows(), "This test is only for Windows OS."); + Assume.That(session.Version.isAtLeast(5, 7, 0), "This test is for MySql 5.7 or higher"); + ExecuteSQL("DROP TABLE IF EXISTS Test"); + ExecuteSQL("CREATE TABLE test (Id int NOT NULL PRIMARY KEY, jsoncolumn JSON)"); + ExecuteSQL("INSERT INTO test VALUES (1, '[1]')"); + ExecuteSQL(@"INSERT INTO test VALUES (2, '[""a"", {""b"": [true, false]}, [10, 20]]')"); + ExecuteSQL(@"INSERT INTO test VALUES (3, '{""id"":1,""name"":""test""}')"); + var r = ExecuteSQL(@"SELECT JSON_EXTRACT('{""id"": 1, ""name"": ""test""}','$.name')").FetchOne(); + Assert.That(r[0], Is.EqualTo("\"test\"")); + } + + [Test, Description("Test MySQLX plugin big int as PK")] + public void BigIntasPK() + { + Assume.That(Platform.IsWindows(), "This test is only for Windows OS."); + Assume.That(session.Version.isAtLeast(5, 7, 0), "This test is for MySql 5.7 or higher"); + + ExecuteSQL("DROP TABLE IF EXISTS Test"); + ExecuteSQL("CREATE TABLE test (Id bigint NOT NULL PRIMARY KEY, jsoncolumn JSON)"); + var res = ExecuteSQL("INSERT INTO test VALUES (934157136952, '[1]')"); + Assert.That(res.AffectedItemsCount, Is.EqualTo(1)); + res = ExecuteSQL(@"INSERT INTO test VALUES (9223372036854775807, '[""a"", {""b"": [true, false]}, [10, 20]]')"); + Assert.That(res.AffectedItemsCount, Is.EqualTo(1)); + Assert.Throws(() => ExecuteSQL("INSERT INTO test VALUES ('str1', '[1]')")); + } + + [Test, Description("Test MySQLX plugin tiny int as PK")] + public void TinyIntasPK() + { + Assume.That(Platform.IsWindows(), "This test is only for Windows OS."); + Assume.That(session.Version.isAtLeast(5, 7, 0), "This test is for MySql 5.7 or higher"); + + using (var ss = MySQLX.GetSession(ConnectionString)) + { + ss.SQL("DROP TABLE IF EXISTS test.test").Execute(); + ss.SQL("CREATE TABLE test.test (Id tinyint NOT NULL PRIMARY KEY, jsoncolumn JSON)").Execute(); + var res = ss.SQL("INSERT INTO test.test VALUES (1, '[1]')").Execute(); + Assert.That(res.AffectedItemsCount, Is.EqualTo(1)); + res = ss.SQL(@"INSERT INTO test.test VALUES (2, '[""a"", {""b"": [true, false]}, [10, 20]]')").Execute(); + Assert.That(res.AffectedItemsCount, Is.EqualTo(1)); + Assert.Throws(() => ss.SQL("INSERT INTO test.test VALUES ('str1', '[1]')").Execute()); + } + } + + [Test, Description("Test MySQLX plugin small int as PK")] + public void SmallIntasPK() + { + Assume.That(Platform.IsWindows(), "This test is only for Windows OS."); + Assume.That(session.Version.isAtLeast(5, 7, 0), "This test is for MySql 5.7 or higher"); + + using (var ss = MySQLX.GetSession(ConnectionString)) + { + ss.SQL("DROP TABLE IF EXISTS test.test").Execute(); + ss.SQL("CREATE TABLE test.test (Id smallint NOT NULL PRIMARY KEY, jsoncolumn JSON)").Execute(); + var res = ss.SQL("INSERT INTO test.test VALUES (99, '[1]')").Execute(); + Assert.That(res.AffectedItemsCount, Is.EqualTo(1)); + res = ss.SQL(@"INSERT INTO test.test VALUES (1, '[""a"", {""b"": [true, false]}, [10, 20]]')").Execute(); + Assert.That(res.AffectedItemsCount, Is.EqualTo(1)); + Assert.Throws(() => ss.SQL("INSERT INTO test.test VALUES ('str1', '[1]')").Execute()); + ss.SQL("DROP TABLE IF EXISTS test.test"); + } + } + + [Test, Description("MySQL sample data insertion and viewing")] + public void DataValidation() + { + ExecuteSQL("DROP TABLE IF EXISTS TEST"); + ExecuteSQL("CREATE TABLE TEST(name VARCHAR(20),id INT NOT NULL,sports VARCHAR(20))"); + ExecuteSQL("INSERT INTO TEST(name,id,sports) VALUES ('Federer',1,'Tennis')"); + ExecuteSQL("INSERT INTO TEST(name,id,sports) VALUES ('Ronaldo',2,'Soccer')"); + ExecuteSQL("INSERT INTO TEST(name,id,sports) VALUES ('Messi',3,'Soccer')"); + var expecteddataValue = new List { "Federer", "Ronaldo", "Messi" }; + using (SqlResult result = ExecuteSQLStatement(session.SQL("SELECT name FROM TEST;"))) + { + while (result.Next()) + { + Assert.That(result.Rows, Has.Exactly(3).Items); + Assert.That(expecteddataValue.Contains(result[0].ToString())); + } + } + } + #endregion + } +} diff --git a/MySQL.Data/tests/MySqlX.Data.Tests/RelationalTests/TableAsyncTests.cs b/MySQL.Data/tests/MySqlX.Data.Tests/RelationalTests/TableAsyncTests.cs index 9fc3ed575..cc1b90324 100644 --- a/MySQL.Data/tests/MySqlX.Data.Tests/RelationalTests/TableAsyncTests.cs +++ b/MySQL.Data/tests/MySqlX.Data.Tests/RelationalTests/TableAsyncTests.cs @@ -1,164 +1,165 @@ -// Copyright (c) 2015, 2021, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data.MySqlClient; -using MySqlX.XDevAPI; -using MySqlX.XDevAPI.Common; -using MySqlX.XDevAPI.Relational; -using NUnit.Framework; -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; - -namespace MySqlX.Data.Tests.RelationalTests -{ - public class TableAsyncTests : BaseTest - { - [TearDown] - public void TearDown() => ExecuteSQL("DROP TABLE IF EXISTS test"); - - [SetUp] - public void SetUp() => ExecuteSQL("CREATE TABLE test.test(id INT, age INT)"); - - [Test] - public void MultipleTableInsertAsync() - { - Table table = testSchema.GetTable("test"); - List> tasksList = new List>(); - - for (int i = 1; i <= 200; i++) - { - tasksList.Add(table.Insert().Values(i, i % 250).ExecuteAsync()); - } - - Assert.True(Task.WaitAll(tasksList.ToArray(), TimeSpan.FromMinutes(2)), "WaitAll timeout"); - Assert.AreEqual(200, table.Count()); - } - - [Test] - public void MultipleTableSelectAsync() - { - var table = testSchema.GetTable("test"); - int rows = 100; - var insert = table.Insert(); - HashSet validator = new HashSet(); - - for (int i = 1; i <= rows; i++) - { - insert.Values(i, i); - } - var result = ExecuteInsertStatement(insert); - - List> tasksList = new List>(); - - for (int i = 1; i <= rows; i++) - { - tasksList.Add(table.Select().Where("age = :age").Bind("aGe", i).ExecuteAsync()); - } - - Assert.True(Task.WaitAll(tasksList.ToArray(), TimeSpan.FromMinutes(2)), "WaitAll timeout"); - foreach (Task task in tasksList) - { - Assert.AreEqual(2, task.Result.Columns.Count); - Assert.That(task.Result.Rows, Has.One.Items); - int value = (int)task.Result.Rows[0][1]; - Assert.False(validator.Contains(value), value + " value exists"); - validator.Add(value); - } - Assert.AreEqual(rows, validator.Count); - } - #region WL14389 - [Test, Description("Table.Select() with shared lock and Table.Update() ")] - public async Task TableSelectAndUpdateAsync() - { - _ = await SubProcess1(); - _ = await SubProcess2(); - } - - private Task SubProcess1() - { - if (!session.Version.isAtLeast(8, 0, 3)) return Task.FromResult(0); - session.SQL("SET autocommit = 0").Execute(); - using (var session2 = MySQLX.GetSession(ConnectionString)) - { - session2.SQL("SET autocommit = 0").Execute(); - var table = session.Schema.GetTable("test"); - try - { - session.SQL("CREATE UNIQUE INDEX myIndex ON test.test (id)").Execute(); - } - catch (MySqlException ex) - { - Assert.True(ex.Message.Contains("Duplicate")); - } - - var table2 = session2.GetSchema("test").GetTable("test"); - session2.SQL("START TRANSACTION").Execute(); - for (var i = 0; i < 1000; i++) - { - var result = table2.Update().Where("id = 1").Set("age", 2).Execute(); - Assert.IsNotNull(result); - } - } - - session.SQL("SET autocommit = 1").Execute(); - return Task.FromResult(0); - } - - - private Task SubProcess2() - { - Thread.Sleep(1000); - if (!session.InternalSession.GetServerVersion().isAtLeast(8, 0, 3)) return Task.FromResult(0); - session.SQL("SET autocommit = 0").Execute(); - - using (var session2 = MySQLX.GetSession(ConnectionString)) - { - session2.SQL("SET autocommit = 0").Execute(); - var table = session.Schema.GetTable("test"); - try - { - session.SQL("CREATE UNIQUE INDEX myIndex ON test.test (id)").Execute(); - } - catch (MySqlException ex) - { - Assert.True(ex.Message.Contains("Duplicate")); - } - - var table2 = session2.GetSchema("test").GetTable("test"); - session.SQL("START TRANSACTION").Execute(); - var rowResult = table.Select().Where("id = 1").LockExclusive().Execute(); - } - - session.SQL("SET autocommit = 0").Execute(); - return Task.FromResult(0); - } - #endregion WL14389 - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data.MySqlClient; +using MySqlX.XDevAPI; +using MySqlX.XDevAPI.Common; +using MySqlX.XDevAPI.Relational; +using NUnit.Framework; +using NUnit.Framework.Legacy; +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace MySqlX.Data.Tests.RelationalTests +{ + public class TableAsyncTests : BaseTest + { + [TearDown] + public void TearDown() => ExecuteSQL("DROP TABLE IF EXISTS test"); + + [SetUp] + public void SetUp() => ExecuteSQL("CREATE TABLE test.test(id INT, age INT)"); + + [Test] + public void MultipleTableInsertAsync() + { + Table table = testSchema.GetTable("test"); + List> tasksList = new List>(); + + for (int i = 1; i <= 200; i++) + { + tasksList.Add(table.Insert().Values(i, i % 250).ExecuteAsync()); + } + + Assert.That(Task.WaitAll(tasksList.ToArray(), TimeSpan.FromMinutes(2)), "WaitAll timeout"); + Assert.That(table.Count(), Is.EqualTo(200)); + } + + [Test] + public void MultipleTableSelectAsync() + { + var table = testSchema.GetTable("test"); + int rows = 100; + var insert = table.Insert(); + HashSet validator = new HashSet(); + + for (int i = 1; i <= rows; i++) + { + insert.Values(i, i); + } + var result = ExecuteInsertStatement(insert); + + List> tasksList = new List>(); + + for (int i = 1; i <= rows; i++) + { + tasksList.Add(table.Select().Where("age = :age").Bind("aGe", i).ExecuteAsync()); + } + + Assert.That(Task.WaitAll(tasksList.ToArray(), TimeSpan.FromMinutes(2)), "WaitAll timeout"); + foreach (Task task in tasksList) + { + Assert.That(task.Result.Columns.Count, Is.EqualTo(2)); + Assert.That(task.Result.Rows, Has.One.Items); + int value = (int)task.Result.Rows[0][1]; + Assert.That(validator.Contains(value), Is.False, value + " value exists"); + validator.Add(value); + } + Assert.That(validator.Count, Is.EqualTo(rows)); + } + #region WL14389 + [Test, Description("Table.Select() with shared lock and Table.Update() ")] + public async Task TableSelectAndUpdateAsync() + { + _ = await SubProcess1(); + _ = await SubProcess2(); + } + + private Task SubProcess1() + { + if (!session.Version.isAtLeast(8, 0, 3)) return Task.FromResult(0); + session.SQL("SET autocommit = 0").Execute(); + using (var session2 = MySQLX.GetSession(ConnectionString)) + { + session2.SQL("SET autocommit = 0").Execute(); + var table = session.Schema.GetTable("test"); + try + { + session.SQL("CREATE UNIQUE INDEX myIndex ON test.test (id)").Execute(); + } + catch (MySqlException ex) + { + Assert.That(ex.Message.Contains("Duplicate")); + } + + var table2 = session2.GetSchema("test").GetTable("test"); + session2.SQL("START TRANSACTION").Execute(); + for (var i = 0; i < 1000; i++) + { + var result = table2.Update().Where("id = 1").Set("age", 2).Execute(); + Assert.That(result, Is.Not.Null); + } + } + + session.SQL("SET autocommit = 1").Execute(); + return Task.FromResult(0); + } + + + private Task SubProcess2() + { + Thread.Sleep(1000); + if (!session.InternalSession.GetServerVersion().isAtLeast(8, 0, 3)) return Task.FromResult(0); + session.SQL("SET autocommit = 0").Execute(); + + using (var session2 = MySQLX.GetSession(ConnectionString)) + { + session2.SQL("SET autocommit = 0").Execute(); + var table = session.Schema.GetTable("test"); + try + { + session.SQL("CREATE UNIQUE INDEX myIndex ON test.test (id)").Execute(); + } + catch (MySqlException ex) + { + Assert.That(ex.Message.Contains("Duplicate")); + } + + var table2 = session2.GetSchema("test").GetTable("test"); + session.SQL("START TRANSACTION").Execute(); + var rowResult = table.Select().Where("id = 1").LockExclusive().Execute(); + } + + session.SQL("SET autocommit = 0").Execute(); + return Task.FromResult(0); + } + #endregion WL14389 + } +} diff --git a/MySQL.Data/tests/MySqlX.Data.Tests/RelationalTests/TableDeleteTests.cs b/MySQL.Data/tests/MySqlX.Data.Tests/RelationalTests/TableDeleteTests.cs index 0ee723123..01f4660ce 100644 --- a/MySQL.Data/tests/MySqlX.Data.Tests/RelationalTests/TableDeleteTests.cs +++ b/MySQL.Data/tests/MySqlX.Data.Tests/RelationalTests/TableDeleteTests.cs @@ -1,116 +1,117 @@ -// Copyright (c) 2015, 2021, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data.MySqlClient; -using MySqlX.XDevAPI.Common; -using MySqlX.XDevAPI.Relational; -using NUnit.Framework; - -namespace MySqlX.Data.Tests.RelationalTests -{ - public class TableDeleteTests : BaseTest - { - [TearDown] - public void TearDown() => ExecuteSQL("DROP TABLE IF EXISTS test"); - - [SetUp] - public void SetUp() - { - ExecuteSQL("CREATE TABLE test.test(id INT, age INT)"); - - var insertStatement = testSchema.GetTable("test").Insert(); - int rowsToInsert = 10; - for (int i = 1; i <= rowsToInsert; i++) - { - insertStatement.Values(i, i); - } - ExecuteInsertStatement(insertStatement); - Assert.AreEqual(rowsToInsert, CountRows()); - } - - private long CountRows() - { - return testSchema.GetTable("test").Count(); - } - - private void ExecuteDelete(TableDeleteStatement statement, int expectedRowsCount) - { - Result result = ExecuteDeleteStatement(statement); - Assert.AreEqual(expectedRowsCount, CountRows()); - } - - [Test] - public void DeleteAllTest() - { - ExecuteDelete(testSchema.GetTable("test").Delete(), 0); - } - - [Test] - public void DeleteConditionTest() - { - ExecuteDelete(testSchema.GetTable("test").Delete().Where("age % 2 = 0"), 5); - } - - [Test] - public void DeleteOrderbyAndLimit() - { - ExecuteDelete(testSchema.GetTable("test").Delete().OrderBy("age Desc").Limit(3), 7); - } - - [Test] - public void DeleteConditionOrderbyAndLimit() - { - ExecuteDelete(testSchema.GetTable("test").Delete().Where("id > 5").OrderBy("id Desc").Limit(2), 8); - } - - [Test] - public void DeleteBindTest() - { - var deleteStmt = testSchema.GetTable("test").Delete().Where("age = :aGe"); - ExecuteDelete(deleteStmt.Bind("Age", 4), 9); - ExecuteDelete(deleteStmt.Bind("age", 6), 8); - } - - [Test] - public void DeleteWithInOperator() - { - Table table = testSchema.GetTable("test"); - Assert.AreEqual(10, CountRows()); - - Assert.AreEqual(2, ExecuteDeleteStatement(table.Delete().Where("id IN (1,2)")).AffectedItemsCount); - Assert.AreEqual(8, CountRows()); - - Assert.Throws(() => ExecuteDeleteStatement(table.Delete().Where("a IN [3]"))); - Assert.Throws(() => ExecuteDeleteStatement(table.Delete().Where("3 IN a"))); - Assert.Throws(() => ExecuteDeleteStatement(table.Delete().Where("age IN [3]"))); - - Assert.AreEqual(1, ExecuteDeleteStatement(table.Delete().Where("age IN (3)")).AffectedItemsCount); - Assert.AreEqual(7, CountRows()); - } - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data.MySqlClient; +using MySqlX.XDevAPI.Common; +using MySqlX.XDevAPI.Relational; +using NUnit.Framework; +using NUnit.Framework.Legacy; + +namespace MySqlX.Data.Tests.RelationalTests +{ + public class TableDeleteTests : BaseTest + { + [TearDown] + public void TearDown() => ExecuteSQL("DROP TABLE IF EXISTS test"); + + [SetUp] + public void SetUp() + { + ExecuteSQL("CREATE TABLE test.test(id INT, age INT)"); + + var insertStatement = testSchema.GetTable("test").Insert(); + int rowsToInsert = 10; + for (int i = 1; i <= rowsToInsert; i++) + { + insertStatement.Values(i, i); + } + ExecuteInsertStatement(insertStatement); + Assert.That(CountRows(), Is.EqualTo(rowsToInsert)); + } + + private long CountRows() + { + return testSchema.GetTable("test").Count(); + } + + private void ExecuteDelete(TableDeleteStatement statement, int expectedRowsCount) + { + Result result = ExecuteDeleteStatement(statement); + Assert.That(CountRows(), Is.EqualTo(expectedRowsCount)); + } + + [Test] + public void DeleteAllTest() + { + ExecuteDelete(testSchema.GetTable("test").Delete(), 0); + } + + [Test] + public void DeleteConditionTest() + { + ExecuteDelete(testSchema.GetTable("test").Delete().Where("age % 2 = 0"), 5); + } + + [Test] + public void DeleteOrderbyAndLimit() + { + ExecuteDelete(testSchema.GetTable("test").Delete().OrderBy("age Desc").Limit(3), 7); + } + + [Test] + public void DeleteConditionOrderbyAndLimit() + { + ExecuteDelete(testSchema.GetTable("test").Delete().Where("id > 5").OrderBy("id Desc").Limit(2), 8); + } + + [Test] + public void DeleteBindTest() + { + var deleteStmt = testSchema.GetTable("test").Delete().Where("age = :aGe"); + ExecuteDelete(deleteStmt.Bind("Age", 4), 9); + ExecuteDelete(deleteStmt.Bind("age", 6), 8); + } + + [Test] + public void DeleteWithInOperator() + { + Table table = testSchema.GetTable("test"); + Assert.That(CountRows(), Is.EqualTo(10)); + + Assert.That(ExecuteDeleteStatement(table.Delete().Where("id IN (1,2)")).AffectedItemsCount, Is.EqualTo(2)); + Assert.That(CountRows(), Is.EqualTo(8)); + + Assert.Throws(() => ExecuteDeleteStatement(table.Delete().Where("a IN [3]"))); + Assert.Throws(() => ExecuteDeleteStatement(table.Delete().Where("3 IN a"))); + Assert.Throws(() => ExecuteDeleteStatement(table.Delete().Where("age IN [3]"))); + + Assert.That(ExecuteDeleteStatement(table.Delete().Where("age IN (3)")).AffectedItemsCount, Is.EqualTo(1)); + Assert.That(CountRows(), Is.EqualTo(7)); + } + } +} diff --git a/MySQL.Data/tests/MySqlX.Data.Tests/RelationalTests/TableInsertTests.cs b/MySQL.Data/tests/MySqlX.Data.Tests/RelationalTests/TableInsertTests.cs index 57b592f69..1f9f379ea 100644 --- a/MySQL.Data/tests/MySqlX.Data.Tests/RelationalTests/TableInsertTests.cs +++ b/MySQL.Data/tests/MySqlX.Data.Tests/RelationalTests/TableInsertTests.cs @@ -1,125 +1,126 @@ -// Copyright (c) 2015, 2022, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data.MySqlClient; -using MySqlX.XDevAPI.Relational; -using NUnit.Framework; -using System.Linq; - -namespace MySqlX.Data.Tests.RelationalTests -{ - public class TableInsertTests : BaseTest - { - [TearDown] - public void TearDown() => ExecuteSQL("DROP TABLE IF EXISTS test"); - public TableInsertTests() - { - } - - [Test] - public void InsertMultipleValues() - { - ExecuteSQL("CREATE TABLE test.test(name VARCHAR(40), age INT)"); - Table table = testSchema.GetTable("test"); - - var result = ExecuteInsertStatement(table.Insert("name", "age") - .Values("Henry", "22") - .Values("Patric", 30) - ); - Assert.AreEqual(2, result.AffectedItemsCount); - - var selectResult = ExecuteSelectStatement(table.Select()); - while (selectResult.Next()) ; - Assert.AreEqual(2, selectResult.Rows.Count); - Assert.AreEqual("Henry", selectResult.Rows.ToArray()[0][0]); - Assert.AreEqual(22, selectResult.Rows.ToArray()[0][1]); - Assert.AreEqual("Patric", selectResult.Rows.ToArray()[1][0]); - Assert.AreEqual(30, selectResult.Rows.ToArray()[1][1]); - - Assert.AreEqual(2, table.Count()); - } - - [Test] - public void InsertExpressions() - { - ExecuteSQL("CREATE TABLE test.test(name VARCHAR(40), age INT)"); - Table table = testSchema.GetTable("test"); - - var result = ExecuteInsertStatement(table.Insert("name", "age").Values("MARK", "34")); - Assert.AreEqual(1, result.AffectedItemsCount); - - var selectResult = ExecuteSelectStatement(table.Select()); - while (selectResult.Next()) ; - Assert.That(selectResult.Rows, Has.One.Items); - Assert.AreEqual("MARK", selectResult.Rows.ToArray()[0][0]); - Assert.AreEqual(34, selectResult.Rows.ToArray()[0][1]); - } - - [Test] - public void ReuseStatement() - { - ExecuteSQL("CREATE TABLE test(name VARCHAR(40), age INT)"); - Table table = testSchema.GetTable("test"); - - var stmt = table.Insert("name", "age"); - var result = ExecuteInsertStatement(stmt.Values("MARK", "34")); - Assert.AreEqual(1, result.AffectedItemsCount); - // error 5014 - Wrong number of fields in row being inserted - Assert.AreEqual(5014u, Assert.Throws(() => result = ExecuteInsertStatement(stmt.Values("George", 34, 1))).Code); - Assert.AreEqual(5014u, Assert.Throws(() => ExecuteInsertStatement(stmt.Values("George", 34))).Code); - Assert.That(ExecuteSelectStatement(table.Select()).FetchAll(), Has.One.Items); - } - - /// - /// Bug#31692694 - TABLEINSERTSTATEMENT STRING SPECIAL CARAC VALUES OBJECT ARE UNCORRECTLY MANAGED - /// - [TestCase("-")] - [TestCase("+")] - [TestCase("*")] - [TestCase("/")] - [TestCase("\\")] - [TestCase("=")] - [TestCase("(")] - [TestCase(")")] - public void InsertWithExpressionsAlikeValues(string specialChar) - { - ExecuteSQL("CREATE TABLE test(ID INT, COLUMN_TEST VARCHAR(40))"); - string value = $"ImproperFieldNameBug {specialChar} Bug"; - - Table table = testSchema.GetTable("test"); - var insertResult = table.Insert("ID", "COLUMN_TEST").Values("1", value).Execute(); - var selectResult = ExecuteSelectStatement(table.Select()); - while (selectResult.Next()) ; - - Assert.AreEqual(1, insertResult.AffectedItemsCount); - Assert.That(selectResult.Rows, Has.One.Items); - StringAssert.AreEqualIgnoringCase("1", selectResult.Rows.ToArray()[0][0].ToString()); - StringAssert.AreEqualIgnoringCase(value, selectResult.Rows.ToArray()[0][1].ToString()); - } - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data.MySqlClient; +using MySqlX.XDevAPI.Relational; +using NUnit.Framework; +using NUnit.Framework.Legacy; +using System.Linq; + +namespace MySqlX.Data.Tests.RelationalTests +{ + public class TableInsertTests : BaseTest + { + [TearDown] + public void TearDown() => ExecuteSQL("DROP TABLE IF EXISTS test"); + public TableInsertTests() + { + } + + [Test] + public void InsertMultipleValues() + { + ExecuteSQL("CREATE TABLE test.test(name VARCHAR(40), age INT)"); + Table table = testSchema.GetTable("test"); + + var result = ExecuteInsertStatement(table.Insert("name", "age") + .Values("Henry", "22") + .Values("Patric", 30) + ); + Assert.That(result.AffectedItemsCount, Is.EqualTo(2)); + + var selectResult = ExecuteSelectStatement(table.Select()); + while (selectResult.Next()) ; + Assert.That(selectResult.Rows.Count, Is.EqualTo(2)); + Assert.That(selectResult.Rows.ToArray()[0][0], Is.EqualTo("Henry")); + Assert.That(selectResult.Rows.ToArray()[0][1], Is.EqualTo(22)); + Assert.That(selectResult.Rows.ToArray()[1][0], Is.EqualTo("Patric")); + Assert.That(selectResult.Rows.ToArray()[1][1], Is.EqualTo(30)); + + Assert.That(table.Count(), Is.EqualTo(2)); + } + + [Test] + public void InsertExpressions() + { + ExecuteSQL("CREATE TABLE test.test(name VARCHAR(40), age INT)"); + Table table = testSchema.GetTable("test"); + + var result = ExecuteInsertStatement(table.Insert("name", "age").Values("MARK", "34")); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1)); + + var selectResult = ExecuteSelectStatement(table.Select()); + while (selectResult.Next()) ; + Assert.That(selectResult.Rows, Has.One.Items); + Assert.That(selectResult.Rows.ToArray()[0][0], Is.EqualTo("MARK")); + Assert.That(selectResult.Rows.ToArray()[0][1], Is.EqualTo(34)); + } + + [Test] + public void ReuseStatement() + { + ExecuteSQL("CREATE TABLE test(name VARCHAR(40), age INT)"); + Table table = testSchema.GetTable("test"); + + var stmt = table.Insert("name", "age"); + var result = ExecuteInsertStatement(stmt.Values("MARK", "34")); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1)); + // error 5014 - Wrong number of fields in row being inserted + Assert.That(Assert.Throws(() => result = ExecuteInsertStatement(stmt.Values("George", 34, 1))).Code, Is.EqualTo(5014u)); + Assert.That(Assert.Throws(() => ExecuteInsertStatement(stmt.Values("George", 34))).Code, Is.EqualTo(5014u)); + Assert.That(ExecuteSelectStatement(table.Select()).FetchAll(), Has.One.Items); + } + + /// + /// Bug#31692694 - TABLEINSERTSTATEMENT STRING SPECIAL CARAC VALUES OBJECT ARE UNCORRECTLY MANAGED + /// + [TestCase("-")] + [TestCase("+")] + [TestCase("*")] + [TestCase("/")] + [TestCase("\\")] + [TestCase("=")] + [TestCase("(")] + [TestCase(")")] + public void InsertWithExpressionsAlikeValues(string specialChar) + { + ExecuteSQL("CREATE TABLE test(ID INT, COLUMN_TEST VARCHAR(40))"); + string value = $"ImproperFieldNameBug {specialChar} Bug"; + + Table table = testSchema.GetTable("test"); + var insertResult = table.Insert("ID", "COLUMN_TEST").Values("1", value).Execute(); + var selectResult = ExecuteSelectStatement(table.Select()); + while (selectResult.Next()) ; + + Assert.That(insertResult.AffectedItemsCount, Is.EqualTo(1)); + Assert.That(selectResult.Rows, Has.One.Items); + Assert.That(selectResult.Rows.ToArray()[0][0].ToString(), Is.EqualTo("1").IgnoreCase); + Assert.That(selectResult.Rows.ToArray()[0][1].ToString(), Is.EqualTo(value).IgnoreCase); + } + } +} diff --git a/MySQL.Data/tests/MySqlX.Data.Tests/RelationalTests/TableSelectTests.cs b/MySQL.Data/tests/MySqlX.Data.Tests/RelationalTests/TableSelectTests.cs index 2ab6b4033..970cf6090 100644 --- a/MySQL.Data/tests/MySqlX.Data.Tests/RelationalTests/TableSelectTests.cs +++ b/MySQL.Data/tests/MySqlX.Data.Tests/RelationalTests/TableSelectTests.cs @@ -1,1754 +1,1755 @@ -// Copyright (c) 2015, 2022, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data.Common; -using MySql.Data.MySqlClient; -using MySqlX.XDevAPI; -using MySqlX.XDevAPI.Common; -using MySqlX.XDevAPI.Relational; -using NUnit.Framework; -using System; -using System.Linq; -using System.Text; - -namespace MySqlX.Data.Tests.RelationalTests -{ - public class TableSelectTests : BaseTest - { - object[][] allRows = { - new object[] { 1, "jonh doe", 38, "{\"company\": \"xyz\", \"hobbies\": \"reading\", \"vehicle\": \"bike\"}" }, - new object[] { 2, "milton green", 45, "{\"company\": \"abc\", \"hobbies\": [\"boxing\", \"running\"], \"vehicle\": \"car\"}" }, - new object[] { 3, "larry smith", 24, "{\"company\": \"zxc\", \"hobbies\": \"painting\", \"vehicle\": \"boat\"}" } - }; - - [SetUp] - public void SetUp() - { - ExecuteSQL("CREATE TABLE test.test (id INT, name VARCHAR(45), age INT, additionalinfo JSON)"); - TableInsertStatement stmt = testSchema.GetTable("test").Insert(); - stmt.Values(allRows[0]); - stmt.Values(allRows[1]); - stmt.Values(allRows[2]); - Result result = ExecuteInsertStatement(stmt); - } - - [TearDown] - public void TearDown() - { - ExecuteSQL("DROP TABLE IF EXISTS test"); - ExecuteSQL("DROP TABLE IF EXISTS testDate"); - } - - [Test] - public void FetchOne() - { - Table t = testSchema.GetTable("test"); - Assert.AreEqual(38, ExecuteSelectStatement(t.Select("age")).FetchOne()["age"]); - } - - private void MultiTableSelectTest(TableSelectStatement statement, object[][] expectedValues) - { - RowResult result = ExecuteSelectStatement(statement); - int rowCount = result.FetchAll().Count; - - Assert.AreEqual(expectedValues.Length, rowCount); - Assert.AreEqual(expectedValues.Length, result.Rows.Count); - for (int i = 0; i < expectedValues.Length; i++) - { - for (int j = 0; j < expectedValues[i].Length; j++) - { - Assert.AreEqual(expectedValues[i][j], result.Rows.ToArray()[i][j]); - } - } - } - - [Test] - public void TableSelect() - { - var table = testSchema.GetTable("test"); - - MultiTableSelectTest(table.Select(), allRows); - MultiTableSelectTest(table.Select("name", "age"), - allRows.Select(c => new[] { c[1], c[2] }).ToArray()); - MultiTableSelectTest(table.Select("name", "age").Where("age == 38"), - allRows.Select(c => new[] { c[1], c[2] }).Where(c => (int)c[1] == 38).ToArray()); - MultiTableSelectTest(table.Select().Where("age == 45"), - allRows.Where(c => (int)c[2] == 45).ToArray()); - MultiTableSelectTest(table.Select().OrderBy("age"), - allRows.OrderBy(c => c[2]).ToArray()); - MultiTableSelectTest(table.Select().OrderBy("age desc"), - allRows.OrderByDescending(c => c[2]).ToArray()); - MultiTableSelectTest(table.Select().OrderBy("age desc, name"), - allRows.OrderByDescending(c => c[2]).ThenBy(c => c[1]).ToArray()); - MultiTableSelectTest(table.Select().Limit(1), - allRows.Take(1).ToArray()); - MultiTableSelectTest(table.Select().Limit(10).Offset(1), - allRows.Skip(1).Take(10).ToArray()); - MultiTableSelectTest(table.Select().Limit(1).Offset(1), - allRows.Skip(1).Take(1).ToArray()); - MultiTableSelectTest(table.Select().Where("name like :name").Bind("nAme", "%jon%"), - allRows.Where(c => c[1].ToString().Contains("jon")).ToArray()); - MultiTableSelectTest(table.Select().Where("name like :name").Bind("naMe", "%on%"), - allRows.Where(c => c[1].ToString().Contains("on")).ToArray()); - } - - [Test] - public void AllColumns() - { - var table = testSchema.GetTable("test"); - var select = ExecuteSelectStatement(table.Select("*, 42 as a_number, '43' as a_string")); - var rows = select.FetchAll(); - Assert.AreEqual(6, select.Columns.Count); - Assert.AreEqual(allRows.Length, rows.Count); - Assert.AreEqual(allRows[0][0], rows[0]["id"]); - Assert.AreEqual(allRows[0][1], rows[0]["name"]); - Assert.AreEqual(allRows[0][2], rows[0]["age"]); - Assert.AreEqual(allRows[0][3], rows[0]["additionalinfo"]); - Assert.AreEqual((sbyte)42, rows[0]["a_number"]); - Assert.AreEqual("43", rows[0]["a_string"]); - } - - [Test] - public void CountAllColumns() - { - var table = testSchema.GetTable("test"); - var select = ExecuteSelectStatement(table.Select("count(*) + 10")); - var rows = select.FetchAll(); - Assert.That(select.Columns, Has.One.Items); - Assert.That(rows, Has.One.Items); - Assert.AreEqual(allRows.Length + 10, (long)rows[0][0]); - } - - [Test] - public void MultipleBind() - { - object[] validationRow = allRows[1]; - var table = testSchema.GetTable("test"); - var select = ExecuteSelectStatement(table.Select().Where("Name = :nAme && Age = :aGe").Bind("agE", validationRow[2]).Bind("naMe", validationRow[1])); - var rows = select.FetchAll(); - Assert.That(rows, Has.One.Items); - Assert.AreEqual(validationRow[1], rows[0]["namE"]); - Assert.AreEqual(validationRow[2], rows[0]["AGe"]); - } - - [Test] - public void DatetimeAndMicroseconds() - { - ExecuteSQL("CREATE TABLE test.testDate (id INT, name VARCHAR(45), birthday DATETIME(6))"); - ExecuteSQL("INSERT INTO test.testDate VALUES(1, 'JOHN', '1985-10-21 16:34:22.123456')"); - ExecuteSQL("INSERT INTO test.testDate VALUES(1, 'BILL', '1985-10-21 10:00:45.987')"); - var rows = ExecuteSelectStatement(GetSession().GetSchema("test").GetTable("testDate").Select()).FetchAll(); - Assert.AreEqual(2, rows.Count); - Assert.AreEqual(new DateTime(1985, 10, 21, 16, 34, 22).AddTicks(1234560), (DateTime)rows[0]["birthday"]); - Assert.AreEqual(new DateTime(1985, 10, 21, 10, 0, 45).AddTicks(9870000), (DateTime)rows[1]["birthday"]); - } - - [Test] - public void DatetimeAndMilliseconds() - { - ExecuteSQL("CREATE TABLE test.testDate2 (id INT, name VARCHAR(45), birthday DATETIME(3))"); - ExecuteSQL("INSERT INTO test.testDate2 VALUES(1, 'JOHN', '1985-10-21 16:34:22.123456')"); - ExecuteSQL("INSERT INTO test.testDate2 VALUES(1, 'BILL', '1985-10-21 10:00:45.098')"); - var rows = ExecuteSelectStatement(GetSession().GetSchema("test").GetTable("testDate2").Select()).FetchAll(); - Assert.AreEqual(2, rows.Count); - Assert.AreEqual(new DateTime(1985, 10, 21, 16, 34, 22).AddTicks(1230000), (DateTime)rows[0]["birthday"]); - Assert.AreEqual(new DateTime(1985, 10, 21, 10, 0, 45).AddTicks(980000), (DateTime)rows[1]["birthday"]); - } - - [Test] - public void RowLockingNotSupportedInOlderVersions() - { - if (session.InternalSession.GetServerVersion().isAtLeast(8, 0, 3)) return; - - Table table = session.Schema.GetTable("test"); - - Exception ex = Assert.Throws(() => ExecuteSelectStatement(table.Select().LockShared())); - Assert.AreEqual("This functionality is only supported from server version 8.0.3 onwards.", ex.Message); - - ex = Assert.Throws(() => ExecuteSelectStatement(table.Select().LockExclusive())); - Assert.AreEqual("This functionality is only supported from server version 8.0.3 onwards.", ex.Message); - } - - [Test] - public void SimpleSharedLock() - { - if (!session.InternalSession.GetServerVersion().isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher"); - - ExecuteSQLStatement(session.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); - using (var session2 = MySQLX.GetSession(ConnectionString)) - { - ExecuteSQLStatement(session2.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); - Table table = session.Schema.GetTable("test"); - Table table2 = session2.GetSchema("test").GetTable("test"); - - ExecuteSQLStatement(session.SQL("START TRANSACTION")); - RowResult rowResult = ExecuteSelectStatement(table.Select().Where("id = 1").LockShared()); - Assert.That(rowResult.FetchAll(), Has.One.Items); - - ExecuteSQLStatement(session2.SQL("START TRANSACTION")); - // Should return immediately since row isn't locked. - rowResult = ExecuteSelectStatement(table2.Select().Where("id = 2").LockShared()); - Assert.That(rowResult.FetchAll(), Has.One.Items); - // Should return immediately due to LockShared() allows reading by other sessions. - rowResult = ExecuteSelectStatement(table2.Select().Where("id = 1").LockShared()); - Assert.That(rowResult.FetchAll(), Has.One.Items); - - ExecuteSQLStatement(session.SQL("ROLLBACK")); - ExecuteSQLStatement(session2.SQL("ROLLBACK")); - } - } - - [Test] - public void SimpleExclusiveLock() - { - if (!session.InternalSession.GetServerVersion().isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher"); - - ExecuteSQLStatement(session.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); - using (var session2 = MySQLX.GetSession(ConnectionString)) - { - ExecuteSQLStatement(session2.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); - Table table = session.Schema.GetTable("test"); - ExecuteSQLStatement(session.SQL("CREATE UNIQUE INDEX myIndex ON test.test (id)")); - Table table2 = session2.GetSchema("test").GetTable("test"); - - ExecuteSQLStatement(session.SQL("START TRANSACTION")); - RowResult rowResult = ExecuteSelectStatement(table.Select().Where("id = 1").LockExclusive()); - Assert.That(rowResult.FetchAll(), Has.One.Items); - - ExecuteSQLStatement(session2.SQL("START TRANSACTION")); - // Should return immediately since row isn't locked. - rowResult = ExecuteSelectStatement(table2.Select().Where("id = 2").LockExclusive()); - Assert.That(rowResult.FetchAll(), Has.One.Items); - // Session2 blocks due to to LockExclusive() not allowing to read locked rows. - ExecuteSQLStatement(session2.SQL("SET SESSION innodb_lock_wait_timeout=1")); - Exception ex = Assert.Throws(() => ExecuteSelectStatement(table2.Select().Where("id = 1").LockExclusive())); - Assert.AreEqual("Lock wait timeout exceeded; try restarting transaction", ex.Message); - - ExecuteSQLStatement(session.SQL("ROLLBACK")); - ExecuteSQLStatement(session2.SQL("ROLLBACK")); - } - } - - [Test] - public void SharedLockForbidsToModifyDocuments() - { - if (!session.InternalSession.GetServerVersion().isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher"); - - ExecuteSQLStatement(session.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); - using (var session2 = MySQLX.GetSession(ConnectionString)) - { - ExecuteSQLStatement(session2.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); - Table table = session.Schema.GetTable("test"); - Table table2 = session2.GetSchema("test").GetTable("test"); - - ExecuteSQLStatement(session.SQL("START TRANSACTION")); - RowResult rowResult = ExecuteSelectStatement(table.Select().Where("id = 1").LockShared()); - Assert.That(rowResult.FetchAll(), Has.One.Items); - - ExecuteSQLStatement(session2.SQL("START TRANSACTION")); - // Reading the same row is allowed with LockShared(). - rowResult = ExecuteSelectStatement(table2.Select().Where("id = 1")); - Assert.That(rowResult.FetchAll(), Has.One.Items); - - // Modify() is allowed for non-locked rows. - Result result = ExecuteUpdateStatement(table2.Update().Where("id = 2").Set("age", 2)); - Assert.AreEqual(1, result.AffectedItemsCount); - // Session1 blocks, Modify() is not allowed for locked rows. - ExecuteSQLStatement(session2.SQL("SET SESSION innodb_lock_wait_timeout=1")); - Exception ex = Assert.Throws(() => ExecuteUpdateStatement(table2.Update().Where("id = 1").Set("age", 2))); - Assert.AreEqual("Lock wait timeout exceeded; try restarting transaction", ex.Message); - - ExecuteSQLStatement(session.SQL("ROLLBACK")); - // Modify() is allowed since row isn't locked anymore. - ExecuteUpdateStatement(table2.Update().Where("id = 1").Set("age", 2)); - ExecuteSQLStatement(session2.SQL("COMMIT")); - } - } - - [Test] - public void ExclusiveLockForbidsToModifyDocuments() - { - if (!session.InternalSession.GetServerVersion().isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher"); - - ExecuteSQLStatement(session.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); - using (var session2 = MySQLX.GetSession(ConnectionString)) - { - ExecuteSQLStatement(session2.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); - Table table = session.Schema.GetTable("test"); - Table table2 = session2.GetSchema("test").GetTable("test"); - - ExecuteSQLStatement(session.SQL("START TRANSACTION")); - RowResult rowResult = ExecuteSelectStatement(table.Select().Where("id = 1").LockExclusive()); - Assert.That(rowResult.FetchAll(), Has.One.Items); - - ExecuteSQLStatement(session2.SQL("START TRANSACTION")); - - // Modify() is allowed for non-locked rows. - Result result = ExecuteUpdateStatement(table2.Update().Where("id = 2").Set("age", 2)); - Assert.AreEqual(1, result.AffectedItemsCount); - // Session1 blocks, Modify() is not allowed for locked rows. - ExecuteSQLStatement(session2.SQL("SET SESSION innodb_lock_wait_timeout=1")); - Exception ex = Assert.Throws(() => ExecuteUpdateStatement(table2.Update().Where("id = 1").Set("age", 2))); - Assert.AreEqual("Lock wait timeout exceeded; try restarting transaction", ex.Message); - - ExecuteSQLStatement(session.SQL("ROLLBACK")); - // Modify() is allowed since row isn't locked anymore. - ExecuteUpdateStatement(table2.Update().Where("id = 1").Set("age", 2)); - ExecuteSQLStatement(session2.SQL("COMMIT")); - } - } - - [Test] - public void SharedLockAfterExclusiveLock() - { - if (!session.InternalSession.GetServerVersion().isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher"); - - ExecuteSQLStatement(session.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); - using (var session2 = MySQLX.GetSession(ConnectionString)) - { - ExecuteSQLStatement(session2.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); - Table table = session.Schema.GetTable("test"); - ExecuteSQLStatement(session.SQL("CREATE UNIQUE INDEX myIndex ON test.test (id)")); - Table table2 = session2.GetSchema("test").GetTable("test"); - - ExecuteSQLStatement(session.SQL("START TRANSACTION")); - RowResult rowResult = ExecuteSelectStatement(table.Select().Where("id = 1").LockExclusive()); - Assert.That(rowResult.FetchAll(), Has.One.Items); - - ExecuteSQLStatement(session2.SQL("START TRANSACTION")); - // Should return immediately since row isn't locked. - rowResult = ExecuteSelectStatement(table2.Select().Where("id = 2").LockShared()); - Assert.That(rowResult.FetchAll(), Has.One.Items); - // Session2 blocks due to LockExclusive() not allowing to read locked rows. - ExecuteSQLStatement(session2.SQL("SET SESSION innodb_lock_wait_timeout=1")); - Exception ex = Assert.Throws(() => ExecuteSelectStatement(table2.Select().Where("id = 1").LockShared())); - Assert.AreEqual("Lock wait timeout exceeded; try restarting transaction", ex.Message); - - // Session unlocks rows. - ExecuteSQLStatement(session.SQL("ROLLBACK")); - // Row can now be recovered. - rowResult = ExecuteSelectStatement(table2.Select().Where("id = 1").LockShared()); - Assert.That(rowResult.FetchAll(), Has.One.Items); - ExecuteSQLStatement(session2.SQL("ROLLBACK")); - } - } - - [Test] - public void ExclusiveLockAfterSharedLock() - { - if (!session.InternalSession.GetServerVersion().isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher"); - - ExecuteSQLStatement(session.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); - using (var session2 = MySQLX.GetSession(ConnectionString)) - { - ExecuteSQLStatement(session2.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); - Table table = session.Schema.GetTable("test"); - ExecuteSQLStatement(session.SQL("CREATE UNIQUE INDEX myIndex ON test.test (id)")); - Table table2 = session2.GetSchema("test").GetTable("test"); - - ExecuteSQLStatement(session.SQL("START TRANSACTION")); - RowResult rowResult = ExecuteSelectStatement(table.Select().Where("id in (1, 3)").LockShared()); - Assert.AreEqual(2, rowResult.FetchAll().Count); - - ExecuteSQLStatement(session2.SQL("START TRANSACTION")); - // Should return immediately since row isn't locked. - rowResult = ExecuteSelectStatement(table2.Select().Where("id = 2").LockExclusive()); - // Should return immediately due to LockShared() allows reading by other sessions. - rowResult = ExecuteSelectStatement(table2.Select().Where("id = 2").LockShared()); - Assert.That(rowResult.FetchAll(), Has.One.Items); - // Session2 blocks due to to LockExclusive() not allowing to read locked rows. - ExecuteSQLStatement(session2.SQL("SET SESSION innodb_lock_wait_timeout=1")); - Exception ex = Assert.Throws(() => ExecuteSelectStatement(table2.Select().Where("id = 1").LockExclusive())); - Assert.AreEqual("Lock wait timeout exceeded; try restarting transaction", ex.Message); - - // Session unlocks rows. - ExecuteSQLStatement(session.SQL("ROLLBACK")); - rowResult = ExecuteSelectStatement(table2.Select().Where("id = 1").LockExclusive()); - Assert.That(rowResult.FetchAll(), Has.One.Items); - ExecuteSQLStatement(session2.SQL("ROLLBACK")); - } - } - - [Test] - public void SelectWithInOperator() - { - Table table = testSchema.GetTable("test"); - Assert.AreEqual(3, ExecuteSelectStatement(table.Select()).FetchAll().Count); - - Assert.AreEqual(2, ExecuteSelectStatement(table.Select().Where("name IN (\"jonh doe\", \"milton green\")")).FetchAll().Count); - Assert.That(ExecuteSelectStatement(table.Select().Where("name NOT IN (\"jonh doe\", \"milton green\")")).FetchAll(), Has.One.Items); - CollectionAssert.IsEmpty(ExecuteSelectStatement(table.Select().Where("name IN (\"\", \"\")")).FetchAll()); - CollectionAssert.IsEmpty(ExecuteSelectStatement(table.Select().Where("\"\" IN (1,2,3)")).FetchAll()); - CollectionAssert.IsEmpty(ExecuteSelectStatement(table.Select().Where("name IN ('', '')")).FetchAll()); - CollectionAssert.IsEmpty(ExecuteSelectStatement(table.Select().Where("'' IN (1,2,3)")).FetchAll()); - Assert.AreEqual(3, ExecuteSelectStatement(table.Select().Where("'' IN ('')")).FetchAll().Count); - - Assert.Throws(() => ExecuteSelectStatement(table.Select().Where("name NOT IN [\"jonh doe\", \"milton green\"]")).FetchAll()); - Assert.Throws(() => ExecuteSelectStatement(table.Select().Where("a IN [3]")).FetchAll()); - Assert.Throws(() => ExecuteSelectStatement(table.Select().Where("3 IN a")).FetchAll()); - } - - [Test] - public void Grouping() - { - ExecuteSQLStatement(GetSession().SQL("set sql_mode = 'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';")); - Table table = testSchema.GetTable("test"); - - // Insert additonal users. - object[][] additionalUsers = { - new object[] { 4, "mary weinstein", 24, null }, - new object[] { 5, "jerry pratt", 45, null }, - new object[] { 6, "hugh jackman", 20, null }, - new object[] { 7, "elizabeth olsen", 31, null } - }; - var statement = table.Insert(); - foreach (object[] user in additionalUsers) - { - statement = statement.Values(user); - } - - Assert.AreEqual(4, ExecuteInsertStatement(statement).AffectedItemsCount); - - // GroupBy returns 5 rows since age 45 and 24 is repeated. - var result = ExecuteSelectStatement(table.Select().GroupBy("age")); - Assert.AreEqual(5, result.FetchAll().Count); - - // GroupBy with null. - result = ExecuteSelectStatement(table.Select("id as ID", "name as Name", "age as Age").GroupBy(null)); - Assert.AreEqual(7, result.FetchAll().Count); - result = ExecuteSelectStatement(table.Select("id as ID", "name as Name", "age as Age").GroupBy(null, null)); - Assert.AreEqual(7, result.FetchAll().Count); - result = ExecuteSelectStatement(table.Select("id as ID", "name as Name", "age as Age").GroupBy(null, "age")); - Assert.AreEqual(5, result.FetchAll().Count); - - // Having operation. - // Having reduces the original 5 rows to 3 since 2 rows have a cnt=2, due to the repeated names. - result = ExecuteSelectStatement(table.Select("id", "count(name) as cnt", "age").GroupBy("age").Having("cnt = 1")); - Assert.AreEqual(3, result.FetchAll().Count); - - // Having with null. - result = ExecuteSelectStatement(table.Select("id as ID", "count(name) as cnt", "age as Age").GroupBy("age").Having(null)); - Assert.AreEqual(5, result.FetchAll().Count); - - // GroupBy with invalid field name. - var ex = Assert.Throws(() => ExecuteSelectStatement(table.Select("id as ID", "name as Name", "age as Age").GroupBy("none"))); - Assert.AreEqual("Unknown column 'none' in 'group statement'", ex.Message); - - // GroupBy with empty strings. - var ex2 = Assert.Throws(() => ExecuteSelectStatement(table.Select("id as ID", "name as Name", "age as Age").GroupBy(""))); - Assert.AreEqual("No more tokens when expecting one at token pos 0", ex2.Message); - ex2 = Assert.Throws(() => ExecuteSelectStatement(table.Select("id as ID", "name as Name", "age as Age").GroupBy(" "))); - Assert.AreEqual("No more tokens when expecting one at token pos 0", ex2.Message); - ex2 = Assert.Throws(() => ExecuteSelectStatement(table.Select("id as ID", "name as Name", "age as Age").GroupBy(string.Empty))); - Assert.AreEqual("No more tokens when expecting one at token pos 0", ex2.Message); - - // Having with invalid field name. - ex = Assert.Throws(() => ExecuteSelectStatement(table.Select("id as ID", "count(name) as cnt", "age as Age").GroupBy("age").Having("none = 1"))); - Assert.AreEqual("Unknown column 'none' in 'having clause'", ex.Message); - - // Having with empty strings. - ex2 = Assert.Throws(() => ExecuteSelectStatement(table.Select("id as ID", "count(name) as cnt", "age as Age").GroupBy("age").Having(""))); - Assert.AreEqual("Unable to parse query ''", ex2.Message); - Assert.AreEqual("No more tokens when expecting one at token pos 0", ex2.InnerException.Message); - ex2 = Assert.Throws(() => ExecuteSelectStatement(table.Select("id as ID", "count(name) as cnt", "age as Age").GroupBy("age").Having(" "))); - Assert.AreEqual("Unable to parse query ' '", ex2.Message); - Assert.AreEqual("No more tokens when expecting one at token pos 0", ex2.InnerException.Message); - ex2 = Assert.Throws(() => ExecuteSelectStatement(table.Select("id as ID", "count(name) as cnt", "age as Age").GroupBy("age").Having(string.Empty))); - Assert.AreEqual("Unable to parse query ''", ex2.Message); - Assert.AreEqual("No more tokens when expecting one at token pos 0", ex2.InnerException.Message); - } - - /// - /// Bug-29838254 - /// RESULTSET ERROR WHEN SELECT IS ISSUED WITH IN OPERATOR WITH BLANKS WITH 8.0.17 SERVER-C/NET8.0.17TRUNK - /// - [Test] - public void SelectWithInBlanksAndBrackets() - { - Session session = GetSession(); - Schema schema = session.GetSchema("test"); - object[][] allRows = - { - new object[] {1, "john doe", 38}, - new object[] {2, "milton green", 45}, - new object[] {3, "milton blue", 46}, - new object[] {4, "milton red", 47}, - new object[] {5, "milton yellow", 48}, - new object[] {6, "milton check", 49}, - new object[] {7, "milton pink", 14}, - new object[] {8, "milton beize", 25}, - new object[] {9, "milton silver", 35}, - new object[] {10, "milton city", 65} - }; - session.SQL("USE test").Execute(); - session.SQL("DROP table if exists test").Execute(); - var r = session.SQL("CREATE TABLE test.test(id INT,name VARCHAR(45), age INT)").Execute(); - var rows = r.HasData ? r.FetchAll() : null; - testSchema = session.GetSchema("test"); - var insertStatement = testSchema.GetTable("test").Insert(); - var rowsToInsert = 10; - for (var i = 0; i < rowsToInsert; i++) - insertStatement.Values(allRows[i]); - insertStatement.Execute(); - var table = testSchema.GetTable("test"); - int count = 0; - - //Exception expected when square brackets are used instead of parenthesis - Assert.Throws(() => table.Select().Where("name IN ['', ' ']").Execute().FetchAll()); - - // Test using parenthesis should return result - count = table.Select().Where("name IN (\"john doe\", \"milton green\")").Execute().FetchAll().Count; - Assert.True(count > 0); - - // Using parenthesis should return empty resultset for empty parameters - count = table.Select().Where("name IN ('', ' ')").Execute().FetchAll().Count; - Assert.True(count == 0); - } - - [TestCase(":hobbies IN additionalinfo->$.hobbies", "hobbies", "painting", 3)] - [TestCase(":hobbies IN additionalinfo->$.hobbies", "hobbies", "[\"boxing\", \"running\"]", 0)] - [TestCase("[\"boxing\", \"running\"] IN additionalinfo->$.hobbies", null, null, 2)] - [TestCase(":hobbies IN additionalinfo$.hobbies", "hobbies", "painting", 3)] - public void InOperatorBindingJson(string condition, string bind, string value, int id) - { - Table table = testSchema.GetTable("test"); - Assert.AreEqual(3, ExecuteSelectStatement(table.Select()).FetchAll().Count); - - var stmt = table.Select().Where(condition); - if (bind != null) stmt.Bind(bind, value); - var result = ExecuteSelectStatement(stmt).FetchAll(); - Assert.AreEqual(id == 0 ? 0 : 1, result.Count); - if (id > 0) - { - Assert.AreEqual(id, result[0]["id"]); - } - } - - #region WL14389 - - [Test, Description("Reading locked document(lock_shared) in a table using lock_exclusive with DEFAULT waiting option.")] - public void ExclusiveLockAfterSharedLockDefaultWaiting() - { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher"); - - session.SQL("DROP TABLE IF EXISTS test.test").Execute(); - session.SQL("CREATE TABLE test.test (id INT, a INT)").Execute(); - var table1 = testSchema.GetTable("test"); - table1.Insert("id", "a").Values(1, 1).Values(2, 2).Values(3, 3).Execute(); - ExecuteSQLStatement(session.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); - using (var session2 = MySQLX.GetSession(ConnectionString)) - { - ExecuteSQLStatement(session2.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); - var table = session.Schema.GetTable("test"); - session.SQL("CREATE UNIQUE INDEX myIndex ON test.test (id)").Execute(); - var table2 = session2.GetSchema("test").GetTable("test"); - - ExecuteSQLStatement(session.SQL("START TRANSACTION")); - var rowResult = ExecuteSelectStatement(table.Select().Where("id = 1").LockShared()); - Assert.AreEqual(1, rowResult.FetchAll().Count, "Matching the document ID"); - - ExecuteSQLStatement(session2.SQL("START TRANSACTION")); - - // Should return immediately since document isn't locked. - rowResult = table2.Select().Where("id = 2").LockExclusive(LockContention.Default).Execute(); - Assert.AreEqual(1, rowResult.FetchAll().Count, "Matching the document ID"); - - // Session2 blocks as LockExclusive trying to access locked document - ExecuteSQLStatement(session2.SQL("SET SESSION innodb_lock_wait_timeout=1")); - Exception ex = Assert.Throws(() => ExecuteSelectStatement(table2.Select().Where("id = 1").LockExclusive(LockContention.Default))); - Assert.AreEqual("Lock wait timeout exceeded; try restarting transaction", ex.Message); - - // Session2 blocks due to to LockShared() not allowing to modify locked documents. - Result result1; - ex = Assert.Throws(() => result1 = table2.Update().Where("id = 1").Set("a", 2).Execute()); - Assert.AreEqual("Lock wait timeout exceeded; try restarting transaction", ex.Message); - - // Session2 returns immediately as session is committed. - session.Commit(); - var result = table2.Update().Where("id = 1").Set("a", 2).Execute(); - Assert.AreEqual(1, result.AffectedItemsCount); - - ExecuteSQLStatement(session.SQL("ROLLBACK")); - ExecuteSQLStatement(session2.SQL("ROLLBACK")); - } - } - - [Test, Description("Reading exclusively locked document in a table using lock_shared with NOWAIT waiting option. ")] - public void SharedLockAfterExclusiveLockWithNoWait() - { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher"); - - session.SQL("DROP TABLE IF EXISTS test.test").Execute(); - session.SQL("CREATE TABLE test.test (id INT, a INT)").Execute(); - var table1 = testSchema.GetTable("test"); - table1.Insert("id", "a").Values(1, 1).Values(2, 2).Values(3, 3).Execute(); - ExecuteSQLStatement(session.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); - using (var session2 = MySQLX.GetSession(ConnectionString)) - { - ExecuteSQLStatement(session2.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); - var table = session.Schema.GetTable("test"); - session.SQL("CREATE UNIQUE INDEX myIndex ON test.test (id)").Execute(); - var table2 = session2.GetSchema("test").GetTable("test"); - - session.SQL("START TRANSACTION").Execute(); - var rowResult = table.Select().Where("id = 1").LockExclusive().Execute(); - Assert.AreEqual(1, rowResult.FetchAll().Count, "Matching the document ID"); - - session2.SQL("START TRANSACTION").Execute(); - // Should return immediately since document isn't locked. - rowResult = table2.Select().Where("id = 2").LockShared(LockContention.NoWait).Execute(); - Assert.AreEqual(1, rowResult.FetchAll().Count, "Matching the document ID"); - - // Session2 blocks due to to LockExclusive() not allowing to read locked documents. - ExecuteSQLStatement(session2.SQL("SET SESSION innodb_lock_wait_timeout=1")); - Assert.Throws(() => ExecuteSelectStatement(table2.Select().Where("id = 1").LockShared(LockContention.NoWait))); - - // Session2 blocks due to to LockExclusive() not allowing to modify locked documents. - Result result1; - Assert.Throws(() => result1 = table2.Update().Where("id = 1").Set("a", 2).Execute()); - - session.Commit(); - var result = table2.Update().Where("id = 1").Set("a", 2).Execute(); - Assert.AreEqual(1, result.AffectedItemsCount); - - ExecuteSQLStatement(session.SQL("ROLLBACK")); - ExecuteSQLStatement(session2.SQL("ROLLBACK")); - } - } - - [Test, Description("Testing Non ASCII characters for utf8mb4 characterset")] - public void NonAsciiCharsForUtf8mb4() - { - //Bug28261283 - string record = "{\"name\": \"New\",\"age\": 4 , "; - string name1 = "\u201C\u2199\u2197\u2196\u2198\u201D"; - string name2 = "{\"age\": 1, \"misc\": 1.2, \"name\": \"\u201C\u2199\u2197\u2196\u2198\u201D\"}"; - - session.SQL($"use {schemaName}").Execute(); - session.SQL("drop table if exists newTable").Execute(); - session.SQL("create table newTable(c1 varchar(200), c2 JSON) CHARACTER SET utf8mb4").Execute(); - var db = session.GetSchema(schemaName); - Table tabNew = db.GetTable("newTable"); - - tabNew.Insert("c1", "c2").Values("\u201C\u2199\u2197\u2196\u2198\u201D", "{ \"name\": \"\u201C\u2199\u2197\u2196\u2198\u201D\", \"age\": 1 , \"misc\": 1.2}").Execute(); - tabNew.Insert().Values("abcNew£¢€©§°√", "{ \"name\": \"abcNew£¢€©§°√\", \"age\": 2 , \"misc\": 1.2}").Execute(); - RowResult result = tabNew.Select("c1", "c2").Where("c1 ='\u201C\u2199\u2197\u2196\u2198\u201D'").Execute(); - var r1 = result.FetchOne(); - Assert.AreEqual(name1, r1[0].ToString());//"“↙↗↖↘”" - Assert.AreNotEqual(name2, r1[1].ToString());//"{\"age\": 1, \"misc\": 1.2, \"name\": \"??????????????????\"}" - var t = session.SQL("SELECT c1, CONVERT(c2 USING utf8mb4) FROM newTable WHERE c1 = '\u201C\u2199\u2197\u2196\u2198\u201D'").Execute(); - r1 = t.FetchOne(); - Assert.AreEqual(name1, r1[0].ToString());//"“↙↗↖↘”" - Assert.AreEqual(name2, r1[1].ToString());//"{\"age\": 1, \"misc\": 1.2, \"name\": \"??????????????????\"}" - - Collection coll = CreateCollection("test"); - - int klen = 1024 * 64; - string[] key = new string[klen]; - int dlen = 1024 * 100; - string[] data = new string[dlen]; - Array.Resize(ref key, 'S'); - Array.Resize(ref data, '$'); - string unicodeString = "Maths use \u03a0 (Pi) for calculations"; - // You can convert a string into a byte array - byte[] asciiBytes = Encoding.ASCII.GetBytes(unicodeString); - // You can convert a byte array into a char array - char[] asciiChars = Encoding.ASCII.GetChars(asciiBytes); - string asciiString = new string(asciiChars); - - record = record + "\""; - record = record + "\":\""; - record = record + asciiString; - record = record + "\"}"; - - Result r = coll.Add("{ \"name\": \"\u201C\u2199\u2197\u2196\u2198\u201D\", \"age\": 4 , \"misc\": 1.2}"). - Add("{ \"name\": \"xyz£¢€©§°√\", \"age\": 6 , \"misc\": 10}").Execute(); - var docs = coll.Find("name = '\u201C\u2199\u2197\u2196\u2198\u201D' and age>= 4 and age <= 6").Execute(); - DbDoc doc = docs.FetchOne(); - Assert.AreEqual(name1, doc["name"]); - session.SQL("drop table if exists test").Execute(); - session.SQL("drop table if exists newTable").Execute(); - } - - [Test, Description("Test MySQLX plugin Datatype Tests")] - public void DatatypesOnCreateTable() - { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher"); - - session.SQL($"use {schemaName}"); - session.SQL("create table test1(c1 int,c2 double GENERATED ALWAYS AS (c1*101/102) Stored COMMENT 'First Gen Col',c3 Json GENERATED ALWAYS AS (concat('{\"F1\":',c1,'}')) VIRTUAL COMMENT 'Second Gen /**/Col', c4 bigint GENERATED ALWAYS as (c1*10000) VIRTUAL UNIQUE KEY Comment '3rd Col' NOT NULL)").Execute(); - session.SQL("insert into test1(c1) values(1000)").Execute(); - RowResult r = session.GetSchema(schemaName).GetTable("test1").Select("c1").Execute(); - r.FetchAll(); - Assert.AreEqual("1000", r.Rows[0][0].ToString(), "Matching the values"); - session.SQL("drop table if exists test1").Execute(); - } - - [Test, Description("Test MySQLX plugin Table Expression using Where")] - public void TableExpressionWhereBindGroupBy() - { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher"); - - string match = null; - session.SQL("create table test1(name VARCHAR(40), age INT)").Execute(); - Table table = session.GetSchema(schemaName).GetTable("test1"); - - for (int i = 10; i < 30; i++) - { - int j = 1; - string name = RandomString(i); - var result = table.Insert("name", "age") - .Values(name, i) - .Execute(); - if (i == 28) - match = name; - Assert.AreEqual((ulong)j, result.AffectedItemsCount, "Matching the values"); - j = j + 1; - } - - var whereResult = table.Select("name", "age").Where("age == 28").Execute(); - int rowCount = whereResult.FetchAll().Count; - Assert.AreEqual(1, rowCount, "Matching the row count"); - Assert.AreEqual(match, whereResult.Rows.ToArray()[0][0].ToString(), "Matching the name"); - - whereResult = table.Select("name", "age").Where("age == 100").Execute(); - rowCount = whereResult.FetchAll().Count; - Assert.AreEqual(0, rowCount, "Matching that there is no such value "); - - whereResult = table.Select().Where("name like :name").Bind("nAme", "%ABCDEFGHIJ%").Execute(); - rowCount = whereResult.FetchAll().Count; - for (int i = 0; i < whereResult.Rows.Count; i++) - { - var res = whereResult.Rows.ToArray()[i][0]; - StringAssert.Contains("ABCDEFGHIJ", res.ToString()); - } - - whereResult = table.Select().Where("name like :name").Bind("nAme", "%ABCD%").Execute(); - rowCount = whereResult.FetchAll().Count; - for (int j = 0; j < whereResult.Rows.Count; j++) - { - var res = whereResult.Rows.ToArray()[j][0]; - StringAssert.Contains("ABCD", res.ToString()); - } - } - - [Test, Description("Test MySQLX plugin Table")] - public void TableSelectFetchValuesInOrder() - { - ExecuteSQL("drop table if exists test1"); - ExecuteSQL("create table test1(name VARCHAR(40), age INT)"); - Table table = session.GetSchema(schemaName).GetTable("test1"); - var result = table.Insert("name", "age") - .Values("MARK", 34) - .Execute(); - - Assert.AreEqual((ulong)1, result.AffectedItemsCount, "Matching the values"); - result = table.Insert("name", "age") - .Values("richie", 16) - .Execute(); - Assert.AreEqual((ulong)1, result.AffectedItemsCount, "Matching the values"); - var selectResult = table.Select().Execute(); - - while (selectResult.Next()) ; - Assert.AreEqual(2, selectResult.Rows.Count, "Matching the row count"); - Assert.AreEqual("MARK", selectResult.Rows.ToArray()[0][0].ToString(), "Matching the value MARK"); - Assert.AreEqual(34, (int)selectResult.Rows.ToArray()[0][1], "Matching the age 34"); - Assert.AreEqual("richie", selectResult.Rows.ToArray()[1][0].ToString(), "Matching the value richie"); - Assert.AreEqual(16, (int)selectResult.Rows.ToArray()[1][1], "Matching the age 16"); - - var result1 = testSchema.GetTable("test").Select().OrderBy("age desc").Execute(); - int rowCount = result1.FetchAll().Count; - for (int i = 0; i < rowCount; i++) - { - Assert.AreEqual("45", result1.Rows[0][2].ToString(), "Matching the values"); - Assert.AreEqual("38", result1.Rows[1][2].ToString(), "Matching the values"); - Assert.AreEqual("24", result1.Rows[2][2].ToString(), "Matching the values"); - } - - result1 = testSchema.GetTable("test").Select().OrderBy("age asc").Execute(); - rowCount = result1.FetchAll().Count; - for (int i = 0; i < rowCount; i++) - { - Assert.AreEqual("24", result1.Rows[0][2].ToString(), "Matching the values"); - Assert.AreEqual("38", result1.Rows[1][2].ToString(), "Matching the values"); - Assert.AreEqual("45", result1.Rows[2][2].ToString(), "Matching the values"); - } - } - - [Test, Description("Reading exclusively locked document in a table using lock_exclusive with NOWAIT waiting option. ")] - public void DoubleExclusiveLockWithNoWait() - { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher"); - - session.SQL("DROP TABLE IF EXISTS test.test").Execute(); - session.SQL("CREATE TABLE test.test (id INT, a INT)").Execute(); - var table1 = testSchema.GetTable("test"); - table1.Insert("id", "a").Values(1, 1).Values(2, 2).Values(3, 3).Execute(); - ExecuteSQLStatement(session.SQL("SET autocommit = 0")); - using (var session2 = MySQLX.GetSession(ConnectionString)) - { - ExecuteSQLStatement(session2.SQL("SET autocommit = 0")); - var table = testSchema.GetTable("test"); - session.SQL("CREATE UNIQUE INDEX myIndex ON test.test (id)").Execute(); - var table2 = session2.GetSchema("test").GetTable("test"); - - session.SQL("START TRANSACTION").Execute(); - var rowResult = table.Select().Where("id = 1").LockExclusive().Execute(); - Assert.AreEqual(1, rowResult.FetchAll().Count, "Matching the document ID"); - - session2.SQL("START TRANSACTION").Execute(); - // Should return immediately since document isn't locked. - rowResult = table2.Select().Where("id = 2").LockExclusive(LockContention.NoWait).Execute(); - Assert.AreEqual(1, rowResult.FetchAll().Count, "Matching the document ID"); - - // Session2 blocks due to to LockExclusive() not allowing to read locked documents. - ExecuteSQLStatement(session2.SQL("SET SESSION innodb_lock_wait_timeout=1")); - Assert.Throws(() => ExecuteSelectStatement(table2.Select().Where("id = 1").LockShared(LockContention.NoWait))); - - // Session2 blocks due to to LockExclusive() not allowing to modify locked documents. - Result result1; - Assert.Throws(() => result1 = table2.Update().Where("id = 1").Set("a", 2).Execute()); - - // Session2 returns immediately as session is committed. - session.Commit(); - var result = table2.Update().Where("id = 1").Set("a", 2).Execute(); - Assert.AreEqual(1, result.AffectedItemsCount); - session.SQL("ROLLBACK").Execute(); - session2.SQL("ROLLBACK").Execute(); - } - - ExecuteSQLStatement(session.SQL("SET autocommit = 1")); - } - - [Test, Description("Reading a locked document(lock_shared) in a table using lock_shared with NOWAIT waiting option. ")] - public void DoubleSharedLockWithNoWait() - { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher"); - - session.SQL("DROP TABLE IF EXISTS test.test").Execute(); - session.SQL("CREATE TABLE test.test (id INT, a INT)").Execute(); - var table1 = testSchema.GetTable("test"); - table1.Insert("id", "a").Values(1, 1).Values(2, 2).Values(3, 3).Execute(); - using (var session2 = MySQLX.GetSession(ConnectionString)) - { - var table = session.Schema.GetTable("test"); - var table2 = session2.GetSchema("test").GetTable("test"); - - session.SQL("START TRANSACTION").Execute(); - var rowResult = table.Select().Where("id = 1").LockShared().Execute(); - Assert.AreEqual(1, rowResult.FetchAll().Count, "Matching the document ID"); - - session2.SQL("START TRANSACTION").Execute(); - // Should return immediately since document isn't locked. - rowResult = table2.Select().Where("id = 2").LockShared(LockContention.NoWait).Execute(); - Assert.AreEqual(1, rowResult.FetchAll().Count, "Matching the document ID"); - - // Session2 doesnt block as LockShare trying to read locked(Lock_shared) document - session2.SQL("SET SESSION innodb_lock_wait_timeout=1").Execute(); - rowResult = table2.Select().Where("id = 1").LockShared(LockContention.NoWait).Execute(); - Assert.AreEqual(1, rowResult.FetchAll().Count, "Matching the document ID"); - - // Session2 blocks due to to LockShared() not allowing to modify locked documents. - Result result1; - Assert.Throws(() => result1 = table2.Update().Where("id = 1").Set("a", 2).Execute()); - - // Session2 returns immediately as session is committed. - session.Commit(); - var result = table2.Update().Where("id = 1").Set("a", 2).Execute(); - Assert.AreEqual(1, result.AffectedItemsCount); - session.SQL("ROLLBACK").Execute(); - session2.SQL("ROLLBACK").Execute(); - } - } - - [Test, Description("Reading a locked document(lock_shared) in a table using lock_shared with NOWAIT waiting option. ")] - public void ExclusiveLockAfterSharedLockWithNoWait() - { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher"); - - session.SQL("DROP TABLE IF EXISTS test.test").Execute(); - session.SQL("CREATE TABLE test.test (id INT, a INT)").Execute(); - var table1 = testSchema.GetTable("test"); - table1.Insert("id", "a").Values(1, 1).Values(2, 2).Values(3, 3).Execute(); - - using (var session2 = MySQLX.GetSession(ConnectionString)) - { - var table = session.Schema.GetTable("test"); - session.SQL("CREATE UNIQUE INDEX myIndex ON test.test (id)").Execute(); - var table2 = session2.GetSchema("test").GetTable("test"); - - session.SQL("START TRANSACTION").Execute(); - var rowResult = table.Select().Where("id = 1").LockShared().Execute(); - Assert.AreEqual(1, rowResult.FetchAll().Count, "Matching the document ID"); - - session2.SQL("START TRANSACTION").Execute(); - // Should return immediately since document isn't locked. - rowResult = table2.Select().Where("id = 2").LockExclusive(LockContention.NoWait).Execute(); - Assert.AreEqual(1, rowResult.FetchAll().Count, "Matching the document ID"); - - // Session2 blocks as LockExclusive() trying to access locked(LockShared) documents. - ExecuteSQLStatement(session2.SQL("SET SESSION innodb_lock_wait_timeout=1")); - Assert.Throws(() => ExecuteSelectStatement(table2.Select().Where("id = 1").LockExclusive(LockContention.NoWait))); - - // Session2 blocks due to to LockShared() not allowing to modify locked documents. - Result result1; - Assert.Throws(() => result1 = table2.Update().Where("id = 1").Set("a", 2).Execute()); - - // Session2 returns immediately as session is committed. - session.Commit(); - var result = table2.Update().Where("id = 1").Set("a", 2).Execute(); - Assert.AreEqual(1, result.AffectedItemsCount); - session.SQL("ROLLBACK").Execute(); - session2.SQL("ROLLBACK").Execute(); - } - } - - [Test, Description("Reading exclusively locked document in a table using lock_shared with SKIPLOCK waiting option. ")] - public void SharedLockAfterExclusiveWithSkiplock() - { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher"); - - session.SQL("DROP TABLE IF EXISTS test.test").Execute(); - session.SQL("CREATE TABLE test.test (id INT, a INT)").Execute(); - var table1 = testSchema.GetTable("test"); - table1.Insert("id", "a").Values(1, 1).Values(2, 2).Values(3, 3).Execute(); - - using (var session2 = MySQLX.GetSession(ConnectionString)) - { - var table = session.Schema.GetTable("test"); - session.SQL("CREATE UNIQUE INDEX myIndex ON test.test (id)").Execute(); - var table2 = session2.GetSchema("test").GetTable("test"); - - session.SQL("START TRANSACTION").Execute(); - var rowResult = table.Select().Where("id = 1").LockExclusive().Execute(); - Assert.AreEqual(1, rowResult.FetchAll().Count, "Matching the document ID"); - - session2.SQL("START TRANSACTION").Execute(); - // Should return immediately since document isn't locked. - rowResult = table2.Select().Where("id = 2").LockShared(LockContention.NoWait).Execute(); - Assert.AreEqual(1, rowResult.FetchAll().Count, "Matching the document ID"); - - // Session2 blocks due to to LockExclusive() not allowing to read locked documents. - ExecuteSQLStatement(session2.SQL("SET SESSION innodb_lock_wait_timeout=1")); - rowResult = table2.Select().Where("id = 1").LockShared(LockContention.SkipLocked).Execute(); - Assert.AreEqual(0, rowResult.FetchAll().Count, "Matching the document ID"); - - // Session2 blocks due to to LockExclusive() not allowing to modify locked documents. - Result result1; - Assert.Throws(() => result1 = table2.Update().Where("id = 1").Set("a", 2).Execute()); - - // Session2 returns immediately as session is committed. - session.Commit(); - var result = table2.Update().Where("id = 1").Set("a", 2).Execute(); - Assert.AreEqual(1, (int)result.AffectedItemsCount, "Matching the record count"); - - session.SQL("ROLLBACK").Execute(); - session2.SQL("ROLLBACK").Execute(); - } - } - - [Test, Description("Reading exclusively locked document in a table using lock_exclusive with SKIPLOCK waiting option.")] - public void DoubleExclusiveLockWithSkiplock() - { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher"); - - session.SQL("DROP TABLE IF EXISTS test.test").Execute(); - session.SQL("CREATE TABLE test.test (id INT, a INT)").Execute(); - var table1 = testSchema.GetTable("test"); - table1.Insert("id", "a").Values(1, 1).Values(2, 2).Values(3, 3).Execute(); - - using (var session2 = MySQLX.GetSession(ConnectionString)) - { - var table = session.Schema.GetTable("test"); - session.SQL("CREATE UNIQUE INDEX myIndex ON test.test (id)").Execute(); - var table2 = session2.GetSchema("test").GetTable("test"); - - session.SQL("START TRANSACTION").Execute(); - var rowResult = table.Select().Where("id = 1").LockExclusive().Execute(); - Assert.AreEqual(1, rowResult.FetchAll().Count, "Matching the document ID"); - - session2.SQL("START TRANSACTION").Execute(); - // Should return immediately since document isn't locked. - rowResult = table2.Select().Where("id = 2").LockExclusive(LockContention.SkipLocked).Execute(); - Assert.AreEqual(1, rowResult.FetchAll().Count, "Matching the document ID"); - - // Session2 doesn't block as SKIPLOCK used - ExecuteSQLStatement(session2.SQL("SET SESSION innodb_lock_wait_timeout=1")); - rowResult = table2.Select().Where("id = 1").LockExclusive(LockContention.SkipLocked).Execute(); - Assert.AreEqual(0, rowResult.FetchAll().Count, "Matching the document ID"); - // Session2 blocks due to to LockExclusive() not allowing to modify locked documents. - Result result1; - Assert.Throws(() => result1 = table2.Update().Where("id = 1").Set("a", 2).Execute()); - - // Session2 returns immediately as session is committed. - session.Commit(); - var result = table2.Update().Where("id = 1").Set("a", 2).Execute(); - Assert.AreEqual(1, (int)result.AffectedItemsCount, "Matching the record count"); - session.SQL("ROLLBACK").Execute(); - session2.SQL("ROLLBACK").Execute(); - } - } - - [Test, Description("Reading a locked document(lock_shared) in a table using lock_shared with SKIPLOCK waiting option. ")] - public void DoubleSharedLockWithSkiplock() - { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher"); - - session.SQL("DROP TABLE IF EXISTS test.test").Execute(); - session.SQL("CREATE TABLE test.test (id INT, a INT)").Execute(); - var table1 = testSchema.GetTable("test"); - table1.Insert("id", "a").Values(1, 1).Values(2, 2).Values(3, 3).Execute(); - - using (var session2 = MySQLX.GetSession(ConnectionString)) - { - var table = session.Schema.GetTable("test"); - var table2 = session2.GetSchema("test").GetTable("test"); - - session.SQL("START TRANSACTION").Execute(); - var rowResult = table.Select().Where("id = 1").LockShared().Execute(); - Assert.AreEqual(1, rowResult.FetchAll().Count, "Matching the document ID"); - - session2.SQL("START TRANSACTION").Execute(); - // Should return immediately since document isn't locked. - rowResult = table2.Select().Where("id = 2").LockShared(LockContention.SkipLocked).Execute(); - Assert.AreEqual(1, rowResult.FetchAll().Count, "Matching the document ID"); - - // Session2 doesn't block as SKIPLOCK being used - ExecuteSQLStatement(session2.SQL("SET SESSION innodb_lock_wait_timeout=1")); - rowResult = table2.Select().Where("id = 1").LockShared(LockContention.SkipLocked).Execute(); - Assert.AreEqual(1, rowResult.FetchAll().Count, "Matching the document ID"); - - // Session2 blocks due to to LockShared() not allowing to modify locked documents. - Result result1; - Assert.Throws(() => result1 = table2.Update().Where("id = 1").Set("a", 2).Execute()); - - // Session2 returns immediately as session is committed. - session.Commit(); - var result = table2.Update().Where("id = 1").Set("a", 2).Execute(); - Assert.AreEqual(1, (int)result.AffectedItemsCount, "Matching the record count"); - session.SQL("ROLLBACK").Execute(); - session2.SQL("ROLLBACK").Execute(); - } - } - - [Test, Description("Reading a locked document(lock_shared) in a table using lock_exclusive with SKIPLOCK waiting option.")] - public void ExclusiveLockAfterSharedLockWithSkiplock() - { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher"); - - session.SQL("DROP TABLE IF EXISTS test.test").Execute(); - session.SQL("CREATE TABLE test.test (id INT, a INT)").Execute(); - var table1 = testSchema.GetTable("test"); - table1.Insert("id", "a").Values(1, 1).Values(2, 2).Values(3, 3).Execute(); - - using (var session2 = MySQLX.GetSession(ConnectionString)) - { - var table = session.Schema.GetTable("test"); - session.SQL("CREATE UNIQUE INDEX myIndex ON test.test (id)").Execute(); - var table2 = session2.GetSchema("test").GetTable("test"); - - session.SQL("START TRANSACTION").Execute(); - var rowResult = table.Select().Where("id = 1").LockShared().Execute(); - Assert.AreEqual(1, rowResult.FetchAll().Count, "Matching the document ID"); - - session2.SQL("START TRANSACTION").Execute(); - // Should return immediately since document isn't locked. - rowResult = table2.Select().Where("id = 2").LockExclusive(LockContention.SkipLocked).Execute(); - Assert.AreEqual(1, rowResult.FetchAll().Count, "Matching the document ID"); - - // Session2 doesn't block as SKIPLOCK being used - ExecuteSQLStatement(session2.SQL("SET SESSION innodb_lock_wait_timeout=1")); - rowResult = table2.Select().Where("id = 1").LockExclusive(LockContention.SkipLocked).Execute(); - Assert.AreEqual(0, rowResult.FetchAll().Count, "Matching the document ID"); - - // Session2 blocks due to to LockExclusive() not allowing to modify locked documents. - Result result1; - Assert.Throws(() => result1 = table2.Update().Where("id = 1").Set("a", 2).Execute()); - - // Session2 returns immediately as session is committed. - session.Commit(); - var result = table2.Update().Where("id = 1").Set("a", 2).Execute(); - Assert.AreEqual(1, (int)result.AffectedItemsCount, "Matching the record count"); - session.SQL("ROLLBACK").Execute(); - session2.SQL("ROLLBACK").Execute(); - } - } - - [Test, Description("Reading an exclusively locked document in a table using lock_shared without any waiting option. ")] - public void ExclusiveLockBeforeSharedLockWithoutAwaiting() - { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher"); - - session.SQL("DROP TABLE IF EXISTS test.test").Execute(); - session.SQL("CREATE TABLE test.test (id INT, a INT)").Execute(); - var table1 = testSchema.GetTable("test"); - table1.Insert("id", "a").Values(1, 1).Values(2, 2).Values(3, 3).Execute(); - - using (var session2 = MySQLX.GetSession(ConnectionString)) - { - var table = session.Schema.GetTable("test"); - session.SQL("CREATE UNIQUE INDEX myIndex ON test.test (id)").Execute(); - var table2 = session2.GetSchema("test").GetTable("test"); - - session.SQL("START TRANSACTION").Execute(); - var rowResult = table.Select().Where("id = 1").LockExclusive().Execute(); - Assert.AreEqual(1, rowResult.FetchAll().Count, "Matching the document ID"); - - session2.SQL("START TRANSACTION").Execute(); - // Should return immediately since document isn't locked. - rowResult = table2.Select().Where("id = 2").LockShared().Execute(); - Assert.AreEqual(1, rowResult.FetchAll().Count, "Matching the document ID"); - - // Session2 blocks due to to LockExclusive() not allowing to read locked documents. - ExecuteSQLStatement(session2.SQL("SET SESSION innodb_lock_wait_timeout=1")); - Assert.Throws(() => ExecuteSelectStatement(table2.Select().Where("id = 1").LockShared())); - - // Session2 blocks due to to LockExclusive() not allowing to modify locked documents. - Result result1; - Assert.Throws(() => result1 = table2.Update().Where("id = 1").Set("a", 2).Execute()); - - // Session2 returns immediately as session is committed. - session.Commit(); - var result = table2.Update().Where("id = 1").Set("a", 2).Execute(); - Assert.AreEqual(1, (int)result.AffectedItemsCount, "Matching the record count"); - session.SQL("ROLLBACK").Execute(); - session2.SQL("ROLLBACK").Execute(); - } - } - - [Test, Description("Reading an exclusively locked document in a table using lock_exclusive without any waiting option.")] - public void DoubleExclusiveLockWithoutWaiting() - { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher"); - - using (var session2 = MySQLX.GetSession(ConnectionString)) - { - var table = session.Schema.GetTable("test"); - session.SQL("CREATE UNIQUE INDEX myIndex ON test.test (id)").Execute(); - var table2 = session2.GetSchema("test").GetTable("test"); - - session.SQL("START TRANSACTION").Execute(); - var rowResult = table.Select().Where("id = 1").LockExclusive().Execute(); - Assert.AreEqual(1, rowResult.FetchAll().Count, "Matching the document ID"); - - session2.SQL("START TRANSACTION").Execute(); - // Should return immediately since document isn't locked. - rowResult = table2.Select().Where("id = 2").LockExclusive().Execute(); - Assert.AreEqual(1, rowResult.FetchAll().Count, "Matching the document ID"); - - // Session2 blocks due to to LockExclusive() not allowing to read locked documents. - ExecuteSQLStatement(session2.SQL("SET SESSION innodb_lock_wait_timeout=1")); - Assert.Throws(() => ExecuteSelectStatement(table2.Select().Where("id = 1").LockExclusive())); - - // Session2 blocks due to to LockExclusive() not allowing to modify locked documents. - Result result1; - Assert.Throws(() => result1 = table2.Update().Where("id = 1").Set("age", 2).Execute()); - - // Session2 returns immediately as session is committed. - session.Commit(); - var result = table2.Update().Where("id = 1").Set("age", 2).Execute(); - Assert.AreEqual(1, (int)result.AffectedItemsCount, "Matching the record count"); - session.SQL("ROLLBACK").Execute(); - session2.SQL("ROLLBACK").Execute(); - } - } - - [Test, Description("Reading a locked document(lock_shared) in a table using lock_shared without any waiting option.")] - public void DoubleSharedLockWithoutWaiting() - { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher"); - - session.SQL("DROP TABLE IF EXISTS test.test").Execute(); - session.SQL("CREATE TABLE test.test (id INT, a INT)").Execute(); - var table1 = testSchema.GetTable("test"); - table1.Insert("id", "a").Values(1, 1).Values(2, 2).Values(3, 3).Execute(); - - using (var session2 = MySQLX.GetSession(ConnectionString)) - { - var table = session.Schema.GetTable("test"); - var table2 = session2.GetSchema("test").GetTable("test"); - - session.SQL("START TRANSACTION").Execute(); - var rowResult = table.Select().Where("id = 1").LockShared().Execute(); - Assert.AreEqual(1, rowResult.FetchAll().Count, "Matching the document ID"); - - session2.SQL("START TRANSACTION").Execute(); - // Should return immediately since document isn't locked. - rowResult = table2.Select().Where("id = 2").LockShared().Execute(); - Assert.AreEqual(1, rowResult.FetchAll().Count, "Matching the document ID"); - - ExecuteSQLStatement(session2.SQL("SET SESSION innodb_lock_wait_timeout=1")); - rowResult = table2.Select().Where("id = 1").LockShared().Execute(); - Assert.AreEqual(1, rowResult.FetchAll().Count, "Matching the document ID"); - - // Session2 blocks due to to LockExclusive() not allowing to modify locked documents. - Result result1; - Assert.Throws(() => result1 = table2.Update().Where("id = 1").Set("a", 2).Execute()); - - // Session2 returns immediately as session is committed. - session.Commit(); - var result = table2.Update().Where("id = 1").Set("a", 2).Execute(); - Assert.AreEqual(1, (int)result.AffectedItemsCount, "Matching the record count"); - session.SQL("ROLLBACK").Execute(); - session2.SQL("ROLLBACK").Execute(); - } - } - - [Test, Description("Reading a locked document(lock_shared) in a table using lock_exclusive without any waiting option. ")] - public void SharedLockBeforeExclusiveLockWithoutWaiting() - { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher"); - - session.SQL("DROP TABLE IF EXISTS test.test").Execute(); - session.SQL("CREATE TABLE test.test (id INT, a INT)").Execute(); - var table1 = testSchema.GetTable("test"); - table1.Insert("id", "a").Values(1, 1).Values(2, 2).Values(3, 3).Execute(); - - using (var session2 = MySQLX.GetSession(ConnectionString)) - { - var table = session.Schema.GetTable("test"); - session.SQL("CREATE UNIQUE INDEX myIndex ON test.test (id)").Execute(); - var table2 = session2.GetSchema("test").GetTable("test"); - - session.SQL("START TRANSACTION").Execute(); - var rowResult = table.Select().Where("id = 1").LockShared().Execute(); - Assert.AreEqual(1, rowResult.FetchAll().Count, "Matching the document ID"); - - session2.SQL("START TRANSACTION").Execute(); - // Should return immediately since document isn't locked. - rowResult = table2.Select().Where("id = 2").LockExclusive().Execute(); - Assert.AreEqual(1, rowResult.FetchAll().Count, "Matching the document ID"); - - // Session2 blocks as LockExclusive() is trying to read locked documents. - ExecuteSQLStatement(session2.SQL("SET SESSION innodb_lock_wait_timeout=1")); - Assert.Throws(() => ExecuteSelectStatement(table2.Select().Where("id = 1").LockExclusive())); - - // Session2 blocks due to to LockShared() not allowing to modify locked documents. - Result result1; - Assert.Throws(() => result1 = table2.Update().Where("id = 1").Set("a", 2).Execute()); - - // Session2 returns immediately as session is committed. - session.Commit(); - var result = table2.Update().Where("id = 1").Set("a", 2).Execute(); - Assert.AreEqual(1, (int)result.AffectedItemsCount, "Matching the record count"); - session.SQL("ROLLBACK").Execute(); - session2.SQL("ROLLBACK").Execute(); - } - } - - [Test, Description("Reading a locked document(shared/exclusive) in a table using SKIPLOCK and NOWAIT waiting options when CRUD is happening parallely")] - public void SingleLockExclusiveWithNoWaitAndSkip() - { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher"); - - session.SQL("DROP TABLE IF EXISTS test.test").Execute(); - session.SQL("CREATE TABLE test.test (id INT, a INT)").Execute(); - var table1 = testSchema.GetTable("test"); - table1.Insert("id", "a").Values(1, 1).Values(2, 2).Values(3, 3).Execute(); - - using (var session2 = MySQLX.GetSession(ConnectionString)) - { - var table = session.Schema.GetTable("test"); - session.SQL("CREATE UNIQUE INDEX myIndex ON test.test (id)").Execute(); - var table2 = session2.GetSchema("test").GetTable("test"); - - session.SQL("START TRANSACTION").Execute(); - var result1 = table.Update().Where("id = 1").Set("a", 2).Execute(); - - session2.SQL("START TRANSACTION").Execute(); - // Should return immediately since document isn't locked. - var rowResult1 = table2.Select().Where("id = 2").LockExclusive(LockContention.NoWait).Execute(); - Assert.AreEqual(1, rowResult1.FetchAll().Count, "Matching the document ID"); - - // Session2 blocks due to to LockExclusive() not allowing to read locked documents. - ExecuteSQLStatement(session2.SQL("SET SESSION innodb_lock_wait_timeout=1")); - Assert.Throws(() => ExecuteSelectStatement(table2.Select().Where("id = 1").LockExclusive(LockContention.NoWait))); - Assert.Throws(() => ExecuteSelectStatement(table2.Select().Where("id = 1").LockShared(LockContention.NoWait))); - - var rowResult = table2.Select().Where("id = 1").LockShared(LockContention.SkipLocked).Execute(); - Assert.AreEqual(0, rowResult.FetchAll().Count, "Matching the document ID"); - - rowResult = table2.Select().Where("id = 1").LockExclusive(LockContention.SkipLocked).Execute(); - Assert.AreEqual(0, rowResult.FetchAll().Count, "Matching the document ID"); - - session.SQL("ROLLBACK").Execute(); - session2.SQL("ROLLBACK").Execute(); - } - } - - [Test, Description("Multiple lock calls on a document in table using NOWAIT and SKIPLOCK waiting options")] - public void ChainedExclusiveLocks() - { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher"); - - session.SQL("DROP TABLE IF EXISTS test.test").Execute(); - session.SQL("CREATE TABLE test.test (id INT, a INT)").Execute(); - var table1 = testSchema.GetTable("test"); - table1.Insert("id", "a").Values(1, 1).Values(2, 2).Values(3, 3).Execute(); - - using (var session2 = MySQLX.GetSession(ConnectionString)) - { - var table = session.Schema.GetTable("test"); - session.SQL("CREATE UNIQUE INDEX myIndex ON test.test (id)").Execute(); - var table2 = session2.GetSchema("test").GetTable("test"); - - session.SQL("START TRANSACTION").Execute(); - var rowResult = table.Select().Where("id = 1").LockShared().Execute(); - Assert.AreEqual(1, rowResult.FetchAll().Count, "Matching the document ID"); - - session2.SQL("START TRANSACTION").Execute(); - ExecuteSQLStatement(session2.SQL("SET SESSION innodb_lock_wait_timeout=1")); - Assert.Throws(() => rowResult = table2.Select().Where("id = 1").LockExclusive(LockContention.SkipLocked).LockExclusive(LockContention.NoWait).Execute()); - - Assert.Throws(() => ExecuteSelectStatement(table2.Select().Where("id = 1") - .LockExclusive(LockContention.SkipLocked) - .LockExclusive(LockContention.NoWait))); - - rowResult = table2.Select().Where("id = 1").LockExclusive(LockContention.SkipLocked).LockShared(LockContention.SkipLocked).Execute(); - Assert.AreEqual(1, rowResult.FetchAll().Count, "Matching the document ID"); - - rowResult = table2.Select().Where("id = 1").LockShared(LockContention.SkipLocked).LockExclusive(LockContention.SkipLocked).Execute(); - Assert.AreEqual(0, rowResult.FetchAll().Count, "Matching the document ID"); - session.SQL("ROLLBACK").Execute(); - session2.SQL("ROLLBACK").Execute(); - } - } - - [Test, Description("Test MySQLX plugin - MYSQLCNET 755 Table GetIncrementValue")] - public void TableGetAutoIncrementValue() - { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher"); - - session.SQL("CREATE TABLE address1" + - "(address_number1 MEDIUMINT NOT NULL AUTO_INCREMENT, " + - "address_number2 CHAR(100) NOT NULL, " + - "PRIMARY KEY (address_number1)" + ");").Execute(); - Table table = testSchema.GetTable("address1"); - var result = table.Insert("address_number1", "address_number2") - .Values(100, "Test the document id in address table") - .Execute(); - - var docId = result.AutoIncrementValue; - Assert.AreEqual("100", docId.ToString(), "Matching the value if already it is inserted"); - - result = table.Insert("address_number2") - .Values("Test the document id by 2nd insert without id in address table") - .Execute(); - docId = result.AutoIncrementValue; - Assert.AreEqual("101", docId.ToString(), "Matching the value if already it is inserted"); - - session.SQL("CREATE TABLE address2" + - "(address_number3 INT NOT NULL AUTO_INCREMENT, " + - "address_number4 CHAR(100) NOT NULL, " + - "PRIMARY KEY (address_number3)" + ");").Execute(); - table = testSchema.GetTable("address2"); - result = table.Insert("address_number4") - .Values("Test the document id in address table without unique id") - .Execute(); - - docId = result.AutoIncrementValue; - Assert.AreEqual("1", docId.ToString(), "Matching the auto increment value"); - - session.SQL("CREATE TABLE address3" + - "(address_number5 MEDIUMINT NOT NULL AUTO_INCREMENT, " + - "address_number6 CHAR(100) NOT NULL, " + - "PRIMARY KEY (address_number5)" + ");").Execute(); - table = testSchema.GetTable("address3"); - result = table.Insert("address_number5", "address_number6") - .Values(100, "Test multiple document ids in address table - 1st document") - .Values(200, "Test multiple document ids in address table - 2nd document") - .Values(300, "Test multiple document ids in address table - 3rd document") - .Execute(); - - docId = result.AutoIncrementValue; - Assert.AreEqual("300", docId.ToString(), "Matching the value if more than one documents inserted"); - - result = table.Insert("address_number6") - .Values("Test multiple document ids in address table - 4th document without ID") - .Values("Test multiple document ids in address table - 5th document without ID") - .Values("Test multiple document ids in address table - 6th document without ID") - .Execute(); - - docId = result.AutoIncrementValue; - Assert.AreEqual("301", docId.ToString(), "Matching the value if more than one documents inserted"); - - session.SQL("CREATE TABLE address4" + - "(address_number7 INT NOT NULL AUTO_INCREMENT, " + - "address_number8 CHAR(100) NOT NULL, " + - "PRIMARY KEY (address_number7)" + ");").Execute(); - table = testSchema.GetTable("address4"); - result = table.Insert("address_number8") - .Values("Test the document ids in address table without unique id - 1st document") - .Values("Test the document ids in address table without unique id - 2nd document") - .Values("Test the document ids in address table without unique id - 3rd document") - .Execute(); - - docId = result.AutoIncrementValue; - Assert.AreEqual("1", docId.ToString(), "Matching the auto increment value"); - - result = table.Insert("address_number8") - .Values("Test the document ids in address table without unique id - 4th document") - .Values("Test the document ids in address table without unique id - 5th document") - .Values("Test the document ids in address table without unique id - 6th document") - .Execute(); - - docId = result.AutoIncrementValue; - Assert.AreEqual("4", docId.ToString(), "Matching the auto increment value"); - - session.SQL("CREATE TABLE address5" + - "(address_number9 INT, " + - "address_number10 CHAR(100));").Execute(); - - session.SQL("ALTER TABLE address5 ADD c INT UNSIGNED NOT NULL AUTO_INCREMENT, ADD PRIMARY KEY(c)").Execute(); - - table = testSchema.GetTable("address5"); - result = table.Insert("address_number9", "address_number10") - .Values(100, "Test the document ids in address table without unique id - 1st document") - .Values(200, "Test the document ids in address table without unique id - 2nd document") - .Values(300, "Test the document ids in address table without unique id - 3rd document") - .Execute(); - - docId = result.AutoIncrementValue; - Assert.AreEqual("1", docId.ToString(), "Matching the auto increment value"); - session.SQL("drop table if exists address1").Execute(); - session.SQL("drop table if exists address2").Execute(); - session.SQL("drop table if exists address3").Execute(); - session.SQL("drop table if exists address4").Execute(); - session.SQL("drop table if exists address5").Execute(); - } - - [Test, Description("Test MySQLX plugin - MYSQLCNET_684 Fetchone returns null when no rows")] - public void FetchoneReturnsNullNoRows() - { - ExecuteSQL("CREATE TABLE test1(id INT)"); - ExecuteSQL("INSERT INTO test1 VALUES (1),(2),(3),(4)"); - ExecuteSQL("CREATE TABLE test2(id INT, val INT)"); - ExecuteSQL("INSERT INTO test2 VALUES (1,0)"); - var rowResult = testSchema.GetTable("test1").Select("id").Execute(); - foreach (var row in rowResult) - { - var result = testSchema.GetTable("test2").Update().Where("id=1").Set("val", row["id"]).Execute(); - //WL11843-Core API v1 alignment Changes - Assert.AreEqual(1, result.AffectedItemsCount, "Matching"); - } - - Row valRow = testSchema.GetTable("test2").Select("val").Execute().FetchOne(); - Assert.AreEqual("4", valRow[0].ToString(), "Matching"); - ExecuteSQL("DELETE FROM test2 WHERE id=1"); - valRow = testSchema.GetTable("test2").Select("val").Execute().FetchOne(); - Assert.IsNull(valRow); - ExecuteSQL("DROP TABLE if exists test1"); - ExecuteSQL("DROP TABLE if exists test2"); - } - - [Test, Description("Test MySQLX plugin - MYSQLCNET_684 Fetchone returns null when no table")] - public void FetchoneReturnsNullNoTable() - { - ExecuteSQL("CREATE TABLE test111(id INT)"); - ExecuteSQL("INSERT INTO test111 VALUES (1),(2),(3),(4)"); - ExecuteSQL("CREATE TABLE test222(id INT, val INT)"); - ExecuteSQL("INSERT INTO test222 VALUES (1,0)"); - var rowResult = testSchema.GetTable("test111").Select("id").Execute(); - foreach (var row in rowResult) - { - var result = testSchema.GetTable("test222").Update().Where("id=1").Set("val", row["id"]).Execute(); - //WL11843-Core API v1 alignment Changes - Assert.AreEqual(1, result.AffectedItemsCount, "Matching"); - } - - Row valRow = testSchema.GetTable("test222").Select("val").Execute().FetchOne(); - Assert.AreEqual("4", valRow[0].ToString(), "Matching"); - ExecuteSQL("DROP TABLE test222"); - Assert.Throws(() => valRow = testSchema.GetTable("test222").Select("val").Execute().FetchOne()); - ExecuteSQL("DROP TABLE IF EXISTS test111"); - } - - [Test, Description("MySQLX CNET-Test Table.Select() with exclusive lock and Table.Update() normal from two sessions. ")] - public void DoubleChainedLocksWithTwoSessions_S1() - { - if (!session.InternalSession.GetServerVersion().isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher"); - - session.SQL("SET autocommit = 0").Execute(); - using (var session2 = MySQLX.GetSession(ConnectionString)) - { - session2.SQL("SET autocommit = 0").Execute(); - var table = session.Schema.GetTable("test"); - session.SQL("CREATE UNIQUE INDEX myIndex ON test.test (id)").Execute(); - var table2 = session2.GetSchema("test").GetTable("test"); - - session.SQL("START TRANSACTION").Execute(); - var rowResult = table.Select().Where("id = 1").LockExclusive().Execute(); - Assert.AreEqual(1, rowResult.FetchAll().Count, "Matching the record ID"); - - session2.SQL("START TRANSACTION").Execute(); - // Should return immediately since document isn't locked. - rowResult = table2.Select().Where("id = 2").LockExclusive().Execute(); - Assert.AreEqual(1, rowResult.FetchAll().Count, "Matching the record ID"); - - // Session2 blocks due to to LockExclusive() not allowing to read locked documents. - ExecuteSQLStatement(session2.SQL("SET SESSION innodb_lock_wait_timeout=1")); - Assert.Throws(() => ExecuteSelectStatement(table2.Select().Where("id = 1").LockExclusive())); - - // Session2 blocks due to to LockExclusive() not allowing to modify locked documents. - Result result1; - Assert.Throws(() => result1 = table2.Update().Where("id = 1").Set("age", 2).Execute()); - - session.SQL("ROLLBACK").Execute(); - session2.SQL("ROLLBACK").Execute(); - } - - using (var session2 = MySQLX.GetSession(ConnectionString)) - { - session2.SQL("SET autocommit = 0").Execute(); - var table = session.Schema.GetTable("test"); - var table2 = session2.GetSchema("test").GetTable("test"); - - session.SQL("START TRANSACTION").Execute(); - var rowResult = table.Select().Where("id = 1").LockShared().LockExclusive().Execute(); - Assert.AreEqual(1, rowResult.FetchAll().Count, "Matching the record ID"); - - session2.SQL("START TRANSACTION").Execute(); - // Should return immediately since document isn't locked. - rowResult = table2.Select().Where("id = 2").LockShared().LockExclusive().Execute(); - Assert.AreEqual(1, rowResult.FetchAll().Count, "Matching the record ID"); - - // Session2 blocks due to to LockExclusive() not allowing to read locked documents. - ExecuteSQLStatement(session2.SQL("SET SESSION innodb_lock_wait_timeout=1")); - Assert.Throws(() => ExecuteSelectStatement(table2.Select().Where("id = 1").LockShared().LockExclusive())); - - // Session2 blocks due to to LockExclusive() not allowing to modify locked documents. - Result result1; - Assert.Throws(() => result1 = table2.Update().Where("id = 1").Set("age", 2).Execute()); - session.SQL("ROLLBACK").Execute(); - session2.SQL("ROLLBACK").Execute(); - } - session.SQL("SET autocommit = 1").Execute(); - } - - [Test, Description("MySQLX CNET-Test Table.Select() with shared lock and Table.Update() normal from two sessions. ")] - public void DoubleChainedLocksWithTwoSessions_S2() - { - if (!session.InternalSession.GetServerVersion().isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher"); - - session.SQL("SET autocommit = 0").Execute(); - using (var session2 = MySQLX.GetSession(ConnectionString)) - { - session2.SQL("SET autocommit = 0").Execute(); - var table = session.Schema.GetTable("test"); - session.SQL("CREATE UNIQUE INDEX myIndex ON test.test (id)").Execute(); - var table2 = session2.GetSchema("test").GetTable("test"); - - session.SQL("START TRANSACTION").Execute(); - var rowResult = table.Select().Where("id = 1").LockShared().Execute(); - Assert.AreEqual(1, rowResult.FetchAll().Count, "Matching the record ID"); - - session2.SQL("START TRANSACTION").Execute(); - // Should return immediately since document isn't locked. - rowResult = table2.Select().Where("id = 1").Execute(); - Assert.AreEqual(1, rowResult.FetchAll().Count, "Matching the record ID"); - - // Session2 blocks due to to LockExclusive() not allowing to read locked documents. - ExecuteSQLStatement(session2.SQL("SET SESSION innodb_lock_wait_timeout=1")); - var result = table2.Update().Where("id = 2").Set("age", 30).Execute(); - Assert.AreEqual(1, (int)result.AffectedItemsCount, "Match being done"); - Assert.Throws(() => ExecuteSelectStatement(table2.Select().Where("id = 1").LockExclusive())); - - // Session2 blocks due to to LockExclusive() not allowing to modify locked documents. - Result result1; - Assert.Throws(() => result1 = table2.Update().Where("id = 1").Set("age", 2).Execute()); - - session.SQL("ROLLBACK").Execute(); - session2.SQL("ROLLBACK").Execute(); - } - - session.SQL("SET autocommit = 0").Execute(); - using (var session2 = MySQLX.GetSession(ConnectionString)) - { - session2.SQL("SET autocommit = 0").Execute(); - var table = session.Schema.GetTable("test"); - var table2 = session2.GetSchema("test").GetTable("test"); - - session.SQL("START TRANSACTION").Execute(); - var rowResult = table.Select().Where("id = 1").LockExclusive().LockShared().Execute(); - Assert.AreEqual(1, rowResult.FetchAll().Count, "Matching the record ID"); - - session2.SQL("START TRANSACTION").Execute(); - // Should return immediately since document isn't locked. - rowResult = table2.Select().Where("id = 1").Execute(); - Assert.AreEqual(1, rowResult.FetchAll().Count, "Matching the record ID"); - - // Session2 blocks due to to LockExclusive() not allowing to read locked documents. - session2.SQL("SET SESSION innodb_lock_wait_timeout=1").Execute(); - var result = table2.Update().Where("id = 2").Set("age", 30).Execute(); - Assert.AreEqual(1, (int)result.AffectedItemsCount, "Match being done"); - Assert.Throws(() => ExecuteSelectStatement(table2.Select().Where("id = 1").LockShared().LockExclusive())); - - // Session2 blocks due to to LockExclusive() not allowing to modify locked documents. - Result result1; - Assert.Throws(() => result1 = table2.Update().Where("id = 1").Set("age", 2).Execute()); - session.SQL("ROLLBACK").Execute(); - session2.SQL("ROLLBACK").Execute(); - } - session.SQL("SET autocommit = 1").Execute(); - } - - [Test, Description("MySQLX CNET-Test Table.Select() with exclusive lock from two sessions. ")] - public void SingleExclusiveLock() - { - if (!session.InternalSession.GetServerVersion().isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher"); - - session.SQL("SET autocommit = 0").Execute(); - using (var session2 = MySQLX.GetSession(ConnectionString)) - { - session2.SQL("SET autocommit = 0").Execute(); - var table = session.Schema.GetTable("test"); - session.SQL("CREATE UNIQUE INDEX myIndex ON test.test (id)").Execute(); - var table2 = session2.GetSchema("test").GetTable("test"); - - session.SQL("START TRANSACTION").Execute(); - var rowResult = table.Select().Where("id = 1").LockExclusive().Execute(); - Assert.AreEqual(1, rowResult.FetchAll().Count, "Matching the record ID"); - - session2.SQL("START TRANSACTION").Execute(); - // Should return immediately since document isn't locked. - rowResult = table2.Select().Where("id = 2").Execute(); - Assert.AreEqual(1, rowResult.FetchAll().Count, "Matching the record ID"); - - // Session2 blocks due to to LockExclusive() not allowing to read locked documents. - session2.SQL("SET SESSION innodb_lock_wait_timeout=1").Execute(); - Assert.Throws(() => ExecuteSelectStatement(table2.Select().Where("id = 1").LockExclusive())); - session.SQL("ROLLBACK").Execute(); - session2.SQL("ROLLBACK").Execute(); - } - session.SQL("SET autocommit = 1").Execute(); - } - - [Test, Description("MySQLX CNET-Test Table.Select() with exclusive lock and Table.Select() with exclusive lock from two sessions-Select multiple records")] - public void SingleTransactionWithLocks() - { - if (!session.InternalSession.GetServerVersion().isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher"); - - session.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED").Execute(); - using (var session2 = MySQLX.GetSession(ConnectionString)) - { - session2.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED").Execute(); - session.SQL("CREATE UNIQUE INDEX myIndex ON test.test (id)").Execute(); - var table = session.Schema.GetTable("test"); - var table2 = session2.GetSchema("test").GetTable("test"); - - session.SQL("START TRANSACTION").Execute(); - var rowResult = table.Select().Where("id in (1,3)").LockShared().Execute(); - Assert.AreEqual(2, rowResult.FetchAll().Count, "Matching the record ID"); - - rowResult = table2.Select().Where("id = 2").LockExclusive().Execute(); - Assert.AreEqual(1, rowResult.FetchAll().Count, "Matching the record ID"); - rowResult = table2.Select().Where("id = 2").LockShared().Execute(); - Assert.AreEqual(1, rowResult.FetchAll().Count, "Matching the record ID"); - // Session2 blocks due to to LockExclusive() not allowing to read locked documents. - session.SQL("SET SESSION innodb_lock_wait_timeout=1").Execute(); - table2.Select().Where("id = 2").LockExclusive().Execute(); - Assert.AreEqual(1, rowResult.FetchAll().Count, "Matching the record ID"); - session2.SQL("SET SESSION innodb_lock_wait_timeout=1").Execute(); - Assert.Throws(() => ExecuteSelectStatement(table2.Select().Where("id = 1").LockExclusive())); - - session2.SQL("SET SESSION innodb_lock_wait_timeout=1").Execute(); - // Session2 blocks due to to LockExclusive() not allowing to modify locked documents. - Assert.Throws(() => ExecuteUpdateStatement(table2.Update().Where("id = 1").Set("age", 2))); - - session.SQL("ROLLBACK").Execute(); - rowResult = table2.Select().Where("id = 1").LockExclusive().Execute(); - Assert.AreEqual(1, rowResult.FetchAll().Count, "Matching the document ID"); - session2.SQL("ROLLBACK").Execute(); - rowResult = table.Select().Where("id = 2").LockExclusive().Execute(); - Assert.AreEqual(1, rowResult.FetchAll().Count, "Matching the document ID"); - } - } - - [Test, Description("MySQLX CNET-Test Table.Select() with exclusive lock and Table.Update() normal from two sessions-50 Iterations")] - public void IteratedExclusiveLocks() - { - if (!Platform.IsWindows()) Assert.Ignore("This test is for Windows OS only"); - if (!session.Version.isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher"); - - session.SQL("SET autocommit = 0").Execute(); - session.SQL("CREATE UNIQUE INDEX myIndex ON test.test (id)").Execute(); - const int iterations = 30; - for (var i = 0; i < iterations; i++) - { - using (var session2 = MySQLX.GetSession(ConnectionString)) - { - session2.SQL("SET autocommit = 0").Execute(); - var table = session.Schema.GetTable("test"); - - var table2 = session2.GetSchema("test").GetTable("test"); - - session.SQL("START TRANSACTION").Execute(); - var rowResult = table.Select().Where("id = 1").LockExclusive().Execute(); - Assert.AreEqual(1, rowResult.FetchAll().Count, "Matching the record ID"); - - session2.SQL("START TRANSACTION").Execute(); - // Should return immediately since document isn't locked. - rowResult = table2.Select().Where("id = 2").LockExclusive().Execute(); - Assert.AreEqual(1, rowResult.FetchAll().Count, "Matching the record ID"); - - // Session2 blocks due to to LockExclusive() not allowing to read locked documents. - session2.SQL("SET SESSION innodb_lock_wait_timeout=1").Execute(); - Assert.Throws(() => ExecuteSelectStatement(table2.Select().Where("id = 1").LockExclusive())); - - // Session2 blocks due to to LockExclusive() not allowing to modify locked documents. - Result result1; - Assert.Throws(() => result1 = table2.Update().Where("id = 1").Set("age", 2).Execute()); - session.SQL("ROLLBACK").Execute(); - session2.SQL("ROLLBACK").Execute(); - } - } - session.SQL("SET autocommit = 1").Execute(); - } - - #endregion WL14389 - - #region Methods - public static string RandomString(int length) - { - const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - const string chars1 = "ABCDEFGHIJ"; - var random = new Random(); - if (length == 20) - { - return chars1; - } - else - { - return new string(Enumerable.Repeat(chars, length) - .Select(s => s[random.Next(s.Length)]).ToArray()); - } - - } - #endregion Methods - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data.Common; +using MySql.Data.MySqlClient; +using MySqlX.XDevAPI; +using MySqlX.XDevAPI.Common; +using MySqlX.XDevAPI.Relational; +using NUnit.Framework; +using NUnit.Framework.Legacy; +using System; +using System.Linq; +using System.Text; + +namespace MySqlX.Data.Tests.RelationalTests +{ + public class TableSelectTests : BaseTest + { + object[][] allRows = { + new object[] { 1, "jonh doe", 38, "{\"company\": \"xyz\", \"hobbies\": \"reading\", \"vehicle\": \"bike\"}" }, + new object[] { 2, "milton green", 45, "{\"company\": \"abc\", \"hobbies\": [\"boxing\", \"running\"], \"vehicle\": \"car\"}" }, + new object[] { 3, "larry smith", 24, "{\"company\": \"zxc\", \"hobbies\": \"painting\", \"vehicle\": \"boat\"}" } + }; + + [SetUp] + public void SetUp() + { + ExecuteSQL("CREATE TABLE test.test (id INT, name VARCHAR(45), age INT, additionalinfo JSON)"); + TableInsertStatement stmt = testSchema.GetTable("test").Insert(); + stmt.Values(allRows[0]); + stmt.Values(allRows[1]); + stmt.Values(allRows[2]); + Result result = ExecuteInsertStatement(stmt); + } + + [TearDown] + public void TearDown() + { + ExecuteSQL("DROP TABLE IF EXISTS test"); + ExecuteSQL("DROP TABLE IF EXISTS testDate"); + } + + [Test] + public void FetchOne() + { + Table t = testSchema.GetTable("test"); + Assert.That(ExecuteSelectStatement(t.Select("age")).FetchOne()["age"], Is.EqualTo(38)); + } + + private void MultiTableSelectTest(TableSelectStatement statement, object[][] expectedValues) + { + RowResult result = ExecuteSelectStatement(statement); + int rowCount = result.FetchAll().Count; + + Assert.That(rowCount, Is.EqualTo(expectedValues.Length)); + Assert.That(result.Rows.Count, Is.EqualTo(expectedValues.Length)); + for (int i = 0; i < expectedValues.Length; i++) + { + for (int j = 0; j < expectedValues[i].Length; j++) + { + Assert.That(result.Rows.ToArray()[i][j], Is.EqualTo(expectedValues[i][j])); + } + } + } + + [Test] + public void TableSelect() + { + var table = testSchema.GetTable("test"); + + MultiTableSelectTest(table.Select(), allRows); + MultiTableSelectTest(table.Select("name", "age"), + allRows.Select(c => new[] { c[1], c[2] }).ToArray()); + MultiTableSelectTest(table.Select("name", "age").Where("age == 38"), + allRows.Select(c => new[] { c[1], c[2] }).Where(c => (int)c[1] == 38).ToArray()); + MultiTableSelectTest(table.Select().Where("age == 45"), + allRows.Where(c => (int)c[2] == 45).ToArray()); + MultiTableSelectTest(table.Select().OrderBy("age"), + allRows.OrderBy(c => c[2]).ToArray()); + MultiTableSelectTest(table.Select().OrderBy("age desc"), + allRows.OrderByDescending(c => c[2]).ToArray()); + MultiTableSelectTest(table.Select().OrderBy("age desc, name"), + allRows.OrderByDescending(c => c[2]).ThenBy(c => c[1]).ToArray()); + MultiTableSelectTest(table.Select().Limit(1), + allRows.Take(1).ToArray()); + MultiTableSelectTest(table.Select().Limit(10).Offset(1), + allRows.Skip(1).Take(10).ToArray()); + MultiTableSelectTest(table.Select().Limit(1).Offset(1), + allRows.Skip(1).Take(1).ToArray()); + MultiTableSelectTest(table.Select().Where("name like :name").Bind("nAme", "%jon%"), + allRows.Where(c => c[1].ToString().Contains("jon")).ToArray()); + MultiTableSelectTest(table.Select().Where("name like :name").Bind("naMe", "%on%"), + allRows.Where(c => c[1].ToString().Contains("on")).ToArray()); + } + + [Test] + public void AllColumns() + { + var table = testSchema.GetTable("test"); + var select = ExecuteSelectStatement(table.Select("*, 42 as a_number, '43' as a_string")); + var rows = select.FetchAll(); + Assert.That(select.Columns.Count, Is.EqualTo(6)); + Assert.That(rows.Count, Is.EqualTo(allRows.Length)); + Assert.That(rows[0]["id"], Is.EqualTo(allRows[0][0])); + Assert.That(rows[0]["name"], Is.EqualTo(allRows[0][1])); + Assert.That(rows[0]["age"], Is.EqualTo(allRows[0][2])); + Assert.That(rows[0]["additionalinfo"], Is.EqualTo(allRows[0][3])); + Assert.That(rows[0]["a_number"], Is.EqualTo((sbyte)42)); + Assert.That(rows[0]["a_string"], Is.EqualTo("43")); + } + + [Test] + public void CountAllColumns() + { + var table = testSchema.GetTable("test"); + var select = ExecuteSelectStatement(table.Select("count(*) + 10")); + var rows = select.FetchAll(); + Assert.That(select.Columns, Has.One.Items); + Assert.That(rows, Has.One.Items); + Assert.That((long)rows[0][0], Is.EqualTo(allRows.Length + 10)); + } + + [Test] + public void MultipleBind() + { + object[] validationRow = allRows[1]; + var table = testSchema.GetTable("test"); + var select = ExecuteSelectStatement(table.Select().Where("Name = :nAme && Age = :aGe").Bind("agE", validationRow[2]).Bind("naMe", validationRow[1])); + var rows = select.FetchAll(); + Assert.That(rows, Has.One.Items); + Assert.That(rows[0]["namE"], Is.EqualTo(validationRow[1])); + Assert.That(rows[0]["AGe"], Is.EqualTo(validationRow[2])); + } + + [Test] + public void DatetimeAndMicroseconds() + { + ExecuteSQL("CREATE TABLE test.testDate (id INT, name VARCHAR(45), birthday DATETIME(6))"); + ExecuteSQL("INSERT INTO test.testDate VALUES(1, 'JOHN', '1985-10-21 16:34:22.123456')"); + ExecuteSQL("INSERT INTO test.testDate VALUES(1, 'BILL', '1985-10-21 10:00:45.987')"); + var rows = ExecuteSelectStatement(GetSession().GetSchema("test").GetTable("testDate").Select()).FetchAll(); + Assert.That(rows.Count, Is.EqualTo(2)); + Assert.That((DateTime)rows[0]["birthday"], Is.EqualTo(new DateTime(1985, 10, 21, 16, 34, 22).AddTicks(1234560))); + Assert.That((DateTime)rows[1]["birthday"], Is.EqualTo(new DateTime(1985, 10, 21, 10, 0, 45).AddTicks(9870000))); + } + + [Test] + public void DatetimeAndMilliseconds() + { + ExecuteSQL("CREATE TABLE test.testDate2 (id INT, name VARCHAR(45), birthday DATETIME(3))"); + ExecuteSQL("INSERT INTO test.testDate2 VALUES(1, 'JOHN', '1985-10-21 16:34:22.123456')"); + ExecuteSQL("INSERT INTO test.testDate2 VALUES(1, 'BILL', '1985-10-21 10:00:45.098')"); + var rows = ExecuteSelectStatement(GetSession().GetSchema("test").GetTable("testDate2").Select()).FetchAll(); + Assert.That(rows.Count, Is.EqualTo(2)); + Assert.That((DateTime)rows[0]["birthday"], Is.EqualTo(new DateTime(1985, 10, 21, 16, 34, 22).AddTicks(1230000))); + Assert.That((DateTime)rows[1]["birthday"], Is.EqualTo(new DateTime(1985, 10, 21, 10, 0, 45).AddTicks(980000))); + } + + [Test] + public void RowLockingNotSupportedInOlderVersions() + { + if (session.InternalSession.GetServerVersion().isAtLeast(8, 0, 3)) return; + + Table table = session.Schema.GetTable("test"); + + Exception ex = Assert.Throws(() => ExecuteSelectStatement(table.Select().LockShared())); + Assert.That(ex.Message, Is.EqualTo("This functionality is only supported from server version 8.0.3 onwards")); + + ex = Assert.Throws(() => ExecuteSelectStatement(table.Select().LockExclusive())); + Assert.That(ex.Message, Is.EqualTo("This functionality is only supported from server version 8.0.3 onwards")); + } + + [Test] + public void SimpleSharedLock() + { + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); + + ExecuteSQLStatement(session.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); + using (var session2 = MySQLX.GetSession(ConnectionString)) + { + ExecuteSQLStatement(session2.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); + Table table = session.Schema.GetTable("test"); + Table table2 = session2.GetSchema("test").GetTable("test"); + + ExecuteSQLStatement(session.SQL("START TRANSACTION")); + RowResult rowResult = ExecuteSelectStatement(table.Select().Where("id = 1").LockShared()); + Assert.That(rowResult.FetchAll(), Has.One.Items); + + ExecuteSQLStatement(session2.SQL("START TRANSACTION")); + // Should return immediately since row isn't locked. + rowResult = ExecuteSelectStatement(table2.Select().Where("id = 2").LockShared()); + Assert.That(rowResult.FetchAll(), Has.One.Items); + // Should return immediately due to LockShared() allows reading by other sessions. + rowResult = ExecuteSelectStatement(table2.Select().Where("id = 1").LockShared()); + Assert.That(rowResult.FetchAll(), Has.One.Items); + + ExecuteSQLStatement(session.SQL("ROLLBACK")); + ExecuteSQLStatement(session2.SQL("ROLLBACK")); + } + } + + [Test] + public void SimpleExclusiveLock() + { + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); + + ExecuteSQLStatement(session.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); + using (var session2 = MySQLX.GetSession(ConnectionString)) + { + ExecuteSQLStatement(session2.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); + Table table = session.Schema.GetTable("test"); + ExecuteSQLStatement(session.SQL("CREATE UNIQUE INDEX myIndex ON test.test (id)")); + Table table2 = session2.GetSchema("test").GetTable("test"); + + ExecuteSQLStatement(session.SQL("START TRANSACTION")); + RowResult rowResult = ExecuteSelectStatement(table.Select().Where("id = 1").LockExclusive()); + Assert.That(rowResult.FetchAll(), Has.One.Items); + + ExecuteSQLStatement(session2.SQL("START TRANSACTION")); + // Should return immediately since row isn't locked. + rowResult = ExecuteSelectStatement(table2.Select().Where("id = 2").LockExclusive()); + Assert.That(rowResult.FetchAll(), Has.One.Items); + // Session2 blocks due to to LockExclusive() not allowing to read locked rows. + ExecuteSQLStatement(session2.SQL("SET SESSION innodb_lock_wait_timeout=1")); + Exception ex = Assert.Throws(() => ExecuteSelectStatement(table2.Select().Where("id = 1").LockExclusive())); + Assert.That(ex.Message, Is.EqualTo("Lock wait timeout exceeded; try restarting transaction")); + + ExecuteSQLStatement(session.SQL("ROLLBACK")); + ExecuteSQLStatement(session2.SQL("ROLLBACK")); + } + } + + [Test] + public void SharedLockForbidsToModifyDocuments() + { + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); + + ExecuteSQLStatement(session.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); + using (var session2 = MySQLX.GetSession(ConnectionString)) + { + ExecuteSQLStatement(session2.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); + Table table = session.Schema.GetTable("test"); + Table table2 = session2.GetSchema("test").GetTable("test"); + + ExecuteSQLStatement(session.SQL("START TRANSACTION")); + RowResult rowResult = ExecuteSelectStatement(table.Select().Where("id = 1").LockShared()); + Assert.That(rowResult.FetchAll(), Has.One.Items); + + ExecuteSQLStatement(session2.SQL("START TRANSACTION")); + // Reading the same row is allowed with LockShared(). + rowResult = ExecuteSelectStatement(table2.Select().Where("id = 1")); + Assert.That(rowResult.FetchAll(), Has.One.Items); + + // Modify() is allowed for non-locked rows. + Result result = ExecuteUpdateStatement(table2.Update().Where("id = 2").Set("age", 2)); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1)); + // Session1 blocks, Modify() is not allowed for locked rows. + ExecuteSQLStatement(session2.SQL("SET SESSION innodb_lock_wait_timeout=1")); + Exception ex = Assert.Throws(() => ExecuteUpdateStatement(table2.Update().Where("id = 1").Set("age", 2))); + Assert.That(ex.Message, Is.EqualTo("Lock wait timeout exceeded; try restarting transaction")); + + ExecuteSQLStatement(session.SQL("ROLLBACK")); + // Modify() is allowed since row isn't locked anymore. + ExecuteUpdateStatement(table2.Update().Where("id = 1").Set("age", 2)); + ExecuteSQLStatement(session2.SQL("COMMIT")); + } + } + + [Test] + public void ExclusiveLockForbidsToModifyDocuments() + { + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); + + ExecuteSQLStatement(session.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); + using (var session2 = MySQLX.GetSession(ConnectionString)) + { + ExecuteSQLStatement(session2.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); + Table table = session.Schema.GetTable("test"); + Table table2 = session2.GetSchema("test").GetTable("test"); + + ExecuteSQLStatement(session.SQL("START TRANSACTION")); + RowResult rowResult = ExecuteSelectStatement(table.Select().Where("id = 1").LockExclusive()); + Assert.That(rowResult.FetchAll(), Has.One.Items); + + ExecuteSQLStatement(session2.SQL("START TRANSACTION")); + + // Modify() is allowed for non-locked rows. + Result result = ExecuteUpdateStatement(table2.Update().Where("id = 2").Set("age", 2)); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1)); + // Session1 blocks, Modify() is not allowed for locked rows. + ExecuteSQLStatement(session2.SQL("SET SESSION innodb_lock_wait_timeout=1")); + Exception ex = Assert.Throws(() => ExecuteUpdateStatement(table2.Update().Where("id = 1").Set("age", 2))); + Assert.That(ex.Message, Is.EqualTo("Lock wait timeout exceeded; try restarting transaction")); + + ExecuteSQLStatement(session.SQL("ROLLBACK")); + // Modify() is allowed since row isn't locked anymore. + ExecuteUpdateStatement(table2.Update().Where("id = 1").Set("age", 2)); + ExecuteSQLStatement(session2.SQL("COMMIT")); + } + } + + [Test] + public void SharedLockAfterExclusiveLock() + { + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); + + ExecuteSQLStatement(session.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); + using (var session2 = MySQLX.GetSession(ConnectionString)) + { + ExecuteSQLStatement(session2.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); + Table table = session.Schema.GetTable("test"); + ExecuteSQLStatement(session.SQL("CREATE UNIQUE INDEX myIndex ON test.test (id)")); + Table table2 = session2.GetSchema("test").GetTable("test"); + + ExecuteSQLStatement(session.SQL("START TRANSACTION")); + RowResult rowResult = ExecuteSelectStatement(table.Select().Where("id = 1").LockExclusive()); + Assert.That(rowResult.FetchAll(), Has.One.Items); + + ExecuteSQLStatement(session2.SQL("START TRANSACTION")); + // Should return immediately since row isn't locked. + rowResult = ExecuteSelectStatement(table2.Select().Where("id = 2").LockShared()); + Assert.That(rowResult.FetchAll(), Has.One.Items); + // Session2 blocks due to LockExclusive() not allowing to read locked rows. + ExecuteSQLStatement(session2.SQL("SET SESSION innodb_lock_wait_timeout=1")); + Exception ex = Assert.Throws(() => ExecuteSelectStatement(table2.Select().Where("id = 1").LockShared())); + Assert.That(ex.Message, Is.EqualTo("Lock wait timeout exceeded; try restarting transaction")); + + // Session unlocks rows. + ExecuteSQLStatement(session.SQL("ROLLBACK")); + // Row can now be recovered. + rowResult = ExecuteSelectStatement(table2.Select().Where("id = 1").LockShared()); + Assert.That(rowResult.FetchAll(), Has.One.Items); + ExecuteSQLStatement(session2.SQL("ROLLBACK")); + } + } + + [Test] + public void ExclusiveLockAfterSharedLock() + { + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); + + ExecuteSQLStatement(session.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); + using (var session2 = MySQLX.GetSession(ConnectionString)) + { + ExecuteSQLStatement(session2.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); + Table table = session.Schema.GetTable("test"); + ExecuteSQLStatement(session.SQL("CREATE UNIQUE INDEX myIndex ON test.test (id)")); + Table table2 = session2.GetSchema("test").GetTable("test"); + + ExecuteSQLStatement(session.SQL("START TRANSACTION")); + RowResult rowResult = ExecuteSelectStatement(table.Select().Where("id in (1, 3)").LockShared()); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(2)); + + ExecuteSQLStatement(session2.SQL("START TRANSACTION")); + // Should return immediately since row isn't locked. + rowResult = ExecuteSelectStatement(table2.Select().Where("id = 2").LockExclusive()); + // Should return immediately due to LockShared() allows reading by other sessions. + rowResult = ExecuteSelectStatement(table2.Select().Where("id = 2").LockShared()); + Assert.That(rowResult.FetchAll(), Has.One.Items); + // Session2 blocks due to to LockExclusive() not allowing to read locked rows. + ExecuteSQLStatement(session2.SQL("SET SESSION innodb_lock_wait_timeout=1")); + Exception ex = Assert.Throws(() => ExecuteSelectStatement(table2.Select().Where("id = 1").LockExclusive())); + Assert.That(ex.Message, Is.EqualTo("Lock wait timeout exceeded; try restarting transaction")); + + // Session unlocks rows. + ExecuteSQLStatement(session.SQL("ROLLBACK")); + rowResult = ExecuteSelectStatement(table2.Select().Where("id = 1").LockExclusive()); + Assert.That(rowResult.FetchAll(), Has.One.Items); + ExecuteSQLStatement(session2.SQL("ROLLBACK")); + } + } + + [Test] + public void SelectWithInOperator() + { + Table table = testSchema.GetTable("test"); + Assert.That(ExecuteSelectStatement(table.Select()).FetchAll().Count, Is.EqualTo(3)); + + Assert.That(ExecuteSelectStatement(table.Select().Where("name IN (\"jonh doe\", \"milton green\")")).FetchAll().Count, Is.EqualTo(2)); + Assert.That(ExecuteSelectStatement(table.Select().Where("name NOT IN (\"jonh doe\", \"milton green\")")).FetchAll(), Has.One.Items); + Assert.That(ExecuteSelectStatement(table.Select().Where("name IN (\"\", \"\")")).FetchAll(), Is.Empty); + Assert.That(ExecuteSelectStatement(table.Select().Where("\"\" IN (1,2,3)")).FetchAll(), Is.Empty); + Assert.That(ExecuteSelectStatement(table.Select().Where("name IN ('', '')")).FetchAll(), Is.Empty); + Assert.That(ExecuteSelectStatement(table.Select().Where("'' IN (1,2,3)")).FetchAll(), Is.Empty); + Assert.That(ExecuteSelectStatement(table.Select().Where("'' IN ('')")).FetchAll().Count, Is.EqualTo(3)); + + Assert.Throws(() => ExecuteSelectStatement(table.Select().Where("name NOT IN [\"jonh doe\", \"milton green\"]")).FetchAll()); + Assert.Throws(() => ExecuteSelectStatement(table.Select().Where("a IN [3]")).FetchAll()); + Assert.Throws(() => ExecuteSelectStatement(table.Select().Where("3 IN a")).FetchAll()); + } + + [Test] + public void Grouping() + { + ExecuteSQLStatement(GetSession().SQL("set sql_mode = 'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';")); + Table table = testSchema.GetTable("test"); + + // Insert additonal users. + object[][] additionalUsers = { + new object[] { 4, "mary weinstein", 24, null }, + new object[] { 5, "jerry pratt", 45, null }, + new object[] { 6, "hugh jackman", 20, null }, + new object[] { 7, "elizabeth olsen", 31, null } + }; + var statement = table.Insert(); + foreach (object[] user in additionalUsers) + { + statement = statement.Values(user); + } + + Assert.That(ExecuteInsertStatement(statement).AffectedItemsCount, Is.EqualTo(4)); + + // GroupBy returns 5 rows since age 45 and 24 is repeated. + var result = ExecuteSelectStatement(table.Select().GroupBy("age")); + Assert.That(result.FetchAll().Count, Is.EqualTo(5)); + + // GroupBy with null. + result = ExecuteSelectStatement(table.Select("id as ID", "name as Name", "age as Age").GroupBy(null)); + Assert.That(result.FetchAll().Count, Is.EqualTo(7)); + result = ExecuteSelectStatement(table.Select("id as ID", "name as Name", "age as Age").GroupBy(null, null)); + Assert.That(result.FetchAll().Count, Is.EqualTo(7)); + result = ExecuteSelectStatement(table.Select("id as ID", "name as Name", "age as Age").GroupBy(null, "age")); + Assert.That(result.FetchAll().Count, Is.EqualTo(5)); + + // Having operation. + // Having reduces the original 5 rows to 3 since 2 rows have a cnt=2, due to the repeated names. + result = ExecuteSelectStatement(table.Select("id", "count(name) as cnt", "age").GroupBy("age").Having("cnt = 1")); + Assert.That(result.FetchAll().Count, Is.EqualTo(3)); + + // Having with null. + result = ExecuteSelectStatement(table.Select("id as ID", "count(name) as cnt", "age as Age").GroupBy("age").Having(null)); + Assert.That(result.FetchAll().Count, Is.EqualTo(5)); + + // GroupBy with invalid field name. + var ex = Assert.Throws(() => ExecuteSelectStatement(table.Select("id as ID", "name as Name", "age as Age").GroupBy("none"))); + Assert.That(ex.Message, Is.EqualTo("Unknown column 'none' in 'group statement'")); + + // GroupBy with empty strings. + var ex2 = Assert.Throws(() => ExecuteSelectStatement(table.Select("id as ID", "name as Name", "age as Age").GroupBy(""))); + Assert.That(ex2.Message, Is.EqualTo("No more tokens when expecting one at token pos 0")); + ex2 = Assert.Throws(() => ExecuteSelectStatement(table.Select("id as ID", "name as Name", "age as Age").GroupBy(" "))); + Assert.That(ex2.Message, Is.EqualTo("No more tokens when expecting one at token pos 0")); + ex2 = Assert.Throws(() => ExecuteSelectStatement(table.Select("id as ID", "name as Name", "age as Age").GroupBy(string.Empty))); + Assert.That(ex2.Message, Is.EqualTo("No more tokens when expecting one at token pos 0")); + + // Having with invalid field name. + ex = Assert.Throws(() => ExecuteSelectStatement(table.Select("id as ID", "count(name) as cnt", "age as Age").GroupBy("age").Having("none = 1"))); + Assert.That(ex.Message, Is.EqualTo("Unknown column 'none' in 'having clause'")); + + // Having with empty strings. + ex2 = Assert.Throws(() => ExecuteSelectStatement(table.Select("id as ID", "count(name) as cnt", "age as Age").GroupBy("age").Having(""))); + Assert.That(ex2.Message, Is.EqualTo("Unable to parse query ''")); + Assert.That(ex2.InnerException.Message, Is.EqualTo("No more tokens when expecting one at token pos 0")); + ex2 = Assert.Throws(() => ExecuteSelectStatement(table.Select("id as ID", "count(name) as cnt", "age as Age").GroupBy("age").Having(" "))); + Assert.That(ex2.Message, Is.EqualTo("Unable to parse query ' '")); + Assert.That(ex2.InnerException.Message, Is.EqualTo("No more tokens when expecting one at token pos 0")); + ex2 = Assert.Throws(() => ExecuteSelectStatement(table.Select("id as ID", "count(name) as cnt", "age as Age").GroupBy("age").Having(string.Empty))); + Assert.That(ex2.Message, Is.EqualTo("Unable to parse query ''")); + Assert.That(ex2.InnerException.Message, Is.EqualTo("No more tokens when expecting one at token pos 0")); + } + + /// + /// Bug-29838254 + /// RESULTSET ERROR WHEN SELECT IS ISSUED WITH IN OPERATOR WITH BLANKS WITH 8.0.17 SERVER-C/NET8.0.17TRUNK + /// + [Test] + public void SelectWithInBlanksAndBrackets() + { + Session session = GetSession(); + Schema schema = session.GetSchema("test"); + object[][] allRows = + { + new object[] {1, "john doe", 38}, + new object[] {2, "milton green", 45}, + new object[] {3, "milton blue", 46}, + new object[] {4, "milton red", 47}, + new object[] {5, "milton yellow", 48}, + new object[] {6, "milton check", 49}, + new object[] {7, "milton pink", 14}, + new object[] {8, "milton beize", 25}, + new object[] {9, "milton silver", 35}, + new object[] {10, "milton city", 65} + }; + session.SQL("USE test").Execute(); + session.SQL("DROP table if exists test").Execute(); + var r = session.SQL("CREATE TABLE test.test(id INT,name VARCHAR(45), age INT)").Execute(); + var rows = r.HasData ? r.FetchAll() : null; + testSchema = session.GetSchema("test"); + var insertStatement = testSchema.GetTable("test").Insert(); + var rowsToInsert = 10; + for (var i = 0; i < rowsToInsert; i++) + insertStatement.Values(allRows[i]); + insertStatement.Execute(); + var table = testSchema.GetTable("test"); + int count = 0; + + //Exception expected when square brackets are used instead of parenthesis + Assert.Throws(() => table.Select().Where("name IN ['', ' ']").Execute().FetchAll()); + + // Test using parenthesis should return result + count = table.Select().Where("name IN (\"john doe\", \"milton green\")").Execute().FetchAll().Count; + Assert.That(count > 0); + + // Using parenthesis should return empty resultset for empty parameters + count = table.Select().Where("name IN ('', ' ')").Execute().FetchAll().Count; + Assert.That(count == 0); + } + + [TestCase(":hobbies IN additionalinfo->$.hobbies", "hobbies", "painting", 3)] + [TestCase(":hobbies IN additionalinfo->$.hobbies", "hobbies", "[\"boxing\", \"running\"]", 0)] + [TestCase("[\"boxing\", \"running\"] IN additionalinfo->$.hobbies", null, null, 2)] + [TestCase(":hobbies IN additionalinfo$.hobbies", "hobbies", "painting", 3)] + public void InOperatorBindingJson(string condition, string bind, string value, int id) + { + Table table = testSchema.GetTable("test"); + Assert.That(ExecuteSelectStatement(table.Select()).FetchAll().Count, Is.EqualTo(3)); + + var stmt = table.Select().Where(condition); + if (bind != null) stmt.Bind(bind, value); + var result = ExecuteSelectStatement(stmt).FetchAll(); + Assert.That(result.Count, Is.EqualTo(id == 0 ? 0 : 1)); + if (id > 0) + { + Assert.That(result[0]["id"], Is.EqualTo(id)); + } + } + + #region WL14389 + + [Test, Description("Reading locked document(lock_shared) in a table using lock_exclusive with DEFAULT waiting option.")] + public void ExclusiveLockAfterSharedLockDefaultWaiting() + { + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); + + session.SQL("DROP TABLE IF EXISTS test.test").Execute(); + session.SQL("CREATE TABLE test.test (id INT, a INT)").Execute(); + var table1 = testSchema.GetTable("test"); + table1.Insert("id", "a").Values(1, 1).Values(2, 2).Values(3, 3).Execute(); + ExecuteSQLStatement(session.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); + using (var session2 = MySQLX.GetSession(ConnectionString)) + { + ExecuteSQLStatement(session2.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); + var table = session.Schema.GetTable("test"); + session.SQL("CREATE UNIQUE INDEX myIndex ON test.test (id)").Execute(); + var table2 = session2.GetSchema("test").GetTable("test"); + + ExecuteSQLStatement(session.SQL("START TRANSACTION")); + var rowResult = ExecuteSelectStatement(table.Select().Where("id = 1").LockShared()); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + + ExecuteSQLStatement(session2.SQL("START TRANSACTION")); + + // Should return immediately since document isn't locked. + rowResult = table2.Select().Where("id = 2").LockExclusive(LockContention.Default).Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + + // Session2 blocks as LockExclusive trying to access locked document + ExecuteSQLStatement(session2.SQL("SET SESSION innodb_lock_wait_timeout=1")); + Exception ex = Assert.Throws(() => ExecuteSelectStatement(table2.Select().Where("id = 1").LockExclusive(LockContention.Default))); + Assert.That(ex.Message, Is.EqualTo("Lock wait timeout exceeded; try restarting transaction")); + + // Session2 blocks due to to LockShared() not allowing to modify locked documents. + Result result1; + ex = Assert.Throws(() => result1 = table2.Update().Where("id = 1").Set("a", 2).Execute()); + Assert.That(ex.Message, Is.EqualTo("Lock wait timeout exceeded; try restarting transaction")); + + // Session2 returns immediately as session is committed. + session.Commit(); + var result = table2.Update().Where("id = 1").Set("a", 2).Execute(); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1)); + + ExecuteSQLStatement(session.SQL("ROLLBACK")); + ExecuteSQLStatement(session2.SQL("ROLLBACK")); + } + } + + [Test, Description("Reading exclusively locked document in a table using lock_shared with NOWAIT waiting option. ")] + public void SharedLockAfterExclusiveLockWithNoWait() + { + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); + + session.SQL("DROP TABLE IF EXISTS test.test").Execute(); + session.SQL("CREATE TABLE test.test (id INT, a INT)").Execute(); + var table1 = testSchema.GetTable("test"); + table1.Insert("id", "a").Values(1, 1).Values(2, 2).Values(3, 3).Execute(); + ExecuteSQLStatement(session.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); + using (var session2 = MySQLX.GetSession(ConnectionString)) + { + ExecuteSQLStatement(session2.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")); + var table = session.Schema.GetTable("test"); + session.SQL("CREATE UNIQUE INDEX myIndex ON test.test (id)").Execute(); + var table2 = session2.GetSchema("test").GetTable("test"); + + session.SQL("START TRANSACTION").Execute(); + var rowResult = table.Select().Where("id = 1").LockExclusive().Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + + session2.SQL("START TRANSACTION").Execute(); + // Should return immediately since document isn't locked. + rowResult = table2.Select().Where("id = 2").LockShared(LockContention.NoWait).Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + + // Session2 blocks due to to LockExclusive() not allowing to read locked documents. + ExecuteSQLStatement(session2.SQL("SET SESSION innodb_lock_wait_timeout=1")); + Assert.Throws(() => ExecuteSelectStatement(table2.Select().Where("id = 1").LockShared(LockContention.NoWait))); + + // Session2 blocks due to to LockExclusive() not allowing to modify locked documents. + Result result1; + Assert.Throws(() => result1 = table2.Update().Where("id = 1").Set("a", 2).Execute()); + + session.Commit(); + var result = table2.Update().Where("id = 1").Set("a", 2).Execute(); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1)); + + ExecuteSQLStatement(session.SQL("ROLLBACK")); + ExecuteSQLStatement(session2.SQL("ROLLBACK")); + } + } + + [Test, Description("Testing Non ASCII characters for utf8mb4 characterset")] + public void NonAsciiCharsForUtf8mb4() + { + //Bug28261283 + string record = "{\"name\": \"New\",\"age\": 4 , "; + string name1 = "\u201C\u2199\u2197\u2196\u2198\u201D"; + string name2 = "{\"age\": 1, \"misc\": 1.2, \"name\": \"\u201C\u2199\u2197\u2196\u2198\u201D\"}"; + + session.SQL($"use {schemaName}").Execute(); + session.SQL("drop table if exists newTable").Execute(); + session.SQL("create table newTable(c1 varchar(200), c2 JSON) CHARACTER SET utf8mb4").Execute(); + var db = session.GetSchema(schemaName); + Table tabNew = db.GetTable("newTable"); + + tabNew.Insert("c1", "c2").Values("\u201C\u2199\u2197\u2196\u2198\u201D", "{ \"name\": \"\u201C\u2199\u2197\u2196\u2198\u201D\", \"age\": 1 , \"misc\": 1.2}").Execute(); + tabNew.Insert().Values("abcNew£¢€©§°√", "{ \"name\": \"abcNew£¢€©§°√\", \"age\": 2 , \"misc\": 1.2}").Execute(); + RowResult result = tabNew.Select("c1", "c2").Where("c1 ='\u201C\u2199\u2197\u2196\u2198\u201D'").Execute(); + var r1 = result.FetchOne(); + Assert.That(r1[0].ToString(), Is.EqualTo(name1));//"“↙↗↖↘”" + Assert.That(r1[1].ToString(), Is.Not.EqualTo(name2));//"{\"age\": 1, \"misc\": 1.2, \"name\": \"??????????????????\"}" + var t = session.SQL("SELECT c1, CONVERT(c2 USING utf8mb4) FROM newTable WHERE c1 = '\u201C\u2199\u2197\u2196\u2198\u201D'").Execute(); + r1 = t.FetchOne(); + Assert.That(r1[0].ToString(), Is.EqualTo(name1));//"“↙↗↖↘”" + Assert.That(r1[1].ToString(), Is.EqualTo(name2));//"{\"age\": 1, \"misc\": 1.2, \"name\": \"??????????????????\"}" + + Collection coll = CreateCollection("test"); + + int klen = 1024 * 64; + string[] key = new string[klen]; + int dlen = 1024 * 100; + string[] data = new string[dlen]; + Array.Resize(ref key, 'S'); + Array.Resize(ref data, '$'); + string unicodeString = "Maths use \u03a0 (Pi) for calculations"; + // You can convert a string into a byte array + byte[] asciiBytes = Encoding.ASCII.GetBytes(unicodeString); + // You can convert a byte array into a char array + char[] asciiChars = Encoding.ASCII.GetChars(asciiBytes); + string asciiString = new string(asciiChars); + + record = record + "\""; + record = record + "\":\""; + record = record + asciiString; + record = record + "\"}"; + + Result r = coll.Add("{ \"name\": \"\u201C\u2199\u2197\u2196\u2198\u201D\", \"age\": 4 , \"misc\": 1.2}"). + Add("{ \"name\": \"xyz£¢€©§°√\", \"age\": 6 , \"misc\": 10}").Execute(); + var docs = coll.Find("name = '\u201C\u2199\u2197\u2196\u2198\u201D' and age>= 4 and age <= 6").Execute(); + DbDoc doc = docs.FetchOne(); + Assert.That(doc["name"], Is.EqualTo(name1)); + session.SQL("drop table if exists test").Execute(); + session.SQL("drop table if exists newTable").Execute(); + } + + [Test, Description("Test MySQLX plugin Datatype Tests")] + public void DatatypesOnCreateTable() + { + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); + + session.SQL($"use {schemaName}"); + session.SQL("create table test1(c1 int,c2 double GENERATED ALWAYS AS (c1*101/102) Stored COMMENT 'First Gen Col',c3 Json GENERATED ALWAYS AS (concat('{\"F1\":',c1,'}')) VIRTUAL COMMENT 'Second Gen /**/Col', c4 bigint GENERATED ALWAYS as (c1*10000) VIRTUAL UNIQUE KEY Comment '3rd Col' NOT NULL)").Execute(); + session.SQL("insert into test1(c1) values(1000)").Execute(); + RowResult r = session.GetSchema(schemaName).GetTable("test1").Select("c1").Execute(); + r.FetchAll(); + Assert.That(r.Rows[0][0].ToString(), Is.EqualTo("1000"), "Matching the values"); + session.SQL("drop table if exists test1").Execute(); + } + + [Test, Description("Test MySQLX plugin Table Expression using Where")] + public void TableExpressionWhereBindGroupBy() + { + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); + + string match = null; + session.SQL("create table test1(name VARCHAR(40), age INT)").Execute(); + Table table = session.GetSchema(schemaName).GetTable("test1"); + + for (int i = 10; i < 30; i++) + { + int j = 1; + string name = RandomString(i); + var result = table.Insert("name", "age") + .Values(name, i) + .Execute(); + if (i == 28) + match = name; + Assert.That(result.AffectedItemsCount, Is.EqualTo((ulong)j), "Matching the values"); + j = j + 1; + } + + var whereResult = table.Select("name", "age").Where("age == 28").Execute(); + int rowCount = whereResult.FetchAll().Count; + Assert.That(rowCount, Is.EqualTo(1), "Matching the row count"); + Assert.That(whereResult.Rows.ToArray()[0][0].ToString(), Is.EqualTo(match), "Matching the name"); + + whereResult = table.Select("name", "age").Where("age == 100").Execute(); + rowCount = whereResult.FetchAll().Count; + Assert.That(rowCount, Is.EqualTo(0), "Matching that there is no such value "); + + whereResult = table.Select().Where("name like :name").Bind("nAme", "%ABCDEFGHIJ%").Execute(); + rowCount = whereResult.FetchAll().Count; + for (int i = 0; i < whereResult.Rows.Count; i++) + { + var res = whereResult.Rows.ToArray()[i][0]; + Assert.That(res.ToString(), Does.Contain("ABCDEFGHIJ")); + } + + whereResult = table.Select().Where("name like :name").Bind("nAme", "%ABCD%").Execute(); + rowCount = whereResult.FetchAll().Count; + for (int j = 0; j < whereResult.Rows.Count; j++) + { + var res = whereResult.Rows.ToArray()[j][0]; + Assert.That(res.ToString(), Does.Contain("ABCD")); + } + } + + [Test, Description("Test MySQLX plugin Table")] + public void TableSelectFetchValuesInOrder() + { + ExecuteSQL("drop table if exists test1"); + ExecuteSQL("create table test1(name VARCHAR(40), age INT)"); + Table table = session.GetSchema(schemaName).GetTable("test1"); + var result = table.Insert("name", "age") + .Values("MARK", 34) + .Execute(); + + Assert.That(result.AffectedItemsCount, Is.EqualTo((ulong)1), "Matching the values"); + result = table.Insert("name", "age") + .Values("richie", 16) + .Execute(); + Assert.That(result.AffectedItemsCount, Is.EqualTo((ulong)1), "Matching the values"); + var selectResult = table.Select().Execute(); + + while (selectResult.Next()) ; + Assert.That(selectResult.Rows.Count, Is.EqualTo(2), "Matching the row count"); + Assert.That(selectResult.Rows.ToArray()[0][0].ToString(), Is.EqualTo("MARK"), "Matching the value MARK"); + Assert.That((int)selectResult.Rows.ToArray()[0][1], Is.EqualTo(34), "Matching the age 34"); + Assert.That(selectResult.Rows.ToArray()[1][0].ToString(), Is.EqualTo("richie"), "Matching the value richie"); + Assert.That((int)selectResult.Rows.ToArray()[1][1], Is.EqualTo(16), "Matching the age 16"); + + var result1 = testSchema.GetTable("test").Select().OrderBy("age desc").Execute(); + int rowCount = result1.FetchAll().Count; + for (int i = 0; i < rowCount; i++) + { + Assert.That(result1.Rows[0][2].ToString(), Is.EqualTo("45"), "Matching the values"); + Assert.That(result1.Rows[1][2].ToString(), Is.EqualTo("38"), "Matching the values"); + Assert.That(result1.Rows[2][2].ToString(), Is.EqualTo("24"), "Matching the values"); + } + + result1 = testSchema.GetTable("test").Select().OrderBy("age asc").Execute(); + rowCount = result1.FetchAll().Count; + for (int i = 0; i < rowCount; i++) + { + Assert.That(result1.Rows[0][2].ToString(), Is.EqualTo("24"), "Matching the values"); + Assert.That(result1.Rows[1][2].ToString(), Is.EqualTo("38"), "Matching the values"); + Assert.That(result1.Rows[2][2].ToString(), Is.EqualTo("45"), "Matching the values"); + } + } + + [Test, Description("Reading exclusively locked document in a table using lock_exclusive with NOWAIT waiting option. ")] + public void DoubleExclusiveLockWithNoWait() + { + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); + + session.SQL("DROP TABLE IF EXISTS test.test").Execute(); + session.SQL("CREATE TABLE test.test (id INT, a INT)").Execute(); + var table1 = testSchema.GetTable("test"); + table1.Insert("id", "a").Values(1, 1).Values(2, 2).Values(3, 3).Execute(); + ExecuteSQLStatement(session.SQL("SET autocommit = 0")); + using (var session2 = MySQLX.GetSession(ConnectionString)) + { + ExecuteSQLStatement(session2.SQL("SET autocommit = 0")); + var table = testSchema.GetTable("test"); + session.SQL("CREATE UNIQUE INDEX myIndex ON test.test (id)").Execute(); + var table2 = session2.GetSchema("test").GetTable("test"); + + session.SQL("START TRANSACTION").Execute(); + var rowResult = table.Select().Where("id = 1").LockExclusive().Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + + session2.SQL("START TRANSACTION").Execute(); + // Should return immediately since document isn't locked. + rowResult = table2.Select().Where("id = 2").LockExclusive(LockContention.NoWait).Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + + // Session2 blocks due to to LockExclusive() not allowing to read locked documents. + ExecuteSQLStatement(session2.SQL("SET SESSION innodb_lock_wait_timeout=1")); + Assert.Throws(() => ExecuteSelectStatement(table2.Select().Where("id = 1").LockShared(LockContention.NoWait))); + + // Session2 blocks due to to LockExclusive() not allowing to modify locked documents. + Result result1; + Assert.Throws(() => result1 = table2.Update().Where("id = 1").Set("a", 2).Execute()); + + // Session2 returns immediately as session is committed. + session.Commit(); + var result = table2.Update().Where("id = 1").Set("a", 2).Execute(); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1)); + session.SQL("ROLLBACK").Execute(); + session2.SQL("ROLLBACK").Execute(); + } + + ExecuteSQLStatement(session.SQL("SET autocommit = 1")); + } + + [Test, Description("Reading a locked document(lock_shared) in a table using lock_shared with NOWAIT waiting option. ")] + public void DoubleSharedLockWithNoWait() + { + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); + + session.SQL("DROP TABLE IF EXISTS test.test").Execute(); + session.SQL("CREATE TABLE test.test (id INT, a INT)").Execute(); + var table1 = testSchema.GetTable("test"); + table1.Insert("id", "a").Values(1, 1).Values(2, 2).Values(3, 3).Execute(); + using (var session2 = MySQLX.GetSession(ConnectionString)) + { + var table = session.Schema.GetTable("test"); + var table2 = session2.GetSchema("test").GetTable("test"); + + session.SQL("START TRANSACTION").Execute(); + var rowResult = table.Select().Where("id = 1").LockShared().Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + + session2.SQL("START TRANSACTION").Execute(); + // Should return immediately since document isn't locked. + rowResult = table2.Select().Where("id = 2").LockShared(LockContention.NoWait).Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + + // Session2 doesnt block as LockShare trying to read locked(Lock_shared) document + session2.SQL("SET SESSION innodb_lock_wait_timeout=1").Execute(); + rowResult = table2.Select().Where("id = 1").LockShared(LockContention.NoWait).Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + + // Session2 blocks due to to LockShared() not allowing to modify locked documents. + Result result1; + Assert.Throws(() => result1 = table2.Update().Where("id = 1").Set("a", 2).Execute()); + + // Session2 returns immediately as session is committed. + session.Commit(); + var result = table2.Update().Where("id = 1").Set("a", 2).Execute(); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1)); + session.SQL("ROLLBACK").Execute(); + session2.SQL("ROLLBACK").Execute(); + } + } + + [Test, Description("Reading a locked document(lock_shared) in a table using lock_shared with NOWAIT waiting option. ")] + public void ExclusiveLockAfterSharedLockWithNoWait() + { + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); + + session.SQL("DROP TABLE IF EXISTS test.test").Execute(); + session.SQL("CREATE TABLE test.test (id INT, a INT)").Execute(); + var table1 = testSchema.GetTable("test"); + table1.Insert("id", "a").Values(1, 1).Values(2, 2).Values(3, 3).Execute(); + + using (var session2 = MySQLX.GetSession(ConnectionString)) + { + var table = session.Schema.GetTable("test"); + session.SQL("CREATE UNIQUE INDEX myIndex ON test.test (id)").Execute(); + var table2 = session2.GetSchema("test").GetTable("test"); + + session.SQL("START TRANSACTION").Execute(); + var rowResult = table.Select().Where("id = 1").LockShared().Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + + session2.SQL("START TRANSACTION").Execute(); + // Should return immediately since document isn't locked. + rowResult = table2.Select().Where("id = 2").LockExclusive(LockContention.NoWait).Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + + // Session2 blocks as LockExclusive() trying to access locked(LockShared) documents. + ExecuteSQLStatement(session2.SQL("SET SESSION innodb_lock_wait_timeout=1")); + Assert.Throws(() => ExecuteSelectStatement(table2.Select().Where("id = 1").LockExclusive(LockContention.NoWait))); + + // Session2 blocks due to to LockShared() not allowing to modify locked documents. + Result result1; + Assert.Throws(() => result1 = table2.Update().Where("id = 1").Set("a", 2).Execute()); + + // Session2 returns immediately as session is committed. + session.Commit(); + var result = table2.Update().Where("id = 1").Set("a", 2).Execute(); + Assert.That(result.AffectedItemsCount, Is.EqualTo(1)); + session.SQL("ROLLBACK").Execute(); + session2.SQL("ROLLBACK").Execute(); + } + } + + [Test, Description("Reading exclusively locked document in a table using lock_shared with SKIPLOCK waiting option. ")] + public void SharedLockAfterExclusiveWithSkiplock() + { + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); + + session.SQL("DROP TABLE IF EXISTS test.test").Execute(); + session.SQL("CREATE TABLE test.test (id INT, a INT)").Execute(); + var table1 = testSchema.GetTable("test"); + table1.Insert("id", "a").Values(1, 1).Values(2, 2).Values(3, 3).Execute(); + + using (var session2 = MySQLX.GetSession(ConnectionString)) + { + var table = session.Schema.GetTable("test"); + session.SQL("CREATE UNIQUE INDEX myIndex ON test.test (id)").Execute(); + var table2 = session2.GetSchema("test").GetTable("test"); + + session.SQL("START TRANSACTION").Execute(); + var rowResult = table.Select().Where("id = 1").LockExclusive().Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + + session2.SQL("START TRANSACTION").Execute(); + // Should return immediately since document isn't locked. + rowResult = table2.Select().Where("id = 2").LockShared(LockContention.NoWait).Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + + // Session2 blocks due to to LockExclusive() not allowing to read locked documents. + ExecuteSQLStatement(session2.SQL("SET SESSION innodb_lock_wait_timeout=1")); + rowResult = table2.Select().Where("id = 1").LockShared(LockContention.SkipLocked).Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(0), "Matching the document ID"); + + // Session2 blocks due to to LockExclusive() not allowing to modify locked documents. + Result result1; + Assert.Throws(() => result1 = table2.Update().Where("id = 1").Set("a", 2).Execute()); + + // Session2 returns immediately as session is committed. + session.Commit(); + var result = table2.Update().Where("id = 1").Set("a", 2).Execute(); + Assert.That((int)result.AffectedItemsCount, Is.EqualTo(1), "Matching the record count"); + + session.SQL("ROLLBACK").Execute(); + session2.SQL("ROLLBACK").Execute(); + } + } + + [Test, Description("Reading exclusively locked document in a table using lock_exclusive with SKIPLOCK waiting option.")] + public void DoubleExclusiveLockWithSkiplock() + { + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); + + session.SQL("DROP TABLE IF EXISTS test.test").Execute(); + session.SQL("CREATE TABLE test.test (id INT, a INT)").Execute(); + var table1 = testSchema.GetTable("test"); + table1.Insert("id", "a").Values(1, 1).Values(2, 2).Values(3, 3).Execute(); + + using (var session2 = MySQLX.GetSession(ConnectionString)) + { + var table = session.Schema.GetTable("test"); + session.SQL("CREATE UNIQUE INDEX myIndex ON test.test (id)").Execute(); + var table2 = session2.GetSchema("test").GetTable("test"); + + session.SQL("START TRANSACTION").Execute(); + var rowResult = table.Select().Where("id = 1").LockExclusive().Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + + session2.SQL("START TRANSACTION").Execute(); + // Should return immediately since document isn't locked. + rowResult = table2.Select().Where("id = 2").LockExclusive(LockContention.SkipLocked).Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + + // Session2 doesn't block as SKIPLOCK used + ExecuteSQLStatement(session2.SQL("SET SESSION innodb_lock_wait_timeout=1")); + rowResult = table2.Select().Where("id = 1").LockExclusive(LockContention.SkipLocked).Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(0), "Matching the document ID"); + // Session2 blocks due to to LockExclusive() not allowing to modify locked documents. + Result result1; + Assert.Throws(() => result1 = table2.Update().Where("id = 1").Set("a", 2).Execute()); + + // Session2 returns immediately as session is committed. + session.Commit(); + var result = table2.Update().Where("id = 1").Set("a", 2).Execute(); + Assert.That((int)result.AffectedItemsCount, Is.EqualTo(1), "Matching the record count"); + session.SQL("ROLLBACK").Execute(); + session2.SQL("ROLLBACK").Execute(); + } + } + + [Test, Description("Reading a locked document(lock_shared) in a table using lock_shared with SKIPLOCK waiting option. ")] + public void DoubleSharedLockWithSkiplock() + { + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); + + session.SQL("DROP TABLE IF EXISTS test.test").Execute(); + session.SQL("CREATE TABLE test.test (id INT, a INT)").Execute(); + var table1 = testSchema.GetTable("test"); + table1.Insert("id", "a").Values(1, 1).Values(2, 2).Values(3, 3).Execute(); + + using (var session2 = MySQLX.GetSession(ConnectionString)) + { + var table = session.Schema.GetTable("test"); + var table2 = session2.GetSchema("test").GetTable("test"); + + session.SQL("START TRANSACTION").Execute(); + var rowResult = table.Select().Where("id = 1").LockShared().Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + + session2.SQL("START TRANSACTION").Execute(); + // Should return immediately since document isn't locked. + rowResult = table2.Select().Where("id = 2").LockShared(LockContention.SkipLocked).Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + + // Session2 doesn't block as SKIPLOCK being used + ExecuteSQLStatement(session2.SQL("SET SESSION innodb_lock_wait_timeout=1")); + rowResult = table2.Select().Where("id = 1").LockShared(LockContention.SkipLocked).Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + + // Session2 blocks due to to LockShared() not allowing to modify locked documents. + Result result1; + Assert.Throws(() => result1 = table2.Update().Where("id = 1").Set("a", 2).Execute()); + + // Session2 returns immediately as session is committed. + session.Commit(); + var result = table2.Update().Where("id = 1").Set("a", 2).Execute(); + Assert.That((int)result.AffectedItemsCount, Is.EqualTo(1), "Matching the record count"); + session.SQL("ROLLBACK").Execute(); + session2.SQL("ROLLBACK").Execute(); + } + } + + [Test, Description("Reading a locked document(lock_shared) in a table using lock_exclusive with SKIPLOCK waiting option.")] + public void ExclusiveLockAfterSharedLockWithSkiplock() + { + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); + + session.SQL("DROP TABLE IF EXISTS test.test").Execute(); + session.SQL("CREATE TABLE test.test (id INT, a INT)").Execute(); + var table1 = testSchema.GetTable("test"); + table1.Insert("id", "a").Values(1, 1).Values(2, 2).Values(3, 3).Execute(); + + using (var session2 = MySQLX.GetSession(ConnectionString)) + { + var table = session.Schema.GetTable("test"); + session.SQL("CREATE UNIQUE INDEX myIndex ON test.test (id)").Execute(); + var table2 = session2.GetSchema("test").GetTable("test"); + + session.SQL("START TRANSACTION").Execute(); + var rowResult = table.Select().Where("id = 1").LockShared().Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + + session2.SQL("START TRANSACTION").Execute(); + // Should return immediately since document isn't locked. + rowResult = table2.Select().Where("id = 2").LockExclusive(LockContention.SkipLocked).Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + + // Session2 doesn't block as SKIPLOCK being used + ExecuteSQLStatement(session2.SQL("SET SESSION innodb_lock_wait_timeout=1")); + rowResult = table2.Select().Where("id = 1").LockExclusive(LockContention.SkipLocked).Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(0), "Matching the document ID"); + + // Session2 blocks due to to LockExclusive() not allowing to modify locked documents. + Result result1; + Assert.Throws(() => result1 = table2.Update().Where("id = 1").Set("a", 2).Execute()); + + // Session2 returns immediately as session is committed. + session.Commit(); + var result = table2.Update().Where("id = 1").Set("a", 2).Execute(); + Assert.That((int)result.AffectedItemsCount, Is.EqualTo(1), "Matching the record count"); + session.SQL("ROLLBACK").Execute(); + session2.SQL("ROLLBACK").Execute(); + } + } + + [Test, Description("Reading an exclusively locked document in a table using lock_shared without any waiting option. ")] + public void ExclusiveLockBeforeSharedLockWithoutAwaiting() + { + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); + + session.SQL("DROP TABLE IF EXISTS test.test").Execute(); + session.SQL("CREATE TABLE test.test (id INT, a INT)").Execute(); + var table1 = testSchema.GetTable("test"); + table1.Insert("id", "a").Values(1, 1).Values(2, 2).Values(3, 3).Execute(); + + using (var session2 = MySQLX.GetSession(ConnectionString)) + { + var table = session.Schema.GetTable("test"); + session.SQL("CREATE UNIQUE INDEX myIndex ON test.test (id)").Execute(); + var table2 = session2.GetSchema("test").GetTable("test"); + + session.SQL("START TRANSACTION").Execute(); + var rowResult = table.Select().Where("id = 1").LockExclusive().Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + + session2.SQL("START TRANSACTION").Execute(); + // Should return immediately since document isn't locked. + rowResult = table2.Select().Where("id = 2").LockShared().Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + + // Session2 blocks due to to LockExclusive() not allowing to read locked documents. + ExecuteSQLStatement(session2.SQL("SET SESSION innodb_lock_wait_timeout=1")); + Assert.Throws(() => ExecuteSelectStatement(table2.Select().Where("id = 1").LockShared())); + + // Session2 blocks due to to LockExclusive() not allowing to modify locked documents. + Result result1; + Assert.Throws(() => result1 = table2.Update().Where("id = 1").Set("a", 2).Execute()); + + // Session2 returns immediately as session is committed. + session.Commit(); + var result = table2.Update().Where("id = 1").Set("a", 2).Execute(); + Assert.That((int)result.AffectedItemsCount, Is.EqualTo(1), "Matching the record count"); + session.SQL("ROLLBACK").Execute(); + session2.SQL("ROLLBACK").Execute(); + } + } + + [Test, Description("Reading an exclusively locked document in a table using lock_exclusive without any waiting option.")] + public void DoubleExclusiveLockWithoutWaiting() + { + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); + + using (var session2 = MySQLX.GetSession(ConnectionString)) + { + var table = session.Schema.GetTable("test"); + session.SQL("CREATE UNIQUE INDEX myIndex ON test.test (id)").Execute(); + var table2 = session2.GetSchema("test").GetTable("test"); + + session.SQL("START TRANSACTION").Execute(); + var rowResult = table.Select().Where("id = 1").LockExclusive().Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + + session2.SQL("START TRANSACTION").Execute(); + // Should return immediately since document isn't locked. + rowResult = table2.Select().Where("id = 2").LockExclusive().Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + + // Session2 blocks due to to LockExclusive() not allowing to read locked documents. + ExecuteSQLStatement(session2.SQL("SET SESSION innodb_lock_wait_timeout=1")); + Assert.Throws(() => ExecuteSelectStatement(table2.Select().Where("id = 1").LockExclusive())); + + // Session2 blocks due to to LockExclusive() not allowing to modify locked documents. + Result result1; + Assert.Throws(() => result1 = table2.Update().Where("id = 1").Set("age", 2).Execute()); + + // Session2 returns immediately as session is committed. + session.Commit(); + var result = table2.Update().Where("id = 1").Set("age", 2).Execute(); + Assert.That((int)result.AffectedItemsCount, Is.EqualTo(1), "Matching the record count"); + session.SQL("ROLLBACK").Execute(); + session2.SQL("ROLLBACK").Execute(); + } + } + + [Test, Description("Reading a locked document(lock_shared) in a table using lock_shared without any waiting option.")] + public void DoubleSharedLockWithoutWaiting() + { + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); + + session.SQL("DROP TABLE IF EXISTS test.test").Execute(); + session.SQL("CREATE TABLE test.test (id INT, a INT)").Execute(); + var table1 = testSchema.GetTable("test"); + table1.Insert("id", "a").Values(1, 1).Values(2, 2).Values(3, 3).Execute(); + + using (var session2 = MySQLX.GetSession(ConnectionString)) + { + var table = session.Schema.GetTable("test"); + var table2 = session2.GetSchema("test").GetTable("test"); + + session.SQL("START TRANSACTION").Execute(); + var rowResult = table.Select().Where("id = 1").LockShared().Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + + session2.SQL("START TRANSACTION").Execute(); + // Should return immediately since document isn't locked. + rowResult = table2.Select().Where("id = 2").LockShared().Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + + ExecuteSQLStatement(session2.SQL("SET SESSION innodb_lock_wait_timeout=1")); + rowResult = table2.Select().Where("id = 1").LockShared().Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + + // Session2 blocks due to to LockExclusive() not allowing to modify locked documents. + Result result1; + Assert.Throws(() => result1 = table2.Update().Where("id = 1").Set("a", 2).Execute()); + + // Session2 returns immediately as session is committed. + session.Commit(); + var result = table2.Update().Where("id = 1").Set("a", 2).Execute(); + Assert.That((int)result.AffectedItemsCount, Is.EqualTo(1), "Matching the record count"); + session.SQL("ROLLBACK").Execute(); + session2.SQL("ROLLBACK").Execute(); + } + } + + [Test, Description("Reading a locked document(lock_shared) in a table using lock_exclusive without any waiting option. ")] + public void SharedLockBeforeExclusiveLockWithoutWaiting() + { + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); + + session.SQL("DROP TABLE IF EXISTS test.test").Execute(); + session.SQL("CREATE TABLE test.test (id INT, a INT)").Execute(); + var table1 = testSchema.GetTable("test"); + table1.Insert("id", "a").Values(1, 1).Values(2, 2).Values(3, 3).Execute(); + + using (var session2 = MySQLX.GetSession(ConnectionString)) + { + var table = session.Schema.GetTable("test"); + session.SQL("CREATE UNIQUE INDEX myIndex ON test.test (id)").Execute(); + var table2 = session2.GetSchema("test").GetTable("test"); + + session.SQL("START TRANSACTION").Execute(); + var rowResult = table.Select().Where("id = 1").LockShared().Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + + session2.SQL("START TRANSACTION").Execute(); + // Should return immediately since document isn't locked. + rowResult = table2.Select().Where("id = 2").LockExclusive().Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + + // Session2 blocks as LockExclusive() is trying to read locked documents. + ExecuteSQLStatement(session2.SQL("SET SESSION innodb_lock_wait_timeout=1")); + Assert.Throws(() => ExecuteSelectStatement(table2.Select().Where("id = 1").LockExclusive())); + + // Session2 blocks due to to LockShared() not allowing to modify locked documents. + Result result1; + Assert.Throws(() => result1 = table2.Update().Where("id = 1").Set("a", 2).Execute()); + + // Session2 returns immediately as session is committed. + session.Commit(); + var result = table2.Update().Where("id = 1").Set("a", 2).Execute(); + Assert.That((int)result.AffectedItemsCount, Is.EqualTo(1), "Matching the record count"); + session.SQL("ROLLBACK").Execute(); + session2.SQL("ROLLBACK").Execute(); + } + } + + [Test, Description("Reading a locked document(shared/exclusive) in a table using SKIPLOCK and NOWAIT waiting options when CRUD is happening parallely")] + public void SingleLockExclusiveWithNoWaitAndSkip() + { + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); + + session.SQL("DROP TABLE IF EXISTS test.test").Execute(); + session.SQL("CREATE TABLE test.test (id INT, a INT)").Execute(); + var table1 = testSchema.GetTable("test"); + table1.Insert("id", "a").Values(1, 1).Values(2, 2).Values(3, 3).Execute(); + + using (var session2 = MySQLX.GetSession(ConnectionString)) + { + var table = session.Schema.GetTable("test"); + session.SQL("CREATE UNIQUE INDEX myIndex ON test.test (id)").Execute(); + var table2 = session2.GetSchema("test").GetTable("test"); + + session.SQL("START TRANSACTION").Execute(); + var result1 = table.Update().Where("id = 1").Set("a", 2).Execute(); + + session2.SQL("START TRANSACTION").Execute(); + // Should return immediately since document isn't locked. + var rowResult1 = table2.Select().Where("id = 2").LockExclusive(LockContention.NoWait).Execute(); + Assert.That(rowResult1.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + + // Session2 blocks due to to LockExclusive() not allowing to read locked documents. + ExecuteSQLStatement(session2.SQL("SET SESSION innodb_lock_wait_timeout=1")); + Assert.Throws(() => ExecuteSelectStatement(table2.Select().Where("id = 1").LockExclusive(LockContention.NoWait))); + Assert.Throws(() => ExecuteSelectStatement(table2.Select().Where("id = 1").LockShared(LockContention.NoWait))); + + var rowResult = table2.Select().Where("id = 1").LockShared(LockContention.SkipLocked).Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(0), "Matching the document ID"); + + rowResult = table2.Select().Where("id = 1").LockExclusive(LockContention.SkipLocked).Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(0), "Matching the document ID"); + + session.SQL("ROLLBACK").Execute(); + session2.SQL("ROLLBACK").Execute(); + } + } + + [Test, Description("Multiple lock calls on a document in table using NOWAIT and SKIPLOCK waiting options")] + public void ChainedExclusiveLocks() + { + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); + + session.SQL("DROP TABLE IF EXISTS test.test").Execute(); + session.SQL("CREATE TABLE test.test (id INT, a INT)").Execute(); + var table1 = testSchema.GetTable("test"); + table1.Insert("id", "a").Values(1, 1).Values(2, 2).Values(3, 3).Execute(); + + using (var session2 = MySQLX.GetSession(ConnectionString)) + { + var table = session.Schema.GetTable("test"); + session.SQL("CREATE UNIQUE INDEX myIndex ON test.test (id)").Execute(); + var table2 = session2.GetSchema("test").GetTable("test"); + + session.SQL("START TRANSACTION").Execute(); + var rowResult = table.Select().Where("id = 1").LockShared().Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + + session2.SQL("START TRANSACTION").Execute(); + ExecuteSQLStatement(session2.SQL("SET SESSION innodb_lock_wait_timeout=1")); + Assert.Throws(() => rowResult = table2.Select().Where("id = 1").LockExclusive(LockContention.SkipLocked).LockExclusive(LockContention.NoWait).Execute()); + + Assert.Throws(() => ExecuteSelectStatement(table2.Select().Where("id = 1") + .LockExclusive(LockContention.SkipLocked) + .LockExclusive(LockContention.NoWait))); + + rowResult = table2.Select().Where("id = 1").LockExclusive(LockContention.SkipLocked).LockShared(LockContention.SkipLocked).Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + + rowResult = table2.Select().Where("id = 1").LockShared(LockContention.SkipLocked).LockExclusive(LockContention.SkipLocked).Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(0), "Matching the document ID"); + session.SQL("ROLLBACK").Execute(); + session2.SQL("ROLLBACK").Execute(); + } + } + + [Test, Description("Test MySQLX plugin - MYSQLCNET 755 Table GetIncrementValue")] + public void TableGetAutoIncrementValue() + { + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); + + session.SQL("CREATE TABLE address1" + + "(address_number1 MEDIUMINT NOT NULL AUTO_INCREMENT, " + + "address_number2 CHAR(100) NOT NULL, " + + "PRIMARY KEY (address_number1)" + ");").Execute(); + Table table = testSchema.GetTable("address1"); + var result = table.Insert("address_number1", "address_number2") + .Values(100, "Test the document id in address table") + .Execute(); + + var docId = result.AutoIncrementValue; + Assert.That(docId.ToString(), Is.EqualTo("100"), "Matching the value if already it is inserted"); + + result = table.Insert("address_number2") + .Values("Test the document id by 2nd insert without id in address table") + .Execute(); + docId = result.AutoIncrementValue; + Assert.That(docId.ToString(), Is.EqualTo("101"), "Matching the value if already it is inserted"); + + session.SQL("CREATE TABLE address2" + + "(address_number3 INT NOT NULL AUTO_INCREMENT, " + + "address_number4 CHAR(100) NOT NULL, " + + "PRIMARY KEY (address_number3)" + ");").Execute(); + table = testSchema.GetTable("address2"); + result = table.Insert("address_number4") + .Values("Test the document id in address table without unique id") + .Execute(); + + docId = result.AutoIncrementValue; + Assert.That(docId.ToString(), Is.EqualTo("1"), "Matching the auto increment value"); + + session.SQL("CREATE TABLE address3" + + "(address_number5 MEDIUMINT NOT NULL AUTO_INCREMENT, " + + "address_number6 CHAR(100) NOT NULL, " + + "PRIMARY KEY (address_number5)" + ");").Execute(); + table = testSchema.GetTable("address3"); + result = table.Insert("address_number5", "address_number6") + .Values(100, "Test multiple document ids in address table - 1st document") + .Values(200, "Test multiple document ids in address table - 2nd document") + .Values(300, "Test multiple document ids in address table - 3rd document") + .Execute(); + + docId = result.AutoIncrementValue; + Assert.That(docId.ToString(), Is.EqualTo("300"), "Matching the value if more than one documents inserted"); + + result = table.Insert("address_number6") + .Values("Test multiple document ids in address table - 4th document without ID") + .Values("Test multiple document ids in address table - 5th document without ID") + .Values("Test multiple document ids in address table - 6th document without ID") + .Execute(); + + docId = result.AutoIncrementValue; + Assert.That(docId.ToString(), Is.EqualTo("301"), "Matching the value if more than one documents inserted"); + + session.SQL("CREATE TABLE address4" + + "(address_number7 INT NOT NULL AUTO_INCREMENT, " + + "address_number8 CHAR(100) NOT NULL, " + + "PRIMARY KEY (address_number7)" + ");").Execute(); + table = testSchema.GetTable("address4"); + result = table.Insert("address_number8") + .Values("Test the document ids in address table without unique id - 1st document") + .Values("Test the document ids in address table without unique id - 2nd document") + .Values("Test the document ids in address table without unique id - 3rd document") + .Execute(); + + docId = result.AutoIncrementValue; + Assert.That(docId.ToString(), Is.EqualTo("1"), "Matching the auto increment value"); + + result = table.Insert("address_number8") + .Values("Test the document ids in address table without unique id - 4th document") + .Values("Test the document ids in address table without unique id - 5th document") + .Values("Test the document ids in address table without unique id - 6th document") + .Execute(); + + docId = result.AutoIncrementValue; + Assert.That(docId.ToString(), Is.EqualTo("4"), "Matching the auto increment value"); + + session.SQL("CREATE TABLE address5" + + "(address_number9 INT, " + + "address_number10 CHAR(100));").Execute(); + + session.SQL("ALTER TABLE address5 ADD c INT UNSIGNED NOT NULL AUTO_INCREMENT, ADD PRIMARY KEY(c)").Execute(); + + table = testSchema.GetTable("address5"); + result = table.Insert("address_number9", "address_number10") + .Values(100, "Test the document ids in address table without unique id - 1st document") + .Values(200, "Test the document ids in address table without unique id - 2nd document") + .Values(300, "Test the document ids in address table without unique id - 3rd document") + .Execute(); + + docId = result.AutoIncrementValue; + Assert.That(docId.ToString(), Is.EqualTo("1"), "Matching the auto increment value"); + session.SQL("drop table if exists address1").Execute(); + session.SQL("drop table if exists address2").Execute(); + session.SQL("drop table if exists address3").Execute(); + session.SQL("drop table if exists address4").Execute(); + session.SQL("drop table if exists address5").Execute(); + } + + [Test, Description("Test MySQLX plugin - MYSQLCNET_684 Fetchone returns null when no rows")] + public void FetchoneReturnsNullNoRows() + { + ExecuteSQL("CREATE TABLE test1(id INT)"); + ExecuteSQL("INSERT INTO test1 VALUES (1),(2),(3),(4)"); + ExecuteSQL("CREATE TABLE test2(id INT, val INT)"); + ExecuteSQL("INSERT INTO test2 VALUES (1,0)"); + var rowResult = testSchema.GetTable("test1").Select("id").Execute(); + foreach (var row in rowResult) + { + var result = testSchema.GetTable("test2").Update().Where("id=1").Set("val", row["id"]).Execute(); + //WL11843-Core API v1 alignment Changes + Assert.That(result.AffectedItemsCount, Is.EqualTo(1), "Matching"); + } + + Row valRow = testSchema.GetTable("test2").Select("val").Execute().FetchOne(); + Assert.That(valRow[0].ToString(), Is.EqualTo("4"), "Matching"); + ExecuteSQL("DELETE FROM test2 WHERE id=1"); + valRow = testSchema.GetTable("test2").Select("val").Execute().FetchOne(); + Assert.That(valRow, Is.Null); + ExecuteSQL("DROP TABLE if exists test1"); + ExecuteSQL("DROP TABLE if exists test2"); + } + + [Test, Description("Test MySQLX plugin - MYSQLCNET_684 Fetchone returns null when no table")] + public void FetchoneReturnsNullNoTable() + { + ExecuteSQL("CREATE TABLE test111(id INT)"); + ExecuteSQL("INSERT INTO test111 VALUES (1),(2),(3),(4)"); + ExecuteSQL("CREATE TABLE test222(id INT, val INT)"); + ExecuteSQL("INSERT INTO test222 VALUES (1,0)"); + var rowResult = testSchema.GetTable("test111").Select("id").Execute(); + foreach (var row in rowResult) + { + var result = testSchema.GetTable("test222").Update().Where("id=1").Set("val", row["id"]).Execute(); + //WL11843-Core API v1 alignment Changes + Assert.That(result.AffectedItemsCount, Is.EqualTo(1), "Matching"); + } + + Row valRow = testSchema.GetTable("test222").Select("val").Execute().FetchOne(); + Assert.That(valRow[0].ToString(), Is.EqualTo("4"), "Matching"); + ExecuteSQL("DROP TABLE test222"); + Assert.Throws(() => valRow = testSchema.GetTable("test222").Select("val").Execute().FetchOne()); + ExecuteSQL("DROP TABLE IF EXISTS test111"); + } + + [Test, Description("MySQLX CNET-Test Table.Select() with exclusive lock and Table.Update() normal from two sessions. ")] + public void DoubleChainedLocksWithTwoSessions_S1() + { + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); + + session.SQL("SET autocommit = 0").Execute(); + using (var session2 = MySQLX.GetSession(ConnectionString)) + { + session2.SQL("SET autocommit = 0").Execute(); + var table = session.Schema.GetTable("test"); + session.SQL("CREATE UNIQUE INDEX myIndex ON test.test (id)").Execute(); + var table2 = session2.GetSchema("test").GetTable("test"); + + session.SQL("START TRANSACTION").Execute(); + var rowResult = table.Select().Where("id = 1").LockExclusive().Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(1), "Matching the record ID"); + + session2.SQL("START TRANSACTION").Execute(); + // Should return immediately since document isn't locked. + rowResult = table2.Select().Where("id = 2").LockExclusive().Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(1), "Matching the record ID"); + + // Session2 blocks due to to LockExclusive() not allowing to read locked documents. + ExecuteSQLStatement(session2.SQL("SET SESSION innodb_lock_wait_timeout=1")); + Assert.Throws(() => ExecuteSelectStatement(table2.Select().Where("id = 1").LockExclusive())); + + // Session2 blocks due to to LockExclusive() not allowing to modify locked documents. + Result result1; + Assert.Throws(() => result1 = table2.Update().Where("id = 1").Set("age", 2).Execute()); + + session.SQL("ROLLBACK").Execute(); + session2.SQL("ROLLBACK").Execute(); + } + + using (var session2 = MySQLX.GetSession(ConnectionString)) + { + session2.SQL("SET autocommit = 0").Execute(); + var table = session.Schema.GetTable("test"); + var table2 = session2.GetSchema("test").GetTable("test"); + + session.SQL("START TRANSACTION").Execute(); + var rowResult = table.Select().Where("id = 1").LockShared().LockExclusive().Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(1), "Matching the record ID"); + + session2.SQL("START TRANSACTION").Execute(); + // Should return immediately since document isn't locked. + rowResult = table2.Select().Where("id = 2").LockShared().LockExclusive().Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(1), "Matching the record ID"); + + // Session2 blocks due to to LockExclusive() not allowing to read locked documents. + ExecuteSQLStatement(session2.SQL("SET SESSION innodb_lock_wait_timeout=1")); + Assert.Throws(() => ExecuteSelectStatement(table2.Select().Where("id = 1").LockShared().LockExclusive())); + + // Session2 blocks due to to LockExclusive() not allowing to modify locked documents. + Result result1; + Assert.Throws(() => result1 = table2.Update().Where("id = 1").Set("age", 2).Execute()); + session.SQL("ROLLBACK").Execute(); + session2.SQL("ROLLBACK").Execute(); + } + session.SQL("SET autocommit = 1").Execute(); + } + + [Test, Description("MySQLX CNET-Test Table.Select() with shared lock and Table.Update() normal from two sessions. ")] + public void DoubleChainedLocksWithTwoSessions_S2() + { + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); + + session.SQL("SET autocommit = 0").Execute(); + using (var session2 = MySQLX.GetSession(ConnectionString)) + { + session2.SQL("SET autocommit = 0").Execute(); + var table = session.Schema.GetTable("test"); + session.SQL("CREATE UNIQUE INDEX myIndex ON test.test (id)").Execute(); + var table2 = session2.GetSchema("test").GetTable("test"); + + session.SQL("START TRANSACTION").Execute(); + var rowResult = table.Select().Where("id = 1").LockShared().Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(1), "Matching the record ID"); + + session2.SQL("START TRANSACTION").Execute(); + // Should return immediately since document isn't locked. + rowResult = table2.Select().Where("id = 1").Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(1), "Matching the record ID"); + + // Session2 blocks due to to LockExclusive() not allowing to read locked documents. + ExecuteSQLStatement(session2.SQL("SET SESSION innodb_lock_wait_timeout=1")); + var result = table2.Update().Where("id = 2").Set("age", 30).Execute(); + Assert.That((int)result.AffectedItemsCount, Is.EqualTo(1), "Match being done"); + Assert.Throws(() => ExecuteSelectStatement(table2.Select().Where("id = 1").LockExclusive())); + + // Session2 blocks due to to LockExclusive() not allowing to modify locked documents. + Result result1; + Assert.Throws(() => result1 = table2.Update().Where("id = 1").Set("age", 2).Execute()); + + session.SQL("ROLLBACK").Execute(); + session2.SQL("ROLLBACK").Execute(); + } + + session.SQL("SET autocommit = 0").Execute(); + using (var session2 = MySQLX.GetSession(ConnectionString)) + { + session2.SQL("SET autocommit = 0").Execute(); + var table = session.Schema.GetTable("test"); + var table2 = session2.GetSchema("test").GetTable("test"); + + session.SQL("START TRANSACTION").Execute(); + var rowResult = table.Select().Where("id = 1").LockExclusive().LockShared().Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(1), "Matching the record ID"); + + session2.SQL("START TRANSACTION").Execute(); + // Should return immediately since document isn't locked. + rowResult = table2.Select().Where("id = 1").Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(1), "Matching the record ID"); + + // Session2 blocks due to to LockExclusive() not allowing to read locked documents. + session2.SQL("SET SESSION innodb_lock_wait_timeout=1").Execute(); + var result = table2.Update().Where("id = 2").Set("age", 30).Execute(); + Assert.That((int)result.AffectedItemsCount, Is.EqualTo(1), "Match being done"); + Assert.Throws(() => ExecuteSelectStatement(table2.Select().Where("id = 1").LockShared().LockExclusive())); + + // Session2 blocks due to to LockExclusive() not allowing to modify locked documents. + Result result1; + Assert.Throws(() => result1 = table2.Update().Where("id = 1").Set("age", 2).Execute()); + session.SQL("ROLLBACK").Execute(); + session2.SQL("ROLLBACK").Execute(); + } + session.SQL("SET autocommit = 1").Execute(); + } + + [Test, Description("MySQLX CNET-Test Table.Select() with exclusive lock from two sessions. ")] + public void SingleExclusiveLock() + { + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); + + session.SQL("SET autocommit = 0").Execute(); + using (var session2 = MySQLX.GetSession(ConnectionString)) + { + session2.SQL("SET autocommit = 0").Execute(); + var table = session.Schema.GetTable("test"); + session.SQL("CREATE UNIQUE INDEX myIndex ON test.test (id)").Execute(); + var table2 = session2.GetSchema("test").GetTable("test"); + + session.SQL("START TRANSACTION").Execute(); + var rowResult = table.Select().Where("id = 1").LockExclusive().Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(1), "Matching the record ID"); + + session2.SQL("START TRANSACTION").Execute(); + // Should return immediately since document isn't locked. + rowResult = table2.Select().Where("id = 2").Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(1), "Matching the record ID"); + + // Session2 blocks due to to LockExclusive() not allowing to read locked documents. + session2.SQL("SET SESSION innodb_lock_wait_timeout=1").Execute(); + Assert.Throws(() => ExecuteSelectStatement(table2.Select().Where("id = 1").LockExclusive())); + session.SQL("ROLLBACK").Execute(); + session2.SQL("ROLLBACK").Execute(); + } + session.SQL("SET autocommit = 1").Execute(); + } + + [Test, Description("MySQLX CNET-Test Table.Select() with exclusive lock and Table.Select() with exclusive lock from two sessions-Select multiple records")] + public void SingleTransactionWithLocks() + { + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); + + session.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED").Execute(); + using (var session2 = MySQLX.GetSession(ConnectionString)) + { + session2.SQL("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED").Execute(); + session.SQL("CREATE UNIQUE INDEX myIndex ON test.test (id)").Execute(); + var table = session.Schema.GetTable("test"); + var table2 = session2.GetSchema("test").GetTable("test"); + + session.SQL("START TRANSACTION").Execute(); + var rowResult = table.Select().Where("id in (1,3)").LockShared().Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(2), "Matching the record ID"); + + rowResult = table2.Select().Where("id = 2").LockExclusive().Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(1), "Matching the record ID"); + rowResult = table2.Select().Where("id = 2").LockShared().Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(1), "Matching the record ID"); + // Session2 blocks due to to LockExclusive() not allowing to read locked documents. + session.SQL("SET SESSION innodb_lock_wait_timeout=1").Execute(); + table2.Select().Where("id = 2").LockExclusive().Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(1), "Matching the record ID"); + session2.SQL("SET SESSION innodb_lock_wait_timeout=1").Execute(); + Assert.Throws(() => ExecuteSelectStatement(table2.Select().Where("id = 1").LockExclusive())); + + session2.SQL("SET SESSION innodb_lock_wait_timeout=1").Execute(); + // Session2 blocks due to to LockExclusive() not allowing to modify locked documents. + Assert.Throws(() => ExecuteUpdateStatement(table2.Update().Where("id = 1").Set("age", 2))); + + session.SQL("ROLLBACK").Execute(); + rowResult = table2.Select().Where("id = 1").LockExclusive().Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + session2.SQL("ROLLBACK").Execute(); + rowResult = table.Select().Where("id = 2").LockExclusive().Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + } + } + + [Test, Description("MySQLX CNET-Test Table.Select() with exclusive lock and Table.Update() normal from two sessions-50 Iterations")] + public void IteratedExclusiveLocks() + { + Assume.That(Platform.IsWindows(), "This test is only for Windows OS."); + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); + + session.SQL("SET autocommit = 0").Execute(); + session.SQL("CREATE UNIQUE INDEX myIndex ON test.test (id)").Execute(); + const int iterations = 30; + for (var i = 0; i < iterations; i++) + { + using (var session2 = MySQLX.GetSession(ConnectionString)) + { + session2.SQL("SET autocommit = 0").Execute(); + var table = session.Schema.GetTable("test"); + + var table2 = session2.GetSchema("test").GetTable("test"); + + session.SQL("START TRANSACTION").Execute(); + var rowResult = table.Select().Where("id = 1").LockExclusive().Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(1), "Matching the record ID"); + + session2.SQL("START TRANSACTION").Execute(); + // Should return immediately since document isn't locked. + rowResult = table2.Select().Where("id = 2").LockExclusive().Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(1), "Matching the record ID"); + + // Session2 blocks due to to LockExclusive() not allowing to read locked documents. + session2.SQL("SET SESSION innodb_lock_wait_timeout=1").Execute(); + Assert.Throws(() => ExecuteSelectStatement(table2.Select().Where("id = 1").LockExclusive())); + + // Session2 blocks due to to LockExclusive() not allowing to modify locked documents. + Result result1; + Assert.Throws(() => result1 = table2.Update().Where("id = 1").Set("age", 2).Execute()); + session.SQL("ROLLBACK").Execute(); + session2.SQL("ROLLBACK").Execute(); + } + } + session.SQL("SET autocommit = 1").Execute(); + } + + #endregion WL14389 + + #region Methods + public static string RandomString(int length) + { + const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + const string chars1 = "ABCDEFGHIJ"; + var random = new Random(); + if (length == 20) + { + return chars1; + } + else + { + return new string(Enumerable.Repeat(chars, length) + .Select(s => s[random.Next(s.Length)]).ToArray()); + } + + } + #endregion Methods + } +} diff --git a/MySQL.Data/tests/MySqlX.Data.Tests/RelationalTests/TableUpdateTests.cs b/MySQL.Data/tests/MySqlX.Data.Tests/RelationalTests/TableUpdateTests.cs index 619b7109e..9129143e4 100644 --- a/MySQL.Data/tests/MySqlX.Data.Tests/RelationalTests/TableUpdateTests.cs +++ b/MySQL.Data/tests/MySqlX.Data.Tests/RelationalTests/TableUpdateTests.cs @@ -1,367 +1,368 @@ -// Copyright (c) 2015, 2021, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data.MySqlClient; -using MySqlX.XDevAPI.Common; -using MySqlX.XDevAPI.Relational; -using NUnit.Framework; -using System; -using System.Collections.Generic; -using MySqlX.XDevAPI; - -namespace MySqlX.Data.Tests.RelationalTests -{ - public class TableUpdateTests : BaseTest - { - Table table; - - [TearDown] - public void TearDown() => ExecuteSQL("DROP TABLE IF EXISTS test"); - - [SetUp] - public void SetUp() - { - ExecuteSQL("CREATE TABLE test.test(id INT, name VARCHAR(40), age INT)"); - - table = testSchema.GetTable("test"); - var insertStatement = table.Insert(); - int rowsToInsert = 10; - for (int i = 1; i <= rowsToInsert; i++) - { - insertStatement.Values(i, i, i); - } - ExecuteInsertStatement(insertStatement); - Assert.AreEqual(rowsToInsert, CountRows()); - } - - private int CountRows() - { - return GetRows(null).Count; - } - - private IReadOnlyCollection GetRows(FilterParams filter) - { - var statement = table.Select(); - if (filter != null) - { - statement.FilterData.Condition = filter.Condition; - statement.FilterData.Limit = filter.Limit; - statement.FilterData.OrderBy = filter.OrderBy; - statement.FilterData.Parameters = filter.Parameters; - } - var result = ExecuteSelectStatement(statement); - while (result.Next()) ; - return result.Rows; - } - - private void ValidateUpdate(TableUpdateStatement statement) - { - Dictionary parameters = new Dictionary(statement.FilterData.Parameters); - var result = ExecuteUpdateStatement(statement); - statement.FilterData.Parameters = parameters; - var rows = GetRows(statement.FilterData); - foreach (var row in rows) - { - foreach (var set in statement.updates) - { - Assert.AreEqual(set.Value.ToString(), row.GetString(set.Path)); - } - } - } - - [Test] - public void EmptyUpdateTest() - { - Assert.Throws(() => ExecuteUpdateStatement(table.Update())); - } - - [Test] - public void UpdateConditionTest() - { - ValidateUpdate(table.Update().Where("id = 5").Set("name", "other")); - } - - [Test] - public void UpdateMultiSet() - { - ValidateUpdate(table.Update().Set("name", "other") - .Set("age", 21) - .Set("id", 30) - .Where("id = 3")); - } - - [Test] - public void UpdateMultiRows() - { - ValidateUpdate(table.Update().Set("age", 85).Where("id % 2 = 0")); - } - - [Test] - public void UpdateAllRows() - { - ValidateUpdate(table.Update().Set("age", 32).Set("name", "jonh")); - } - - [Test] - public void UpdateOrderbyAndLimit() - { - ValidateUpdate(table.Update().Set("age", 15).OrderBy("id DES").Limit(5)); - } - - [Test] - public void UpdateBind() - { - var stmt = table.Update().Set("age", 55).Where("id = :id or id = :id or id = :id2"); - ValidateUpdate(stmt.Bind("id", 4).Bind("id2", 7)); - ValidateUpdate(stmt.Bind("id", 5).Bind("id2", 8)); - } - - [Test] - public void UpdateWithInOperator() - { - Table table = testSchema.GetTable("test"); - Assert.AreEqual(10, CountRows()); - - Assert.AreEqual(2, ExecuteUpdateStatement(table.Update().Where("id IN (1,2)").Set("id", 0)).AffectedItemsCount); - Assert.AreEqual(2, ExecuteSelectStatement(table.Select().Where("id = 0")).FetchAll().Count); - - Assert.Throws(() => ExecuteDeleteStatement(table.Delete().Where("a IN [3]"))); - Assert.Throws(() => ExecuteDeleteStatement(table.Delete().Where("3 IN a"))); - Assert.Throws(() => ExecuteUpdateStatement(table.Update().Where("age IN [3]").Set("id", 0))); - - Assert.AreEqual(1, ExecuteUpdateStatement(table.Update().Where("age IN (3)").Set("id", 0)).AffectedItemsCount); - Assert.AreEqual(3, ExecuteSelectStatement(table.Select().Where("id = 0")).FetchAll().Count); - } - - #region WL14389 - - [Test, Description("Collection.Find(condition).GroupBy(SearchExprStr)")] - public void TableSelectGroupBy() - { - ExecuteSQLStatement(session.SQL("set sql_mode = 'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';")); - session.SQL("delete from test").Execute(); - Table table = testSchema.GetTable("test"); - var result1 = table.Insert("id", "name", "age") - .Values(1, "jonh doe", 38) - .Values(2, "milton greenh", 45) - .Values(3, "larry smith", 24) - .Values(4, "mary weinstein", 24) - .Values(5, "jerry pratt", 45) - .Values(6, "hugh jackman", 20) - .Values(7, "elizabeth olsen", 31) - .Execute(); - RowResult result = table.Select().OrderBy("age desc").Execute(); - Assert.Throws(() => table.Delete().Limit(1).Offset(3).Execute()); - - var t2 = table.Delete().Limit(1).Offset(0).Execute(); - result1 = table.Insert("id", "name", "age") - .Values(1, "jonh doe", 38) - .Execute(); - - Assert.Throws(() => table.Update().Set("name", "updated").Limit(1).Offset(3).Execute()); - - t2 = table.Update().Set("name", "updated").Limit(1).Offset(0).Execute(); - var t = table.Select().Limit(1).Offset(3).Execute(); - t = table.Select().Limit(10).Offset(3).Execute(); - Assert.Throws(() => ExecuteSelectStatement(table.Select().Limit(-1).Offset(3))); - - t = table.Select().Limit(100000000).Offset(3).Execute(); - t = table.Select().Limit(2).Offset(-1).Execute(); - t = table.Select().Limit(2).Offset(1000000).Execute(); - - result = table.Select().GroupBy("age").Execute(); - Assert.AreEqual(5, result.FetchAll().Count); - - // GroupBy with null. - result = table.Select("id as ID", "name as Name", "age as Age").GroupBy(null).Execute(); - Assert.AreEqual(7, result.FetchAll().Count); - - result = table.Select("id as ID", "name as Name", "age as Age").GroupBy(null, null).Execute(); - Assert.AreEqual(7, result.FetchAll().Count); - - result = table.Select("id as ID", "name as Name", "age as Age").GroupBy(null, "age").Execute(); - Assert.AreEqual(5, result.FetchAll().Count); - - // Having operation. - // Having reduces the original 5 rows to 3 since 2 rows have a cnt=2, due to the repeated names. - result = table.Select("id", "count(name) as cnt", "age").GroupBy("age").Having("cnt = 1").Execute(); - Assert.AreEqual(3, result.FetchAll().Count); - - // Having with null. - result = table.Select("id as ID", "count(name) as cnt", "age as Age").GroupBy("age").Having(null).Execute(); - Assert.AreEqual(5, result.FetchAll().Count); - - // GroupBy with invalid field name. - Exception ex = Assert.Throws(() => ExecuteSelectStatement(table.Select("id as ID", "name as Name", "age as Age").GroupBy("Required"))); - Assert.AreEqual("Unknown column 'Required' in 'group statement'", ex.Message); - - ex = Assert.Throws(() => ExecuteSelectStatement(table.Select("id as ID", "name as Name", "age as Age").GroupBy(""))); - Assert.AreEqual("No more tokens when expecting one at token pos 0", ex.Message); - - ex = Assert.Throws(() => ExecuteSelectStatement(table.Select("id as ID", "name as Name", "age as Age").GroupBy(" "))); - Assert.AreEqual("No more tokens when expecting one at token pos 0", ex.Message); - - ex = Assert.Throws(() => ExecuteSelectStatement(table.Select("id as ID", "name as Name", "age as Age").GroupBy(string.Empty))); - Assert.AreEqual("No more tokens when expecting one at token pos 0", ex.Message); - - ex = Assert.Throws(() => ExecuteSelectStatement(table.Select("id as ID", "count(name) as cnt", "age as Age").GroupBy("age").Having("Required = 1"))); - Assert.AreEqual("Unknown column 'Required' in 'having clause'", ex.Message); - - ex = Assert.Throws(() => ExecuteSelectStatement(table.Select("id as ID", "count(name) as cnt", "age as Age").GroupBy("age").Having(""))); - Assert.AreEqual("Unable to parse query ''", ex.Message); - Assert.AreEqual("No more tokens when expecting one at token pos 0", ex.InnerException.Message); - - Assert.Throws(() => ExecuteSelectStatement(table.Select("id as ID", "count(name) as cnt", "age as Age").GroupBy("age").Having(" "))); - Assert.Throws(() => ExecuteSelectStatement(table.Select("id as ID", "count(name) as cnt", "age as Age").GroupBy("age").Having(string.Empty))); - } - - [Test, Description("Reading exclusively locked document in a table using lock_shared with DEFAULT waiting option.")] - public void ExclusiveLockBeforeSharedLockDefaultWaiting() - { - if (!session.InternalSession.GetServerVersion().isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher"); - - session.SQL("DROP TABLE IF EXISTS test.test").Execute(); - session.SQL("CREATE TABLE test.test (id INT, a INT)").Execute(); - var table1 = testSchema.GetTable("test"); - table1.Insert("id", "a").Values(1, 1).Values(2, 2).Values(3, 3).Execute(); - using (var session2 = MySQLX.GetSession(ConnectionString)) - { - var table = session.Schema.GetTable("test"); - session.SQL("CREATE UNIQUE INDEX myIndex ON test.test (id)").Execute(); - var table2 = session2.GetSchema("test").GetTable("test"); - - session.SQL("START TRANSACTION").Execute(); - var rowResult = table.Select().Where("id = 1").LockExclusive().Execute(); - Assert.AreEqual(1, rowResult.FetchAll().Count, "Matching the document ID"); - - session2.SQL("START TRANSACTION").Execute(); - // Should return immediately since document isn't locked. - rowResult = table2.Select().Where("id = 2").LockShared(LockContention.Default).Execute(); - Assert.AreEqual(1, rowResult.FetchAll().Count, "Matching the document ID"); - - // Session2 blocks due to to LockExclusive() not allowing to read locked documents. - session2.SQL("SET SESSION innodb_lock_wait_timeout=1").Execute(); - Assert.Throws(() => ExecuteSelectStatement(table2.Select().Where("id = 1").LockShared(LockContention.Default))); - - // Session2 blocks due to to LockExclusive() not allowing to modify locked documents. - Result result1; - Assert.Throws(() => result1 = table2.Update().Where("id = 1").Set("a", 2).Execute()); - - // Session2 returns immediately as session is committed. - session.Commit(); - var result = table2.Update().Where("id = 1").Set("a", 2).Execute(); - Assert.AreEqual(1, (int)result.AffectedItemsCount, "Matching the deleted record count"); - - session.SQL("ROLLBACK").Execute(); - session2.SQL("ROLLBACK").Execute(); - } - } - - [Test, Description("Reading locked document(lock_shared) in a table using lock_shared with DEFAULT waiting option.")] - public void SharedLockDefaultWaiting() - { - if (!session.InternalSession.GetServerVersion().isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher"); - - session.SQL("DROP TABLE IF EXISTS test.test").Execute(); - session.SQL("CREATE TABLE test.test (id INT, a INT)").Execute(); - var table1 = testSchema.GetTable("test"); - table1.Insert("id", "a").Values(1, 1).Values(2, 2).Values(3, 3).Execute(); - using (var session2 = MySQLX.GetSession(ConnectionString)) - { - var table = session.Schema.GetTable("test"); - var table2 = session2.GetSchema("test").GetTable("test"); - - session.SQL("START TRANSACTION").Execute(); - var rowResult = table.Select().Where("id = 1").LockShared().Execute(); - Assert.AreEqual(1, rowResult.FetchAll().Count, "Matching the document ID"); - - session2.SQL("START TRANSACTION").Execute(); - // Should return immediately since document isn't locked. - rowResult = table2.Select().Where("id = 2").LockShared(LockContention.Default).Execute(); - Assert.AreEqual(1, rowResult.FetchAll().Count, "Matching the document ID"); - - session2.SQL("SET SESSION innodb_lock_wait_timeout=1").Execute(); - rowResult = table2.Select().Where("id = 1").LockShared(LockContention.Default).Execute(); - Assert.AreEqual(1, rowResult.FetchAll().Count, "Matching the document ID"); - // Session2 blocks due to to LockShared() not allowing to modify locked documents. - Result result1; - Assert.Throws(() => result1 = table2.Update().Where("id = 1").Set("a", 2).Execute()); - - // Session2 returns immediately as session is committed. - session.Commit(); - var result = table2.Update().Where("id = 1").Set("a", 2).Execute(); - - session.SQL("ROLLBACK").Execute(); - session2.SQL("ROLLBACK").Execute(); - } - } - - [Test,Description("Reading exclusively locked document in a table using lock_exclusive with DEFAULT waiting option ")] - public void OnlyExclusiveLocksWithDefaultWaiting() - { - if (!session.InternalSession.GetServerVersion().isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher"); - - session.SQL("DROP TABLE IF EXISTS test.test").Execute(); - session.SQL("CREATE TABLE test.test (id INT, a INT)").Execute(); - var table1 = testSchema.GetTable("test"); - table1.Insert("id", "a").Values(1, 1).Values(2, 2).Values(3, 3).Execute(); - using (var session2 = MySQLX.GetSession(ConnectionString)) - { - var table = session.Schema.GetTable("test"); - session.SQL("CREATE UNIQUE INDEX myIndex ON test.test (id)").Execute(); - var table2 = session2.GetSchema("test").GetTable("test"); - - session.SQL("START TRANSACTION").Execute(); - var rowResult = table.Select().Where("id = 1").LockExclusive().Execute(); - Assert.AreEqual(1, rowResult.FetchAll().Count, "Matching the document ID"); - - session2.SQL("START TRANSACTION").Execute(); - // Should return immediately since document isn't locked. - rowResult = table2.Select().Where("id = 2").LockExclusive(LockContention.Default).Execute(); - Assert.AreEqual(1, rowResult.FetchAll().Count, "Matching the document ID"); - - // Session2 blocks due to to LockExclusive() not allowing to read locked documents. - session2.SQL("SET SESSION innodb_lock_wait_timeout=1").Execute(); - Assert.Throws(() => ExecuteSelectStatement(table2.Select().Where("id = 1").LockExclusive(LockContention.Default))); - - // Session2 blocks due to to LockExclusive() not allowing to modify locked documents. - Result result1; - Assert.Throws(() => result1 = table2.Update().Where("id = 1").Set("a", 2).Execute()); - - // Session2 returns immediately as session is committed. - session.Commit(); - var result = table2.Update().Where("id = 1").Set("a", 2).Execute(); - session.SQL("ROLLBACK").Execute(); - session2.SQL("ROLLBACK").Execute(); - } - } - - #endregion WL14389 - - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data.MySqlClient; +using MySqlX.XDevAPI.Common; +using MySqlX.XDevAPI.Relational; +using NUnit.Framework; +using NUnit.Framework.Legacy; +using System; +using System.Collections.Generic; +using MySqlX.XDevAPI; + +namespace MySqlX.Data.Tests.RelationalTests +{ + public class TableUpdateTests : BaseTest + { + Table table; + + [TearDown] + public void TearDown() => ExecuteSQL("DROP TABLE IF EXISTS test"); + + [SetUp] + public void SetUp() + { + ExecuteSQL("CREATE TABLE test.test(id INT, name VARCHAR(40), age INT)"); + + table = testSchema.GetTable("test"); + var insertStatement = table.Insert(); + int rowsToInsert = 10; + for (int i = 1; i <= rowsToInsert; i++) + { + insertStatement.Values(i, i, i); + } + ExecuteInsertStatement(insertStatement); + Assert.That(CountRows(), Is.EqualTo(rowsToInsert)); + } + + private int CountRows() + { + return GetRows(null).Count; + } + + private IReadOnlyCollection GetRows(FilterParams filter) + { + var statement = table.Select(); + if (filter != null) + { + statement.FilterData.Condition = filter.Condition; + statement.FilterData.Limit = filter.Limit; + statement.FilterData.OrderBy = filter.OrderBy; + statement.FilterData.Parameters = filter.Parameters; + } + var result = ExecuteSelectStatement(statement); + while (result.Next()) ; + return result.Rows; + } + + private void ValidateUpdate(TableUpdateStatement statement) + { + Dictionary parameters = new Dictionary(statement.FilterData.Parameters); + var result = ExecuteUpdateStatement(statement); + statement.FilterData.Parameters = parameters; + var rows = GetRows(statement.FilterData); + foreach (var row in rows) + { + foreach (var set in statement.updates) + { + Assert.That(row.GetString(set.Path), Is.EqualTo(set.Value.ToString())); + } + } + } + + [Test] + public void EmptyUpdateTest() + { + Assert.Throws(() => ExecuteUpdateStatement(table.Update())); + } + + [Test] + public void UpdateConditionTest() + { + ValidateUpdate(table.Update().Where("id = 5").Set("name", "other")); + } + + [Test] + public void UpdateMultiSet() + { + ValidateUpdate(table.Update().Set("name", "other") + .Set("age", 21) + .Set("id", 30) + .Where("id = 3")); + } + + [Test] + public void UpdateMultiRows() + { + ValidateUpdate(table.Update().Set("age", 85).Where("id % 2 = 0")); + } + + [Test] + public void UpdateAllRows() + { + ValidateUpdate(table.Update().Set("age", 32).Set("name", "jonh")); + } + + [Test] + public void UpdateOrderbyAndLimit() + { + ValidateUpdate(table.Update().Set("age", 15).OrderBy("id DES").Limit(5)); + } + + [Test] + public void UpdateBind() + { + var stmt = table.Update().Set("age", 55).Where("id = :id or id = :id or id = :id2"); + ValidateUpdate(stmt.Bind("id", 4).Bind("id2", 7)); + ValidateUpdate(stmt.Bind("id", 5).Bind("id2", 8)); + } + + [Test] + public void UpdateWithInOperator() + { + Table table = testSchema.GetTable("test"); + Assert.That(CountRows(), Is.EqualTo(10)); + + Assert.That(ExecuteUpdateStatement(table.Update().Where("id IN (1,2)").Set("id", 0)).AffectedItemsCount, Is.EqualTo(2)); + Assert.That(ExecuteSelectStatement(table.Select().Where("id = 0")).FetchAll().Count, Is.EqualTo(2)); + + Assert.Throws(() => ExecuteDeleteStatement(table.Delete().Where("a IN [3]"))); + Assert.Throws(() => ExecuteDeleteStatement(table.Delete().Where("3 IN a"))); + Assert.Throws(() => ExecuteUpdateStatement(table.Update().Where("age IN [3]").Set("id", 0))); + + Assert.That(ExecuteUpdateStatement(table.Update().Where("age IN (3)").Set("id", 0)).AffectedItemsCount, Is.EqualTo(1)); + Assert.That(ExecuteSelectStatement(table.Select().Where("id = 0")).FetchAll().Count, Is.EqualTo(3)); + } + + #region WL14389 + + [Test, Description("Collection.Find(condition).GroupBy(SearchExprStr)")] + public void TableSelectGroupBy() + { + ExecuteSQLStatement(session.SQL("set sql_mode = 'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';")); + session.SQL("delete from test").Execute(); + Table table = testSchema.GetTable("test"); + var result1 = table.Insert("id", "name", "age") + .Values(1, "jonh doe", 38) + .Values(2, "milton greenh", 45) + .Values(3, "larry smith", 24) + .Values(4, "mary weinstein", 24) + .Values(5, "jerry pratt", 45) + .Values(6, "hugh jackman", 20) + .Values(7, "elizabeth olsen", 31) + .Execute(); + RowResult result = table.Select().OrderBy("age desc").Execute(); + Assert.Throws(() => table.Delete().Limit(1).Offset(3).Execute()); + + var t2 = table.Delete().Limit(1).Offset(0).Execute(); + result1 = table.Insert("id", "name", "age") + .Values(1, "jonh doe", 38) + .Execute(); + + Assert.Throws(() => table.Update().Set("name", "updated").Limit(1).Offset(3).Execute()); + + t2 = table.Update().Set("name", "updated").Limit(1).Offset(0).Execute(); + var t = table.Select().Limit(1).Offset(3).Execute(); + t = table.Select().Limit(10).Offset(3).Execute(); + Assert.Throws(() => ExecuteSelectStatement(table.Select().Limit(-1).Offset(3))); + + t = table.Select().Limit(100000000).Offset(3).Execute(); + t = table.Select().Limit(2).Offset(-1).Execute(); + t = table.Select().Limit(2).Offset(1000000).Execute(); + + result = table.Select().GroupBy("age").Execute(); + Assert.That(result.FetchAll().Count, Is.EqualTo(5)); + + // GroupBy with null. + result = table.Select("id as ID", "name as Name", "age as Age").GroupBy(null).Execute(); + Assert.That(result.FetchAll().Count, Is.EqualTo(7)); + + result = table.Select("id as ID", "name as Name", "age as Age").GroupBy(null, null).Execute(); + Assert.That(result.FetchAll().Count, Is.EqualTo(7)); + + result = table.Select("id as ID", "name as Name", "age as Age").GroupBy(null, "age").Execute(); + Assert.That(result.FetchAll().Count, Is.EqualTo(5)); + + // Having operation. + // Having reduces the original 5 rows to 3 since 2 rows have a cnt=2, due to the repeated names. + result = table.Select("id", "count(name) as cnt", "age").GroupBy("age").Having("cnt = 1").Execute(); + Assert.That(result.FetchAll().Count, Is.EqualTo(3)); + + // Having with null. + result = table.Select("id as ID", "count(name) as cnt", "age as Age").GroupBy("age").Having(null).Execute(); + Assert.That(result.FetchAll().Count, Is.EqualTo(5)); + + // GroupBy with invalid field name. + Exception ex = Assert.Throws(() => ExecuteSelectStatement(table.Select("id as ID", "name as Name", "age as Age").GroupBy("Required"))); + Assert.That(ex.Message, Is.EqualTo("Unknown column 'Required' in 'group statement'")); + + ex = Assert.Throws(() => ExecuteSelectStatement(table.Select("id as ID", "name as Name", "age as Age").GroupBy(""))); + Assert.That(ex.Message, Is.EqualTo("No more tokens when expecting one at token pos 0")); + + ex = Assert.Throws(() => ExecuteSelectStatement(table.Select("id as ID", "name as Name", "age as Age").GroupBy(" "))); + Assert.That(ex.Message, Is.EqualTo("No more tokens when expecting one at token pos 0")); + + ex = Assert.Throws(() => ExecuteSelectStatement(table.Select("id as ID", "name as Name", "age as Age").GroupBy(string.Empty))); + Assert.That(ex.Message, Is.EqualTo("No more tokens when expecting one at token pos 0")); + + ex = Assert.Throws(() => ExecuteSelectStatement(table.Select("id as ID", "count(name) as cnt", "age as Age").GroupBy("age").Having("Required = 1"))); + Assert.That(ex.Message, Is.EqualTo("Unknown column 'Required' in 'having clause'")); + + ex = Assert.Throws(() => ExecuteSelectStatement(table.Select("id as ID", "count(name) as cnt", "age as Age").GroupBy("age").Having(""))); + Assert.That(ex.Message, Is.EqualTo("Unable to parse query ''")); + Assert.That(ex.InnerException.Message, Is.EqualTo("No more tokens when expecting one at token pos 0")); + + Assert.Throws(() => ExecuteSelectStatement(table.Select("id as ID", "count(name) as cnt", "age as Age").GroupBy("age").Having(" "))); + Assert.Throws(() => ExecuteSelectStatement(table.Select("id as ID", "count(name) as cnt", "age as Age").GroupBy("age").Having(string.Empty))); + } + + [Test, Description("Reading exclusively locked document in a table using lock_shared with DEFAULT waiting option.")] + public void ExclusiveLockBeforeSharedLockDefaultWaiting() + { + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); + + session.SQL("DROP TABLE IF EXISTS test.test").Execute(); + session.SQL("CREATE TABLE test.test (id INT, a INT)").Execute(); + var table1 = testSchema.GetTable("test"); + table1.Insert("id", "a").Values(1, 1).Values(2, 2).Values(3, 3).Execute(); + using (var session2 = MySQLX.GetSession(ConnectionString)) + { + var table = session.Schema.GetTable("test"); + session.SQL("CREATE UNIQUE INDEX myIndex ON test.test (id)").Execute(); + var table2 = session2.GetSchema("test").GetTable("test"); + + session.SQL("START TRANSACTION").Execute(); + var rowResult = table.Select().Where("id = 1").LockExclusive().Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + + session2.SQL("START TRANSACTION").Execute(); + // Should return immediately since document isn't locked. + rowResult = table2.Select().Where("id = 2").LockShared(LockContention.Default).Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + + // Session2 blocks due to to LockExclusive() not allowing to read locked documents. + session2.SQL("SET SESSION innodb_lock_wait_timeout=1").Execute(); + Assert.Throws(() => ExecuteSelectStatement(table2.Select().Where("id = 1").LockShared(LockContention.Default))); + + // Session2 blocks due to to LockExclusive() not allowing to modify locked documents. + Result result1; + Assert.Throws(() => result1 = table2.Update().Where("id = 1").Set("a", 2).Execute()); + + // Session2 returns immediately as session is committed. + session.Commit(); + var result = table2.Update().Where("id = 1").Set("a", 2).Execute(); + Assert.That((int)result.AffectedItemsCount, Is.EqualTo(1), "Matching the deleted record count"); + + session.SQL("ROLLBACK").Execute(); + session2.SQL("ROLLBACK").Execute(); + } + } + + [Test, Description("Reading locked document(lock_shared) in a table using lock_shared with DEFAULT waiting option.")] + public void SharedLockDefaultWaiting() + { + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); + + session.SQL("DROP TABLE IF EXISTS test.test").Execute(); + session.SQL("CREATE TABLE test.test (id INT, a INT)").Execute(); + var table1 = testSchema.GetTable("test"); + table1.Insert("id", "a").Values(1, 1).Values(2, 2).Values(3, 3).Execute(); + using (var session2 = MySQLX.GetSession(ConnectionString)) + { + var table = session.Schema.GetTable("test"); + var table2 = session2.GetSchema("test").GetTable("test"); + + session.SQL("START TRANSACTION").Execute(); + var rowResult = table.Select().Where("id = 1").LockShared().Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + + session2.SQL("START TRANSACTION").Execute(); + // Should return immediately since document isn't locked. + rowResult = table2.Select().Where("id = 2").LockShared(LockContention.Default).Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + + session2.SQL("SET SESSION innodb_lock_wait_timeout=1").Execute(); + rowResult = table2.Select().Where("id = 1").LockShared(LockContention.Default).Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + // Session2 blocks due to to LockShared() not allowing to modify locked documents. + Result result1; + Assert.Throws(() => result1 = table2.Update().Where("id = 1").Set("a", 2).Execute()); + + // Session2 returns immediately as session is committed. + session.Commit(); + var result = table2.Update().Where("id = 1").Set("a", 2).Execute(); + + session.SQL("ROLLBACK").Execute(); + session2.SQL("ROLLBACK").Execute(); + } + } + + [Test,Description("Reading exclusively locked document in a table using lock_exclusive with DEFAULT waiting option ")] + public void OnlyExclusiveLocksWithDefaultWaiting() + { + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); + + session.SQL("DROP TABLE IF EXISTS test.test").Execute(); + session.SQL("CREATE TABLE test.test (id INT, a INT)").Execute(); + var table1 = testSchema.GetTable("test"); + table1.Insert("id", "a").Values(1, 1).Values(2, 2).Values(3, 3).Execute(); + using (var session2 = MySQLX.GetSession(ConnectionString)) + { + var table = session.Schema.GetTable("test"); + session.SQL("CREATE UNIQUE INDEX myIndex ON test.test (id)").Execute(); + var table2 = session2.GetSchema("test").GetTable("test"); + + session.SQL("START TRANSACTION").Execute(); + var rowResult = table.Select().Where("id = 1").LockExclusive().Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + + session2.SQL("START TRANSACTION").Execute(); + // Should return immediately since document isn't locked. + rowResult = table2.Select().Where("id = 2").LockExclusive(LockContention.Default).Execute(); + Assert.That(rowResult.FetchAll().Count, Is.EqualTo(1), "Matching the document ID"); + + // Session2 blocks due to to LockExclusive() not allowing to read locked documents. + session2.SQL("SET SESSION innodb_lock_wait_timeout=1").Execute(); + Assert.Throws(() => ExecuteSelectStatement(table2.Select().Where("id = 1").LockExclusive(LockContention.Default))); + + // Session2 blocks due to to LockExclusive() not allowing to modify locked documents. + Result result1; + Assert.Throws(() => result1 = table2.Update().Where("id = 1").Set("a", 2).Execute()); + + // Session2 returns immediately as session is committed. + session.Commit(); + var result = table2.Update().Where("id = 1").Set("a", 2).Execute(); + session.SQL("ROLLBACK").Execute(); + session2.SQL("ROLLBACK").Execute(); + } + } + + #endregion WL14389 + + } +} diff --git a/MySQL.Data/tests/MySqlX.Data.Tests/RelationalTests/ViewTests.cs b/MySQL.Data/tests/MySqlX.Data.Tests/RelationalTests/ViewTests.cs index dd1975c2d..40903ff04 100644 --- a/MySQL.Data/tests/MySqlX.Data.Tests/RelationalTests/ViewTests.cs +++ b/MySQL.Data/tests/MySqlX.Data.Tests/RelationalTests/ViewTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2016, 2021, Oracle and/or its affiliates. +// Copyright © 2016, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -29,6 +29,7 @@ using MySql.Data.MySqlClient; using MySqlX.XDevAPI.Relational; using NUnit.Framework; +using NUnit.Framework.Legacy; using System.Collections.Generic; using System.Linq; using MySqlX.XDevAPI; @@ -53,12 +54,12 @@ public void TryUpdatingView() ExecuteSQL("CREATE VIEW view2 AS select *, 1 from test"); List
tables = testSchema.GetTables(); - Assert.AreEqual(2, tables.Count); + Assert.That(tables.Count, Is.EqualTo(2)); Table view = tables.First(i => i.IsView); - Assert.AreEqual("view2", view.Name); + Assert.That(view.Name, Is.EqualTo("view2")); MySqlException ex = Assert.Throws(() => ExecuteInsertStatement(view.Insert().Values(1))); - Assert.AreEqual("Column '1' is not updatable", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Column '1' is not updatable")); } [Test] @@ -69,8 +70,8 @@ public void GetView() Table table = testSchema.GetTable("test"); Table view = testSchema.GetTable("view1"); - Assert.True(view.IsView); - Assert.False(table.IsView); + Assert.That(view.IsView); + Assert.That(table.IsView, Is.False); ExecuteSQL("DROP VIEW view1"); } @@ -99,13 +100,13 @@ public void CreateJoinAndGetTableValidation() ExecuteSQL("CREATE VIEW view2 AS select * from test.test2"); var tables = testSchema.GetTables(); - Assert.AreEqual(true, tables.Count == 4, "Match being done"); - Assert.AreEqual(2, tables.Count(i => !i.IsView), "Match being done when isview not true"); - Assert.AreEqual(2, tables.Count(i => i.IsView), "Match being done when isview true"); + Assert.That(tables.Count == 4, Is.EqualTo(true), "Match being done"); + Assert.That(tables.Count(i => !i.IsView), Is.EqualTo(2), "Match being done when isview not true"); + Assert.That(tables.Count(i => i.IsView), Is.EqualTo(2), "Match being done when isview true"); List colls = testSchema.GetCollections(); - Assert.AreEqual(1, colls.Count, "Match being done"); + Assert.That(colls.Count, Is.EqualTo(1), "Match being done"); var view1 = testSchema.GetTable("view1"); - Assert.True(view1.IsView); + Assert.That(view1.IsView); //Valid Scenario-1 view1.Select().Execute(); @@ -124,7 +125,7 @@ public void CreateJoinAndGetTableValidation() "CREATE VIEW myView AS SELECT a.ID1 as a_tID,b.ID2 as b_tID, a.firstname as a_firstname, " + "b.lastname as b_lastname FROM test1 a JOIN test2 b ON a.ID1=b.ID2;"); var joinedview = testSchema.GetTable("myView"); - Assert.True(joinedview.IsView); + Assert.That(joinedview.IsView); joinedview.Select().Execute(); result = joinedview.Update().Set("a_firstname", "Peter").Where("a_tID=1").Execute(); @@ -136,7 +137,7 @@ public void CreateJoinAndGetTableValidation() //Valid View - Invalid Select/Insert/Update Statements-Scenario-3 var view2 = testSchema.GetTable("view2"); - Assert.True(view2.IsView); + Assert.That(view2.IsView); Assert.Throws(() => view2.Select("id2", "age").Execute()); @@ -147,7 +148,7 @@ public void CreateJoinAndGetTableValidation() view2.Select().Execute(); var res = view2.Delete().Where("id2=100").Execute(); - Assert.AreEqual(0, res.AffectedItemsCount, "View2-Not Possible to remove an invalid record"); + Assert.That(res.AffectedItemsCount, Is.EqualTo(0), "View2-Not Possible to remove an invalid record"); //View Doesn't Exist-Scenario-4 var view3 = testSchema.GetTable("view3"); @@ -159,7 +160,7 @@ public void CreateJoinAndGetTableValidation() //View Passed as Null-Scenario-6 var view4 = testSchema.GetTable("test1"); - Assert.IsFalse(view4.IsView); + Assert.That(view4.IsView, Is.False); //Change the query processing env-Scenario-7 ExecuteSQL("SET sql_mode = '';"); @@ -186,14 +187,14 @@ public void ViewsGetTables() ExecuteSQL("CREATE VIEW view2 AS select * from test.test2"); ExecuteSQL("SELECT * FROM view2"); var tables = testSchema.GetTables(); - Assert.True(tables.Count >= 4, "Match being done"); - Assert.AreEqual(2, tables.Count(i => !i.IsView), "Match being done when isview not true"); - Assert.AreEqual(2, tables.Count(i => i.IsView), "Match being done when isview true"); + Assert.That(tables.Count >= 4, "Match being done"); + Assert.That(tables.Count(i => !i.IsView), Is.EqualTo(2), "Match being done when isview not true"); + Assert.That(tables.Count(i => i.IsView), Is.EqualTo(2), "Match being done when isview true"); List colls = testSchema.GetCollections(); - Assert.AreEqual(1, colls.Count, "Match being done"); + Assert.That(colls.Count, Is.EqualTo(1), "Match being done"); var view1 = tables[2]; - Assert.True(view1.IsView); + Assert.That(view1.IsView); //Valid Scenario-1 view1.Select().Execute(); @@ -212,7 +213,7 @@ public void ViewsGetTables() "CREATE VIEW myView AS SELECT a.ID1 as a_tID,b.ID2 as b_tID, a.firstname as a_firstname, " + "b.lastname as b_lastname FROM test1 a JOIN test2 b ON a.ID1=b.ID2;"); var joinedview = testSchema.GetTables(); - Assert.True(joinedview[0].IsView); + Assert.That(joinedview[0].IsView); joinedview[0].Select().Execute(); result = joinedview[0].Update().Set("a_firstname", "Peter").Where("a_tID=1").Execute(); result = joinedview[0].Update().Set("a_firstname", "Rob").Where("a_tID=1").Execute(); @@ -224,7 +225,7 @@ public void ViewsGetTables() ExecuteSQL("DROP VIEW " + joinedview[0].Name); //Valid View - Invalid Select/Insert/Update Statements-Scenario-3 var view2 = testSchema.GetTables(); - Assert.True(view2[3].IsView); + Assert.That(view2[3].IsView); Assert.Throws(() => view2[3].Select("id2", "age").Execute()); @@ -237,7 +238,7 @@ public void ViewsGetTables() view2[3].Select().Execute(); var res = view2[3].Delete().Where("id2=100").Execute(); //WL11843-Core API v1 alignment Changes - Assert.AreEqual(0, res.AffectedItemsCount); + Assert.That(res.AffectedItemsCount, Is.EqualTo(0)); //Change the query processing env-Scenario-5 ExecuteSQL("SET sql_mode = '';"); @@ -249,7 +250,7 @@ public void ViewsGetTables() ExecuteSQL("DROP VIEW view2"); //GetTables when there no tables/views -Scenario-4 var view3 = testSchema.GetTables(); - Assert.AreEqual(0, view3.Count()); + Assert.That(view3.Count(), Is.EqualTo(0)); } #endregion WL14389 diff --git a/MySQL.Data/tests/MySqlX.Data.Tests/SchemaTests.cs b/MySQL.Data/tests/MySqlX.Data.Tests/SchemaTests.cs index a2151ce2c..601db8a74 100644 --- a/MySQL.Data/tests/MySqlX.Data.Tests/SchemaTests.cs +++ b/MySQL.Data/tests/MySqlX.Data.Tests/SchemaTests.cs @@ -1,297 +1,298 @@ -// Copyright (c) 2015, 2021, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data.MySqlClient; -using MySqlX.XDevAPI; -using MySqlX.XDevAPI.Common; -using MySqlX.XDevAPI.Relational; -using NUnit.Framework; -using System; -using System.Collections.Generic; -using System.Linq; - -namespace MySqlX.Data.Tests -{ - public class SchemaTests : BaseTest - { - [TearDown] - public void TearDown() => ExecuteSQL("DROP TABLE IF EXISTS test"); - [Test] - public void GetSchemas() - { - Session session = GetSession(); - List schemas = session.GetSchemas(); - - Assert.True(schemas.Exists(s => s.Name == base.testSchema.Name)); - - Schema schema = session.GetSchema(schemaName); - Assert.AreEqual(schemaName, schema.Name); - schema = session.GetSchema(null); - Assert.IsNull(schema.Name); - } - - [Test] - public void GetInvalidSchema() - { - Session s = GetSession(); - Schema schema = s.GetSchema("test-schema"); - Assert.False(SchemaExistsInDatabase(schema)); - } - - [Test] - public void GetAllTables() - { - ExecuteSQL("DROP TABLE IF EXISTS test"); - ExecuteSQL("CREATE TABLE test(id int)"); - - List
tables = testSchema.GetTables(); - Assert.True(tables.Count == 1); - } - - [Test] - public void GetAllViews() - { - CreateCollection("coll"); - - ExecuteSQL("DROP TABLE IF EXISTS test"); - ExecuteSQL("CREATE TABLE test(id int)"); - ExecuteSQL("CREATE VIEW view1 AS select * from test"); - ExecuteSQL("CREATE VIEW view2 AS select * from test"); - - List
tables = testSchema.GetTables(); - Assert.AreEqual(3, tables.Count); - Assert.AreEqual(1, tables.Count(i => !i.IsView)); - Assert.AreEqual(2, tables.Count(i => i.IsView)); - - List colls = testSchema.GetCollections(); - Assert.That(colls, Has.One.Items); - } - - [Test] - [Ignore("Fix for 8.0.13")] - public void GetCollectionAsTable() - { - Collection testCollection = CreateCollection("test"); - - Result r = ExecuteAddStatement(testCollection.Add(@"{ ""_id"": 1, ""foo"": 1 }")); - Assert.AreEqual(1, r.AffectedItemsCount); - - Table test = testSchema.GetCollectionAsTable("test"); - Assert.True(TableExistsInDatabase(test)); - - RowResult result = ExecuteSelectStatement(test.Select("_id")); - Assert.True(result.Next()); - Assert.AreEqual("1", result[0]); - } - - [Test] - public void DropSchema() - { - string schemaName = "testDrop"; - Session session = GetSession(); - session.CreateSchema(schemaName); - Schema schema = session.GetSchema(schemaName); - Assert.True(SchemaExistsInDatabase(schema)); - - // Drop existing schema. - session.DropSchema(schemaName); - Assert.False(SchemaExistsInDatabase(schema)); - - // Drop non-existing schema. - session.DropSchema(schemaName); - Assert.False(SchemaExistsInDatabase(schema)); - - // Empty, whitespace and null schema name. - Assert.Throws(() => session.DropSchema(string.Empty)); - Assert.Throws(() => session.DropSchema(" ")); - Assert.Throws(() => session.DropSchema(" ")); - Assert.Throws(() => session.DropSchema(null)); - } - - #region WL14389 - - [Test, Description("Test MySQLX plugin Exception Handling Scenario 1")] - public void ExceptionHandlingSchema() - { - Session sessionPlain = MySQLX.GetSession(ConnectionString); - sessionPlain.DropSchema("test1"); - var db = sessionPlain.CreateSchema("test1"); - db = sessionPlain.GetSchema("test1"); - if (db.ExistsInDatabase()) - { - sessionPlain.DropSchema("test1"); - db = sessionPlain.CreateSchema("test1"); - db.DropCollection("test"); - var coll = db.CreateCollection("test"); - var res = coll.Add("{\"_id\":null,\"FLD1\":\"nulldata\"}").Execute(); - var docIds = res.GeneratedIds.Count; - - var docs = coll.Find("$.FLD1 == 'nulldata'").Execute(); - while (docs.Next()) - { - Assert.Throws(() => docs.Current["_id"].ToString()); - } - } - else { db = sessionPlain.CreateSchema("test1"); } - Assert.Throws(() => sessionPlain.CreateSchema("test1")); - sessionPlain.SQL(@"drop database if exists test1;").Execute(); - - sessionPlain.SQL(@"drop database if exists `test\84`;").Execute(); - db = sessionPlain.CreateSchema("test\\84"); - - sessionPlain.SQL(@"drop database if exists `test\84`;").Execute(); - db = sessionPlain.CreateSchema(@"test\84"); - - sessionPlain.SQL(@"drop database if exists `test\84`;").Execute(); - } - - [Test, Description("Test MySQLX plugin Exception Handling Scenario 2")] - public void ExceptionHandlingCollection() - { - if (!session.Version.isAtLeast(5, 7, 0)) Assert.Ignore("This test is for MySql 5.7 or higher."); - - Session sessionPlain = MySQLX.GetSession(ConnectionString); - - if (sessionPlain.GetSchema("test_collection_123456789").ExistsInDatabase()) - { - sessionPlain.DropSchema("test_collection_123456789"); - } - var db = sessionPlain.CreateSchema("test_collection_123456789"); - if (db.GetCollection("my_collection_123456789").ExistsInDatabase()) - { - db.DropCollection("my_collection_123456789"); - } - db.CreateCollection("my_collection_123456789"); - Assert.Throws(() => db.CreateCollection("my_collection_123456789")); - - sessionPlain.DropSchema("test_collection_123456789"); - } - - [Test, Description("GetSession Create Schema Valid Name(Session and Session)")] - public void CreateValidSchema() - { - Schema db = session.GetSchema("test_123456789"); - if (db.ExistsInDatabase()) - { - session.DropSchema("test_123456789"); - db = session.CreateSchema("test_123456789"); - } - else { db = session.CreateSchema("test_123456789"); } - Assert.True(db.ExistsInDatabase()); - Assert.Throws(() => session.CreateSchema("test_123456789")); - session.DropSchema("test_123456789"); - Assert.Throws(() => session.CreateSchema("test_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789")); - Assert.Throws(() => session.CreateSchema(null)); - } - - [Test, Description("Set Node Schema")] - public void SessionSetSchema() - { - if (!session.Version.isAtLeast(5, 7, 0)) Assert.Ignore("This test is for MySql 5.7 or higher."); - if (!session.GetSchema("test1").ExistsInDatabase()) - session.CreateSchema("test1"); - Assert.DoesNotThrow(() => session.SetCurrentSchema("test1")); - Assert.AreEqual("test1", session.Schema.Name); - // Retry the same schema - Assert.DoesNotThrow(() => session.SetCurrentSchema("test1")); - Assert.AreEqual("test1", session.Schema.Name); - session.Schema.CreateCollection("my_collection_123456789"); - session.Schema.DropCollection("my_collection_123456789"); - //Exceptions - Assert.Throws(() => session.SQL("USE nonExistingSchema").Execute()); - Assert.Throws(() => session.SetCurrentSchema("nonExistingSchema")); - Assert.Throws(() => session.SetCurrentSchema(null)); - session.DropSchema("test1"); - //No Active Schema - using (Session sessionPlain = MySQLX.GetSession(ConnectionString)) - { - Assert.IsNull(sessionPlain.GetCurrentSchema()); - } - } - - [Test, Description("Session Status before Execution - Negative")] - public void SessionClosedBeforeExecution() - { - if (!session.Version.isAtLeast(5, 7, 0)) Assert.Ignore("This test is for MySql 5.7 or higher."); - Schema schema = null; - Session sessionPlain = MySQLX.GetSession(ConnectionString); - schema = sessionPlain.GetSchema(schemaName); - schema.CreateCollection("test123"); - schema.DropCollection("test123"); - sessionPlain.Close(); - Assert.Throws(() => schema.CreateCollection("test123")); - sessionPlain.Dispose(); - } - - [Test, Description("Session Switch-SetCurrentSchema(Same and Different Session)")] - public void SessionChangeCurrentSchema() - { - using (Session session = MySQLX.GetSession(ConnectionString)) - { - session.SQL("DROP DATABASE IF EXISTS dbname1").Execute(); - session.SQL("CREATE DATABASE dbname1").Execute(); - session.SQL("USE dbname1").Execute(); - StringAssert.AreEqualIgnoringCase("dbname1", session.GetCurrentSchema().Name); - session.SQL("CREATE TABLE address1" + - "(address_number INT NOT NULL AUTO_INCREMENT, " + - "building_name VARCHAR(100) NOT NULL, " + - "district VARCHAR(100) NOT NULL, PRIMARY KEY (address_number)" + ");").Execute(); - session.SQL("INSERT INTO address1" + - "(address_number,building_name,district)" + - " VALUES " + - "(1,'MySQL1','BGL1');").Execute(); - - session.SQL("DROP DATABASE IF EXISTS dbname2").Execute(); - session.SQL("CREATE DATABASE dbname2").Execute(); - session.SQL("USE dbname2").Execute(); - StringAssert.AreEqualIgnoringCase("dbname2", session.GetCurrentSchema().Name); - session.SQL("CREATE TABLE address2" + - "(address_number INT NOT NULL AUTO_INCREMENT, " + - "building_name VARCHAR(100) NOT NULL, " + - "district VARCHAR(100) NOT NULL, PRIMARY KEY (address_number)" + ");").Execute(); - session.SQL("INSERT INTO address2" + - "(address_number,building_name,district)" + - " VALUES " + - "(2,'MySQL2','BGL2');").Execute(); - session.SetCurrentSchema("dbname1"); - Assert.AreEqual("dbname1", session.Schema.Name); - session.SQL("SELECT * FROM address1").Execute(); - session.SQL("DROP TABLE address1").Execute(); - session.SetCurrentSchema("dbname2"); - StringAssert.AreEqualIgnoringCase("dbName2", session.Schema.Name); - session.SQL("SELECT * FROM address2").Execute(); - session.SQL("DROP TABLE address2").Execute(); - session.SQL("DROP DATABASE dbname1").Execute(); - session.SQL("DROP DATABASE dbname2").Execute(); - session.Close(); - session.Dispose(); - } - } - #endregion WL14389 - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data.MySqlClient; +using MySqlX.XDevAPI; +using MySqlX.XDevAPI.Common; +using MySqlX.XDevAPI.Relational; +using NUnit.Framework; +using NUnit.Framework.Legacy; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace MySqlX.Data.Tests +{ + public class SchemaTests : BaseTest + { + [TearDown] + public void TearDown() => ExecuteSQL("DROP TABLE IF EXISTS test"); + [Test] + public void GetSchemas() + { + Session session = GetSession(); + List schemas = session.GetSchemas(); + + Assert.That(schemas.Exists(s => s.Name == base.testSchema.Name)); + + Schema schema = session.GetSchema(schemaName); + Assert.That(schema.Name, Is.EqualTo(schemaName)); + schema = session.GetSchema(null); + Assert.That(schema.Name, Is.Null); + } + + [Test] + public void GetInvalidSchema() + { + Session s = GetSession(); + Schema schema = s.GetSchema("test-schema"); + Assert.That(SchemaExistsInDatabase(schema), Is.False); + } + + [Test] + public void GetAllTables() + { + ExecuteSQL("DROP TABLE IF EXISTS test"); + ExecuteSQL("CREATE TABLE test(id int)"); + + List
tables = testSchema.GetTables(); + Assert.That(tables.Count == 1); + } + + [Test] + public void GetAllViews() + { + CreateCollection("coll"); + + ExecuteSQL("DROP TABLE IF EXISTS test"); + ExecuteSQL("CREATE TABLE test(id int)"); + ExecuteSQL("CREATE VIEW view1 AS select * from test"); + ExecuteSQL("CREATE VIEW view2 AS select * from test"); + + List
tables = testSchema.GetTables(); + Assert.That(tables.Count, Is.EqualTo(3)); + Assert.That(tables.Count(i => !i.IsView), Is.EqualTo(1)); + Assert.That(tables.Count(i => i.IsView), Is.EqualTo(2)); + + List colls = testSchema.GetCollections(); + Assert.That(colls, Has.One.Items); + } + + [Test] + [Ignore("Fix for 8.0.13")] + public void GetCollectionAsTable() + { + Collection testCollection = CreateCollection("test"); + + Result r = ExecuteAddStatement(testCollection.Add(@"{ ""_id"": 1, ""foo"": 1 }")); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); + + Table test = testSchema.GetCollectionAsTable("test"); + Assert.That(TableExistsInDatabase(test)); + + RowResult result = ExecuteSelectStatement(test.Select("_id")); + Assert.That(result.Next()); + Assert.That(result[0], Is.EqualTo("1")); + } + + [Test] + public void DropSchema() + { + string schemaName = "testDrop"; + Session session = GetSession(); + session.CreateSchema(schemaName); + Schema schema = session.GetSchema(schemaName); + Assert.That(SchemaExistsInDatabase(schema)); + + // Drop existing schema. + session.DropSchema(schemaName); + Assert.That(SchemaExistsInDatabase(schema), Is.False); + + // Drop non-existing schema. + session.DropSchema(schemaName); + Assert.That(SchemaExistsInDatabase(schema), Is.False); + + // Empty, whitespace and null schema name. + Assert.Throws(() => session.DropSchema(string.Empty)); + Assert.Throws(() => session.DropSchema(" ")); + Assert.Throws(() => session.DropSchema(" ")); + Assert.Throws(() => session.DropSchema(null)); + } + + #region WL14389 + + [Test, Description("Test MySQLX plugin Exception Handling Scenario 1")] + public void ExceptionHandlingSchema() + { + Session sessionPlain = MySQLX.GetSession(ConnectionString); + sessionPlain.DropSchema("test1"); + var db = sessionPlain.CreateSchema("test1"); + db = sessionPlain.GetSchema("test1"); + if (db.ExistsInDatabase()) + { + sessionPlain.DropSchema("test1"); + db = sessionPlain.CreateSchema("test1"); + db.DropCollection("test"); + var coll = db.CreateCollection("test"); + var res = coll.Add("{\"_id\":null,\"FLD1\":\"nulldata\"}").Execute(); + var docIds = res.GeneratedIds.Count; + + var docs = coll.Find("$.FLD1 == 'nulldata'").Execute(); + while (docs.Next()) + { + Assert.Throws(() => docs.Current["_id"].ToString()); + } + } + else { db = sessionPlain.CreateSchema("test1"); } + Assert.Throws(() => sessionPlain.CreateSchema("test1")); + sessionPlain.SQL(@"drop database if exists test1;").Execute(); + + sessionPlain.SQL(@"drop database if exists `test\84`;").Execute(); + db = sessionPlain.CreateSchema("test\\84"); + + sessionPlain.SQL(@"drop database if exists `test\84`;").Execute(); + db = sessionPlain.CreateSchema(@"test\84"); + + sessionPlain.SQL(@"drop database if exists `test\84`;").Execute(); + } + + [Test, Description("Test MySQLX plugin Exception Handling Scenario 2")] + public void ExceptionHandlingCollection() + { + Assume.That(session.Version.isAtLeast(5, 7, 0), "This test is for MySql 5.7 or higher"); + + Session sessionPlain = MySQLX.GetSession(ConnectionString); + + if (sessionPlain.GetSchema("test_collection_123456789").ExistsInDatabase()) + { + sessionPlain.DropSchema("test_collection_123456789"); + } + var db = sessionPlain.CreateSchema("test_collection_123456789"); + if (db.GetCollection("my_collection_123456789").ExistsInDatabase()) + { + db.DropCollection("my_collection_123456789"); + } + db.CreateCollection("my_collection_123456789"); + Assert.Throws(() => db.CreateCollection("my_collection_123456789")); + + sessionPlain.DropSchema("test_collection_123456789"); + } + + [Test, Description("GetSession Create Schema Valid Name(Session and Session)")] + public void CreateValidSchema() + { + Schema db = session.GetSchema("test_123456789"); + if (db.ExistsInDatabase()) + { + session.DropSchema("test_123456789"); + db = session.CreateSchema("test_123456789"); + } + else { db = session.CreateSchema("test_123456789"); } + Assert.That(db.ExistsInDatabase()); + Assert.Throws(() => session.CreateSchema("test_123456789")); + session.DropSchema("test_123456789"); + Assert.Throws(() => session.CreateSchema("test_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789")); + Assert.Throws(() => session.CreateSchema(null)); + } + + [Test, Description("Set Node Schema")] + public void SessionSetSchema() + { + Assume.That(session.Version.isAtLeast(5, 7, 0), "This test is for MySql 5.7 or higher"); + if (!session.GetSchema("test1").ExistsInDatabase()) + session.CreateSchema("test1"); + Assert.DoesNotThrow(() => session.SetCurrentSchema("test1")); + Assert.That(session.Schema.Name, Is.EqualTo("test1")); + // Retry the same schema + Assert.DoesNotThrow(() => session.SetCurrentSchema("test1")); + Assert.That(session.Schema.Name, Is.EqualTo("test1")); + session.Schema.CreateCollection("my_collection_123456789"); + session.Schema.DropCollection("my_collection_123456789"); + //Exceptions + Assert.Throws(() => session.SQL("USE nonExistingSchema").Execute()); + Assert.Throws(() => session.SetCurrentSchema("nonExistingSchema")); + Assert.Throws(() => session.SetCurrentSchema(null)); + session.DropSchema("test1"); + //No Active Schema + using (Session sessionPlain = MySQLX.GetSession(ConnectionString)) + { + Assert.That(sessionPlain.GetCurrentSchema(), Is.Null); + } + } + + [Test, Description("Session Status before Execution - Negative")] + public void SessionClosedBeforeExecution() + { + Assume.That(session.Version.isAtLeast(5, 7, 0), "This test is for MySql 5.7 or higher"); + Schema schema = null; + Session sessionPlain = MySQLX.GetSession(ConnectionString); + schema = sessionPlain.GetSchema(schemaName); + schema.CreateCollection("test123"); + schema.DropCollection("test123"); + sessionPlain.Close(); + Assert.Throws(() => schema.CreateCollection("test123")); + sessionPlain.Dispose(); + } + + [Test, Description("Session Switch-SetCurrentSchema(Same and Different Session)")] + public void SessionChangeCurrentSchema() + { + using (Session session = MySQLX.GetSession(ConnectionString)) + { + session.SQL("DROP DATABASE IF EXISTS dbname1").Execute(); + session.SQL("CREATE DATABASE dbname1").Execute(); + session.SQL("USE dbname1").Execute(); + Assert.That(session.GetCurrentSchema().Name, Is.EqualTo("dbname1").IgnoreCase); + session.SQL("CREATE TABLE address1" + + "(address_number INT NOT NULL AUTO_INCREMENT, " + + "building_name VARCHAR(100) NOT NULL, " + + "district VARCHAR(100) NOT NULL, PRIMARY KEY (address_number)" + ");").Execute(); + session.SQL("INSERT INTO address1" + + "(address_number,building_name,district)" + + " VALUES " + + "(1,'MySQL1','BGL1');").Execute(); + + session.SQL("DROP DATABASE IF EXISTS dbname2").Execute(); + session.SQL("CREATE DATABASE dbname2").Execute(); + session.SQL("USE dbname2").Execute(); + Assert.That(session.GetCurrentSchema().Name, Is.EqualTo("dbname2").IgnoreCase); + session.SQL("CREATE TABLE address2" + + "(address_number INT NOT NULL AUTO_INCREMENT, " + + "building_name VARCHAR(100) NOT NULL, " + + "district VARCHAR(100) NOT NULL, PRIMARY KEY (address_number)" + ");").Execute(); + session.SQL("INSERT INTO address2" + + "(address_number,building_name,district)" + + " VALUES " + + "(2,'MySQL2','BGL2');").Execute(); + session.SetCurrentSchema("dbname1"); + Assert.That(session.Schema.Name, Is.EqualTo("dbname1")); + session.SQL("SELECT * FROM address1").Execute(); + session.SQL("DROP TABLE address1").Execute(); + session.SetCurrentSchema("dbname2"); + Assert.That(session.Schema.Name, Is.EqualTo("dbName2").IgnoreCase); + session.SQL("SELECT * FROM address2").Execute(); + session.SQL("DROP TABLE address2").Execute(); + session.SQL("DROP DATABASE dbname1").Execute(); + session.SQL("DROP DATABASE dbname2").Execute(); + session.Close(); + session.Dispose(); + } + } + #endregion WL14389 + } +} diff --git a/MySQL.Data/tests/MySqlX.Data.Tests/SessionTests.cs b/MySQL.Data/tests/MySqlX.Data.Tests/SessionTests.cs index 9ad0e0057..d1fe27a25 100644 --- a/MySQL.Data/tests/MySqlX.Data.Tests/SessionTests.cs +++ b/MySQL.Data/tests/MySqlX.Data.Tests/SessionTests.cs @@ -1,2389 +1,2519 @@ -// Copyright (c) 2015, 2022, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data; -using MySql.Data.Common; -using MySql.Data.MySqlClient; -using MySqlX.XDevAPI; -using MySqlX.XDevAPI.Relational; -using NUnit.Framework; -using System; -using System.Collections.Generic; -using System.Data; -using System.Diagnostics; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace MySqlX.Data.Tests -{ - public class SessionTests : BaseTest - { - [Test] - [Property("Category", "Security")] - public void CanCloseSession() - { - Session s = MySQLX.GetSession(ConnectionString); - Assert.True(s.InternalSession.SessionState == SessionState.Open); - s.Close(); - Assert.AreEqual(s.InternalSession.SessionState, SessionState.Closed); - } - - [Test] - [Property("Category", "Security")] - public void NoPassword() - { - Session session = MySQLX.GetSession(ConnectionStringNoPassword); - Assert.True(session.InternalSession.SessionState == SessionState.Open); - session.Close(); - Assert.AreEqual(session.InternalSession.SessionState, SessionState.Closed); - } - - [Test] - [Property("Category", "Security")] - public void SessionClose() - { - Session session = MySQLX.GetSession(ConnectionString); - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); - session.Close(); - Assert.AreEqual(SessionState.Closed, session.InternalSession.SessionState); - } - - [Test] - [Property("Category", "Security")] - [Ignore("Check this. Result is not always the same")] - public void CountClosedSession() - { - int sessions, newSessions; - - using (Session nodeSession = MySQLX.GetSession(ConnectionString)) - { - sessions = ExecuteSQLStatement(nodeSession.SQL("show processlist")).FetchAll().Count; - - for (int i = 0; i < 20; i++) - { - Session session = MySQLX.GetSession(ConnectionString); - Assert.True(session.InternalSession.SessionState == SessionState.Open); - session.Close(); - Assert.AreEqual(session.InternalSession.SessionState, SessionState.Closed); - } - - newSessions = ExecuteSQLStatement(nodeSession.SQL("show processlist")).FetchAll().Count; - } - - Assert.AreEqual(sessions, newSessions); - } - - [Test] - [Property("Category", "Security")] - public void ConnectionStringAsAnonymousType() - { - var connstring = new - { - server = session.Settings.Server, - port = session.Settings.Port, - user = session.Settings.UserID, - password = session.Settings.Password - }; - - using (var testSession = MySQLX.GetSession(connstring)) - { - Assert.AreEqual(SessionState.Open, testSession.InternalSession.SessionState); - } - } - - [Test] - [Property("Category", "Security")] - public void SessionGetSetCurrentSchema() - { - using (Session testSession = MySQLX.GetSession(ConnectionString)) - { - Assert.AreEqual(SessionState.Open, testSession.InternalSession.SessionState); - Assert.Null(testSession.GetCurrentSchema()); - Assert.Throws(() => testSession.SetCurrentSchema("")); - testSession.SetCurrentSchema(schemaName); - Assert.AreEqual(schemaName, testSession.Schema.Name); - Assert.AreEqual(schemaName, testSession.GetCurrentSchema().Name); - } - } - - [Test] - [Property("Category", "Security")] - public void SessionUsingSchema() - { - using (Session mySession = MySQLX.GetSession(ConnectionString + $";database={schemaName};")) - { - Assert.AreEqual(SessionState.Open, mySession.InternalSession.SessionState); - Assert.AreEqual(schemaName, mySession.Schema.Name); - Assert.AreEqual(schemaName, mySession.GetCurrentSchema().Name); - Assert.True(SchemaExistsInDatabase(mySession.Schema)); - } - } - - [Test] - [Property("Category", "Security")] - public void SessionUsingDefaultSchema() - { - using (Session mySession = MySQLX.GetSession(ConnectionString + $";database={schemaName};")) - { - Assert.AreEqual(SessionState.Open, mySession.InternalSession.SessionState); - Assert.AreEqual(schemaName, mySession.DefaultSchema.Name); - Assert.AreEqual(schemaName, mySession.GetCurrentSchema().Name); - Assert.True(mySession.Schema.ExistsInDatabase()); - mySession.SetCurrentSchema("mysql"); - Assert.AreNotEqual(mySession.DefaultSchema.Name, mySession.Schema.Name); - } - - // DefaultSchema is null because no database was provided in the connection string/URI. - using (Session mySession = MySQLX.GetSession(ConnectionString)) - { - Assert.AreEqual(SessionState.Open, mySession.InternalSession.SessionState); - Assert.Null(mySession.DefaultSchema); - } - } - - [Test] - [Property("Category", "Security")] - public void SessionUsingDefaultSchemaWithAnonymousObject() - { - var globalSession = GetSession(); - - using (var internalSession = MySQLX.GetSession(new - { - server = globalSession.Settings.Server, - port = globalSession.Settings.Port, - user = globalSession.Settings.UserID, - password = globalSession.Settings.Password, - sslmode = MySqlSslMode.Required, - database = "mysql" - })) - { - Assert.AreEqual("mysql", internalSession.DefaultSchema.Name); - } - - // DefaultSchema is null when no database is provided. - using (var internalSession = MySQLX.GetSession(new - { - server = globalSession.Settings.Server, - port = globalSession.Settings.Port, - user = globalSession.Settings.UserID, - password = globalSession.Settings.Password, - sslmode = MySqlSslMode.Required, - })) - { - Assert.Null(internalSession.DefaultSchema); - } - - // Access denied error is raised when database does not exist for servers 8.0.12 and below. - // This behavior was fixed since MySql Server 8.0.13 version. Now the error - // shows the proper message, "Unknown database..." - if (session.InternalSession.GetServerVersion().isAtLeast(8, 0, 13)) return; - var exception = Assert.Throws(() => MySQLX.GetSession(new - { - server = globalSession.Settings.Server, - port = globalSession.Settings.Port, - user = globalSession.Settings.UserID, - password = globalSession.Settings.Password, - sslmode = MySqlSslMode.Required, - database = "test1" - } - )); - - if (session.InternalSession.GetServerVersion().isAtLeast(8, 0, 13)) - StringAssert.StartsWith(string.Format("Unknown database 'test1'"), exception.Message); - else - StringAssert.StartsWith(string.Format("Access denied"), exception.Message); - } - - [Test] - [Property("Category", "Security")] - public void SessionUsingDefaultSchemaWithConnectionURI() - { - using (var session = MySQLX.GetSession(ConnectionStringUri + "?database=mysql")) - { - Assert.AreEqual("mysql", session.DefaultSchema.Name); - } - } - - [Test] - [Property("Category", "Security")] - public void CheckConnectionUri() - { - CheckConnectionData($"mysqlx://myuser:password@{Host}:{XPort}", "myuser", "password", Host, uint.Parse(XPort)); - CheckConnectionData($"mysqlx://my%3Auser:p%40ssword@{Host}:{XPort}", "my:user", "p@ssword", Host, uint.Parse(XPort)); - CheckConnectionData($"mysqlx://my%20user:p%40ss%20word@{Host}:{XPort}", "my user", "p@ss word", Host, uint.Parse(XPort)); - CheckConnectionData($"mysqlx:// myuser : p%40ssword@{Host}:{XPort}", "myuser", "p@ssword", Host, uint.Parse(XPort)); - CheckConnectionData($"mysqlx://myuser@{Host}:{XPort}", "myuser", "", Host, uint.Parse(XPort)); - CheckConnectionData($"mysqlx://myuser:p%40ssword@{Host}", "myuser", "p@ssword", Host, uint.Parse(XPort)); - CheckConnectionData($"mysqlx://myuser:p%40ssw%40rd@{Host}", "myuser", "p@ssw@rd", Host, uint.Parse(XPort)); - CheckConnectionData($"mysqlx://my%40user:p%40ssword@{Host}", "my@user", "p@ssword", Host, uint.Parse(XPort)); - CheckConnectionData($"mysqlx://myuser@{Host}", "myuser", "", Host, uint.Parse(XPort)); - CheckConnectionData($"mysqlx://myuser@{Host}", "myuser", "", Host, uint.Parse(XPort)); - CheckConnectionData("mysqlx://myuser@[::1]", "myuser", "", "[::1]", uint.Parse(XPort)); - CheckConnectionData("mysqlx://myuser:password@[2606:b400:440:1040:bd41:e449:45ee:2e1a]", "myuser", "password", "[2606:b400:440:1040:bd41:e449:45ee:2e1a]", uint.Parse(XPort)); - CheckConnectionData($"mysqlx://myuser:password@[2606:b400:440:1040:bd41:e449:45ee:2e1a]:{XPort}", "myuser", "password", "[2606:b400:440:1040:bd41:e449:45ee:2e1a]", uint.Parse(XPort)); - Assert.Throws(() => CheckConnectionData("mysqlx://myuser:password@[2606:b400:440:1040:bd41:e449:45ee:2e1a:33060]", "myuser", "password", "[2606:b400:440:1040:bd41:e449:45ee:2e1a]", uint.Parse(XPort))); - Assert.Throws(() => CheckConnectionData($"mysqlx://myuser:password@2606:b400:440:1040:bd41:e449:45ee:2e1a:{XPort}", "myuser", "password", "[2606:b400:440:1040:bd41:e449:45ee:2e1a]", uint.Parse(XPort))); - CheckConnectionData("mysqlx://myuser:password@[fe80::bd41:e449:45ee:2e1a%17]", "myuser", "password", "[fe80::bd41:e449:45ee:2e1a]", uint.Parse(XPort)); - CheckConnectionData("mysqlx://myuser:password@[(address=[fe80::bd41:e449:45ee:2e1a%17],priority=100)]", "myuser", "password", "[fe80::bd41:e449:45ee:2e1a]", uint.Parse(XPort)); - CheckConnectionData("mysqlx://myuser:password@[(address=[fe80::bd41:e449:45ee:2e1a%17]:3305,priority=100)]", "myuser", "password", "[fe80::bd41:e449:45ee:2e1a]", 3305); - Assert.Throws(() => CheckConnectionData("mysqlx://myuser:password@[(address=fe80::bd41:e449:45ee:2e1a%17,priority=100)]", "myuser", "password", "[fe80::bd41:e449:45ee:2e1a]", 33060)); - CheckConnectionData("mysqlx://myuser@localhost/test", "myuser", "", "localhost", 33060, "database", schemaName); -#if NET7_0 - CheckConnectionData("mysqlx://myuser@localhost/test?ssl%20mode=disabled&connecttimeout=10", "myuser", "", "localhost", 33060, "database", schemaName, "ssl mode", "None", "connecttimeout", "10"); -#else - CheckConnectionData("mysqlx://myuser@localhost/test?ssl%20mode=disabled&connecttimeout=10", "myuser", "", "localhost", 33060, "database", schemaName, "ssl mode", "Disabled", "connecttimeout", "10"); -#endif - CheckConnectionData("mysqlx://_%21%22%23%24s%26%2F%3D-%25r@localhost", "_!\"#$s&/=-%r", "", "localhost", 33060); - CheckConnectionData("mysql://myuser@localhost", "", "", "", 33060); - CheckConnectionData("myuser@localhost", "", "", "", 33060); - Assert.Throws(() => CheckConnectionData("mysqlx://uid=myuser;server=localhost", "", "", "", 33060)); - CheckConnectionData("mysqlx://user:password@server.example.com/", "user", "password", "server.example.com", 33060, "ssl mode", "Required"); - CheckConnectionData("mysqlx://user:password@server.example.com/?ssl-ca=(c:%5Cclient.pfx)", "user", "password", "server.example.com", 33060, "ssl mode", "Required", "ssl-ca", "c:\\client.pfx"); - Assert.Throws(() => CheckConnectionData("mysqlx://user:password@server.example.com/?ssl-crl=(c:%5Ccrl.pfx)", "user", "password", "server.example.com", 33060, "ssl mode", "Required", "ssl-crl", "(c:\\crl.pfx)")); - // tls-version - CheckConnectionData("mysqlx://myuser:password@localhost:33060?tls-version=TlSv1.2", "myuser", "password", "localhost", 33060, "tls-version", "Tls12"); - CheckConnectionData("mysqlx://myuser:password@localhost:33060?tls-version=TlS1.2", "myuser", "password", "localhost", 33060, "tls-version", "Tls12"); - CheckConnectionData("mysqlx://myuser:password@localhost:33060?tls-version=TlSv12", "myuser", "password", "localhost", 33060, "tls-version", "Tls12"); - CheckConnectionData("mysqlx://myuser:password@localhost:33060?tls-version=TlS12", "myuser", "password", "localhost", 33060, "tls-version", "Tls12"); - CheckConnectionData("mysqlx://myuser:password@localhost:33060?tls-version=[ TlSv1.2 ,tLsV11, TLSv1.0 , tls13 ]", "myuser", "password", "localhost", 33060, "tls-version", "Tls12, Tls13"); - CheckConnectionData("mysqlx://myuser:password@localhost:33060?tls-version=( TlSv1.2 ,tLsV11, TLSv1 , tls13 )", "myuser", "password", "localhost", 33060, "tls-version", "Tls12, Tls13"); - CheckConnectionData("mysqlx://myuser:password@localhost:33060?tls-version= TlSv1.2 ,tLsV11, TLSv10 , tls13", "myuser", "password", "localhost", 33060, "tls-version", "Tls12, Tls13"); - Assert.Throws(() => CheckConnectionData("mysqlx://myuser:password@localhost:33060?tls-version=SSL3", "myuser", "password", "localhost", 33060, "tls-version", "")); - } - - [Test] - [Property("Category", "Security")] - public void ConnectionUsingUri() - { - using (var session = MySQLX.GetSession(ConnectionStringUri)) - { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); - } - } - - [Test] - [Property("Category", "Security")] - public void ConnectionStringNull() - { - Assert.Throws(() => MySQLX.GetSession(null)); - } - - [Test] - [Property("Category", "Security")] - public void IPv6() - { - var csBuilder = new MySqlXConnectionStringBuilder(ConnectionString); - csBuilder.Server = GetMySqlServerIp(true); - csBuilder.Port = uint.Parse(XPort); - - if (string.IsNullOrEmpty(csBuilder.Server)) Assert.Ignore("No IPv6 available."); - - using (var session = MySQLX.GetSession(csBuilder.ToString())) - { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); - } - } - - [Test] - [Property("Category", "Security")] - public void IPv6AsUrl() - { - var csBuilder = new MySqlXConnectionStringBuilder(ConnectionString); - string ipv6 = GetMySqlServerIp(true); - if (string.IsNullOrEmpty(ipv6)) Assert.Ignore("No IPv6 available."); - - string connString = $"mysqlx://{csBuilder.UserID}:{csBuilder.Password}@[{ipv6}]:{XPort}"; - using (Session session = MySQLX.GetSession(connString)) - { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); - } - } - - [Test] - [Property("Category", "Security")] - public void IPv6AsAnonymous() - { - var csBuilder = new MySqlXConnectionStringBuilder(ConnectionString); - string ipv6 = GetMySqlServerIp(true); - if (string.IsNullOrEmpty(ipv6)) Assert.Ignore("No IPv6 available."); - - using (Session session = MySQLX.GetSession(new { server = ipv6, user = csBuilder.UserID, password = csBuilder.Password, port = XPort })) - { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); - } - } - - [Test] - [Property("Category", "Security")] - public void CreateSessionWithUnsupportedOptions() - { - var errorMessage = "Option not supported."; - var connectionUri = string.Format("{0}?", ConnectionStringUri); - - // Use a connection URI. - var ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "pipe=MYSQL")); - StringAssert.StartsWith(errorMessage, ex.Message); - ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "compress=true")); - StringAssert.StartsWith(errorMessage, ex.Message); - ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "allow batch=false")); - StringAssert.StartsWith(errorMessage, ex.Message); - ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "logging=true")); - StringAssert.StartsWith(errorMessage, ex.Message); - ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "sharedmemoryname=MYSQL")); - StringAssert.StartsWith(errorMessage, ex.Message); - ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "defaultcommandtimeout=30")); - StringAssert.StartsWith(errorMessage, ex.Message); - ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "usedefaultcommandtimeoutforef=true")); - StringAssert.StartsWith(errorMessage, ex.Message); - ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "persistsecurityinfo=false")); - StringAssert.StartsWith(errorMessage, ex.Message); - ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "encrypt=false")); - StringAssert.StartsWith(errorMessage, ex.Message); - ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "integratedsecurity=true")); - StringAssert.StartsWith(errorMessage, ex.Message); - ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "allowpublickeyretrieval=false")); - StringAssert.StartsWith(errorMessage, ex.Message); - ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "autoenlist=true")); - StringAssert.StartsWith(errorMessage, ex.Message); - ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "includesecurityasserts=false")); - StringAssert.StartsWith(errorMessage, ex.Message); - ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "allowzerodatetime=true")); - StringAssert.StartsWith(errorMessage, ex.Message); - ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "convert zero datetime=false")); - StringAssert.StartsWith(errorMessage, ex.Message); - ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "useusageadvisor=true")); - StringAssert.StartsWith(errorMessage, ex.Message); - ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "procedurecachesize=50")); - StringAssert.StartsWith(errorMessage, ex.Message); - ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "useperformancemonitor=true")); - StringAssert.StartsWith(errorMessage, ex.Message); - ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "respectbinaryflags=true")); - StringAssert.StartsWith(errorMessage, ex.Message); - ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "treat tiny as boolean=false")); - StringAssert.StartsWith(errorMessage, ex.Message); - ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "allowuservariables=true")); - StringAssert.StartsWith(errorMessage, ex.Message); - ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "interactive=false")); - StringAssert.StartsWith(errorMessage, ex.Message); - ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "functionsreturnstring=true")); - StringAssert.StartsWith(errorMessage, ex.Message); - ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "useaffectedrows=false")); - StringAssert.StartsWith(errorMessage, ex.Message); - ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "oldguids=true")); - StringAssert.StartsWith(errorMessage, ex.Message); - ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "sqlservermode=false")); - StringAssert.StartsWith(errorMessage, ex.Message); - ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "tablecaching=true")); - StringAssert.StartsWith(errorMessage, ex.Message); - ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "defaulttablecacheage=60")); - StringAssert.StartsWith(errorMessage, ex.Message); - ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "checkparameters=true")); - StringAssert.StartsWith(errorMessage, ex.Message); - ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "replication=replication_group")); - StringAssert.StartsWith(errorMessage, ex.Message); - ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "exceptioninterceptors=none")); - StringAssert.StartsWith(errorMessage, ex.Message); - ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "commandinterceptors=none")); - StringAssert.StartsWith(errorMessage, ex.Message); - ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "connectionlifetime=100")); - StringAssert.StartsWith(errorMessage, ex.Message); - ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "pooling=false")); - StringAssert.StartsWith(errorMessage, ex.Message); - ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "minpoolsize=0")); - StringAssert.StartsWith(errorMessage, ex.Message); - ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "maxpoolsize=20")); - StringAssert.StartsWith(errorMessage, ex.Message); - ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "connectionreset=false")); - StringAssert.StartsWith(errorMessage, ex.Message); - ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "cacheserverproperties=true")); - StringAssert.StartsWith(errorMessage, ex.Message); - - // Use a connection string. - ex = Assert.Throws(() => MySQLX.GetSession("treatblobsasutf8=false")); - StringAssert.StartsWith(errorMessage, ex.Message); - ex = Assert.Throws(() => MySQLX.GetSession("blobasutf8includepattern=pattern")); - StringAssert.StartsWith(errorMessage, ex.Message); - ex = Assert.Throws(() => MySQLX.GetSession("blobasutf8excludepattern=pattern")); - StringAssert.StartsWith(errorMessage, ex.Message); - } - - [Test] - [Property("Category", "Security")] - public void CreateBuilderWithUnsupportedOptions() - { - var errorMessage = "Option not supported."; - var ex = Assert.Throws(() => new MySqlXConnectionStringBuilder("pipe=MYSQL")); - StringAssert.StartsWith(errorMessage, ex.Message); - ex = Assert.Throws(() => new MySqlXConnectionStringBuilder("allow batch=false")); - StringAssert.StartsWith(errorMessage, ex.Message); - ex = Assert.Throws(() => new MySqlXConnectionStringBuilder("respectbinaryflags=true")); - StringAssert.StartsWith(errorMessage, ex.Message); - ex = Assert.Throws(() => new MySqlXConnectionStringBuilder("pooling=false")); - StringAssert.StartsWith(errorMessage, ex.Message); - ex = Assert.Throws(() => new MySqlXConnectionStringBuilder("cacheserverproperties=true")); - StringAssert.StartsWith(errorMessage, ex.Message); - } - - [Test] - [Property("Category", "Security")] - public void GetUri() - { - using (var internalSession = MySQLX.GetSession(session.Uri)) - { - // Validate that all properties keep their original value. - foreach (var connectionOption in session.Settings.values) - { - // SslCrl connection option is skipped since it isn't currently supported. - if (connectionOption.Key == "sslcrl") - continue; - - try - { - Assert.AreEqual(session.Settings[connectionOption.Key], internalSession.Settings[connectionOption.Key]); - } - catch (ArgumentException ex) - { - StringAssert.StartsWith("Option not supported.", ex.Message); - } - } - } - } - - /// - /// WL #12177 Implement connect timeout - /// - [Test] - [Property("Category", "Security")] - public void ConnectTimeout() - { - if (Platform.IsMacOSX()) Assert.Ignore("Check failure on MacOS: (() => MySQLX.GetSession(conn)); - TimeSpan diff = DateTime.Now.Subtract(start); - Assert.True(diff.TotalSeconds > 19 && diff.TotalSeconds < 21, String.Format("Timeout exceeded ({0}). Actual time: {1}", "Fail over failure", diff)); - - // Valid session no time out - start = DateTime.Now; - using (Session session = MySQLX.GetSession(ConnectionStringUri + "?connecttimeout=2000")) - session.SQL("SELECT SLEEP(10)").Execute(); - diff = DateTime.Now.Subtract(start); - Assert.True(diff.TotalSeconds > 10); - - //Invalid Values for Connection Timeout parameter - var ex = Assert.Throws(() => MySQLX.GetSession(ConnectionString + ";connect-timeout=-1;")); - Assert.AreEqual(ResourcesX.InvalidConnectionTimeoutValue, ex.Message); - - ex = Assert.Throws(() => MySQLX.GetSession(ConnectionString + ";connect-timeout=foo;")); - Assert.AreEqual(ResourcesX.InvalidConnectionTimeoutValue, ex.Message); - - ex = Assert.Throws(() => MySQLX.GetSession(ConnectionString + ";connect-timeout='';")); - Assert.AreEqual(ResourcesX.InvalidConnectionTimeoutValue, ex.Message); - - ex = Assert.Throws(() => MySQLX.GetSession(ConnectionString + ";connect-timeout=10.5;")); - Assert.AreEqual(ResourcesX.InvalidConnectionTimeoutValue, ex.Message); - - ex = Assert.Throws(() => MySQLX.GetSession(ConnectionString + ";connect-timeout=" + Int32.MaxValue + 1)); - Assert.AreEqual(ResourcesX.InvalidConnectionTimeoutValue, ex.Message); - - ex = Assert.Throws(() => MySQLX.GetSession(ConnectionString + ";connect-timeout=10.5;")); - Assert.AreEqual(ResourcesX.InvalidConnectionTimeoutValue, ex.Message); - - ex = Assert.Throws(() => MySQLX.GetSession(ConnectionString + ";connect-timeout=;")); - Assert.AreEqual(ResourcesX.InvalidConnectionTimeoutValue, ex.Message); - - ex = Assert.Throws(() => MySQLX.GetSession(ConnectionStringUri + "?connect-timeout= ")); - Assert.AreEqual(ResourcesX.InvalidConnectionTimeoutValue, ex.Message); - - ex = Assert.Throws(() => MySQLX.GetSession(ConnectionStringUri + "?connecttimeout=")); - Assert.AreEqual(ResourcesX.InvalidConnectionTimeoutValue, ex.Message); - - // Valid value for ConnectionTimeout, invalid credentials - var exception = Assert.Throws(() => MySQLX.GetSession($"server={Host};user=test;password=noPass;port={XPort};connect-timeout=2000;")); - Assert.NotNull(exception); - } - - private void TestConnectTimeoutFailureTimeout(String connString, int minTime, int maxTime, string test) - { - DateTime start = DateTime.Now; - Assert.Throws(() => MySQLX.GetSession(connString)); - TimeSpan diff = DateTime.Now.Subtract(start); - Assert.True(diff.TotalSeconds > minTime && diff.TotalSeconds < maxTime, String.Format("Timeout exceeded ({0}). Actual time: {1}", test, diff)); - } - - private void TestConnectTimeoutSuccessTimeout(String connString, int minTime, int maxTime, string test) - { - DateTime start = DateTime.Now; - MySQLX.GetSession(connString); - TimeSpan diff = DateTime.Now.Subtract(start); - Assert.True(diff.TotalSeconds > minTime && diff.TotalSeconds < maxTime, String.Format("Timeout exceeded ({0}). Actual time: {1}", test, diff)); - } - - [Test] - [Property("Category", "Security")] - public void MaxConnections() - { - try - { - List sessions = new List(); - ExecuteSqlAsRoot("SET @@global.mysqlx_max_connections = 2"); - for (int i = 0; i <= 2; i++) - { - Session newSession = MySQLX.GetSession(ConnectionString); - sessions.Add(newSession); - } - Assert.False(true, "MySqlException should be thrown"); - } - catch (MySqlException ex) - { - Assert.AreEqual(ResourcesX.UnableToOpenSession, ex.Message); - } - finally - { - ExecuteSqlAsRoot("SET @@global.mysqlx_max_connections = 100"); - } - } - - protected void CheckConnectionData(string connectionData, string user, string password, string server, uint port, params string[] parameters) - { - string result = this.session.ParseConnectionData(connectionData); - var csbuilder = new MySqlXConnectionStringBuilder(result); - Assert.True(user == csbuilder.UserID, string.Format("Expected:{0} Current:{1} in {2}", user, csbuilder.UserID, connectionData)); - Assert.True(password == csbuilder.Password, string.Format("Expected:{0} Current:{1} in {2}", password, csbuilder.Password, connectionData)); - Assert.True(server == csbuilder.Server, string.Format("Expected:{0} Current:{1} in {2}", server, csbuilder.Server, connectionData)); - Assert.True(port == csbuilder.Port, string.Format("Expected:{0} Current:{1} in {2}", port, csbuilder.Port, connectionData)); - if (parameters != null) - { - if (parameters.Length % 2 != 0) - throw new ArgumentOutOfRangeException(); - for (int i = 0; i < parameters.Length; i += 2) - { - Assert.True(csbuilder.ContainsKey(parameters[i])); - Assert.AreEqual(parameters[i + 1], csbuilder[parameters[i]].ToString()); - } - } - } - - /// - /// WL12514 - DevAPI: Support session-connect-attributes - /// - [Test] - [Property("Category", "Security")] - public void ConnectionAttributes() - { - if (!(session.Version.isAtLeast(8, 0, 16))) return; - - // Validate that MySQLX.GetSession() supports a new 'connection-attributes' query parameter - // with default values and all the client attributes starts with a '_'. - TestConnectionAttributes(ConnectionString + ";connection-attributes=true;"); - TestConnectionAttributes(ConnectionStringUri + "?connectionattributes"); - - // Validate that no attributes, client or user defined, are sent to server when the value is "false". - TestConnectionAttributes(ConnectionString + ";connection-attributes=false;"); - TestConnectionAttributes(ConnectionStringUri + "?connectionattributes=false"); - - // Validate default behavior with different scenarios. - TestConnectionAttributes(ConnectionString + ";connection-attributes;"); - TestConnectionAttributes(ConnectionStringUri + "?connectionattributes=true"); - TestConnectionAttributes(ConnectionString + ";connection-attributes=;"); - TestConnectionAttributes(ConnectionStringUri + "?connectionattributes=[]"); - - // Validate user-defined attributes to be sent to server. - Dictionary userAttrs = new Dictionary - { - { "foo", "bar" }, - { "quua", "qux" }, - { "key", null } - }; - TestConnectionAttributes(ConnectionString + ";connection-attributes=[foo=bar,quua=qux,key]", userAttrs); - TestConnectionAttributes(ConnectionStringUri + "?connectionattributes=[foo=bar,quua=qux,key=]", userAttrs); - - // Errors - var ex = Assert.Throws(() => MySQLX.GetSession(ConnectionString + ";connection-attributes=[_key=value]")); - Assert.AreEqual(ResourcesX.InvalidUserDefinedAttribute, ex.Message); - - ex = Assert.Throws(() => MySQLX.GetSession(ConnectionString + ";connection-attributes=123")); - Assert.AreEqual(ResourcesX.InvalidConnectionAttributes, ex.Message); - - ex = Assert.Throws(() => MySQLX.GetSession(ConnectionString + ";connection-attributes=[key=value,key=value2]")); - Assert.AreEqual(string.Format(ResourcesX.DuplicateUserDefinedAttribute, "key"), ex.Message); - - ex = Assert.Throws(() => MySQLX.GetSession(new { server = Host, port = XPort, user = RootUser, connectionattributes = "=" })); - - ex = Assert.Throws(() => MySQLX.GetSession(ConnectionString + ";connectionattributes=[=bar]")); - Assert.AreEqual(string.Format(ResourcesX.EmptyKeyConnectionAttribute), ex.Message); - } - - private void TestConnectionAttributes(string connString, Dictionary userAttrs = null) - { - string sql = "SELECT * FROM performance_schema.session_account_connect_attrs WHERE PROCESSLIST_ID = connection_id()"; - - using (Session session = MySQLX.GetSession(connString)) - { - Assert.AreEqual(SessionState.Open, session.XSession.SessionState); - var result = session.SQL(sql).Execute().FetchAll(); - - if (session.Settings.ConnectionAttributes == "false") - CollectionAssert.IsEmpty(result); - else - { - CollectionAssert.IsNotEmpty(result); - MySqlConnectAttrs clientAttrs = new MySqlConnectAttrs(); - - if (userAttrs == null) - { - Assert.AreEqual(8, result.Count); - - foreach (Row row in result) - StringAssert.StartsWith("_", row[1].ToString()); - } - else - { - Assert.AreEqual(11, result.Count); - - for (int i = 0; i < userAttrs.Count; i++) - { - Assert.True(userAttrs.ContainsKey(result.ElementAt(i)[1].ToString())); - Assert.True(userAttrs.ContainsValue(result.ElementAt(i)[2])); - } - } - } - } - } - - [TestCase("localhost")] - [TestCase("127.0.0.1")] - [TestCase("[::1]")] - [Description("IPv6 connection Scenario [localhost],[127.0.0.1]")] - public void ConnectionTest(string serverName) - { - if (!Platform.IsWindows()) Assert.Ignore("This test only applies foe Windows OS."); - - serverName = serverName.Replace("localhost", Host); - - MySqlXConnectionStringBuilder sb = new MySqlXConnectionStringBuilder(ConnectionString); - string connStr = "server=" + Host + ";user=" + sb.UserID + ";port=" + XPort + ";password=" + sb.Password + ";" + "sslmode=" + MySqlSslMode.Required; - - using (var sessionTest = MySQLX.GetSession(connStr)) - { - Assert.AreEqual(SessionState.Open, sessionTest.InternalSession.SessionState); - } - - using (var sessionTest = MySQLX.GetSession("mysqlx://" + sb.UserID + ":" + sb.Password + "@" + serverName + ":" + XPort)) - { - Assert.AreEqual(SessionState.Open, sessionTest.InternalSession.SessionState); - } - - using (var sessionTest = MySQLX.GetSession(new { server = serverName, port = XPort, user = sb.UserID, password = sb.Password })) - { - Assert.AreEqual(SessionState.Open, sessionTest.InternalSession.SessionState); - } - //wrong port - connStr = "server=" + sb.Server + ";user=" + sb.UserID + ";port=" + 33090 + ";password=" + sb.Password + ";" + "sslmode=" + MySqlSslMode.Required; - Assert.Throws(() => MySQLX.GetSession(connStr)); - - } - - [TestCase("[::$]")] - [TestCase("[::11]")] - [Description("IPv6 connection server * and ::$,invalid hostname")] - public void IPv6ConnectionExceptions(string serverName) - { - if (!Platform.IsWindows()) return; - - Session sessionTest = null; - string connStr = "server=" + serverName + ";user=test;port=" + XPort + ";password=test;sslmode=" + MySqlSslMode.Required; - Assert.Catch(() => sessionTest = MySQLX.GetSession(connStr)); - Assert.Catch(() => sessionTest = MySQLX.GetSession("mysqlx://test:test@" + serverName + ":" + XPort)); - Assert.Catch(() => sessionTest = MySQLX.GetSession(new { server = serverName, port = XPort, user = schemaName, password = schemaName })); - } - - [Test, Description("Unified connection string refinement-Negative Scenarios")] - public void ConnectionNegativeScenarios() - { - if (!Platform.IsWindows()) Assert.Ignore("This test is for Windows OS only"); - var ipv6HostName2 = GetIPV6Address(); - string ipAddress = GetMySqlServerIp(); - - Session session1 = null; - Assert.Catch(() => session1 = MySQLX.GetSession("mysql:x//test:test@" + ipAddress + ":" + XPort)); - Assert.Catch(() => session1 = MySQLX.GetSession("my:sqlx//test:test@" + ipAddress + ":" + XPort)); - Assert.Catch(() => session1 = MySQLX.GetSession("mysqlx:://test:test@" + ipAddress + ":" + XPort)); - string ipv6address = "f345::" + GetIPV6Address() + ":1xde"; - Assert.Catch(() => session1 = MySQLX.GetSession("mysqlx://test:test@[" + ipv6address + "]:" + XPort)); - Assert.Catch(() => session1 = MySQLX.GetSession("mysqlx://test:test@" + ipAddress + ":" + XPort + "/" + "unknowndatabase")); - string connStr = "mysqlx://test:test@" + session.Settings.Server + ":" + XPort + "/?" + "ssl-mode=VerifyFull&ssl-ca=" + sslCa + "&ssl-ca-pwd=wrongpass"; - Assert.Catch(() => session1 = MySQLX.GetSession(connStr)); - } - - [Test, Description("Session.Uri")] - public void SessionUriAndDefaultSchemaTest() - { - if (!Platform.IsWindows()) return; - - using (var session1 = MySQLX.GetSession(ConnectionString)) - { - Assert.IsNotNull(session1.Uri); - } - - MySqlXConnectionStringBuilder sb = new MySqlXConnectionStringBuilder(ConnectionString); - var connectionString = ConnectionStringUserWithSSLPEM + ";protocol=TCP;database=" - + sb.Database + ";characterset=utf8mb4;sslmode=Required;connect-timeout=10;keepalive=10;auth=PLAIN"; - using (var session1 = MySQLX.GetSession(connectionString)) - { - Assert.IsNotNull(session1.Uri); - } - - using (var session1 = MySQLX.GetSession(new - { - server = sb.Server, - port = XPort, - user = sb.UserID, - password = sb.Password, - sslmode = MySqlSslMode.Required - })) - { - Assert.IsNotNull(session1.Uri); - } - - var conn = new MySqlConnectionStringBuilder(); - conn.Server = sb.Server; - conn.UserID = sb.UserID; - conn.Password = sb.Password; - conn.Port = Convert.ToUInt32(XPort); - conn.Database = schemaName; - conn.CharacterSet = "utf8mb4"; - conn.SslMode = MySqlSslMode.VerifyCA; - conn.SslCa = sslCa; - conn.CertificatePassword = sslCertificatePassword; - conn.Keepalive = 10; - conn.ConnectionProtocol = MySqlConnectionProtocol.Tcp; - - using (var session1 = MySQLX.GetSession(conn.ConnectionString)) - { - Assert.IsNotNull(session1.Uri); - } - - using (var session1 = MySQLX.GetSession(ConnectionStringUri + "/?ssl-mode=Required;")) - { - Assert.IsNotNull(session1.Uri); - } - - conn = new MySqlConnectionStringBuilder(); - conn.Server = sb.Server; - conn.UserID = sb.UserID; - conn.Password = sb.Password; - conn.Port = Convert.ToUInt32(XPort); - conn.ConnectionProtocol = MySqlConnectionProtocol.Tcp; - conn.Database = schemaName; - conn.CharacterSet = "utf8mb4"; - conn.SslMode = MySqlSslMode.Required; - conn.SslCa = sslCa; - conn.CertificatePassword = sslCertificatePassword; - conn.Keepalive = 10; - connectionString = conn.ConnectionString; - using (var session1 = MySQLX.GetSession(connectionString)) - { - Assert.AreEqual(schemaName, session1.DefaultSchema.Name); - Assert.IsNotNull(session1.Uri); - } - - conn = new MySqlConnectionStringBuilder(); - conn.Server = sb.Server; - conn.UserID = sb.UserID; - conn.Password = sb.Password; - conn.Port = Convert.ToUInt32(XPort); - conn.ConnectionProtocol = MySqlConnectionProtocol.Tcp; - conn.Database = schemaName; - conn.CharacterSet = "utf8mb4"; - conn.SslMode = MySqlSslMode.VerifyCA; - conn.SslCa = sslCa; - conn.CertificatePassword = sslCertificatePassword; - conn.Keepalive = 10; - connectionString = conn.ConnectionString; - using (var session1 = MySQLX.GetSession(connectionString)) - { - Assert.AreEqual(schemaName, session1.DefaultSchema.Name); - Assert.IsNotNull(session1.Uri); - } - - conn = new MySqlConnectionStringBuilder(); - conn.Server = sb.Server; - conn.UserID = sb.UserID; - conn.Password = sb.Password; - conn.Port = Convert.ToUInt32(XPort); - conn.ConnectionProtocol = MySqlConnectionProtocol.Tcp; - conn.Database = schemaName; - conn.CharacterSet = "utf8mb4"; - conn.Keepalive = 10; - connectionString = conn.ConnectionString; - using (var session1 = MySQLX.GetSession(connectionString)) - { - Assert.AreEqual(schemaName, session1.DefaultSchema.Name); - Assert.IsNotNull(session1.Uri); - session1.DropSchema("㭋玤䂜蚌"); - session1.CreateSchema("㭋玤䂜蚌"); - session1.SQL("USE 㭋玤䂜蚌").Execute(); - Assert.AreEqual(schemaName, session1.DefaultSchema.Name); - } - - conn.Database = "㭋玤䂜蚌"; - connectionString = conn.ConnectionString; - using (var session1 = MySQLX.GetSession(connectionString)) - { - Assert.AreEqual("㭋玤䂜蚌", session1.DefaultSchema.Name); - Assert.IsNotNull(session1.Uri); - } - - conn.Server = sb.Server; - conn.UserID = sb.UserID; - conn.Password = sb.Password; - conn.Port = Convert.ToUInt32(XPort); - conn.ConnectionProtocol = MySqlConnectionProtocol.Tcp; - conn.Database = "㭋玤䂜蚌"; - conn.CharacterSet = "utf8mb4"; - conn.SslMode = MySqlSslMode.VerifyCA; - conn.SslCa = sslCa; - conn.CertificatePassword = sslCertificatePassword; - conn.Keepalive = 10; - connectionString = conn.ConnectionString; - using (var session1 = MySQLX.GetSession(connectionString)) - { - Assert.AreEqual("㭋玤䂜蚌", session1.DefaultSchema.Name); - Assert.IsNotNull(session1.Uri); - session1.DropSchema("㭋玤䂜蚌"); - } - - } - - [Test, Description("Test MySqlX plugin Connection for user with wrong password")] - public void GetSessionWithWrongPassword() - { - MySqlXConnectionStringBuilder sb = new MySqlXConnectionStringBuilder(ConnectionString); - sb.Password = "wrongPassword"; - Assert.Throws(() => MySQLX.GetSession(sb.ConnectionString)); - } - - [Test, Description("Test MySqlX plugin Connection for user with correct password but non MysqlX Server")] - public void GetSessionWithWrongPort() - { - MySqlXConnectionStringBuilder sb = new MySqlXConnectionStringBuilder(ConnectionString); - sb.Port = Convert.ToUInt32(Port); - Assert.Throws(() => MySQLX.GetSession(sb.ConnectionString)); - } - - [Test, Description("Test MySqlX plugin Issue a drop command after session already closed")] - public void GetSessionDropAlreadyClosedConnection() - { - Session testSession = MySQLX.GetSession(ConnectionString); - testSession.Close(); - testSession.Close();//works and behaviour expected but any input command should fail - Assert.Throws(() => testSession.DropSchema(schemaName)); - - testSession = MySQLX.GetSession(ConnectionStringNoPassword); - testSession.Close(); - testSession.Close();//works and behaviour expected but any input command should fail - Assert.Throws(() => testSession.DropSchema(schemaName)); - } - - [Test, Description("Session.DefaultSchema")] - public void SessionDefaultSchema() - { - if (!Platform.IsWindows()) return; - - MySqlXConnectionStringBuilder sb = new MySqlXConnectionStringBuilder(ConnectionString); - sb.Database = null; - var session1 = MySQLX.GetSession(sb.ConnectionString); - Assert.AreEqual(null, session1.DefaultSchema); - string connectionString = ConnectionString + ";protocol=Socket;database=" + schemaName + ";characterset=utf8mb4;sslmode=VerifyCA;ssl-ca=" + - sslCa + ";certificatepassword=" + sslCertificatePassword + ";connect-timeout=10;keepalive=10;auth=PLAIN"; - session1 = MySQLX.GetSession(connectionString); - Assert.AreEqual(schemaName, session1.DefaultSchema.Name); - - session1 = MySQLX.GetSession(ConnectionStringUri + "/" + schemaName + "?" + "auth=PLAIN&characterset=utf8mb4"); - Assert.AreEqual(schemaName, session1.DefaultSchema.Name); - - session1 = MySQLX.GetSession(new - { - server = sb.Server, - port = XPort, - user = sb.UserID, - password = sb.Password, - sslmode = MySqlSslMode.Required, - database = schemaName - }); - Assert.AreEqual(schemaName, session1.DefaultSchema.Name); - session1.DefaultSchema.CreateCollection("tester"); - session1.DefaultSchema.DropCollection("tester"); - Assert.AreEqual(schemaName, session1.DefaultSchema.Session.DefaultSchema.Name); - - var conn = new MySqlConnectionStringBuilder(); - session1.DropSchema("㭋玤䂜蚌"); - session1.CreateSchema("㭋玤䂜蚌"); - session1.SQL("USE 㭋玤䂜蚌").Execute(); - Assert.AreEqual(schemaName, session1.DefaultSchema.Name); - session1.Dispose(); - conn.Server = sb.Server; - conn.UserID = sb.UserID; - conn.Password = sb.Password; - conn.Port = Convert.ToUInt32(XPort); - conn.ConnectionProtocol = MySqlConnectionProtocol.Tcp; - conn.Database = "㭋玤䂜蚌"; - conn.CharacterSet = "utf8mb4"; - conn.SslMode = MySqlSslMode.Required; - conn.SslCa = sslCa; - conn.CertificatePassword = sslCertificatePassword; - conn.Keepalive = 10; - connectionString = conn.ConnectionString; - session1 = MySQLX.GetSession(connectionString); - Assert.AreEqual("㭋玤䂜蚌", session1.DefaultSchema.Name); - StringAssert.Contains("㭋玤䂜蚌", session1.Uri); - - conn.Server = sb.Server; - conn.UserID = sb.UserID; - conn.Password = sb.Password; - conn.Port = Convert.ToUInt32(XPort); - conn.ConnectionProtocol = MySqlConnectionProtocol.Tcp; - conn.Database = "㭋玤䂜蚌"; - conn.CharacterSet = "utf8mb4"; - conn.SslMode = MySqlSslMode.Required; - conn.SslCa = sslCa; - conn.CertificatePassword = sslCertificatePassword; - conn.Keepalive = 10; - connectionString = conn.ConnectionString; - session1 = MySQLX.GetSession(connectionString); - Assert.AreEqual("㭋玤䂜蚌", session1.DefaultSchema.Name); - StringAssert.Contains("㭋玤䂜蚌", session1.Uri); - session1.DefaultSchema.CreateCollection("tester"); - session1.DefaultSchema.DropCollection("tester"); - Assert.AreEqual("㭋玤䂜蚌", session1.DefaultSchema.Session.DefaultSchema.Name); - } - - [Test, Description("Session BaseString/MySQLXConnectionString Builder")] - public void ConnectionStringBuilderXpluginTests() - { - if (!Platform.IsWindows()) return; - - MySqlXConnectionStringBuilder mysqlx0 = new MySqlXConnectionStringBuilder(ConnectionString); - mysqlx0.ConnectionProtocol = MySqlConnectionProtocol.Tcp; - mysqlx0.CharacterSet = "utf8mb4"; - mysqlx0.SslMode = MySqlSslMode.Required; - mysqlx0.ConnectTimeout = 10; - mysqlx0.Keepalive = 10; - mysqlx0.CertificateFile = sslCa; - mysqlx0.CertificatePassword = sslCertificatePassword; - mysqlx0.CertificateStoreLocation = MySqlCertificateStoreLocation.LocalMachine; - mysqlx0.CertificateThumbprint = ""; - - - using (var xpluginconn = MySQLX.GetSession(mysqlx0.ConnectionString)) - { - Assert.AreEqual(SessionState.Open, xpluginconn.InternalSession.SessionState); - } - - mysqlx0 = new MySqlXConnectionStringBuilder(ConnectionString); - mysqlx0.Server = "::1"; - mysqlx0.Database = schemaName; - mysqlx0.CharacterSet = "utf8mb4"; - mysqlx0.ConnectionProtocol = MySqlConnectionProtocol.Tcp; - mysqlx0.SslMode = MySqlSslMode.Required; - mysqlx0.ConnectTimeout = 10; - mysqlx0.Keepalive = 10; - mysqlx0.CertificateFile = sslCa; - mysqlx0.CertificatePassword = sslCertificatePassword; - mysqlx0.CertificateStoreLocation = MySqlCertificateStoreLocation.LocalMachine; - mysqlx0.CertificateThumbprint = sslCertificatePassword; - - using (var xpluginconn = MySQLX.GetSession(mysqlx0.ConnectionString)) - { - Assert.AreEqual(SessionState.Open, xpluginconn.InternalSession.SessionState); - } - - mysqlx0 = new MySqlXConnectionStringBuilder(ConnectionString); - mysqlx0.Database = schemaName; - mysqlx0.ConnectionProtocol = MySqlConnectionProtocol.Tcp; - mysqlx0.CharacterSet = "utf8mb4"; - mysqlx0.SslMode = MySqlSslMode.VerifyCA; - mysqlx0.ConnectTimeout = 10; - mysqlx0.Keepalive = 10; - mysqlx0.CertificateFile = sslCa; - mysqlx0.CertificatePassword = "pass"; - mysqlx0.CertificateStoreLocation = MySqlCertificateStoreLocation.LocalMachine; - mysqlx0.CertificateThumbprint = ""; - - using (var xpluginconn = MySQLX.GetSession(mysqlx0.ConnectionString)) - { - Assert.AreEqual(SessionState.Open, xpluginconn.InternalSession.SessionState); - } - - mysqlx0 = new MySqlXConnectionStringBuilder(ConnectionString); - mysqlx0.Database = schemaName; - mysqlx0.ConnectionProtocol = MySqlConnectionProtocol.Tcp; - mysqlx0.CharacterSet = "utf8mb4"; - mysqlx0.SslMode = MySqlSslMode.Required; - mysqlx0.ConnectTimeout = 10; - mysqlx0.Keepalive = 10; - - using (var xpluginconn = MySQLX.GetSession(mysqlx0.ConnectionString)) - { - Assert.AreEqual(SessionState.Open, xpluginconn.InternalSession.SessionState); - } - - //Scenario-2 - string valid = "server=" + mysqlx0.Server + ";user id=" + mysqlx0.UserID + ";password=" + mysqlx0.Password + ";port=" + XPort + ";protocol=Socket;database=" + schemaName + ";characterset=utf8mb4;sslmode=Required;certificatefile=" + sslCa + ";certificatepassword=" + sslCertificatePassword + ";connect-timeout=10;keepalive=10;certificatestorelocation=LocalMachine;certificatethumbprint=;"; - using (var xpluginconn = MySQLX.GetSession(valid)) - { - Assert.AreEqual(SessionState.Open, xpluginconn.InternalSession.SessionState); - } - - //Scenario-3 - mysqlx0 = new MySqlXConnectionStringBuilder(ConnectionString); - mysqlx0.Database = schemaName; - mysqlx0.ConnectionProtocol = MySqlConnectionProtocol.Tcp; - mysqlx0.CharacterSet = "utf8mb4"; - mysqlx0.SslMode = MySqlSslMode.Required; - mysqlx0.ConnectTimeout = 10; - mysqlx0.Keepalive = 10; - mysqlx0.CertificateFile = sslCa; - mysqlx0.CertificatePassword = sslCertificatePassword; - mysqlx0.CertificateStoreLocation = MySqlCertificateStoreLocation.LocalMachine; - mysqlx0.CertificateThumbprint = ""; - mysqlx0.Auth = MySqlAuthenticationMode.AUTO; - mysqlx0.SslCa = sslCa; - using (var xpluginconn = MySQLX.GetSession(mysqlx0.ConnectionString)) - { - Assert.AreEqual(SessionState.Open, xpluginconn.InternalSession.SessionState); - } - - //Basic Scenarios - var connectionstr = "server=" + mysqlx0.Server + ";database=" + mysqlx0.Database + ";port=" - + XPort + ";userid=" + mysqlx0.UserID + ";password=" - + mysqlx0.Password - + ";characterset=utf8mb4;sslmode=Required;connect-timeout=20000;keepalive=20000;certificatefile=" - + sslCa + ";certificatepassword=" + sslCertificatePassword - + ";certificatestorelocation=LocalMachine;certificatethumbprint="; - using (var xpluginconn = MySQLX.GetSession(connectionstr)) - { - Assert.AreEqual(SessionState.Open, xpluginconn.InternalSession.SessionState); - } - - connectionstr = "mysqlx://" + mysqlx0.Server + ":" + XPort + "/" + - schemaName + "?connect-timeout=10&userid=" + mysqlx0.UserID + "&password=" - + mysqlx0.Password + "&sslca=" + sslCa + "&certificatepassword=" - + sslCertificatePassword + "&keepalive=10&characterset=utf8mb4"; - - using (var xpluginconn = MySQLX.GetSession(connectionstr)) - { - Assert.AreEqual(SessionState.Open, xpluginconn.InternalSession.SessionState); - } - - using (var xpluginconn = MySQLX.GetSession(new - { - server = mysqlx0.Server, - port = XPort, - user = mysqlx0.UserID, - password = mysqlx0.Password - })) - { - Assert.AreEqual(SessionState.Open, xpluginconn.InternalSession.SessionState); - } - - } - - [Test, Description("Connection Measurement Test")] - public void ConnectionTimeTest() - { - int secondsExpected = 15; - var connObject = new { server = Host, port = XPort, user = session.Settings.UserID, password = session.Settings.Password }; - MeasureConnectionString(ConnectionString, secondsExpected, "Connection String", 5); - MeasureConnectionString(ConnectionStringUri, secondsExpected, "Connection String URI", 5); - MeasureConnectionObject(connObject, secondsExpected, "Connection Object", 5); - } - - [Test, Description("Connection time with Database set")] - public void ConnectionTimeWithDatabaseTest() - { - int secondsExpected = 15; - var connString = ConnectionString + ";database=test"; - var connStringURI = ConnectionStringUri + "/?database=test"; - MySqlXConnectionStringBuilder sb = new MySqlXConnectionStringBuilder(ConnectionString); - var connectionObject = new - { - server = sb.Server, - port = XPort, - user = sb.UserID, - password = sb.Password, - database = schemaName - }; - MeasureConnectionString(connString, secondsExpected, "Connection String", 5); - MeasureConnectionString(connStringURI, secondsExpected, "Connection String URI", 5); - MeasureConnectionObject(connectionObject, secondsExpected, "Connection Object", 5); - } - - [Test, Description("REFACTOR PARSING OF CONNECTION STRING IN X DEVAPI")] - [Ignore("Uncomment to execute")] - public void ParseConnectionStringBenchmark_S1() - { - long transactions = 0; - long startTime = 0; - long endTime = 0; - long queryRunTime = 0; - int iterations = 10; - long NANO_TO_MILLI = 1000000; - long elapsedTime = 0; - long conTime = 0; - int i = 0; - - string connStr = ConnectionString; - - var session = MySQLX.GetSession(connStr); - session.Close(); - - for (int j = 0; j < 1; j++) - { - transactions = 0; - startTime = 0; - endTime = 0; - queryRunTime = 0; - iterations = 20; - elapsedTime = 0; - conTime = 0; - connStr = ConnectionStringUri; - startTime = NanoTime(); - for (i = 0; i < iterations; i++) - { - queryRunTime = queryRunTime + DoConnectString(connStr); - } - endTime = NanoTime(); - transactions = i; - elapsedTime = (endTime - startTime); //in nano - conTime = (elapsedTime / NANO_TO_MILLI) - (queryRunTime / NANO_TO_MILLI); - var t = CalculateTPS(conTime, transactions); - var log = ("Connected to MySQL using URI with iterations " + iterations + " with TPS:" + t); - Assert.IsNotNull(t); - - transactions = 0; - startTime = 0; - endTime = 0; - queryRunTime = 0; - iterations = 20; - elapsedTime = 0; - conTime = 0; - connStr = ConnectionString; - startTime = NanoTime(); - for (i = 0; i < iterations; i++) - { - queryRunTime = queryRunTime + DoConnectString(connStr); - } - endTime = NanoTime(); - transactions = i; - elapsedTime = (endTime - startTime); //in nano - conTime = (elapsedTime / NANO_TO_MILLI) - (queryRunTime / NANO_TO_MILLI); - t = CalculateTPS(conTime, transactions); - log = ("Connected to MySQL using connection string with iterations " + iterations + " with TPS:" + t); - Console.WriteLine(log); - Assert.IsNotNull(t); - - transactions = 0; - startTime = 0; - endTime = 0; - queryRunTime = 0; - iterations = 20; - elapsedTime = 0; - conTime = 0; - MySqlXConnectionStringBuilder sb = new MySqlXConnectionStringBuilder(ConnectionString); - var conn = new - { - server = sb.Server, - port = XPort, - user = sb.UserID, - password = sb.Password - }; - startTime = NanoTime(); - for (i = 0; i < iterations; i++) - { - queryRunTime = queryRunTime + DoConnectObject(conn); - } - endTime = NanoTime(); - transactions = i; - elapsedTime = (endTime - startTime); //in nano - conTime = (elapsedTime / NANO_TO_MILLI) - (queryRunTime / NANO_TO_MILLI); - t = CalculateTPS(conTime, transactions); - log = ("Connected to MySQL using Anonymous with iterations " - + iterations + - " with TPS:" + t); - } - } - - [Test, Description("REFACTOR PARSING OF CONNECTION STRING IN X DEVAPI")] - [Ignore("Uncomment to execute")] - public void ParseConnectionStringBenchmark_S2() - { - var connStr = ConnectionStringUri; - long queryStartTime = 0, queryRunTime = 0; - queryStartTime = NanoTime(); - var session1 = MySQLX.GetSession(connStr); - queryRunTime = NanoTime() - queryStartTime; - session1.Close(); - for (int j = 0; j < 20; j++) - { - connStr = ConnectionStringUri; - queryStartTime = 0; queryRunTime = 0; - queryStartTime = NanoTime(); - session1 = MySQLX.GetSession(connStr); - queryRunTime = NanoTime() - queryStartTime; - session1.Close(); - session1.Dispose(); - var log = ("Connected to MySQL using URI:" + queryRunTime / 1000000); - - connStr = ConnectionString; - queryStartTime = 0; queryRunTime = 0; - queryStartTime = NanoTime(); - session1 = MySQLX.GetSession(connStr); - queryRunTime = NanoTime() - queryStartTime; - session1.Close(); - session1.Dispose(); - log = ("Connected to MySQL using connection string:" + queryRunTime / 1000000); - - MySqlXConnectionStringBuilder sb = new MySqlXConnectionStringBuilder(ConnectionString); - var conn = new - { - server = sb.Server, - port = XPort, - user = sb.UserID, - password = sb.Password - }; - queryStartTime = 0; queryRunTime = 0; - queryStartTime = NanoTime(); - session1 = MySQLX.GetSession(conn); - queryRunTime = NanoTime() - queryStartTime; - session1.Close(); - session1.Dispose(); - log = ("Connected to MySQL using Connection Object:" + queryRunTime / 1000000); - } - } - - [Test, Description("Getsession/Session-URI")] - public void GetSessionUriPositiveTests() - { - string[] positiveStringList = new string[6]; - MySqlXConnectionStringBuilder sb = new MySqlXConnectionStringBuilder(ConnectionString); - positiveStringList[0] = "mysqlx://" + sb.UserID + ":" + sb.Password + "@" + sb.Server + ":" + XPort + "/?ssl-mode=Required"; - positiveStringList[1] = "mysqlx://" + sb.UserID + ":" + sb.Password + "@" + Host + ":" + XPort + "/?ssl-mode=Required"; - positiveStringList[2] = "mysqlx://" + sb.UserID + ":" + sb.Password + "@" + Host + ":" + XPort + "/" + schemaName + "?ssl-mode=Required"; - positiveStringList[3] = "mysqlx://" + sb.UserID + ":" + sb.Password + "@" + sb.Server + ":" + XPort + "/" + schemaName + "?ssl-mode=Required&auth=SHA256_MEMORY"; - positiveStringList[4] = "mysqlx://" + sb.UserID + ":" + sb.Password + "@" + sb.Server + ":" + XPort + "/" + schemaName + "?ssl-mode=Required&characterset=utf8mb4"; - positiveStringList[5] = "mysqlx://" + sb.UserID + ":" + sb.Password + "@" + sb.Server + ":" + XPort + "/" + schemaName + "?" + "ssl-mode=Required"; - - foreach (var connStr in positiveStringList) - { - using (Session c = MySQLX.GetSession(connStr)) - { - Assert.AreEqual(SessionState.Open, c.InternalSession.SessionState); - } - } - } - - [Test, Description("Getsession/Session-URI Negative Scenarios")] - public void GetSessionUriNegativeTests() - { - string[] NegativeStringList = new string[8]; - MySqlXConnectionStringBuilder sb = new MySqlXConnectionStringBuilder(ConnectionString); - NegativeStringList[0] = "mysqlx://" + sb.UserID + ":" + sb.Password + "@" + sb.Server + ":" + 9999 + ";ssl-mode=required"; - NegativeStringList[1] = "mysqlx://" + sb.UserID + ":" + sb.Password + "@" + "129.0.0.1" + ":" + XPort + ";ssl-mode=required"; - NegativeStringList[2] = "mysqlx://" + sb.UserID + ":" + "wrongpassword" + "@" + "localhost" + ":" + XPort + "/" + schemaName + "?ssl-mode=required"; - NegativeStringList[3] = "mysqlxyzzzz://" + sb.UserID + ":" + sb.Password + "@" + sb.Server + ":" + XPort + "/" + schemaName + "?ssl-mode=required"; - NegativeStringList[4] = "mysqlx://" + "wrongsb.UserID" + ":" + sb.Password + "@" + sb.Server + ":" + XPort + "/" + schemaName + "?ssl-mode=required"; - NegativeStringList[5] = "mysqlx://" + sb.UserID + ":" + sb.Password + "@" + "wronglocalhost" + "/" + schemaName + "?sslmode=required"; - NegativeStringList[6] = "mysqlx://" + sb.UserID + ":" + sb.Password + "@" + sb.Server + ":" + XPort + "/" + schemaName + "?" + "ssl-mode*&^%$#@!invalidvalues123*()"; - NegativeStringList[7] = "mysqlx://" + sb.UserID + ":" + sb.Password + "@" + sb.Server + ":" + XPort + "/" + schemaName + "?" + "invalidvalues123invalidvalues123invalidvalues123invalidvalues123invalidvalues123invalidvalues123invalidvalues123invalidvalues123" + ";ssl-mode=required"; - - foreach (var connStr in NegativeStringList) - { - Assert.Catch(() => MySQLX.GetSession(connStr)); - } - } - - [Test, Description("Getsession using Anonymous Type Negative-Wrong Password")] - public void GetSessionAnonymousTypeNegative() - { - var connectionStringObject = new { connection = $"server={Host};user={session.Settings.UserID};port={XPort};password=wrong_password;sslmode={MySqlSslMode.Required}" }; - Assert.Throws(() => MySQLX.GetSession(connectionStringObject.connection)); - } - - [Test, Description("Support Session Anonymous as uri string Positive")] - public void GetSessionWithAnonymousObjectURI() - { - var connectionStringObject = new { connection = ConnectionStringUri }; - using (Session sessionPlain = MySQLX.GetSession(connectionStringObject.connection)) - { - var db = sessionPlain.GetSchema(schemaName); - var col = db.GetCollection("my_collection_123456789"); - if (col.ExistsInDatabase()) - { - db.DropCollection("my_collection_123456789"); - db.CreateCollection("my_collection_123456789"); - } - else { db.CreateCollection("my_collection_123456789"); } - db.DropCollection("my_collection_123456789"); - } - if (Convert.ToInt32(XPort) == 33060)//Connect to server on localhost with user userx using URI string default port - { - MySqlXConnectionStringBuilder sb = new MySqlXConnectionStringBuilder(ConnectionString); - connectionStringObject = new { connection = "mysqlx://" + sb.UserID + ":" + sb.Password + "@" + sb.Server }; - using (Session sessionPlain = MySQLX.GetSession(connectionStringObject.connection)) - { - var db = sessionPlain.GetSchema(schemaName); - var col = db.GetCollection("my_collection_123456789"); - if (col.ExistsInDatabase()) - { - db.DropCollection("my_collection_123456789"); - db.CreateCollection("my_collection_123456789"); - } - else { db.CreateCollection("my_collection_123456789"); } - db.DropCollection("my_collection_123456789"); - } - } - } - - [Test, Description("Support Session connection string as uri string Negative-Invalid Password")] - public void GetSessionURIWrongPassword() - { - string invalidPassword = "invalid"; - MySqlXConnectionStringBuilder sb = new MySqlXConnectionStringBuilder(ConnectionString); - string connectionString = "mysqlx://" + sb.UserID + ":" + invalidPassword + "@" + sb.Server + ":" + XPort; - Assert.Throws(() => MySQLX.GetSession(connectionString)); - connectionString = "mysqlx://" + sb.UserID + ":" + invalidPassword + "@" + sb.Server; - Assert.Throws(() => MySQLX.GetSession(connectionString)); - } - - // Connection Timeout Tests - [Test, Description("Remote offline host without connect-timeout parameter.Mysql getclient with pooling and maxsize 2 and queue timeout 2000 milliseconds")] - public void TimeoutUsingClientAndPooling_S1() - { - MySqlXConnectionStringBuilder sb = new MySqlXConnectionStringBuilder(ConnectionString); - string serverName = "10.10.10.10"; - string connStr = "server=" + serverName + ";user=" + sb.UserID + ";port=" + XPort + ";password=" - + sb.Password + ";"; - var connectionpooling = "{ \"pooling\": { \"maxSize\": 1, \"queueTimeout\": 2000 , \"maxIdleTime\":1000, \"enabled\": true} }"; - var connectionpoolingObject = new { pooling = new { enabled = true, maxSize = 1, queueTimeout = 2000, maxIdleTime = 1000 } }; - Client client = MySQLX.GetClient(connStr, connectionpoolingObject); - TestFailureTimeout(client, 9, 11, "Timeout value between 9 and 11 seconds"); - var connStrUri = "mysqlx://" + sb.UserID + ":" + sb.Password + "@" + serverName + ":" + XPort; - client = MySQLX.GetClient(connStrUri, connectionpoolingObject); - TestFailureTimeout(client, 9, 11, "Timeout value between 9 and 11 seconds"); - var connObj = new { server = serverName, port = XPort, user = sb.UserID, password = sb.Password }; - client = MySQLX.GetClient(connObj, connectionpoolingObject); - TestFailureTimeout(client, 9, 11, "Timeout value between 9 and 11 seconds"); - client = MySQLX.GetClient(connStr, connectionpooling); - TestFailureTimeout(client, 9, 11, "Timeout value between 9 and 11 seconds"); - client = MySQLX.GetClient(connStrUri, connectionpooling); - TestFailureTimeout(client, 9, 11, "Timeout value between 9 and 11 seconds"); - client = MySQLX.GetClient(connObj, connectionpooling); - TestFailureTimeout(client, 9, 11, "Timeout value between 9 and 11 seconds"); - } - - [Test, Description("failover connection string with one offline host and one online host and disable connect - timeout parameter(set to 0) " + - ".Mysql getclient with pooling and maxsize 2 and queue timeout 2000 milliseconds.Both the session should be successful after" + - "waiting for the respective lower layer socket timeout")] - public void TimeoutUsingClientAndPooling_S2() - { - int connectTimeout = 1; - string hostList = string.Empty; - string localIP = session.Settings.Server; - int minTime = 0; - int maxTime = 30; - session.Settings.UserID = "testAnyhost"; - string connStr = "server=10.10.10.10," + localIP + ";port=" + XPort + ";uid=" + session.Settings.UserID + ";" + "password=" + session.Settings.Password + - ";connect-timeout=" + connectTimeout; - var connectionpoolingObject = new { pooling = new { enabled = true, maxSize = 1, queueTimeout = 20000, maxIdleTime = 1000 } }; - - TestClientSuccessTimeout(minTime, maxTime, $"Timeout value between {minTime} and {maxTime} seconds", connStr, connectionpoolingObject); - - var connStrUri = "mysqlx://" + session.Settings.UserID + ":" + session.Settings.Password + "@[192.1.10.10," + localIP + ":" + XPort + "]" + "/?connect-timeout=" + connectTimeout; - TestClientSuccessTimeout(minTime, maxTime, $"Timeout value between {minTime} and {maxTime} seconds", connStr, connectionpoolingObject); - - } - - [Test, Description("connect - timeout parameter set as 1000 milliseconds.Create a pool of two sessions." + - "pooling(enabled:true,maxSize:2,queueTimeout: 2000 milliseconds).Try to create a third connection and verify the behaviour(Queue timeout expected)")] - public void TimeoutReachingMaxSizePool() - { - int connectTimeout = 1000; - string hostList = string.Empty; - string localIP = session.Settings.Server; - string connStr = "server=" + localIP + ";port=" + XPort + ";uid=" + session.Settings.UserID + ";" + "password=" + session.Settings.Password + - ";connect-timeout=" + connectTimeout; - var connectionpooling = "{ \"pooling\": { \"maxSize\": 2, \"queueTimeout\": 2000 , \"maxIdleTime\":1000, \"enabled\": true} }"; - var connectionpoolingObject = new { pooling = new { enabled = true, maxSize = 2, queueTimeout = 2000, maxIdleTime = 1000 } }; - using (Client client = MySQLX.GetClient(connStr, connectionpoolingObject)) - { - var session1 = client.GetSession(); - var session2 = client.GetSession(); - TestClientQueueTimeout(client, 1, 3, "Test queue timeout"); - } - var connStrUri = "mysqlx://" + session.Settings.UserID + ":" + session.Settings.Password + "@[" + localIP + ":" + XPort + "]" + "/?connect-timeout=" + connectTimeout; - using (var client = MySQLX.GetClient(connStrUri, connectionpoolingObject)) - { - - var session1 = client.GetSession(); - var session2 = client.GetSession(); - TestClientQueueTimeout(client, 1, 3, "Test queue timeout"); - } - var connObj = new { server = "" + localIP, port = XPort, uid = session.Settings.UserID, password = session.Settings.Password, connecttimeout = connectTimeout }; - using (var client = MySQLX.GetClient(connObj, connectionpoolingObject)) - { - var session1 = client.GetSession(); - var session2 = client.GetSession(); - TestClientQueueTimeout(client, 1, 3, "Test queue timeout"); - } - - using (Client client = MySQLX.GetClient(connStr, connectionpooling)) - { - var session1 = client.GetSession(); - var session2 = client.GetSession(); - TestClientQueueTimeout(client, 1, 3, "Test queue timeout"); - } - using (var client = MySQLX.GetClient(connStrUri, connectionpooling)) - { - var session1 = client.GetSession(); - var session2 = client.GetSession(); - TestClientQueueTimeout(client, 1, 3, "Test queue timeout"); - } - using (var client = MySQLX.GetClient(connObj, connectionpooling)) - { - var session1 = client.GetSession(); - var session2 = client.GetSession(); - TestClientQueueTimeout(client, 1, 3, "Test queue timeout"); - } - for (var i = 1; i <= 2; i++) - { - hostList = "(address=143.24.20.36,priority=1),(address=" + localIP + ",priority=0)"; - } - connStr = "server=" + hostList + ";user=" + session.Settings.UserID + ";port=" + XPort + ";password=" - + session.Settings.Password + ";connect-timeout=" + connectTimeout; - - using (var client = MySQLX.GetClient(connStr, connectionpoolingObject)) - { - var session1 = client.GetSession(); - var session2 = client.GetSession(); - TestClientQueueTimeout(client, 1, 3, "Test queue timeout X"); - } - - var connObj1 = new { server = hostList, port = XPort, user = session.Settings.UserID, password = session.Settings.Password, connecttimeout = connectTimeout }; - using (var client = MySQLX.GetClient(connObj1, connectionpoolingObject)) - { - var session1 = client.GetSession(); - var session2 = client.GetSession(); - TestClientQueueTimeout(client, 1, 3, "Test queue timeout Y"); - } - using (var client = MySQLX.GetClient(connStr, connectionpooling)) - { - var session1 = client.GetSession(); - var session2 = client.GetSession(); - TestClientQueueTimeout(client, 1, 3, "Test queue timeout X"); - } - connObj1 = new { server = hostList, port = XPort, user = session.Settings.UserID, password = session.Settings.Password, connecttimeout = connectTimeout }; - using (var client = MySQLX.GetClient(connObj1, connectionpooling)) - { - var session1 = client.GetSession(); - var session2 = client.GetSession(); - TestClientQueueTimeout(client, 1, 3, "Test queue timeout A"); - } - - } - - [Test, Description("scenario 0(connectionString,connectionUri,Anonymous Object)-Without connect timeout and max timeout should be 10s")] - public void TimeoutWithWrongHost() - { - string serverName = "vigdis07.no.oracle.com"; - string connStr = "server=" + serverName + ";user=" + session.Settings.UserID + ";port=" + XPort + ";password=" - + session.Settings.Password + ";"; - TestConnectStringTimeoutFailureTimeout(connStr, 0, 11, "Timeout value between 9 and 11 seconds"); - connStr = "mysqlx://" + session.Settings.UserID + ":" + session.Settings.Password + "@" + serverName + ":" + XPort; - TestConnectStringTimeoutFailureTimeout(connStr, 0, 11, "Timeout value between 9 and 11 seconds"); - var connObj = new { server = serverName, port = XPort, user = session.Settings.UserID, password = session.Settings.Password }; - TestConnectObjTimeoutFailureTimeout(connObj, 0, 11, "Timeout value between 9 and 11 seconds"); - - } - - [Test, Description("scenario 1(connectionString,connectionUri,Anonymous Object)")] - public void MeasureNoTimeoutResponse() - { - string connStr = "server=" + session.Settings.Server + ";user=" + session.Settings.UserID + ";port=" + XPort + ";password=" - + session.Settings.Password + ";" + "connect-timeout=90;"; - TestConnectStringTimeoutSuccessTimeout(connStr, 0, 3, "Timeout value between 0 and 1 second"); - connStr = "mysqlx://" + session.Settings.UserID + ":" + session.Settings.Password + "@" + session.Settings.Server + ":" + XPort + "?connect-timeout=900;"; - TestConnectStringTimeoutSuccessTimeout(connStr, 0, 3, "Timeout value between 0 and 1 second"); - var connObj = new { server = session.Settings.Server, port = XPort, user = session.Settings.UserID, password = session.Settings.Password, connecttimeout = 9000 }; - TestConnectObjectTimeoutSuccessTimeout(connObj, 0, 3, "Timeout value between 0 and 1 second"); - } - - [Test, Description("scenario 2(connectionString,connectionUri,Anonymous Object with all options)")] - public void NoTimeoutWithManyOptions() - { - if (!Platform.IsWindows()) return; - string connStr = "server=" + session.Settings.Server + ";user id=" + session.Settings.UserID + ";password=" + - session.Settings.Password + ";port=" + XPort + ";protocol=Socket;" + - "database=" + schemaName + ";characterset=utf8mb4;sslmode=VerifyCA;ssl-ca=" - + sslCa + ";certificatepassword=pass;keepalive=10;auth=PLAIN;" - + "connect-timeout=900;"; - TestConnectStringTimeoutSuccessTimeout(connStr, 0, 1, "Timeout value between 0 and 1 second"); - connStr = "mysqlx://" + session.Settings.Server + ":" + XPort + "/" + schemaName - + "?" + "user id=" + session.Settings.UserID + "&password=" + session.Settings.Password + "&sslca=" - + sslCa + "&certificatepassword=pass&keepalive=10&characterset=utf8mb4&auth=PLAIN&connect-timeout=900"; - TestConnectStringTimeoutSuccessTimeout(connStr, 0, 1, "Timeout value between 0 and 1 second"); - var connObj = - new - { - server = session.Settings.Server, - port = XPort, - user = session.Settings.UserID, - password = session.Settings.Password, - sslmode = MySqlSslMode.VerifyCA, - CertificateFile = sslCa, - CertificatePassword = sslCertificatePassword, - database = schemaName, - keepalive = 10, - characterset = "utf8mb4", - auth = MySqlAuthenticationMode.PLAIN, - connecttimeout = 9000 - }; - TestConnectStringTimeoutSuccessTimeout(connStr, 0, 1, "Timeout value between 0 and 1 second"); - } - - [Test, Description("scenario 1(MysqlxStringBuilder)")] - public void TimeoutSuccessWithStringBuilder() - { - var connStrBuilder = new MySqlXConnectionStringBuilder(); - connStrBuilder.ConnectTimeout = 9000; - connStrBuilder.UserID = session.Settings.UserID; - connStrBuilder.Password = session.Settings.Password; - connStrBuilder.Port = Convert.ToUInt32(XPort); - connStrBuilder.Server = session.Settings.Server; - TestConnectStringTimeoutSuccessTimeout(connStrBuilder.ConnectionString, 0, 3, "Timeout value between 0 and 3 second"); - string connStr = "server=" + session.Settings.Server + ";user=" + session.Settings.UserID + ";port=" + XPort + ";password=" - + session.Settings.Password + ";" + "connect-timeout=9000;"; - connStrBuilder = new MySqlXConnectionStringBuilder(connStr); - TestConnectStringTimeoutSuccessTimeout(connStrBuilder.ConnectionString, 0, 3, "Timeout value between 0 and 3 second"); - } - - [Test, Description("scenario 2(MysqlxStringBuilder with all options)")] - public void TimeoutSuccessWithStringBuilderAllOptions() - { - string connStr = null; - MySqlXConnectionStringBuilder mysqlx0 = null; - if (!Platform.IsWindows()) return; - connStr = "server=" + session.Settings.Server + ";user id=" + session.Settings.UserID + ";password=" + - session.Settings.Password + ";port=" + XPort + ";protocol=Socket;" + - "database=" + schemaName + ";characterset=utf8mb4;sslmode=Required;ssl-ca=" - + sslCa + $";certificatepassword={sslCertificatePassword};certificatestorelocation=LocalMachine;" - + ";keepalive =10;auth=PLAIN;certificatethumbprint=;" - + "connect-timeout=" + 9000; - mysqlx0 = new MySqlXConnectionStringBuilder(connStr); - TestConnectStringTimeoutSuccessTimeout(mysqlx0.ConnectionString, 0, 1, "Timeout value between 0 and 1 second"); - mysqlx0 = new MySqlXConnectionStringBuilder(); - mysqlx0.Server = session.Settings.Server; - mysqlx0.UserID = session.Settings.UserID; - mysqlx0.Password = session.Settings.Password; - mysqlx0.Port = Convert.ToUInt32(XPort); - mysqlx0.ConnectionProtocol = MySqlConnectionProtocol.Tcp; - mysqlx0.Database = schemaName; - mysqlx0.CharacterSet = "utf8mb4"; - mysqlx0.SslMode = MySqlSslMode.Required; - mysqlx0.SslCa = sslCa; - mysqlx0.CertificatePassword = sslCertificatePassword; - mysqlx0.CertificateStoreLocation = MySqlCertificateStoreLocation.LocalMachine; - mysqlx0.Keepalive = 10; - mysqlx0.Auth = MySqlAuthenticationMode.PLAIN; - mysqlx0.CertificateThumbprint = ""; - mysqlx0.ConnectTimeout = (uint)90000; - TestConnectStringTimeoutSuccessTimeout(mysqlx0.ConnectionString, 0, 1, "Timeout value between 0 and 1 second"); - } - - [Test, Description("scenario 3(MysqlxStringBuilder with all options-set minimum timeout to 1 and keep on increasing till gets connected)")] - public void TimeoutIncreasingUntilConnect() - { - string connStr = null; - MySqlXConnectionStringBuilder mysqlx0 = null; - - for (int i = 1; i < 20; i++) - { - connStr = ConnectionString + ";protocol=Socket;" + - "database=" + schemaName + ";characterset=utf8mb4;sslmode=VerifyCA;ssl-ca=" - + sslCa + $";certificatepassword={sslCertificatePassword};certificatestorelocation=LocalMachine;" - + ";auth=PLAIN;certificatethumbprint=;" - + "connect-timeout=" + i; - mysqlx0 = new MySqlXConnectionStringBuilder(connStr); - using (var conn = MySQLX.GetSession(mysqlx0.ConnectionString)) - { - Assert.IsNotNull(conn.Uri); - } - break; - } - - for (int i = 1; i < 20; i++) - { - mysqlx0 = new MySqlXConnectionStringBuilder(); - mysqlx0.Server = session.Settings.Server; - mysqlx0.UserID = session.Settings.UserID; - mysqlx0.Password = session.Settings.Password; - mysqlx0.Port = Convert.ToUInt32(XPort); - mysqlx0.ConnectionProtocol = MySqlConnectionProtocol.Tcp; - mysqlx0.Database = schemaName; - mysqlx0.CharacterSet = "utf8mb4"; - mysqlx0.SslMode = MySqlSslMode.VerifyCA; - mysqlx0.SslCa = sslCa; - mysqlx0.CertificatePassword = sslCertificatePassword; - mysqlx0.CertificateStoreLocation = MySqlCertificateStoreLocation.LocalMachine; - mysqlx0.Auth = MySqlAuthenticationMode.PLAIN; - mysqlx0.CertificateThumbprint = ""; - mysqlx0.ConnectTimeout = (uint)i; - - using (var conn = MySQLX.GetSession(mysqlx0.ConnectionString)) - { - Assert.IsNotNull(conn.Uri); - } - break; - } - } - - [Test, Description("scenario 1(connectionString,connectionUri,Anonymous Object with default timeout)")] - public void ValidateDefaultTimeoutParameter() - { - uint defaultTimeout = 1; - string connStr = ConnectionString + ";" + "connect-timeout=" + defaultTimeout; - for (int i = 0; i < 10; i++) - { - using (var conn = MySQLX.GetSession(connStr)) - { - Assert.AreEqual(conn.Settings.ConnectTimeout, defaultTimeout); - } - } - connStr = "mysqlx://" + session.Settings.UserID + ":" + session.Settings.Password + "@" + session.Settings.Server + ":" + XPort + "?connect-timeout=" + defaultTimeout; - for (int i = 0; i < 10; i++) - { - using (var conn = MySQLX.GetSession(connStr)) - { - Assert.AreEqual(conn.Settings.ConnectTimeout, defaultTimeout); - } - } - var connObj1 = new { server = session.Settings.Server, port = XPort, user = session.Settings.UserID, password = session.Settings.Password, connecttimeout = defaultTimeout }; - for (int i = 0; i < 10; i++) - { - using (var conn = MySQLX.GetSession(connObj1)) - { - Assert.AreEqual(conn.Settings.ConnectTimeout, defaultTimeout); - } - } - } - - [Test, Description("scenario 2(MysqlxStringBuilder with default timeout)")] - public void ValidateDefaultTimeoutParameterWithStringBuilder() - { - uint defaultTimeout = 1; - var connStrBuilder = new MySqlXConnectionStringBuilder(); - connStrBuilder.ConnectTimeout = defaultTimeout; - connStrBuilder.UserID = session.Settings.UserID; - connStrBuilder.Password = session.Settings.Password; - connStrBuilder.Port = Convert.ToUInt32(XPort); - connStrBuilder.Server = session.Settings.Server; - for (int i = 0; i < 10; i++) - { - using (var conn = MySQLX.GetSession(connStrBuilder.ConnectionString)) - { - Assert.AreEqual(conn.Settings.ConnectTimeout, defaultTimeout); - } - } - string connStr = ConnectionString + ";" + "connect-timeout=" + defaultTimeout; - connStrBuilder = new MySqlXConnectionStringBuilder(connStr); - for (int i = 0; i < 10; i++) - { - using (var conn = MySQLX.GetSession(connStrBuilder.ConnectionString)) - { - Assert.AreEqual(conn.Settings.ConnectTimeout, defaultTimeout); - } - } - } - - [Test, Description("scenario 1(MysqlxStringBuilder with connect timeout option for offline server)")] - public void TimeoutOfflineServerWithStringBuilder() - { - int connectionTimeout = 2000; - string serverName = "vigdis07.no.oracle.com"; - var connStrBuilder = new MySqlXConnectionStringBuilder(); - connStrBuilder.ConnectTimeout = (uint)connectionTimeout; - connStrBuilder.UserID = session.Settings.UserID; - connStrBuilder.Password = session.Settings.Password; - connStrBuilder.Port = Convert.ToUInt32(XPort); - connStrBuilder.Server = serverName; - TestConnectStringTimeoutFailureTimeout(connStrBuilder.ConnectionString, 0, 21, "Offline host timeout value in between 1 and 21 seconds"); - - string connStr = "server=" + serverName + ";user=" + session.Settings.UserID + ";port=" + XPort + ";password=" - + session.Settings.Password + ";" + "connect-timeout=" + connectionTimeout; - connStrBuilder = new MySqlXConnectionStringBuilder(connStr); - TestConnectStringTimeoutFailureTimeout(connStrBuilder.ConnectionString, 0, 21, "Offline host timeout value in between 1 and 21 seconds"); - } - - [Test, Description("scenario 1(connectionString,connectionUri,Anonymous Object,MysqlxStringBuilder with connect timeout option=1 for online server)")] - public void TimeoutSuccessConnectOptionOne() - { - int connectionTimeout = 1; - string connStr = ConnectionString + ";" + "connect-timeout=" + connectionTimeout; - TestConnectStringTimeoutSuccessTimeout(connStr, 0, 5, "Checking the timeout between 0 to 5 seconds"); - connStr = ConnectionStringUri + "?connect-timeout=" + connectionTimeout; - TestConnectStringTimeoutSuccessTimeout(connStr, 0, 5, "Checking the timeout between 0 to 5 seconds"); - var connectionObj = new { server = session.Settings.Server, port = XPort, user = session.Settings.UserID, password = session.Settings.Password, connecttimeout = connectionTimeout }; - TestConnectObjectTimeoutSuccessTimeout(connectionObj, 0, 5, "Checking the timeout between 0 to 5 seconds"); - - var connStrBuilder = new MySqlXConnectionStringBuilder(); - connStrBuilder.ConnectTimeout = (uint)connectionTimeout; - connStrBuilder.UserID = session.Settings.UserID; - connStrBuilder.Password = session.Settings.Password; - connStrBuilder.Port = Convert.ToUInt32(XPort); - connStrBuilder.Server = session.Settings.Server; - TestConnectStringTimeoutSuccessTimeout(connStrBuilder.ConnectionString, 0, 5, "Checking the timeout between 0 to 5 seconds"); - - connStr = ConnectionString + ";" + "connect-timeout=" + connectionTimeout; - connStrBuilder = new MySqlXConnectionStringBuilder(connStr); - TestConnectStringTimeoutSuccessTimeout(connStrBuilder.ConnectionString, 0, 5, "Checking the timeout between 0 to 5 seconds"); - - } - - [Test, Description("scenario 1(connectionString,connectionUri,Anonymous Object,MysqlxStringBuilder with connect timeout option=0 for offline server)")] - public void TimeoutOfflineServerConnectOptionZero() - { - int connectionTimeout = 0; - string serverName = "vigdis07.no.oracle.com"; - - string connStr = "server=" + serverName + ";user=" + session.Settings.UserID + ";port=" + XPort + ";password=" - + session.Settings.Password + ";" + "connect-timeout=" + connectionTimeout; - TestConnectStringTimeoutFailureTimeout(connStr, 0, 50000, "Checking the timeout between 0 to 50000 milliseconds"); - - connStr = "mysqlx://" + session.Settings.UserID + ":" + session.Settings.Password + "@" + serverName + ":" + XPort + "?connect-timeout=" + connectionTimeout; - TestConnectStringTimeoutFailureTimeout(connStr, 0, 50000, "Checking the timeout between 0 to 50000 milliseconds"); - - var connObj = new { server = serverName, port = XPort, user = session.Settings.UserID, password = session.Settings.Password, connecttimeout = connectionTimeout }; - TestConnectObjTimeoutFailureTimeout(connObj, 0, 50000, "Checking the timeout between 0 to 50000 milliseconds"); - - var connStrBuilder = new MySqlXConnectionStringBuilder(); - connStrBuilder.ConnectTimeout = (uint)connectionTimeout; - connStrBuilder.UserID = session.Settings.UserID; - connStrBuilder.Password = session.Settings.Password; - connStrBuilder.Port = Convert.ToUInt32(XPort); - connStrBuilder.Server = serverName; - TestConnectStringTimeoutFailureTimeout(connStr, 0, 50000, "Checking the timeout between 0 to 50000 milliseconds"); - - connStr = "server=" + serverName + ";user=" + session.Settings.UserID + ";port=" + XPort + ";password=" - + session.Settings.Password + ";" + "connect-timeout=" + connectionTimeout; - connStrBuilder = new MySqlXConnectionStringBuilder(connStr); - TestConnectStringTimeoutFailureTimeout(connStr, 0, 50000, "Checking the timeout between 0 to 50000 milliseconds"); - - } - - [Test, Description("(connectionString,connectionUri,Anonymous Object.Test that the timeout will be reset for each connection attempt in a failover scenario")] - public void ConnectTimeoutSeveralAddreses() - { - StringBuilder hostList = new StringBuilder(); - int connectionTimeout = 1000; - var priority = 100; - for (var i = 1; i <= 101; i++) - { - hostList.Append("(address=server" + i + ".example,priority=" + (priority != 0 ? priority-- : 0) + "),"); - if (i == 101) hostList.Append($"(address={Host},priority=0)"); - } - - using (var session1 = MySQLX.GetSession("server=" + hostList + ";port=" + XPort + ";uid=" + - session.Settings.UserID + ";password=" + session.Settings.Password + ";connect-timeout=" + - connectionTimeout + ";ssl-mode=required")) - { - Assert.AreEqual(SessionState.Open, session1.InternalSession.SessionState); - var schema = session1.GetSchema("test"); - Assert.IsNotNull(schema); - } - - var connStr = "mysqlx://" + session.Settings.UserID + ":" + session.Settings.Password + "@[" + hostList + "]/?connect-timeout=" + connectionTimeout; - using (var session1 = MySQLX.GetSession(connStr)) - { - Assert.AreEqual(SessionState.Open, session1.InternalSession.SessionState); - var schema = session1.GetSchema("test"); - Assert.IsNotNull(schema); - } - - using (var session1 = MySQLX.GetSession(new - { - server = hostList.ToString(), - port = XPort, - user = session.Settings.UserID, - password = session.Settings.Password, - sslmode = MySqlSslMode.Required - })) - { - Assert.AreEqual(SessionState.Open, session1.InternalSession.SessionState); - var schema = session1.GetSchema("test"); - Assert.IsNotNull(schema); - } - - var strList = "(address=143.24.20.36,priority=0),(address=10.172.165.157,priority=1)"; - connectionTimeout = 2000; - var connString = "server=" + strList + ";port=" + XPort + ";uid=" + - session.Settings.UserID + ";password=" + session.Settings.Password + ";connect-timeout=" + - connectionTimeout + ";ssl-mode=required"; - Stopwatch sw = new Stopwatch(); - sw.Start(); - Assert.Throws(() => MySQLX.GetSession(connString)); - sw.Stop(); - Assert.True(sw.Elapsed.Seconds > 0 && sw.Elapsed.Seconds < 21); - - connStr = "mysqlx://" + session.Settings.UserID + ":" + session.Settings.Password + "@[" + strList + "]" + "/?connect-timeout=" + connectionTimeout; - sw = new Stopwatch(); - sw.Start(); - Assert.Throws(() => MySQLX.GetSession(connString)); - sw.Stop(); - Assert.True(sw.Elapsed.Seconds > 0 && sw.Elapsed.Seconds < 21); - - var connObj1 = new - { - server = strList, - port = XPort, - user = session.Settings.UserID, - password = session.Settings.Password, - connecttimeout = connectionTimeout - }; - sw = new Stopwatch(); - sw.Start(); - Assert.Throws(() => MySQLX.GetSession(connString)); - sw.Stop(); - Assert.True(sw.Elapsed.Seconds > 0 && sw.Elapsed.Seconds < 21); - } - - [Test, Description("(connectionString,connectionUri,Anonymous Object.Test that the timeout will be reset for each connection attempt in a failover scenario")] - public void ConnectTimeoutWithFailoverAndNotValidHost() - { - string hostList = "(address=143.24.20.36,priority=0),(address=143.24.70.98,priority=1)"; - int connectionTimeout = 2000; - // URL - var connString = "server=" + hostList + ";port=" + XPort + ";uid=" + - session.Settings.UserID + ";password=" + session.Settings.Password + ";connect-timeout=" + - connectionTimeout; - Stopwatch sw = new Stopwatch(); - sw.Start(); - Assert.Throws(() => MySQLX.GetSession(connString)); - sw.Stop(); - Assert.True(sw.Elapsed.Seconds > 0 && sw.Elapsed.Seconds < 10); - // URI - var connStr = "mysqlx://" + session.Settings.UserID + ":" + session.Settings.Password + "@[" + hostList + "]" + "/?connect-timeout=" + connectionTimeout; - sw = new Stopwatch(); - sw.Start(); - Assert.Throws(() => MySQLX.GetSession(connString)); - sw.Stop(); - Assert.True(sw.Elapsed.Seconds > 0 && sw.Elapsed.Seconds < 10); - - // Object - var connObj = new - { - server = hostList, - port = XPort, - user = session.Settings.UserID, - password = session.Settings.Password, - connecttimeout = connectionTimeout - }; - sw = new Stopwatch(); - sw.Start(); - Assert.Throws(() => MySQLX.GetSession(connString)); - sw.Stop(); - Assert.True(sw.Elapsed.Seconds > 0 && sw.Elapsed.Seconds < 10); - } - - [Test, Description("Confirm that the timeout is only applied to the connection process, not to any subsequent operation after the connection is established")] - public void ValidateConnectTimeoutScope() - { - if (!Platform.IsWindows()) return; - string connStr = null; - connStr = "server=" + session.Settings.Server + ";user=" + session.Settings.UserID + ";port=" + XPort + ";password=" - + session.Settings.Password + ";" + "connect-timeout=10000;"; - using (var conn = MySQLX.GetSession(connStr)) - { - conn.SQL("SELECT SLEEP(10)").Execute(); - var res = conn.SQL("select @@port").Execute().FirstOrDefault(); - Assert.IsNotNull(res); - } - - connStr = "mysqlx://" + session.Settings.UserID + ":" + session.Settings.Password + "@" + session.Settings.Server + ":" + XPort + "?connect-timeout=10000;"; - using (var conn = MySQLX.GetSession(connStr)) - { - conn.SQL("SELECT SLEEP(10)").Execute(); - var res = conn.SQL("select @@port").Execute().FirstOrDefault(); - Assert.IsNotNull(res); - } - - var connObj = new - { - server = session.Settings.Server, - port = XPort, - user = session.Settings.UserID, - password = session.Settings.Password, - connecttimeout = 10000 - }; - using (var conn = MySQLX.GetSession(connObj)) - { - conn.SQL("SELECT SLEEP(10)").Execute(); - var res = conn.SQL("select @@port").Execute().FirstOrDefault(); - Assert.IsNotNull(res); - } - - var connStrBuilder = new MySqlXConnectionStringBuilder(); - connStrBuilder.ConnectTimeout = 10000; - connStrBuilder.UserID = session.Settings.UserID; - connStrBuilder.Password = session.Settings.Password; - connStrBuilder.Port = Convert.ToUInt32(XPort); - connStrBuilder.Server = session.Settings.Server; - using (var conn = MySQLX.GetSession(connStrBuilder.ConnectionString)) - { - conn.SQL("SELECT SLEEP(10)").Execute(); - var res = conn.SQL("select @@port").Execute().FirstOrDefault(); - Assert.IsNotNull(res); - } - - connStr = "server=" + session.Settings.Server + ";user=" + session.Settings.UserID + ";port=" + XPort + ";password=" - + session.Settings.Password + ";" + "connect-timeout=10000;"; - connStrBuilder = new MySqlXConnectionStringBuilder(connStr); - using (var conn = MySQLX.GetSession(connStrBuilder.ConnectionString)) - { - conn.SQL("SELECT SLEEP(10)").Execute(); - var res = conn.SQL("select @@port").Execute().FirstOrDefault(); - Assert.IsNotNull(res); - } - - connStr = ConnectionString + ";protocol=Socket;" + - "database=" + schemaName + ";characterset=utf8mb4;sslmode=Required;ssl-ca=" - + sslCa + $";certificatepassword={sslCertificatePassword};certificatestorelocation=LocalMachine;" - + ";keepalive =10;auth=PLAIN;certificatethumbprint=;" - + "connect-timeout=" + 10000; - var mysqlx0 = new MySqlXConnectionStringBuilder(connStr); - using (var conn = MySQLX.GetSession(mysqlx0.ConnectionString)) - { - conn.SQL("SELECT SLEEP(10)").Execute(); - var res = conn.SQL("select @@port").Execute().FirstOrDefault(); - Assert.IsNotNull(res); - } - - mysqlx0 = new MySqlXConnectionStringBuilder(); - mysqlx0.UserID = session.Settings.UserID; - mysqlx0.Password = session.Settings.Password; - mysqlx0.Port = Convert.ToUInt32(XPort); - mysqlx0.Server = session.Settings.Server; - mysqlx0.ConnectionProtocol = MySqlConnectionProtocol.Tcp; - mysqlx0.Database = schemaName; - mysqlx0.CharacterSet = "utf8mb4"; - mysqlx0.SslMode = MySqlSslMode.Required; - mysqlx0.SslCa = sslCa; - mysqlx0.CertificatePassword = sslCertificatePassword; - mysqlx0.CertificateStoreLocation = MySqlCertificateStoreLocation.LocalMachine; - mysqlx0.Keepalive = 10; - mysqlx0.Auth = MySqlAuthenticationMode.PLAIN; - mysqlx0.CertificateThumbprint = ""; - mysqlx0.ConnectTimeout = (uint)10000; - - using (var conn = MySQLX.GetSession(mysqlx0.ConnectionString)) - { - conn.SQL("SELECT SLEEP(10)").Execute(); - var res = conn.SQL("select @@port").Execute().FirstOrDefault(); - Assert.IsNotNull(res); - } - } - - [Test, Description("Test that if an unexpected error occurs during the specified time frame, the execution should stop and the error must be reported to the user")] - public void WrongPasswordException() - { - string connStr = null; - string password = "wrongpassword"; - Object[] ConnectTimeout = new Object[] { 10000 }; - for (int i = 0; i < ConnectTimeout.Length; i++) - { - // Connection String - connStr = "server=" + session.Settings.Server + ";user=" + session.Settings.UserID + ";port=" + XPort + ";password=" - + password + ";" + "connect-timeout=" + ConnectTimeout[i]; - Assert.Throws(() => MySQLX.GetSession(connStr)); - //String Builder - var connStrBuilder = new MySqlXConnectionStringBuilder(connStr); - Assert.Throws(() => MySQLX.GetSession(connStrBuilder.ConnectionString)); - // Uri - connStr = "mysqlx://" + session.Settings.UserID + ":" + password + "@" + session.Settings.Server + ":" + XPort + "?connect-timeout=" + ConnectTimeout[i]; - Assert.Throws(() => MySQLX.GetSession(connStr)); - // Anonymous Object - var connObj = new { server = session.Settings.Server, port = XPort, user = session.Settings.UserID, password = password, connecttimeout = ConnectTimeout[i] }; - Assert.Throws(() => MySQLX.GetSession(connStr)); - } - } - - [Test, Description("Test the default connect timeout with offline server with concurrent connections")] - [Ignore("Test its not well implemented")] // TO DO - public async Task ConnectTimeoutConcurrentConnections() - { - await Task.Run(() => SubThread1()); - await Task.Run(() => SubThread2()); - } - - private void SubThread1() - { - string serverName = "vigdis07.no.oracle.com"; - for (int i = 0; i < 5; i++) - { - string connStr = "server=" + serverName + ";user=" + session.Settings.UserID + ";port=" + XPort + ";password=" - + session.Settings.Password + ";" + "connect-timeout=2000;"; - TestConnectStringTimeoutFailureTimeout(connStr, 0, 5, "Timeout value between 1 and 3 second"); - } - } - - private void SubThread2() - { - string serverName = "vigdis07.no.oracle.com"; - for (int i = 0; i < 5; i++) - { - string connStr = "server=" + serverName + ";user=" + session.Settings.UserID + ";port=" + XPort + ";password=" - + session.Settings.Password + ";" + "connect-timeout=2000;"; - TestConnectStringTimeoutFailureTimeout(connStr, 0, 5, "Timeout value between 1 and 3 second"); - } - } - - - [Test, Description("CONNECT-TIMEOUT WORKS WITH BLANK VALUES FOR CONNECTION STRING AND URI")] - public void ConnectTimeoutBlankValues() - { - var connObj = new { server = session.Settings.Server, port = XPort, user = session.Settings.UserID, password = session.Settings.Password, connecttimeout = "" }; - Assert.Throws(() => MySQLX.GetSession(connObj)); - - connObj = new { server = session.Settings.Server, port = XPort, user = session.Settings.UserID, password = session.Settings.Password, connecttimeout = " " }; - Assert.Throws(() => MySQLX.GetSession(connObj)); - - var connStr = $"server={session.Settings.Server};user={session.Settings.UserID};port={XPort};password={session.Settings.Password};connect-timeout=''"; - Assert.Throws(() => MySQLX.GetSession(connStr)); - - connStr = $"server={session.Settings.Server};user={session.Settings.UserID};port={XPort};password={session.Settings.Password};connect-timeout=' '"; - Assert.Throws(() => MySQLX.GetSession(connStr)); - - connStr = $"server={session.Settings.Server};user={session.Settings.UserID};port={XPort};password={session.Settings.Password};connect-timeout="; - Assert.Throws(() => MySQLX.GetSession(connStr)); - - connStr = $"server={session.Settings.Server};user={session.Settings.UserID};port={XPort};password={session.Settings.Password};connect-timeout= "; - Assert.Throws(() => MySQLX.GetSession(connStr)); - - connStr = $"mysqlx://{session.Settings.UserID}:{session.Settings.Password}@{session.Settings.Server}:{XPort}?connect-timeout="; - Assert.Throws(() => MySQLX.GetSession(connStr)); - - connStr = $"mysqlx://{session.Settings.UserID}:{session.Settings.Password}@{session.Settings.Server}:{XPort}?connect-timeout= "; - Assert.Throws(() => MySQLX.GetSession(connStr)); - } - - /// - /// Bug28624010 - /// - [Test, Description("CONNECTIONTIMEOUT OPT WORKS WITH XPLUGN IF A CLASSIC CONN IS ESTABLISD")] - public void TimeoutWithClassicConnection() - { - int connectionTimeout = 10; - var connStr1 = $"server={session.Settings.Server};user={session.Settings.UserID};port={Port};password={session.Settings.Password};sslmode={MySqlSslMode.Required}"; - var conn = new MySqlConnection(connStr1); - conn.Open(); - conn.Close(); - var connStr = $"server={session.Settings.Server};user={session.Settings.UserID};port={XPort};password={session.Settings.Password};connectiontimeout={connectionTimeout}"; - Assert.Throws(() => MySQLX.GetSession(connStr)); - - connStr = $"mysqlx://{session.Settings.UserID}:{session.Settings.Password}@{session.Settings.Server}:{XPort}?connectiontimeout={connectionTimeout} "; - Assert.Throws(() => MySQLX.GetSession(connStr)); - - var connObj = new { server = session.Settings.Server, port = XPort, user = session.Settings.UserID, password = session.Settings.Password, connectiontimeout = connectionTimeout }; - Assert.Throws(() => MySQLX.GetSession(connObj)); - } - - [Test, Description("MySQLX Session Stress test")] - public void SessionStressTest() - { - for (int i = 0; i < 1000; i++) - { - using (Session session1 = MySQLX.GetSession(ConnectionString)) - { - Assert.AreEqual(SessionState.Open, session1.InternalSession.SessionState); - session1.Close(); - } - } - } - - [Test, Description("Getsession using Anonymous Type-Positive")] - public void GetSessionAnonymousTypePositiveStress() - { - for (int i = 0; i < 200; i++) - { - var connectionStringObject = new { connection = $"server={Host};user={session.Settings.UserID};port={XPort};password={session.Settings.Password};sslmode={MySqlSslMode.Required};" }; - using (Session sessionPlain = MySQLX.GetSession(connectionStringObject.connection)) - { - var db = sessionPlain.GetSchema(schemaName); - var col = CreateCollection("my_collection_123456789"); - sessionPlain.Close(); - } - } - } - - [Test, Description("Test Audit Plugin")] - public void SessionAuditPluginTest() - { - using (var mysqlx = MySQLX.GetSession(ConnectionString)) - { - Assert.AreEqual(SessionState.Open, mysqlx.InternalSession.SessionState); - mysqlx.Close(); - } - using (var mysql = new MySqlConnection($"server={Host};user={session.Settings.UserID};port={Port};password={session.Settings.Password}")) - { - mysql.Open(); - Assert.AreEqual(ConnectionState.Open, mysql.connectionState); - mysql.Close(); - } - Assert.Throws(() => MySQLX.GetSession($"server={Host};user={session.Settings.UserID};port={XPort};password=wrong")); - } - - [Test, Description("Classic Client with xprotocol server")] - public void ClassicClientXProtocol() - { - if (!Platform.IsWindows()) Assert.Ignore("This test is for Windows OS only"); - if (!session.Version.isAtLeast(5, 7, 0)) Assert.Ignore("This test is for MySql 5.7 or higher"); - - string connectionString = $"server={Host};user={session.Settings.UserID};port={XPort};password={session.Settings.Password}"; - using (var session1 = new MySqlConnection(connectionString)) - { - Exception ex = Assert.Throws(() => session1.Open()); - Assert.AreEqual("Unsupported protocol version.", ex.Message); - } - } - - #region Methods - - public void TestConnectObjectTimeoutSuccessTimeout(object connString, int minTime, int maxTime, string test) - { - Stopwatch sw = new Stopwatch(); - sw.Start(); - var conn = MySQLX.GetSession(connString); - sw.Stop(); - Assert.True(sw.Elapsed.Seconds >= minTime && sw.Elapsed.Seconds <= maxTime, String.Format("Timeout exceeded ({0}). Actual time: {1}", test, sw.Elapsed)); - } - - public void TestConnectStringTimeoutSuccessTimeout(String connString, int minTime, int maxTime, string test) - { - Stopwatch sw = new Stopwatch(); - sw.Start(); - var conn = MySQLX.GetSession(connString); - sw.Stop(); - Assert.True(sw.Elapsed.Seconds >= minTime && sw.Elapsed.Seconds <= maxTime, String.Format("Timeout exceeded ({0}). Actual time: {1}", test, sw.Elapsed)); - } - - public void TestConnectObjTimeoutFailureTimeout(object connString, int minTime, int maxTime, string test) - { - Stopwatch sw = new Stopwatch(); - sw.Start(); - Assert.Catch(() => MySQLX.GetSession(connString)); - sw.Stop(); - Assert.True(sw.Elapsed.Seconds >= minTime && sw.Elapsed.Seconds < maxTime, String.Format("Timeout exceeded ({0}). Actual time: {1}", test, sw.Elapsed)); - } - - public void TestConnectStringTimeoutFailureTimeout(String connString, int minTime, int maxTime, string test) - { - Stopwatch sw = new Stopwatch(); - sw.Start(); - Assert.Catch(() => MySQLX.GetSession(connString)); - sw.Stop(); - Assert.True(sw.Elapsed.Seconds >= minTime && sw.Elapsed.Seconds < maxTime, String.Format("Timeout exceeded ({0}). Actual time: {1}", test, sw.Elapsed)); - } - - public void TestClientQueueTimeout(Client client, int minTime, int maxTime, string test) - { - Stopwatch sw = new Stopwatch(); - sw.Start(); - Assert.Throws(() => client.GetSession()); - sw.Stop(); - Assert.True(sw.Elapsed.Seconds >= minTime && sw.Elapsed.Seconds < maxTime, - String.Format("Timeout exceeded ({0}). Actual time: {1}", test, sw.Elapsed)); - } - - public void TestClientSuccessTimeout(int minTime, int maxTime, string test, string connectionString, object poolingObject) - { - using (var client = MySQLX.GetClient(connectionString, poolingObject)) - { - Stopwatch sw = new Stopwatch(); - sw.Start(); - client.GetSession(); - sw.Stop(); - Assert.True(sw.Elapsed.Seconds >= minTime && sw.Elapsed.Seconds < maxTime, String.Format("Timeout exceeded ({0}). Actual time: {1}", test, sw.Elapsed)); - } - } - - public void TestClientSuccessTimeout(int minTime, int maxTime, string test, object connectionObject, object poolingObject) - { - using (var client = MySQLX.GetClient(connectionObject, poolingObject)) - { - Stopwatch sw = new Stopwatch(); - sw.Start(); - client.GetSession(); - sw.Stop(); - Assert.True(sw.Elapsed.Seconds >= minTime && sw.Elapsed.Seconds < maxTime, String.Format("Timeout exceeded ({0}). Actual time: {1}", test, sw.Elapsed)); - } - } - public void TestFailureTimeout(Client client, int minTime, int maxTime, string test) - { - DateTime start = DateTime.Now; - Assert.Catch(() => client.GetSession()); - TimeSpan diff = DateTime.Now.Subtract(start); - Assert.True(diff.TotalSeconds >= minTime && diff.TotalSeconds < maxTime, String.Format("Timeout exceeded ({0}). Actual time: {1}", test, diff)); - } - - private void MeasureConnectionString(string connStr, int maxTime, string test, int iteration) - { - Stopwatch sw = new Stopwatch(); - sw.Start(); - - for (int i = 0; i < iteration; i++) - { - using Session conn = MySQLX.GetSession(connStr); - } - - sw.Stop(); - Assert.True(sw.Elapsed.Seconds < maxTime, String.Format("Timeout exceeded ({0}). Actual time: {1}", test, sw.Elapsed)); - } - - private void MeasureConnectionObject(object connStr, int maxTime, string test, int iteration) - { - Stopwatch sw = new Stopwatch(); - sw.Start(); - - for (int i = 0; i < iteration; i++) - { - using Session conn = MySQLX.GetSession(connStr); - } - - sw.Stop(); - Assert.True(sw.Elapsed.Seconds < maxTime, String.Format("Timeout exceeded ({0}). Actual time: {1}", test, sw.Elapsed)); - } - - public long NanoTime() - { - long nano = 10000L * Stopwatch.GetTimestamp(); - nano /= TimeSpan.TicksPerMillisecond; - nano *= 100L; - return nano; - } - - public long DoConnectString(string connectionString) - { - long queryStartTime, queryRunTime = 0; - queryStartTime = NanoTime(); - var session = MySQLX.GetSession(connectionString); - queryRunTime = NanoTime() - queryStartTime; - session.Close(); - session.Dispose(); - return queryRunTime; - } - - public long DoConnectObject(object connectionString) - { - long queryStartTime, queryRunTime = 0; - queryStartTime = NanoTime(); - var session = MySQLX.GetSession(connectionString); - queryRunTime = NanoTime() - queryStartTime; - session.Close(); - session.Dispose(); - return queryRunTime; - } - - /// - /// Calculate the Connection per second - /// Total execution time.(Connection+query execution time) - /// Query execution time - public float CalculateTPS(long elapsedTime, long transactions) - { - float tps = 0; - if (elapsedTime > 0.0) - { - tps = (float)transactions / elapsedTime; - tps = tps * 1000; - } - return tps; - } - - #endregion Methods - - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data; +using MySql.Data.Common; +using MySql.Data.MySqlClient; +using MySqlX.XDevAPI; +using MySqlX.XDevAPI.Relational; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Data; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MySqlX.Data.Tests +{ + public class SessionTests : BaseTest + { + [Test] + [Property("Category", "Security")] + public void CanCloseSession() + { + Session s = MySQLX.GetSession(ConnectionString); + Assert.That(s.InternalSession.SessionState == SessionState.Open); + s.Close(); + Assert.That(SessionState.Closed, Is.EqualTo(s.InternalSession.SessionState)); + } + + [Test] + [Property("Category", "Security")] + public void NoPassword() + { + Session session = MySQLX.GetSession(ConnectionStringNoPassword); + Assert.That(session.InternalSession.SessionState == SessionState.Open); + session.Close(); + Assert.That(SessionState.Closed, Is.EqualTo(session.InternalSession.SessionState)); + } + + [Test] + [Property("Category", "Security")] + public void SessionClose() + { + Session session = MySQLX.GetSession(ConnectionString); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + session.Close(); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Closed)); + } + + [Test] + [Property("Category", "Security")] + [Ignore("Check this. Result is not always the same")] + public void CountClosedSession() + { + int sessions, newSessions; + + using (Session nodeSession = MySQLX.GetSession(ConnectionString)) + { + sessions = ExecuteSQLStatement(nodeSession.SQL("show processlist")).FetchAll().Count; + + for (int i = 0; i < 20; i++) + { + Session session = MySQLX.GetSession(ConnectionString); + Assert.That(session.InternalSession.SessionState == SessionState.Open); + session.Close(); + Assert.That(SessionState.Closed, Is.EqualTo(session.InternalSession.SessionState)); + } + + newSessions = ExecuteSQLStatement(nodeSession.SQL("show processlist")).FetchAll().Count; + } + + Assert.That(newSessions, Is.EqualTo(sessions)); + } + + [Test] + [Property("Category", "Security")] + public void ConnectionStringAsAnonymousType() + { + var connstring = new + { + server = session.Settings.Server, + port = session.Settings.Port, + user = session.Settings.UserID, + password = session.Settings.Password + }; + + using (var testSession = MySQLX.GetSession(connstring)) + { + Assert.That(testSession.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + } + } + + [Test] + [Property("Category", "Security")] + public void SessionGetSetCurrentSchema() + { + using (Session testSession = MySQLX.GetSession(ConnectionString)) + { + Assert.That(testSession.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + Assert.That(testSession.GetCurrentSchema(), Is.Null); + Assert.Throws(() => testSession.SetCurrentSchema("")); + testSession.SetCurrentSchema(schemaName); + Assert.That(testSession.Schema.Name, Is.EqualTo(schemaName)); + Assert.That(testSession.GetCurrentSchema().Name, Is.EqualTo(schemaName)); + } + } + + [Test] + [Property("Category", "Security")] + public void SessionUsingSchema() + { + using (Session mySession = MySQLX.GetSession(ConnectionString + $";database={schemaName};")) + { + Assert.That(mySession.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + Assert.That(mySession.Schema.Name, Is.EqualTo(schemaName)); + Assert.That(mySession.GetCurrentSchema().Name, Is.EqualTo(schemaName)); + Assert.That(SchemaExistsInDatabase(mySession.Schema)); + } + } + + [Test] + [Property("Category", "Security")] + public void SessionUsingDefaultSchema() + { + using (Session mySession = MySQLX.GetSession(ConnectionString + $";database={schemaName};")) + { + Assert.That(mySession.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + Assert.That(mySession.DefaultSchema.Name, Is.EqualTo(schemaName)); + Assert.That(mySession.GetCurrentSchema().Name, Is.EqualTo(schemaName)); + Assert.That(mySession.Schema.ExistsInDatabase()); + mySession.SetCurrentSchema("mysql"); + Assert.That(mySession.Schema.Name, Is.Not.EqualTo(mySession.DefaultSchema.Name)); + } + + // DefaultSchema is null because no database was provided in the connection string/URI. + using (Session mySession = MySQLX.GetSession(ConnectionString)) + { + Assert.That(mySession.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + Assert.That(mySession.DefaultSchema, Is.Null); + } + } + + [Test] + [Property("Category", "Security")] + public void SessionUsingDefaultSchemaWithAnonymousObject() + { + var globalSession = GetSession(); + + using (var internalSession = MySQLX.GetSession(new + { + server = globalSession.Settings.Server, + port = globalSession.Settings.Port, + user = globalSession.Settings.UserID, + password = globalSession.Settings.Password, + sslmode = MySqlSslMode.Required, + database = "mysql" + })) + { + Assert.That(internalSession.DefaultSchema.Name, Is.EqualTo("mysql")); + } + + // DefaultSchema is null when no database is provided. + using (var internalSession = MySQLX.GetSession(new + { + server = globalSession.Settings.Server, + port = globalSession.Settings.Port, + user = globalSession.Settings.UserID, + password = globalSession.Settings.Password, + sslmode = MySqlSslMode.Required, + })) + { + Assert.That(internalSession.DefaultSchema, Is.Null); + } + + // Access denied error is raised when database does not exist for servers 8.0.12 and below. + // This behavior was fixed since MySql Server 8.0.13 version. Now the error + // shows the proper message, "Unknown database..." + if (session.InternalSession.GetServerVersion().isAtLeast(8, 0, 13)) return; + var exception = Assert.Throws(() => MySQLX.GetSession(new + { + server = globalSession.Settings.Server, + port = globalSession.Settings.Port, + user = globalSession.Settings.UserID, + password = globalSession.Settings.Password, + sslmode = MySqlSslMode.Required, + database = "test1" + } + )); + + if (session.InternalSession.GetServerVersion().isAtLeast(8, 0, 13)) + Assert.That(exception.Message, Does.StartWith(string.Format("Unknown database 'test1'"))); + else + Assert.That(exception.Message, Does.StartWith(string.Format("Access denied"))); + } + + [Test] + [Property("Category", "Security")] + public void SessionUsingDefaultSchemaWithConnectionURI() + { + using (var session = MySQLX.GetSession(ConnectionStringUri + "?database=mysql")) + { + Assert.That(session.DefaultSchema.Name, Is.EqualTo("mysql")); + } + } + + [Test] + [Property("Category", "Security")] + public void CheckConnectionUri() + { + CheckConnectionData($"mysqlx://myuser:password@{Host}:{XPort}", "myuser", "password", Host, uint.Parse(XPort)); + CheckConnectionData($"mysqlx://my%3Auser:p%40ssword@{Host}:{XPort}", "my:user", "p@ssword", Host, uint.Parse(XPort)); + CheckConnectionData($"mysqlx://my%20user:p%40ss%20word@{Host}:{XPort}", "my user", "p@ss word", Host, uint.Parse(XPort)); + CheckConnectionData($"mysqlx:// myuser : p%40ssword@{Host}:{XPort}", "myuser", "p@ssword", Host, uint.Parse(XPort)); + CheckConnectionData($"mysqlx://myuser@{Host}:{XPort}", "myuser", "", Host, uint.Parse(XPort)); + CheckConnectionData($"mysqlx://myuser:p%40ssword@{Host}", "myuser", "p@ssword", Host, uint.Parse(XPort)); + CheckConnectionData($"mysqlx://myuser:p%40ssw%40rd@{Host}", "myuser", "p@ssw@rd", Host, uint.Parse(XPort)); + CheckConnectionData($"mysqlx://my%40user:p%40ssword@{Host}", "my@user", "p@ssword", Host, uint.Parse(XPort)); + CheckConnectionData($"mysqlx://myuser@{Host}", "myuser", "", Host, uint.Parse(XPort)); + CheckConnectionData($"mysqlx://myuser@{Host}", "myuser", "", Host, uint.Parse(XPort)); + CheckConnectionData("mysqlx://myuser@[::1]", "myuser", "", "[::1]", uint.Parse(XPort)); + CheckConnectionData("mysqlx://myuser:password@[2606:b400:440:1040:bd41:e449:45ee:2e1a]", "myuser", "password", "[2606:b400:440:1040:bd41:e449:45ee:2e1a]", uint.Parse(XPort)); + CheckConnectionData($"mysqlx://myuser:password@[2606:b400:440:1040:bd41:e449:45ee:2e1a]:{XPort}", "myuser", "password", "[2606:b400:440:1040:bd41:e449:45ee:2e1a]", uint.Parse(XPort)); + Assert.Throws(() => CheckConnectionData("mysqlx://myuser:password@[2606:b400:440:1040:bd41:e449:45ee:2e1a:33060]", "myuser", "password", "[2606:b400:440:1040:bd41:e449:45ee:2e1a]", uint.Parse(XPort))); + Assert.Throws(() => CheckConnectionData($"mysqlx://myuser:password@2606:b400:440:1040:bd41:e449:45ee:2e1a:{XPort}", "myuser", "password", "[2606:b400:440:1040:bd41:e449:45ee:2e1a]", uint.Parse(XPort))); + CheckConnectionData("mysqlx://myuser:password@[fe80::bd41:e449:45ee:2e1a%17]", "myuser", "password", "[fe80::bd41:e449:45ee:2e1a]", uint.Parse(XPort)); + CheckConnectionData("mysqlx://myuser:password@[(address=[fe80::bd41:e449:45ee:2e1a%17],priority=100)]", "myuser", "password", "[fe80::bd41:e449:45ee:2e1a]", uint.Parse(XPort)); + CheckConnectionData("mysqlx://myuser:password@[(address=[fe80::bd41:e449:45ee:2e1a%17]:3305,priority=100)]", "myuser", "password", "[fe80::bd41:e449:45ee:2e1a]", 3305); + Assert.Throws(() => CheckConnectionData("mysqlx://myuser:password@[(address=fe80::bd41:e449:45ee:2e1a%17,priority=100)]", "myuser", "password", "[fe80::bd41:e449:45ee:2e1a]", 33060)); + CheckConnectionData("mysqlx://myuser@localhost/test", "myuser", "", "localhost", 33060, "database", schemaName); +#if NET8_0_OR_GREATER + CheckConnectionData("mysqlx://myuser@localhost/test?ssl%20mode=disabled&connecttimeout=10", "myuser", "", "localhost", 33060, "database", schemaName, "ssl mode", "None", "connecttimeout", "10"); +#else + CheckConnectionData("mysqlx://myuser@localhost/test?ssl%20mode=disabled&connecttimeout=10", "myuser", "", "localhost", 33060, "database", schemaName, "ssl mode", "Disabled", "connecttimeout", "10"); +#endif + CheckConnectionData("mysqlx://_%21%22%23%24s%26%2F%3D-%25r@localhost", "_!\"#$s&/=-%r", "", "localhost", 33060); + CheckConnectionData("mysql://myuser@localhost", "", "", "", 33060); + CheckConnectionData("myuser@localhost", "", "", "", 33060); + Assert.Throws(() => CheckConnectionData("mysqlx://uid=myuser;server=localhost", "", "", "", 33060)); + CheckConnectionData("mysqlx://user:password@server.example.com/", "user", "password", "server.example.com", 33060, "ssl mode", "Required"); + CheckConnectionData("mysqlx://user:password@server.example.com/?ssl-ca=(c:%5Cclient.pfx)", "user", "password", "server.example.com", 33060, "ssl mode", "Required", "ssl-ca", "c:\\client.pfx"); + Assert.Throws(() => CheckConnectionData("mysqlx://user:password@server.example.com/?ssl-crl=(c:%5Ccrl.pfx)", "user", "password", "server.example.com", 33060, "ssl mode", "Required", "ssl-crl", "(c:\\crl.pfx)")); + // tls-version + CheckConnectionData("mysqlx://myuser:password@localhost:33060?tls-version=TlSv1.2", "myuser", "password", "localhost", 33060, "tls-version", "Tls12"); + CheckConnectionData("mysqlx://myuser:password@localhost:33060?tls-version=TlS1.2", "myuser", "password", "localhost", 33060, "tls-version", "Tls12"); + CheckConnectionData("mysqlx://myuser:password@localhost:33060?tls-version=TlSv12", "myuser", "password", "localhost", 33060, "tls-version", "Tls12"); + CheckConnectionData("mysqlx://myuser:password@localhost:33060?tls-version=TlS12", "myuser", "password", "localhost", 33060, "tls-version", "Tls12"); + CheckConnectionData("mysqlx://myuser:password@localhost:33060?tls-version=[ TlSv1.2 ,tLsV11, TLSv1.0 , tls13 ]", "myuser", "password", "localhost", 33060, "tls-version", "Tls12, Tls13"); + CheckConnectionData("mysqlx://myuser:password@localhost:33060?tls-version=( TlSv1.2 ,tLsV11, TLSv1 , tls13 )", "myuser", "password", "localhost", 33060, "tls-version", "Tls12, Tls13"); + CheckConnectionData("mysqlx://myuser:password@localhost:33060?tls-version= TlSv1.2 ,tLsV11, TLSv10 , tls13", "myuser", "password", "localhost", 33060, "tls-version", "Tls12, Tls13"); + Assert.Throws(() => CheckConnectionData("mysqlx://myuser:password@localhost:33060?tls-version=SSL3", "myuser", "password", "localhost", 33060, "tls-version", "")); + } + + [Test] + [Property("Category", "Security")] + public void ConnectionUsingUri() + { + using (var session = MySQLX.GetSession(ConnectionStringUri)) + { + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + } + } + + [Test] + [Property("Category", "Security")] + public void ConnectionStringNull() + { + Assert.Throws(() => MySQLX.GetSession(null)); + } + + [Test] + [Property("Category", "Security")] + public void IPv6() + { + var csBuilder = new MySqlXConnectionStringBuilder(ConnectionString); + csBuilder.Server = GetMySqlServerIp(true); + csBuilder.Port = uint.Parse(XPort); + + Assume.That(!string.IsNullOrEmpty(csBuilder.Server), "No IPv6 available."); + + using (var session = MySQLX.GetSession(csBuilder.ToString())) + { + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + } + } + + [Test] + [Property("Category", "Security")] + public void IPv6AsUrl() + { + var csBuilder = new MySqlXConnectionStringBuilder(ConnectionString); + string ipv6 = GetMySqlServerIp(true); + Assume.That(!string.IsNullOrEmpty(ipv6), "No IPv6 available."); + + string connString = $"mysqlx://{csBuilder.UserID}:{csBuilder.Password}@[{ipv6}]:{XPort}"; + using (Session session = MySQLX.GetSession(connString)) + { + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + } + } + + [Test] + [Property("Category", "Security")] + public void IPv6AsAnonymous() + { + var csBuilder = new MySqlXConnectionStringBuilder(ConnectionString); + string ipv6 = GetMySqlServerIp(true); + Assume.That(!string.IsNullOrEmpty(ipv6), "No IPv6 available."); + + using (Session session = MySQLX.GetSession(new { server = ipv6, user = csBuilder.UserID, password = csBuilder.Password, port = XPort })) + { + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + } + } + + [Test] + [Property("Category", "Security")] + public void CreateSessionWithUnsupportedOptions() + { + var errorMessage = "Option not supported"; + var connectionUri = string.Format("{0}?", ConnectionStringUri); + + // Use a connection URI. + var ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "pipe=MYSQL")); + Assert.That(ex.Message, Does.StartWith(errorMessage)); + ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "compress=true")); + Assert.That(ex.Message, Does.StartWith(errorMessage)); + ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "allow batch=false")); + Assert.That(ex.Message, Does.StartWith(errorMessage)); + ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "logging=true")); + Assert.That(ex.Message, Does.StartWith(errorMessage)); + ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "sharedmemoryname=MYSQL")); + Assert.That(ex.Message, Does.StartWith(errorMessage)); + ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "defaultcommandtimeout=30")); + Assert.That(ex.Message, Does.StartWith(errorMessage)); + ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "usedefaultcommandtimeoutforef=true")); + Assert.That(ex.Message, Does.StartWith(errorMessage)); + ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "persistsecurityinfo=false")); + Assert.That(ex.Message, Does.StartWith(errorMessage)); + ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "encrypt=false")); + Assert.That(ex.Message, Does.StartWith(errorMessage)); + ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "integratedsecurity=true")); + Assert.That(ex.Message, Does.StartWith(errorMessage)); + ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "allowpublickeyretrieval=false")); + Assert.That(ex.Message, Does.StartWith(errorMessage)); + ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "autoenlist=true")); + Assert.That(ex.Message, Does.StartWith(errorMessage)); + ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "includesecurityasserts=false")); + Assert.That(ex.Message, Does.StartWith(errorMessage)); + ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "allowzerodatetime=true")); + Assert.That(ex.Message, Does.StartWith(errorMessage)); + ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "convert zero datetime=false")); + Assert.That(ex.Message, Does.StartWith(errorMessage)); + ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "useusageadvisor=true")); + Assert.That(ex.Message, Does.StartWith(errorMessage)); + ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "procedurecachesize=50")); + Assert.That(ex.Message, Does.StartWith(errorMessage)); + ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "useperformancemonitor=true")); + Assert.That(ex.Message, Does.StartWith(errorMessage)); + ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "respectbinaryflags=true")); + Assert.That(ex.Message, Does.StartWith(errorMessage)); + ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "treat tiny as boolean=false")); + Assert.That(ex.Message, Does.StartWith(errorMessage)); + ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "allowuservariables=true")); + Assert.That(ex.Message, Does.StartWith(errorMessage)); + ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "interactive=false")); + Assert.That(ex.Message, Does.StartWith(errorMessage)); + ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "functionsreturnstring=true")); + Assert.That(ex.Message, Does.StartWith(errorMessage)); + ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "useaffectedrows=false")); + Assert.That(ex.Message, Does.StartWith(errorMessage)); + ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "oldguids=true")); + Assert.That(ex.Message, Does.StartWith(errorMessage)); + ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "sqlservermode=false")); + Assert.That(ex.Message, Does.StartWith(errorMessage)); + ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "tablecaching=true")); + Assert.That(ex.Message, Does.StartWith(errorMessage)); + ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "defaulttablecacheage=60")); + Assert.That(ex.Message, Does.StartWith(errorMessage)); + ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "checkparameters=true")); + Assert.That(ex.Message, Does.StartWith(errorMessage)); + ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "replication=replication_group")); + Assert.That(ex.Message, Does.StartWith(errorMessage)); + ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "exceptioninterceptors=none")); + Assert.That(ex.Message, Does.StartWith(errorMessage)); + ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "commandinterceptors=none")); + Assert.That(ex.Message, Does.StartWith(errorMessage)); + ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "connectionlifetime=100")); + Assert.That(ex.Message, Does.StartWith(errorMessage)); + ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "pooling=false")); + Assert.That(ex.Message, Does.StartWith(errorMessage)); + ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "minpoolsize=0")); + Assert.That(ex.Message, Does.StartWith(errorMessage)); + ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "maxpoolsize=20")); + Assert.That(ex.Message, Does.StartWith(errorMessage)); + ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "connectionreset=false")); + Assert.That(ex.Message, Does.StartWith(errorMessage)); + ex = Assert.Throws(() => MySQLX.GetSession(connectionUri + "cacheserverproperties=true")); + Assert.That(ex.Message, Does.StartWith(errorMessage)); + + // Use a connection string. + ex = Assert.Throws(() => MySQLX.GetSession("treatblobsasutf8=false")); + Assert.That(ex.Message, Does.StartWith(errorMessage)); + ex = Assert.Throws(() => MySQLX.GetSession("blobasutf8includepattern=pattern")); + Assert.That(ex.Message, Does.StartWith(errorMessage)); + ex = Assert.Throws(() => MySQLX.GetSession("blobasutf8excludepattern=pattern")); + Assert.That(ex.Message, Does.StartWith(errorMessage)); + } + + [Test] + [Property("Category", "Security")] + public void CreateBuilderWithUnsupportedOptions() + { + var errorMessage = "Option not supported"; + var ex = Assert.Throws(() => new MySqlXConnectionStringBuilder("pipe=MYSQL")); + Assert.That(ex.Message, Does.StartWith(errorMessage)); + ex = Assert.Throws(() => new MySqlXConnectionStringBuilder("allow batch=false")); + Assert.That(ex.Message, Does.StartWith(errorMessage)); + ex = Assert.Throws(() => new MySqlXConnectionStringBuilder("respectbinaryflags=true")); + Assert.That(ex.Message, Does.StartWith(errorMessage)); + ex = Assert.Throws(() => new MySqlXConnectionStringBuilder("pooling=false")); + Assert.That(ex.Message, Does.StartWith(errorMessage)); + ex = Assert.Throws(() => new MySqlXConnectionStringBuilder("cacheserverproperties=true")); + Assert.That(ex.Message, Does.StartWith(errorMessage)); + } + + [Test] + [Property("Category", "Security")] + public void GetUri() + { + using (var internalSession = MySQLX.GetSession(session.Uri)) + { + // Validate that all properties keep their original value. + foreach (var connectionOption in session.Settings.values) + { + // SslCrl connection option is skipped since it isn't currently supported. + if (connectionOption.Key == "sslcrl") + continue; + + try + { + Assert.That(internalSession.Settings[connectionOption.Key], Is.EqualTo(session.Settings[connectionOption.Key])); + } + catch (ArgumentException ex) + { + Assert.That(ex.Message, Does.StartWith("Option not supported.")); + } + } + } + } + + /// + /// WL #16033 Fix timeout tests + /// + [Test] + [Property("Category", "Security")] + [TestCase($"server=_server;user=test;password=test;port=_port;connect-timeout=0;", 0, 1000, true, true)] + [TestCase($"server=_server;user=test;password=test;port=_port;", 8, 25, true)] + [TestCase($"server=_server,server_;port=port_;user=test;password=test;", 0, 25, false)] + [TestCase($"server=_server;user=test;password=test;port=_port;connect-timeout=5000;", 3, 15, true)] + [TestCase($"mysqlx://test:test@[_server:_port]", 0, 25, true, false, true)] + public void ConnectionTimeout(string connstring,int min,int max,bool failure, bool usemockservertimeout=false, bool isUri=false) + { + MockServer mServer = new MockServer(usemockservertimeout); + mServer.StartServer(); + + if (failure) + { + if (isUri) + { + if (Uri.TryCreate(connstring, UriKind.Absolute, out _)) + { + TestConnectTimeoutFailureTimeout(connstring.Replace("_server", mServer.Address.ToString()).Replace("_port", mServer.Port.ToString()), min, max, "default timeout", usemockservertimeout); + } + else + { + mServer.StopServer(); + mServer.DisposeListener(); + Assert.Ignore("not parseable Uri: "+ connstring); + } + } + else + { + TestConnectTimeoutFailureTimeout(connstring.Replace("_server", mServer.Address.ToString()).Replace("_port", mServer.Port.ToString()), min, max, "default timeout", usemockservertimeout); + } + } + else + { + connstring = connstring.Replace("_server", mServer.Address.ToString()).Replace("_port", mServer.Port.ToString()).Replace("server_", Host).Replace("port_", XPort); + TestConnectTimeoutSuccessTimeout(connstring, min, max, "Fail over success"); + } + mServer.StopServer(); + mServer.DisposeListener(); + } + + /// + /// WL #12177 Implement connect timeout + /// + [Test] + [Property("Category", "Security")] + public void ConnectTimeoutParameterValidation() + { + Assume.That(!Platform.IsMacOSX(), "Check failure on MacOS: (() => MySQLX.GetSession(conn)); + TimeSpan diff = DateTime.Now.Subtract(start); + Assert.That(diff.TotalSeconds > 1 && diff.TotalSeconds < 45, String.Format("Timeout exceeded ({0}). Actual time: {1}", "Fail over failure", diff)); + mServer1.StopServer(); + mServer1.DisposeListener(); + mServer2.StopServer(); + mServer2.DisposeListener(); + + // Valid session no time out + start = DateTime.Now; + using (Session session = MySQLX.GetSession(ConnectionStringUri+ "?connecttimeout=0")) + session.SQL("SELECT SLEEP(10)").Execute(); + diff = DateTime.Now.Subtract(start); + Assert.That(diff.TotalSeconds > 10); + + //Invalid Values for Connection Timeout parameter + var ex = Assert.Throws(() => MySQLX.GetSession(ConnectionString + ";connect-timeout=-1;")); + Assert.That(ex.Message, Is.EqualTo(ResourcesX.InvalidConnectionTimeoutValue)); + + ex = Assert.Throws(() => MySQLX.GetSession(ConnectionString + ";connect-timeout=foo;")); + Assert.That(ex.Message, Is.EqualTo(ResourcesX.InvalidConnectionTimeoutValue)); + + ex = Assert.Throws(() => MySQLX.GetSession(ConnectionString + ";connect-timeout='';")); + Assert.That(ex.Message, Is.EqualTo(ResourcesX.InvalidConnectionTimeoutValue)); + + ex = Assert.Throws(() => MySQLX.GetSession(ConnectionString + ";connect-timeout=10.5;")); + Assert.That(ex.Message, Is.EqualTo(ResourcesX.InvalidConnectionTimeoutValue)); + + ex = Assert.Throws(() => MySQLX.GetSession(ConnectionString + ";connect-timeout=" + Int32.MaxValue + 1)); + Assert.That(ex.Message, Is.EqualTo(ResourcesX.InvalidConnectionTimeoutValue)); + + ex = Assert.Throws(() => MySQLX.GetSession(ConnectionString + ";connect-timeout=10.5;")); + Assert.That(ex.Message, Is.EqualTo(ResourcesX.InvalidConnectionTimeoutValue)); + + ex = Assert.Throws(() => MySQLX.GetSession(ConnectionString + ";connect-timeout=;")); + Assert.That(ex.Message, Is.EqualTo(ResourcesX.InvalidConnectionTimeoutValue)); + + ex = Assert.Throws(() => MySQLX.GetSession(ConnectionStringUri + "?connect-timeout= ")); + Assert.That(ex.Message, Is.EqualTo(ResourcesX.InvalidConnectionTimeoutValue)); + + ex = Assert.Throws(() => MySQLX.GetSession(ConnectionStringUri + "?connecttimeout=")); + Assert.That(ex.Message, Is.EqualTo(ResourcesX.InvalidConnectionTimeoutValue)); + + // Valid value for ConnectionTimeout, invalid credentials + var exception = Assert.Throws(() => MySQLX.GetSession($"server={Host};user=test;password=noPass;port={XPort};connect-timeout=2000;")); + Assert.That(exception, Is.Not.Null); + } + + private void TestConnectTimeoutFailureTimeout(String connString, int minTime, int maxTime, string test, bool usingmocktimeout) + { + DateTime start = DateTime.Now; + if(usingmocktimeout) + Assert.Throws(() => MySQLX.GetSession(connString)); + else + Assert.Throws(() => MySQLX.GetSession(connString)); + TimeSpan diff = DateTime.Now.Subtract(start); + Assert.That(diff.TotalSeconds > minTime && diff.TotalSeconds < maxTime, String.Format("Timeout exceeded ({0}). Actual time: {1}", test, diff)); + } + + private void TestConnectTimeoutSuccessTimeout(String connString, int minTime, int maxTime, string test) + { + DateTime start = DateTime.Now; + MySQLX.GetSession(connString); + TimeSpan diff = DateTime.Now.Subtract(start); + Assert.That(diff.TotalSeconds > minTime && diff.TotalSeconds < maxTime, String.Format("Timeout exceeded ({0}). Actual time: {1}", test, diff)); + } + + [Test] + [Property("Category", "Security")] + public void MaxConnections() + { + try + { + List sessions = new List(); + ExecuteSqlAsRoot("SET @@global.mysqlx_max_connections = 2"); + for (int i = 0; i <= 2; i++) + { + Session newSession = MySQLX.GetSession(ConnectionString); + sessions.Add(newSession); + } + Assert.That(true, Is.False, "MySqlException should be thrown"); + } + catch (MySqlException ex) + { + Assert.That(ex.Message, Is.EqualTo(ResourcesX.UnableToOpenSession)); + } + finally + { + ExecuteSqlAsRoot("SET @@global.mysqlx_max_connections = 100"); + } + } + + protected void CheckConnectionData(string connectionData, string user, string password, string server, uint port, params string[] parameters) + { + string result = this.session.ParseConnectionData(connectionData); + var csbuilder = new MySqlXConnectionStringBuilder(result); + Assert.That(user == csbuilder.UserID, string.Format("Expected:{0} Current:{1} in {2}", user, csbuilder.UserID, connectionData)); + Assert.That(password == csbuilder.Password, string.Format("Expected:{0} Current:{1} in {2}", password, csbuilder.Password, connectionData)); + Assert.That(server == csbuilder.Server, string.Format("Expected:{0} Current:{1} in {2}", server, csbuilder.Server, connectionData)); + Assert.That(port == csbuilder.Port, string.Format("Expected:{0} Current:{1} in {2}", port, csbuilder.Port, connectionData)); + if (parameters != null) + { + if (parameters.Length % 2 != 0) + throw new ArgumentOutOfRangeException(); + for (int i = 0; i < parameters.Length; i += 2) + { + Assert.That(csbuilder.ContainsKey(parameters[i])); + Assert.That(csbuilder[parameters[i]].ToString(), Is.EqualTo(parameters[i + 1])); + } + } + } + + /// + /// WL12514 - DevAPI: Support session-connect-attributes + /// + [Test] + [Property("Category", "Security")] + public void ConnectionAttributes() + { + if (!(session.Version.isAtLeast(8, 0, 16))) return; + + // Validate that MySQLX.GetSession() supports a new 'connection-attributes' query parameter + // with default values and all the client attributes starts with a '_'. + TestConnectionAttributes(ConnectionString + ";connection-attributes=true;"); + TestConnectionAttributes(ConnectionStringUri + "?connectionattributes"); + + // Validate that no attributes, client or user defined, are sent to server when the value is "false". + TestConnectionAttributes(ConnectionString + ";connection-attributes=false;"); + TestConnectionAttributes(ConnectionStringUri + "?connectionattributes=false"); + + // Validate default behavior with different scenarios. + TestConnectionAttributes(ConnectionString + ";connection-attributes;"); + TestConnectionAttributes(ConnectionStringUri + "?connectionattributes=true"); + TestConnectionAttributes(ConnectionString + ";connection-attributes=;"); + TestConnectionAttributes(ConnectionStringUri + "?connectionattributes=[]"); + + // Validate user-defined attributes to be sent to server. + Dictionary userAttrs = new Dictionary + { + { "foo", "bar" }, + { "quua", "qux" }, + { "key", null } + }; + TestConnectionAttributes(ConnectionString + ";connection-attributes=[foo=bar,quua=qux,key]", userAttrs); + TestConnectionAttributes(ConnectionStringUri + "?connectionattributes=[foo=bar,quua=qux,key=]", userAttrs); + + // Errors + var ex = Assert.Throws(() => MySQLX.GetSession(ConnectionString + ";connection-attributes=[_key=value]")); + Assert.That(ex.Message, Is.EqualTo(ResourcesX.InvalidUserDefinedAttribute)); + + ex = Assert.Throws(() => MySQLX.GetSession(ConnectionString + ";connection-attributes=123")); + Assert.That(ex.Message, Is.EqualTo(ResourcesX.InvalidConnectionAttributes)); + + ex = Assert.Throws(() => MySQLX.GetSession(ConnectionString + ";connection-attributes=[key=value,key=value2]")); + Assert.That(ex.Message, Is.EqualTo(string.Format(ResourcesX.DuplicateUserDefinedAttribute, "key"))); + + ex = Assert.Throws(() => MySQLX.GetSession(new { server = Host, port = XPort, user = RootUser, connectionattributes = "=" })); + + ex = Assert.Throws(() => MySQLX.GetSession(ConnectionString + ";connectionattributes=[=bar]")); + Assert.That(ex.Message, Is.EqualTo(string.Format(ResourcesX.EmptyKeyConnectionAttribute))); + } + + private void TestConnectionAttributes(string connString, Dictionary userAttrs = null) + { + string sql = "SELECT * FROM performance_schema.session_account_connect_attrs WHERE PROCESSLIST_ID = connection_id()"; + + using (Session session = MySQLX.GetSession(connString)) + { + Assert.That(session.XSession.SessionState, Is.EqualTo(SessionState.Open)); + var result = session.SQL(sql).Execute().FetchAll(); + + if (session.Settings.ConnectionAttributes == "false") + Assert.That(result, Is.Empty); + else + { + Assert.That(result, Is.Not.Empty); + MySqlConnectAttrs clientAttrs = new MySqlConnectAttrs(); + + if (userAttrs == null) + { + Assert.That(result.Count, Is.EqualTo(8)); + + foreach (Row row in result) + Assert.That(row[1].ToString(), Does.StartWith("_")); + } + else + { + Assert.That(result.Count, Is.EqualTo(11)); + + for (int i = 0; i < userAttrs.Count; i++) + { + Assert.That(userAttrs.ContainsKey(result.ElementAt(i)[1].ToString())); + Assert.That(userAttrs.ContainsValue(result.ElementAt(i)[2])); + } + } + } + } + } + + [TestCase("localhost")] + [TestCase("127.0.0.1")] + [TestCase("[::1]")] + [Description("IPv6 connection Scenario [localhost],[127.0.0.1]")] + public void ConnectionTest(string serverName) + { + Assume.That(Platform.IsWindows(), "This test is only for Windows OS."); + + serverName = serverName.Replace("localhost", Host); + + MySqlXConnectionStringBuilder sb = new MySqlXConnectionStringBuilder(ConnectionString); + string connStr = "server=" + Host + ";user=" + sb.UserID + ";port=" + XPort + ";password=" + sb.Password + ";" + "sslmode=" + MySqlSslMode.Required; + + using (var sessionTest = MySQLX.GetSession(connStr)) + { + Assert.That(sessionTest.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + } + + using (var sessionTest = MySQLX.GetSession("mysqlx://" + sb.UserID + ":" + sb.Password + "@" + serverName + ":" + XPort)) + { + Assert.That(sessionTest.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + } + + using (var sessionTest = MySQLX.GetSession(new { server = serverName, port = XPort, user = sb.UserID, password = sb.Password })) + { + Assert.That(sessionTest.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + } + //wrong port + connStr = "server=" + sb.Server + ";user=" + sb.UserID + ";port=" + 33090 + ";password=" + sb.Password + ";" + "sslmode=" + MySqlSslMode.Required; + Assert.Throws(() => MySQLX.GetSession(connStr)); + + } + + [TestCase("[::$]")] + [TestCase("[::11]")] + [Description("IPv6 connection server * and ::$,invalid hostname")] + public void IPv6ConnectionExceptions(string serverName) + { + Assume.That(Platform.IsWindows(), "This test is only for Windows OS."); + + Session sessionTest = null; + string connStr = "server=" + serverName + ";user=test;port=" + XPort + ";password=test;sslmode=" + MySqlSslMode.Required; + Assert.Catch(() => sessionTest = MySQLX.GetSession(connStr)); + Assert.Catch(() => sessionTest = MySQLX.GetSession("mysqlx://test:test@" + serverName + ":" + XPort)); + Assert.Catch(() => sessionTest = MySQLX.GetSession(new { server = serverName, port = XPort, user = schemaName, password = schemaName })); + } + + [Test, Description("Unified connection string refinement-Negative Scenarios")] + public void ConnectionNegativeScenarios() + { + Assume.That(Platform.IsWindows(), "This test is only for Windows OS."); + var ipv6HostName2 = GetIPV6Address(); + string ipAddress = GetMySqlServerIp(); + + Session session1 = null; + Assert.Catch(() => session1 = MySQLX.GetSession("mysql:x//test:test@" + ipAddress + ":" + XPort)); + Assert.Catch(() => session1 = MySQLX.GetSession("my:sqlx//test:test@" + ipAddress + ":" + XPort)); + Assert.Catch(() => session1 = MySQLX.GetSession("mysqlx:://test:test@" + ipAddress + ":" + XPort)); + string ipv6address = "f345::" + GetIPV6Address() + ":1xde"; + Assert.Catch(() => session1 = MySQLX.GetSession("mysqlx://test:test@[" + ipv6address + "]:" + XPort)); + Assert.Catch(() => session1 = MySQLX.GetSession("mysqlx://test:test@" + ipAddress + ":" + XPort + "/" + "unknowndatabase")); + string connStr = "mysqlx://test:test@" + session.Settings.Server + ":" + XPort + "/?" + "ssl-mode=VerifyFull&ssl-ca=" + sslCa + "&ssl-ca-pwd=wrongpass"; + Assert.Catch(() => session1 = MySQLX.GetSession(connStr)); + } + + [Test, Description("Session.Uri")] + public void SessionUriAndDefaultSchemaTest() + { + if (!Platform.IsWindows()) return; + + using (var session1 = MySQLX.GetSession(ConnectionString)) + { + Assert.That(session1.Uri, Is.Not.Null); + } + + MySqlXConnectionStringBuilder sb = new MySqlXConnectionStringBuilder(ConnectionString); + var connectionString = ConnectionStringUserWithSSLPEM + ";protocol=TCP;database=" + + sb.Database + ";characterset=utf8mb4;sslmode=Required;connect-timeout=10;keepalive=10;auth=PLAIN"; + using (var session1 = MySQLX.GetSession(connectionString)) + { + Assert.That(session1.Uri, Is.Not.Null); + } + + using (var session1 = MySQLX.GetSession(new + { + server = sb.Server, + port = XPort, + user = sb.UserID, + password = sb.Password, + sslmode = MySqlSslMode.Required + })) + { + Assert.That(session1.Uri, Is.Not.Null); + } + + var conn = new MySqlConnectionStringBuilder(); + conn.Server = sb.Server; + conn.UserID = sb.UserID; + conn.Password = sb.Password; + conn.Port = Convert.ToUInt32(XPort); + conn.Database = schemaName; + conn.CharacterSet = "utf8mb4"; + conn.SslMode = MySqlSslMode.VerifyCA; + conn.SslCa = sslCa; + conn.CertificatePassword = sslCertificatePassword; + conn.Keepalive = 10; + conn.ConnectionProtocol = MySqlConnectionProtocol.Tcp; + + using (var session1 = MySQLX.GetSession(conn.ConnectionString)) + { + Assert.That(session1.Uri, Is.Not.Null); + } + + using (var session1 = MySQLX.GetSession(ConnectionStringUri + "/?ssl-mode=Required;")) + { + Assert.That(session1.Uri, Is.Not.Null); + } + + conn = new MySqlConnectionStringBuilder(); + conn.Server = sb.Server; + conn.UserID = sb.UserID; + conn.Password = sb.Password; + conn.Port = Convert.ToUInt32(XPort); + conn.ConnectionProtocol = MySqlConnectionProtocol.Tcp; + conn.Database = schemaName; + conn.CharacterSet = "utf8mb4"; + conn.SslMode = MySqlSslMode.Required; + conn.SslCa = sslCa; + conn.CertificatePassword = sslCertificatePassword; + conn.Keepalive = 10; + connectionString = conn.ConnectionString; + using (var session1 = MySQLX.GetSession(connectionString)) + { + Assert.That(session1.DefaultSchema.Name, Is.EqualTo(schemaName)); + Assert.That(session1.Uri, Is.Not.Null); + } + + conn = new MySqlConnectionStringBuilder(); + conn.Server = sb.Server; + conn.UserID = sb.UserID; + conn.Password = sb.Password; + conn.Port = Convert.ToUInt32(XPort); + conn.ConnectionProtocol = MySqlConnectionProtocol.Tcp; + conn.Database = schemaName; + conn.CharacterSet = "utf8mb4"; + conn.SslMode = MySqlSslMode.VerifyCA; + conn.SslCa = sslCa; + conn.CertificatePassword = sslCertificatePassword; + conn.Keepalive = 10; + connectionString = conn.ConnectionString; + using (var session1 = MySQLX.GetSession(connectionString)) + { + Assert.That(session1.DefaultSchema.Name, Is.EqualTo(schemaName)); + Assert.That(session1.Uri, Is.Not.Null); + } + + conn = new MySqlConnectionStringBuilder(); + conn.Server = sb.Server; + conn.UserID = sb.UserID; + conn.Password = sb.Password; + conn.Port = Convert.ToUInt32(XPort); + conn.ConnectionProtocol = MySqlConnectionProtocol.Tcp; + conn.Database = schemaName; + conn.CharacterSet = "utf8mb4"; + conn.Keepalive = 10; + connectionString = conn.ConnectionString; + using (var session1 = MySQLX.GetSession(connectionString)) + { + Assert.That(session1.DefaultSchema.Name, Is.EqualTo(schemaName)); + Assert.That(session1.Uri, Is.Not.Null); + session1.DropSchema("㭋玤䂜蚌"); + session1.CreateSchema("㭋玤䂜蚌"); + session1.SQL("USE 㭋玤䂜蚌").Execute(); + Assert.That(session1.DefaultSchema.Name, Is.EqualTo(schemaName)); + } + + conn.Database = "㭋玤䂜蚌"; + connectionString = conn.ConnectionString; + using (var session1 = MySQLX.GetSession(connectionString)) + { + Assert.That(session1.DefaultSchema.Name, Is.EqualTo("㭋玤䂜蚌")); + Assert.That(session1.Uri, Is.Not.Null); + } + + conn.Server = sb.Server; + conn.UserID = sb.UserID; + conn.Password = sb.Password; + conn.Port = Convert.ToUInt32(XPort); + conn.ConnectionProtocol = MySqlConnectionProtocol.Tcp; + conn.Database = "㭋玤䂜蚌"; + conn.CharacterSet = "utf8mb4"; + conn.SslMode = MySqlSslMode.VerifyCA; + conn.SslCa = sslCa; + conn.CertificatePassword = sslCertificatePassword; + conn.Keepalive = 10; + connectionString = conn.ConnectionString; + using (var session1 = MySQLX.GetSession(connectionString)) + { + Assert.That(session1.DefaultSchema.Name, Is.EqualTo("㭋玤䂜蚌")); + Assert.That(session1.Uri, Is.Not.Null); + session1.DropSchema("㭋玤䂜蚌"); + } + + } + + [Test, Description("Test MySqlX plugin Connection for user with wrong password")] + public void GetSessionWithWrongPassword() + { + MySqlXConnectionStringBuilder sb = new MySqlXConnectionStringBuilder(ConnectionString); + sb.Password = "wrongPassword"; + Assert.Throws(() => MySQLX.GetSession(sb.ConnectionString)); + } + + [Test, Description("Test MySqlX plugin Connection for user with correct password but non MysqlX Server")] + public void GetSessionWithWrongPort() + { + MySqlXConnectionStringBuilder sb = new MySqlXConnectionStringBuilder(ConnectionString); + sb.Port = Convert.ToUInt32(Port); + Assert.Throws(() => MySQLX.GetSession(sb.ConnectionString)); + } + + [Test, Description("Test MySqlX plugin Issue a drop command after session already closed")] + public void GetSessionDropAlreadyClosedConnection() + { + Session testSession = MySQLX.GetSession(ConnectionString); + testSession.Close(); + testSession.Close();//works and behaviour expected but any input command should fail + Assert.Throws(() => testSession.DropSchema(schemaName)); + + testSession = MySQLX.GetSession(ConnectionStringNoPassword); + testSession.Close(); + testSession.Close();//works and behaviour expected but any input command should fail + Assert.Throws(() => testSession.DropSchema(schemaName)); + } + + [Test, Description("Session.DefaultSchema")] + public void SessionDefaultSchema() + { + if (!Platform.IsWindows()) return; + + MySqlXConnectionStringBuilder sb = new MySqlXConnectionStringBuilder(ConnectionString); + sb.Database = null; + var session1 = MySQLX.GetSession(sb.ConnectionString); + Assert.That(session1.DefaultSchema, Is.EqualTo(null)); + string connectionString = ConnectionString + ";protocol=Socket;database=" + schemaName + ";characterset=utf8mb4;sslmode=VerifyCA;ssl-ca=" + + sslCa + ";certificatepassword=" + sslCertificatePassword + ";connect-timeout=10;keepalive=10;auth=PLAIN"; + session1 = MySQLX.GetSession(connectionString); + Assert.That(session1.DefaultSchema.Name, Is.EqualTo(schemaName)); + + session1 = MySQLX.GetSession(ConnectionStringUri + "/" + schemaName + "?" + "auth=PLAIN&characterset=utf8mb4"); + Assert.That(session1.DefaultSchema.Name, Is.EqualTo(schemaName)); + + session1 = MySQLX.GetSession(new + { + server = sb.Server, + port = XPort, + user = sb.UserID, + password = sb.Password, + sslmode = MySqlSslMode.Required, + database = schemaName + }); + Assert.That(session1.DefaultSchema.Name, Is.EqualTo(schemaName)); + session1.DefaultSchema.CreateCollection("tester"); + session1.DefaultSchema.DropCollection("tester"); + Assert.That(session1.DefaultSchema.Session.DefaultSchema.Name, Is.EqualTo(schemaName)); + + var conn = new MySqlConnectionStringBuilder(); + session1.DropSchema("㭋玤䂜蚌"); + session1.CreateSchema("㭋玤䂜蚌"); + session1.SQL("USE 㭋玤䂜蚌").Execute(); + Assert.That(session1.DefaultSchema.Name, Is.EqualTo(schemaName)); + session1.Dispose(); + conn.Server = sb.Server; + conn.UserID = sb.UserID; + conn.Password = sb.Password; + conn.Port = Convert.ToUInt32(XPort); + conn.ConnectionProtocol = MySqlConnectionProtocol.Tcp; + conn.Database = "㭋玤䂜蚌"; + conn.CharacterSet = "utf8mb4"; + conn.SslMode = MySqlSslMode.Required; + conn.SslCa = sslCa; + conn.CertificatePassword = sslCertificatePassword; + conn.Keepalive = 10; + connectionString = conn.ConnectionString; + session1 = MySQLX.GetSession(connectionString); + Assert.That(session1.DefaultSchema.Name, Is.EqualTo("㭋玤䂜蚌")); + Assert.That(session1.Uri, Does.Contain("㭋玤䂜蚌")); + + conn.Server = sb.Server; + conn.UserID = sb.UserID; + conn.Password = sb.Password; + conn.Port = Convert.ToUInt32(XPort); + conn.ConnectionProtocol = MySqlConnectionProtocol.Tcp; + conn.Database = "㭋玤䂜蚌"; + conn.CharacterSet = "utf8mb4"; + conn.SslMode = MySqlSslMode.Required; + conn.SslCa = sslCa; + conn.CertificatePassword = sslCertificatePassword; + conn.Keepalive = 10; + connectionString = conn.ConnectionString; + session1 = MySQLX.GetSession(connectionString); + Assert.That(session1.DefaultSchema.Name, Is.EqualTo("㭋玤䂜蚌")); + Assert.That(session1.Uri, Does.Contain("㭋玤䂜蚌")); + session1.DefaultSchema.CreateCollection("tester"); + session1.DefaultSchema.DropCollection("tester"); + Assert.That(session1.DefaultSchema.Session.DefaultSchema.Name, Is.EqualTo("㭋玤䂜蚌")); + } + + [Test, Description("Session BaseString/MySQLXConnectionString Builder")] + public void ConnectionStringBuilderXpluginTests() + { + if (!Platform.IsWindows()) return; + + MySqlXConnectionStringBuilder mysqlx0 = new MySqlXConnectionStringBuilder(ConnectionString); + mysqlx0.ConnectionProtocol = MySqlConnectionProtocol.Tcp; + mysqlx0.CharacterSet = "utf8mb4"; + mysqlx0.SslMode = MySqlSslMode.Required; + mysqlx0.ConnectTimeout = 10; + mysqlx0.Keepalive = 10; + mysqlx0.CertificateFile = sslCa; + mysqlx0.CertificatePassword = sslCertificatePassword; + mysqlx0.CertificateStoreLocation = MySqlCertificateStoreLocation.LocalMachine; + mysqlx0.CertificateThumbprint = ""; + + + using (var xpluginconn = MySQLX.GetSession(mysqlx0.ConnectionString)) + { + Assert.That(xpluginconn.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + } + + mysqlx0 = new MySqlXConnectionStringBuilder(ConnectionString); + mysqlx0.Server = "::1"; + mysqlx0.Database = schemaName; + mysqlx0.CharacterSet = "utf8mb4"; + mysqlx0.ConnectionProtocol = MySqlConnectionProtocol.Tcp; + mysqlx0.SslMode = MySqlSslMode.Required; + mysqlx0.ConnectTimeout = 10; + mysqlx0.Keepalive = 10; + mysqlx0.CertificateFile = sslCa; + mysqlx0.CertificatePassword = sslCertificatePassword; + mysqlx0.CertificateStoreLocation = MySqlCertificateStoreLocation.LocalMachine; + mysqlx0.CertificateThumbprint = sslCertificatePassword; + + using (var xpluginconn = MySQLX.GetSession(mysqlx0.ConnectionString)) + { + Assert.That(xpluginconn.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + } + + mysqlx0 = new MySqlXConnectionStringBuilder(ConnectionString); + mysqlx0.Database = schemaName; + mysqlx0.ConnectionProtocol = MySqlConnectionProtocol.Tcp; + mysqlx0.CharacterSet = "utf8mb4"; + mysqlx0.SslMode = MySqlSslMode.VerifyCA; + mysqlx0.ConnectTimeout = 10; + mysqlx0.Keepalive = 10; + mysqlx0.CertificateFile = sslCa; + mysqlx0.CertificatePassword = "pass"; + mysqlx0.CertificateStoreLocation = MySqlCertificateStoreLocation.LocalMachine; + mysqlx0.CertificateThumbprint = ""; + + using (var xpluginconn = MySQLX.GetSession(mysqlx0.ConnectionString)) + { + Assert.That(xpluginconn.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + } + + mysqlx0 = new MySqlXConnectionStringBuilder(ConnectionString); + mysqlx0.Database = schemaName; + mysqlx0.ConnectionProtocol = MySqlConnectionProtocol.Tcp; + mysqlx0.CharacterSet = "utf8mb4"; + mysqlx0.SslMode = MySqlSslMode.Required; + mysqlx0.ConnectTimeout = 10; + mysqlx0.Keepalive = 10; + + using (var xpluginconn = MySQLX.GetSession(mysqlx0.ConnectionString)) + { + Assert.That(xpluginconn.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + } + + //Scenario-2 + string valid = "server=" + mysqlx0.Server + ";user id=" + mysqlx0.UserID + ";password=" + mysqlx0.Password + ";port=" + XPort + ";protocol=Socket;database=" + schemaName + ";characterset=utf8mb4;sslmode=Required;certificatefile=" + sslCa + ";certificatepassword=" + sslCertificatePassword + ";connect-timeout=10;keepalive=10;certificatestorelocation=LocalMachine;certificatethumbprint=;"; + using (var xpluginconn = MySQLX.GetSession(valid)) + { + Assert.That(xpluginconn.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + } + + //Scenario-3 + mysqlx0 = new MySqlXConnectionStringBuilder(ConnectionString); + mysqlx0.Database = schemaName; + mysqlx0.ConnectionProtocol = MySqlConnectionProtocol.Tcp; + mysqlx0.CharacterSet = "utf8mb4"; + mysqlx0.SslMode = MySqlSslMode.Required; + mysqlx0.ConnectTimeout = 10; + mysqlx0.Keepalive = 10; + mysqlx0.CertificateFile = sslCa; + mysqlx0.CertificatePassword = sslCertificatePassword; + mysqlx0.CertificateStoreLocation = MySqlCertificateStoreLocation.LocalMachine; + mysqlx0.CertificateThumbprint = ""; + mysqlx0.Auth = MySqlAuthenticationMode.AUTO; + mysqlx0.SslCa = sslCa; + using (var xpluginconn = MySQLX.GetSession(mysqlx0.ConnectionString)) + { + Assert.That(xpluginconn.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + } + + //Basic Scenarios + var connectionstr = "server=" + mysqlx0.Server + ";database=" + mysqlx0.Database + ";port=" + + XPort + ";userid=" + mysqlx0.UserID + ";password=" + + mysqlx0.Password + + ";characterset=utf8mb4;sslmode=Required;connect-timeout=20000;keepalive=20000;certificatefile=" + + sslCa + ";certificatepassword=" + sslCertificatePassword + + ";certificatestorelocation=LocalMachine;certificatethumbprint="; + using (var xpluginconn = MySQLX.GetSession(connectionstr)) + { + Assert.That(xpluginconn.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + } + + connectionstr = "mysqlx://" + mysqlx0.Server + ":" + XPort + "/" + + schemaName + "?connect-timeout=10&userid=" + mysqlx0.UserID + "&password=" + + mysqlx0.Password + "&sslca=" + sslCa + "&certificatepassword=" + + sslCertificatePassword + "&keepalive=10&characterset=utf8mb4"; + + using (var xpluginconn = MySQLX.GetSession(connectionstr)) + { + Assert.That(xpluginconn.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + } + + using (var xpluginconn = MySQLX.GetSession(new + { + server = mysqlx0.Server, + port = XPort, + user = mysqlx0.UserID, + password = mysqlx0.Password + })) + { + Assert.That(xpluginconn.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + } + + } + + [Test, Description("Connection Measurement Test")] + public void ConnectionTimeTest() + { + int secondsExpected = 15; + var connObject = new { server = Host, port = XPort, user = session.Settings.UserID, password = session.Settings.Password }; + MeasureConnectionString(ConnectionString, secondsExpected, "Connection String", 5); + MeasureConnectionString(ConnectionStringUri, secondsExpected, "Connection String URI", 5); + MeasureConnectionObject(connObject, secondsExpected, "Connection Object", 5); + } + + [Test, Description("Connection time with Database set")] + public void ConnectionTimeWithDatabaseTest() + { + int secondsExpected = 15; + var connString = ConnectionString + ";database=test"; + var connStringURI = ConnectionStringUri + "/?database=test"; + MySqlXConnectionStringBuilder sb = new MySqlXConnectionStringBuilder(ConnectionString); + var connectionObject = new + { + server = sb.Server, + port = XPort, + user = sb.UserID, + password = sb.Password, + database = schemaName + }; + MeasureConnectionString(connString, secondsExpected, "Connection String", 5); + MeasureConnectionString(connStringURI, secondsExpected, "Connection String URI", 5); + MeasureConnectionObject(connectionObject, secondsExpected, "Connection Object", 5); + } + + [Test, Description("REFACTOR PARSING OF CONNECTION STRING IN X DEVAPI")] + [Ignore("Uncomment to execute")] + public void ParseConnectionStringBenchmark_S1() + { + long transactions = 0; + long startTime = 0; + long endTime = 0; + long queryRunTime = 0; + int iterations = 10; + long NANO_TO_MILLI = 1000000; + long elapsedTime = 0; + long conTime = 0; + int i = 0; + + string connStr = ConnectionString; + + var session = MySQLX.GetSession(connStr); + session.Close(); + + for (int j = 0; j < 1; j++) + { + transactions = 0; + startTime = 0; + endTime = 0; + queryRunTime = 0; + iterations = 20; + elapsedTime = 0; + conTime = 0; + connStr = ConnectionStringUri; + startTime = NanoTime(); + for (i = 0; i < iterations; i++) + { + queryRunTime = queryRunTime + DoConnectString(connStr); + } + endTime = NanoTime(); + transactions = i; + elapsedTime = (endTime - startTime); //in nano + conTime = (elapsedTime / NANO_TO_MILLI) - (queryRunTime / NANO_TO_MILLI); + var t = CalculateTPS(conTime, transactions); + var log = ("Connected to MySQL using URI with iterations " + iterations + " with TPS:" + t); + Assert.That(t, Is.Not.Empty); + + transactions = 0; + startTime = 0; + endTime = 0; + queryRunTime = 0; + iterations = 20; + elapsedTime = 0; + conTime = 0; + connStr = ConnectionString; + startTime = NanoTime(); + for (i = 0; i < iterations; i++) + { + queryRunTime = queryRunTime + DoConnectString(connStr); + } + endTime = NanoTime(); + transactions = i; + elapsedTime = (endTime - startTime); //in nano + conTime = (elapsedTime / NANO_TO_MILLI) - (queryRunTime / NANO_TO_MILLI); + t = CalculateTPS(conTime, transactions); + log = ("Connected to MySQL using connection string with iterations " + iterations + " with TPS:" + t); + Console.WriteLine(log); + Assert.That(t, Is.Not.Empty); + + transactions = 0; + startTime = 0; + endTime = 0; + queryRunTime = 0; + iterations = 20; + elapsedTime = 0; + conTime = 0; + MySqlXConnectionStringBuilder sb = new MySqlXConnectionStringBuilder(ConnectionString); + var conn = new + { + server = sb.Server, + port = XPort, + user = sb.UserID, + password = sb.Password + }; + startTime = NanoTime(); + for (i = 0; i < iterations; i++) + { + queryRunTime = queryRunTime + DoConnectObject(conn); + } + endTime = NanoTime(); + transactions = i; + elapsedTime = (endTime - startTime); //in nano + conTime = (elapsedTime / NANO_TO_MILLI) - (queryRunTime / NANO_TO_MILLI); + t = CalculateTPS(conTime, transactions); + log = ("Connected to MySQL using Anonymous with iterations " + + iterations + + " with TPS:" + t); + } + } + + [Test, Description("REFACTOR PARSING OF CONNECTION STRING IN X DEVAPI")] + [Ignore("Uncomment to execute")] + public void ParseConnectionStringBenchmark_S2() + { + var connStr = ConnectionStringUri; + long queryStartTime = 0, queryRunTime = 0; + queryStartTime = NanoTime(); + var session1 = MySQLX.GetSession(connStr); + queryRunTime = NanoTime() - queryStartTime; + session1.Close(); + for (int j = 0; j < 20; j++) + { + connStr = ConnectionStringUri; + queryStartTime = 0; queryRunTime = 0; + queryStartTime = NanoTime(); + session1 = MySQLX.GetSession(connStr); + queryRunTime = NanoTime() - queryStartTime; + session1.Close(); + session1.Dispose(); + var log = ("Connected to MySQL using URI:" + queryRunTime / 1000000); + + connStr = ConnectionString; + queryStartTime = 0; queryRunTime = 0; + queryStartTime = NanoTime(); + session1 = MySQLX.GetSession(connStr); + queryRunTime = NanoTime() - queryStartTime; + session1.Close(); + session1.Dispose(); + log = ("Connected to MySQL using connection string:" + queryRunTime / 1000000); + + MySqlXConnectionStringBuilder sb = new MySqlXConnectionStringBuilder(ConnectionString); + var conn = new + { + server = sb.Server, + port = XPort, + user = sb.UserID, + password = sb.Password + }; + queryStartTime = 0; queryRunTime = 0; + queryStartTime = NanoTime(); + session1 = MySQLX.GetSession(conn); + queryRunTime = NanoTime() - queryStartTime; + session1.Close(); + session1.Dispose(); + log = ("Connected to MySQL using Connection Object:" + queryRunTime / 1000000); + } + } + + [Test, Description("Getsession/Session-URI")] + public void GetSessionUriPositiveTests() + { + string[] positiveStringList = new string[6]; + MySqlXConnectionStringBuilder sb = new MySqlXConnectionStringBuilder(ConnectionString); + positiveStringList[0] = "mysqlx://" + sb.UserID + ":" + sb.Password + "@" + sb.Server + ":" + XPort + "/?ssl-mode=Required"; + positiveStringList[1] = "mysqlx://" + sb.UserID + ":" + sb.Password + "@" + Host + ":" + XPort + "/?ssl-mode=Required"; + positiveStringList[2] = "mysqlx://" + sb.UserID + ":" + sb.Password + "@" + Host + ":" + XPort + "/" + schemaName + "?ssl-mode=Required"; + positiveStringList[3] = "mysqlx://" + sb.UserID + ":" + sb.Password + "@" + sb.Server + ":" + XPort + "/" + schemaName + "?ssl-mode=Required&auth=SHA256_MEMORY"; + positiveStringList[4] = "mysqlx://" + sb.UserID + ":" + sb.Password + "@" + sb.Server + ":" + XPort + "/" + schemaName + "?ssl-mode=Required&characterset=utf8mb4"; + positiveStringList[5] = "mysqlx://" + sb.UserID + ":" + sb.Password + "@" + sb.Server + ":" + XPort + "/" + schemaName + "?" + "ssl-mode=Required"; + + foreach (var connStr in positiveStringList) + { + using (Session c = MySQLX.GetSession(connStr)) + { + Assert.That(c.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + } + } + } + + [Test, Description("Getsession/Session-URI Negative Scenarios")] + public void GetSessionUriNegativeTests() + { + string[] NegativeStringList = new string[8]; + MySqlXConnectionStringBuilder sb = new MySqlXConnectionStringBuilder(ConnectionString); + NegativeStringList[0] = "mysqlx://" + sb.UserID + ":" + sb.Password + "@" + sb.Server + ":" + 9999 + ";ssl-mode=required"; + NegativeStringList[1] = "mysqlx://" + sb.UserID + ":" + sb.Password + "@" + "129.0.0.1" + ":" + XPort + ";ssl-mode=required"; + NegativeStringList[2] = "mysqlx://" + sb.UserID + ":" + "wrongpassword" + "@" + "localhost" + ":" + XPort + "/" + schemaName + "?ssl-mode=required"; + NegativeStringList[3] = "mysqlxyzzzz://" + sb.UserID + ":" + sb.Password + "@" + sb.Server + ":" + XPort + "/" + schemaName + "?ssl-mode=required"; + NegativeStringList[4] = "mysqlx://" + "wrongsb.UserID" + ":" + sb.Password + "@" + sb.Server + ":" + XPort + "/" + schemaName + "?ssl-mode=required"; + NegativeStringList[5] = "mysqlx://" + sb.UserID + ":" + sb.Password + "@" + "wronglocalhost" + "/" + schemaName + "?sslmode=required"; + NegativeStringList[6] = "mysqlx://" + sb.UserID + ":" + sb.Password + "@" + sb.Server + ":" + XPort + "/" + schemaName + "?" + "ssl-mode*&^%$#@!invalidvalues123*()"; + NegativeStringList[7] = "mysqlx://" + sb.UserID + ":" + sb.Password + "@" + sb.Server + ":" + XPort + "/" + schemaName + "?" + "invalidvalues123invalidvalues123invalidvalues123invalidvalues123invalidvalues123invalidvalues123invalidvalues123invalidvalues123" + ";ssl-mode=required"; + + foreach (var connStr in NegativeStringList) + { + Assert.Catch(() => MySQLX.GetSession(connStr)); + } + } + + [Test, Description("Getsession using Anonymous Type Negative-Wrong Password")] + public void GetSessionAnonymousTypeNegative() + { + var connectionStringObject = new { connection = $"server={Host};user={session.Settings.UserID};port={XPort};password=wrong_password;sslmode={MySqlSslMode.Required}" }; + Assert.Throws(() => MySQLX.GetSession(connectionStringObject.connection)); + } + + [Test, Description("Support Session Anonymous as uri string Positive")] + public void GetSessionWithAnonymousObjectURI() + { + var connectionStringObject = new { connection = ConnectionStringUri }; + using (Session sessionPlain = MySQLX.GetSession(connectionStringObject.connection)) + { + var db = sessionPlain.GetSchema(schemaName); + var col = db.GetCollection("my_collection_123456789"); + if (col.ExistsInDatabase()) + { + db.DropCollection("my_collection_123456789"); + db.CreateCollection("my_collection_123456789"); + } + else { db.CreateCollection("my_collection_123456789"); } + db.DropCollection("my_collection_123456789"); + } + if (Convert.ToInt32(XPort) == 33060)//Connect to server on localhost with user userx using URI string default port + { + MySqlXConnectionStringBuilder sb = new MySqlXConnectionStringBuilder(ConnectionString); + connectionStringObject = new { connection = "mysqlx://" + sb.UserID + ":" + sb.Password + "@" + sb.Server }; + using (Session sessionPlain = MySQLX.GetSession(connectionStringObject.connection)) + { + var db = sessionPlain.GetSchema(schemaName); + var col = db.GetCollection("my_collection_123456789"); + if (col.ExistsInDatabase()) + { + db.DropCollection("my_collection_123456789"); + db.CreateCollection("my_collection_123456789"); + } + else { db.CreateCollection("my_collection_123456789"); } + db.DropCollection("my_collection_123456789"); + } + } + } + + [Test, Description("Support Session connection string as uri string Negative-Invalid Password")] + public void GetSessionURIWrongPassword() + { + string invalidPassword = "invalid"; + MySqlXConnectionStringBuilder sb = new MySqlXConnectionStringBuilder(ConnectionString); + string connectionString = "mysqlx://" + sb.UserID + ":" + invalidPassword + "@" + sb.Server + ":" + XPort; + Assert.Throws(() => MySQLX.GetSession(connectionString)); + connectionString = "mysqlx://" + sb.UserID + ":" + invalidPassword + "@" + sb.Server; + Assert.Throws(() => MySQLX.GetSession(connectionString)); + } + + // Connection Timeout Tests + [Test, Description("Remote offline host without connect-timeout parameter.Mysql getclient with pooling and maxsize 2 and queue timeout 2000 milliseconds")] + public void TimeoutUsingClientAndPooling_S1() + { + MySqlXConnectionStringBuilder sb = new MySqlXConnectionStringBuilder(ConnectionString); + string serverName = "10.10.10.10"; + string connStr = "server=" + serverName + ";user=" + sb.UserID + ";port=" + XPort + ";password=" + + sb.Password + ";"; + var connectionpooling = "{ \"pooling\": { \"maxSize\": 1, \"queueTimeout\": 2000 , \"maxIdleTime\":1000, \"enabled\": true} }"; + var connectionpoolingObject = new { pooling = new { enabled = true, maxSize = 1, queueTimeout = 2000, maxIdleTime = 1000 } }; + Client client = MySQLX.GetClient(connStr, connectionpoolingObject); + TestFailureTimeout(client, 1, 11, "Timeout value between 9 and 11 seconds"); + var connStrUri = "mysqlx://" + sb.UserID + ":" + sb.Password + "@" + serverName + ":" + XPort; + client = MySQLX.GetClient(connStrUri, connectionpoolingObject); + TestFailureTimeout(client, 1, 11, "Timeout value between 9 and 11 seconds"); + var connObj = new { server = serverName, port = XPort, user = sb.UserID, password = sb.Password }; + client = MySQLX.GetClient(connObj, connectionpoolingObject); + TestFailureTimeout(client, 1, 11, "Timeout value between 9 and 11 seconds"); + client = MySQLX.GetClient(connStr, connectionpooling); + TestFailureTimeout(client, 1, 11, "Timeout value between 9 and 11 seconds"); + client = MySQLX.GetClient(connStrUri, connectionpooling); + TestFailureTimeout(client, 1, 11, "Timeout value between 9 and 11 seconds"); + client = MySQLX.GetClient(connObj, connectionpooling); + TestFailureTimeout(client, 1, 11, "Timeout value between 9 and 11 seconds"); + } + + [Test, Description("failover connection string with one offline host and one online host and disable connect - timeout parameter(set to 0) " + + ".Mysql getclient with pooling and maxsize 2 and queue timeout 2000 milliseconds.Both the session should be successful after" + + "waiting for the respective lower layer socket timeout")] + public void TimeoutUsingClientAndPooling_S2() + { + int connectTimeout = 1; + string hostList = string.Empty; + string localIP = session.Settings.Server; + int minTime = 0; + int maxTime = 30; + session.Settings.UserID = "testAnyhost"; + string connStr = "server=10.10.10.10," + localIP + ";port=" + XPort + ";uid=" + session.Settings.UserID + ";" + "password=" + session.Settings.Password + + ";connect-timeout=" + connectTimeout; + var connectionpoolingObject = new { pooling = new { enabled = true, maxSize = 1, queueTimeout = 20000, maxIdleTime = 1000 } }; + + TestClientSuccessTimeout(minTime, maxTime, $"Timeout value between {minTime} and {maxTime} seconds", connStr, connectionpoolingObject); + + var connStrUri = "mysqlx://" + session.Settings.UserID + ":" + session.Settings.Password + "@[192.1.10.10," + localIP + ":" + XPort + "]" + "/?connect-timeout=" + connectTimeout; + TestClientSuccessTimeout(minTime, maxTime, $"Timeout value between {minTime} and {maxTime} seconds", connStr, connectionpoolingObject); + + } + + [Test, Description("connect - timeout parameter set as 1000 milliseconds.Create a pool of two sessions." + + "pooling(enabled:true,maxSize:2,queueTimeout: 2000 milliseconds).Try to create a third connection and verify the behaviour(Queue timeout expected)")] + public void TimeoutReachingMaxSizePool() + { + int connectTimeout = 1000; + string hostList = string.Empty; + string localIP = session.Settings.Server; + string connStr = "server=" + localIP + ";port=" + XPort + ";uid=" + session.Settings.UserID + ";" + "password=" + session.Settings.Password + + ";connect-timeout=" + connectTimeout; + var connectionpooling = "{ \"pooling\": { \"maxSize\": 2, \"queueTimeout\": 2000 , \"maxIdleTime\":1000, \"enabled\": true} }"; + var connectionpoolingObject = new { pooling = new { enabled = true, maxSize = 2, queueTimeout = 2000, maxIdleTime = 1000 } }; + using (Client client = MySQLX.GetClient(connStr, connectionpoolingObject)) + { + var session1 = client.GetSession(); + var session2 = client.GetSession(); + TestClientQueueTimeout(client, 1, 3, "Test queue timeout"); + } + var connStrUri = "mysqlx://" + session.Settings.UserID + ":" + session.Settings.Password + "@[" + localIP + ":" + XPort + "]" + "/?connect-timeout=" + connectTimeout; + using (var client = MySQLX.GetClient(connStrUri, connectionpoolingObject)) + { + + var session1 = client.GetSession(); + var session2 = client.GetSession(); + TestClientQueueTimeout(client, 1, 3, "Test queue timeout"); + } + var connObj = new { server = "" + localIP, port = XPort, uid = session.Settings.UserID, password = session.Settings.Password, connecttimeout = connectTimeout }; + using (var client = MySQLX.GetClient(connObj, connectionpoolingObject)) + { + var session1 = client.GetSession(); + var session2 = client.GetSession(); + TestClientQueueTimeout(client, 1, 3, "Test queue timeout"); + } + + using (Client client = MySQLX.GetClient(connStr, connectionpooling)) + { + var session1 = client.GetSession(); + var session2 = client.GetSession(); + TestClientQueueTimeout(client, 1, 3, "Test queue timeout"); + } + using (var client = MySQLX.GetClient(connStrUri, connectionpooling)) + { + var session1 = client.GetSession(); + var session2 = client.GetSession(); + TestClientQueueTimeout(client, 1, 3, "Test queue timeout"); + } + using (var client = MySQLX.GetClient(connObj, connectionpooling)) + { + var session1 = client.GetSession(); + var session2 = client.GetSession(); + TestClientQueueTimeout(client, 1, 3, "Test queue timeout"); + } + for (var i = 1; i <= 2; i++) + { + hostList = "(address=143.24.20.36,priority=1),(address=" + localIP + ",priority=0)"; + } + connStr = "server=" + hostList + ";user=" + session.Settings.UserID + ";port=" + XPort + ";password=" + + session.Settings.Password + ";connect-timeout=" + connectTimeout; + + using (var client = MySQLX.GetClient(connStr, connectionpoolingObject)) + { + var session1 = client.GetSession(); + var session2 = client.GetSession(); + TestClientQueueTimeout(client, 1, 3, "Test queue timeout X"); + } + + var connObj1 = new { server = hostList, port = XPort, user = session.Settings.UserID, password = session.Settings.Password, connecttimeout = connectTimeout }; + using (var client = MySQLX.GetClient(connObj1, connectionpoolingObject)) + { + var session1 = client.GetSession(); + var session2 = client.GetSession(); + TestClientQueueTimeout(client, 1, 3, "Test queue timeout Y"); + } + using (var client = MySQLX.GetClient(connStr, connectionpooling)) + { + var session1 = client.GetSession(); + var session2 = client.GetSession(); + TestClientQueueTimeout(client, 1, 3, "Test queue timeout X"); + } + connObj1 = new { server = hostList, port = XPort, user = session.Settings.UserID, password = session.Settings.Password, connecttimeout = connectTimeout }; + using (var client = MySQLX.GetClient(connObj1, connectionpooling)) + { + var session1 = client.GetSession(); + var session2 = client.GetSession(); + TestClientQueueTimeout(client, 1, 3, "Test queue timeout A"); + } + + } + + [Test, Description("scenario 0(connectionString,connectionUri,Anonymous Object)-Without connect timeout and max timeout should be 10s")] + public void TimeoutWithWrongHost() + { + MockServer mServer= new MockServer(false); + mServer.StartServer(); + + string connStr = $"server={mServer.Address.ToString()};user={session.Settings.UserID};port={mServer.Port.ToString()};password={ session.Settings.Password};"; + TestConnectStringTimeoutFailureTimeout(connStr, 9, 100, "Timeout value between 9 and 20 seconds"); + mServer.StopServer(); + mServer.DisposeListener(); + + mServer = new MockServer(false); + mServer.StartServer(); + connStr = $"mysqlx://{session.Settings.UserID}:{ session.Settings.Password}@{mServer.Address.ToString()}:{mServer.Port.ToString()}"; + if(Uri.TryCreate(connStr, UriKind.Absolute, out _)) + TestConnectStringTimeoutFailureTimeout(connStr, 9, 100, "Timeout value between 9 and 20 seconds"); + + var connObj = new { server = mServer.Address.ToString(), port = mServer.Port.ToString(), user = session.Settings.UserID, password = session.Settings.Password }; + TestConnectObjTimeoutFailureTimeout(connObj, 9, 100, "Timeout value between 9 and 20 seconds"); + + mServer.StopServer(); + mServer.DisposeListener(); + } + + [Test, Description("scenario 1(connectionString,connectionUri,Anonymous Object)")] + public void MeasureNoTimeoutResponse() + { + string connStr = "server=" + session.Settings.Server + ";user=" + session.Settings.UserID + ";port=" + XPort + ";password=" + + session.Settings.Password + ";" + "connect-timeout=90;"; + TestConnectStringTimeoutSuccessTimeout(connStr, 0, 3, "Timeout value between 0 and 1 second"); + connStr = "mysqlx://" + session.Settings.UserID + ":" + session.Settings.Password + "@" + session.Settings.Server + ":" + XPort + "?connect-timeout=900;"; + TestConnectStringTimeoutSuccessTimeout(connStr, 0, 3, "Timeout value between 0 and 1 second"); + var connObj = new { server = session.Settings.Server, port = XPort, user = session.Settings.UserID, password = session.Settings.Password, connecttimeout = 9000 }; + TestConnectObjectTimeoutSuccessTimeout(connObj, 0, 3, "Timeout value between 0 and 1 second"); + } + + [Test, Description("scenario 2(connectionString,connectionUri,Anonymous Object with all options)")] + public void NoTimeoutWithManyOptions() + { + if (!Platform.IsWindows()) return; + string connStr = "server=" + session.Settings.Server + ";user id=" + session.Settings.UserID + ";password=" + + session.Settings.Password + ";port=" + XPort + ";protocol=Socket;" + + "database=" + schemaName + ";characterset=utf8mb4;sslmode=VerifyCA;ssl-ca=" + + sslCa + ";certificatepassword=pass;keepalive=10;auth=PLAIN;" + + "connect-timeout=900;"; + TestConnectStringTimeoutSuccessTimeout(connStr, 0, 1, "Timeout value between 0 and 1 second"); + connStr = "mysqlx://" + session.Settings.Server + ":" + XPort + "/" + schemaName + + "?" + "user id=" + session.Settings.UserID + "&password=" + session.Settings.Password + "&sslca=" + + sslCa + "&certificatepassword=pass&keepalive=10&characterset=utf8mb4&auth=PLAIN&connect-timeout=900"; + TestConnectStringTimeoutSuccessTimeout(connStr, 0, 1, "Timeout value between 0 and 1 second"); + var connObj = + new + { + server = session.Settings.Server, + port = XPort, + user = session.Settings.UserID, + password = session.Settings.Password, + sslmode = MySqlSslMode.VerifyCA, + CertificateFile = sslCa, + CertificatePassword = sslCertificatePassword, + database = schemaName, + keepalive = 10, + characterset = "utf8mb4", + auth = MySqlAuthenticationMode.PLAIN, + connecttimeout = 9000 + }; + TestConnectStringTimeoutSuccessTimeout(connStr, 0, 1, "Timeout value between 0 and 1 second"); + } + + [Test, Description("scenario 1(MysqlxStringBuilder)")] + public void TimeoutSuccessWithStringBuilder() + { + var connStrBuilder = new MySqlXConnectionStringBuilder(); + connStrBuilder.ConnectTimeout = 2000; + connStrBuilder.UserID = session.Settings.UserID; + connStrBuilder.Password = session.Settings.Password; + connStrBuilder.Port = Convert.ToUInt32(XPort); + connStrBuilder.Server = session.Settings.Server; + TestConnectStringTimeoutSuccessTimeout(connStrBuilder.ConnectionString, 0, 3, "Timeout value between 0 and 3 second"); + string connStr = "server=" + session.Settings.Server + ";user=" + session.Settings.UserID + ";port=" + XPort + ";password=" + + session.Settings.Password + ";" + "connect-timeout=9000;"; + connStrBuilder = new MySqlXConnectionStringBuilder(connStr); + TestConnectStringTimeoutSuccessTimeout(connStrBuilder.ConnectionString, 0, 3, "Timeout value between 0 and 3 second"); + } + + [Test, Description("scenario 2(MysqlxStringBuilder with all options)")] + public void TimeoutSuccessWithStringBuilderAllOptions() + { + string connStr = null; + MySqlXConnectionStringBuilder mysqlx0 = null; + if (!Platform.IsWindows()) return; + connStr = "server=" + session.Settings.Server + ";user id=" + session.Settings.UserID + ";password=" + + session.Settings.Password + ";port=" + XPort + ";protocol=Socket;" + + "database=" + schemaName + ";characterset=utf8mb4;sslmode=Required;ssl-ca=" + + sslCa + $";certificatepassword={sslCertificatePassword};certificatestorelocation=LocalMachine;" + + ";keepalive =10;auth=PLAIN;certificatethumbprint=;" + + "connect-timeout=" + 9000; + mysqlx0 = new MySqlXConnectionStringBuilder(connStr); + TestConnectStringTimeoutSuccessTimeout(mysqlx0.ConnectionString, 0, 1, "Timeout value between 0 and 1 second"); + mysqlx0 = new MySqlXConnectionStringBuilder(); + mysqlx0.Server = session.Settings.Server; + mysqlx0.UserID = session.Settings.UserID; + mysqlx0.Password = session.Settings.Password; + mysqlx0.Port = Convert.ToUInt32(XPort); + mysqlx0.ConnectionProtocol = MySqlConnectionProtocol.Tcp; + mysqlx0.Database = schemaName; + mysqlx0.CharacterSet = "utf8mb4"; + mysqlx0.SslMode = MySqlSslMode.Required; + mysqlx0.SslCa = sslCa; + mysqlx0.CertificatePassword = sslCertificatePassword; + mysqlx0.CertificateStoreLocation = MySqlCertificateStoreLocation.LocalMachine; + mysqlx0.Keepalive = 10; + mysqlx0.Auth = MySqlAuthenticationMode.PLAIN; + mysqlx0.CertificateThumbprint = ""; + mysqlx0.ConnectTimeout = (uint)90000; + TestConnectStringTimeoutSuccessTimeout(mysqlx0.ConnectionString, 0, 1, "Timeout value between 0 and 1 second"); + } + + [Test, Description("scenario 3(MysqlxStringBuilder with all options-set minimum timeout to 1 and keep on increasing till gets connected)")] + public void TimeoutIncreasingUntilConnect() + { + string connStr = null; + MySqlXConnectionStringBuilder mysqlx0 = null; + + for (int i = 1; i < 20; i++) + { + connStr = ConnectionString + ";protocol=Socket;" + + "database=" + schemaName + ";characterset=utf8mb4;sslmode=VerifyCA;ssl-ca=" + + sslCa + $";certificatepassword={sslCertificatePassword};certificatestorelocation=LocalMachine;" + + ";auth=PLAIN;certificatethumbprint=;" + + "connect-timeout=" + (i * 1000); + mysqlx0 = new MySqlXConnectionStringBuilder(connStr); + using (var conn = MySQLX.GetSession(mysqlx0.ConnectionString)) + { + Assert.That(conn.Uri, Is.Not.Null); + } + break; + } + + for (int i = 1; i < 20; i++) + { + mysqlx0 = new MySqlXConnectionStringBuilder(); + mysqlx0.Server = session.Settings.Server; + mysqlx0.UserID = session.Settings.UserID; + mysqlx0.Password = session.Settings.Password; + mysqlx0.Port = Convert.ToUInt32(XPort); + mysqlx0.ConnectionProtocol = MySqlConnectionProtocol.Tcp; + mysqlx0.Database = schemaName; + mysqlx0.CharacterSet = "utf8mb4"; + mysqlx0.SslMode = MySqlSslMode.VerifyCA; + mysqlx0.SslCa = sslCa; + mysqlx0.CertificatePassword = sslCertificatePassword; + mysqlx0.CertificateStoreLocation = MySqlCertificateStoreLocation.LocalMachine; + mysqlx0.Auth = MySqlAuthenticationMode.PLAIN; + mysqlx0.CertificateThumbprint = ""; + mysqlx0.ConnectTimeout = (uint)(i * 1000); + + using (var conn = MySQLX.GetSession(mysqlx0.ConnectionString)) + { + Assert.That(conn.Uri, Is.Not.Null); + } + break; + } + } + + [Test, Description("scenario 1(connectionString,connectionUri,Anonymous Object with default timeout)")] + public void ValidateDefaultTimeoutParameter() + { + uint defaultTimeout = 1000; + string connStr = ConnectionString + ";" + "connect-timeout=" + defaultTimeout; + for (int i = 0; i < 10; i++) + { + using (var conn = MySQLX.GetSession(connStr)) + { + Assert.That(defaultTimeout, Is.EqualTo(conn.Settings.ConnectTimeout)); + } + } + connStr = "mysqlx://" + session.Settings.UserID + ":" + session.Settings.Password + "@" + session.Settings.Server + ":" + XPort + "?connect-timeout=" + defaultTimeout; + for (int i = 0; i < 10; i++) + { + using (var conn = MySQLX.GetSession(connStr)) + { + Assert.That(defaultTimeout, Is.EqualTo(conn.Settings.ConnectTimeout)); + } + } + var connObj1 = new { server = session.Settings.Server, port = XPort, user = session.Settings.UserID, password = session.Settings.Password, connecttimeout = defaultTimeout }; + for (int i = 0; i < 10; i++) + { + using (var conn = MySQLX.GetSession(connObj1)) + { + Assert.That(defaultTimeout, Is.EqualTo(conn.Settings.ConnectTimeout)); + } + } + } + + [Test, Description("scenario 2(MysqlxStringBuilder with default timeout)")] + public void ValidateDefaultTimeoutParameterWithStringBuilder() + { + uint defaultTimeout = 1000; + var connStrBuilder = new MySqlXConnectionStringBuilder(); + connStrBuilder.ConnectTimeout = defaultTimeout; + connStrBuilder.UserID = session.Settings.UserID; + connStrBuilder.Password = session.Settings.Password; + connStrBuilder.Port = Convert.ToUInt32(XPort); + connStrBuilder.Server = session.Settings.Server; + for (int i = 0; i < 10; i++) + { + using (var conn = MySQLX.GetSession(connStrBuilder.ConnectionString)) + { + Assert.That(defaultTimeout, Is.EqualTo(conn.Settings.ConnectTimeout)); + } + } + string connStr = ConnectionString + ";" + "connect-timeout=" + defaultTimeout; + connStrBuilder = new MySqlXConnectionStringBuilder(connStr); + for (int i = 0; i < 10; i++) + { + using (var conn = MySQLX.GetSession(connStrBuilder.ConnectionString)) + { + Assert.That(defaultTimeout, Is.EqualTo(conn.Settings.ConnectTimeout)); + } + } + } + + [Test, Description("scenario 1(MysqlxStringBuilder with connect timeout option for offline server)")] + public void TimeoutOfflineServerWithStringBuilder() + { + MockServer mServer = new MockServer(false); + mServer.StartServer(); + + int connectionTimeout = 2000; + var connStrBuilder = new MySqlXConnectionStringBuilder(); + connStrBuilder.ConnectTimeout = (uint)connectionTimeout; + connStrBuilder.UserID = session.Settings.UserID; + connStrBuilder.Password = session.Settings.Password; + connStrBuilder.Port = Convert.ToUInt32(mServer.Port); + connStrBuilder.Server = mServer.Address.ToString(); + TestConnectStringTimeoutFailureTimeout(connStrBuilder.ConnectionString, 0, 21, "Offline host timeout value in between 1 and 21 seconds"); + mServer.StopServer(); + mServer.DisposeListener(); + + mServer = new MockServer(false); + mServer.StartServer(); + string connStr = $"server={mServer.Address.ToString()};user={session.Settings.UserID}; port={mServer.Port.ToString()};password={session.Settings.Password};connect-timeout={connectionTimeout}"; + connStrBuilder = new MySqlXConnectionStringBuilder(connStr); + TestConnectStringTimeoutFailureTimeout(connStrBuilder.ConnectionString, 0, 21, "Offline host timeout value in between 1 and 21 seconds"); + + mServer.StopServer(); + mServer.DisposeListener(); + } + + [Test, Description("scenario 1(connectionString,connectionUri,Anonymous Object,MysqlxStringBuilder with connect timeout option=1 for online server)")] + public void TimeoutSuccessConnectOptionOne() + { + int connectionTimeout = 2000; + string connStr = ConnectionString + ";" + "connect-timeout=" + connectionTimeout; + TestConnectStringTimeoutSuccessTimeout(connStr, 0, 5, "Checking the timeout between 0 to 5 seconds"); + connStr = ConnectionStringUri + "?connect-timeout=" + connectionTimeout; + TestConnectStringTimeoutSuccessTimeout(connStr, 0, 5, "Checking the timeout between 0 to 5 seconds"); + var connectionObj = new { server = session.Settings.Server, port = XPort, user = session.Settings.UserID, password = session.Settings.Password, connecttimeout = connectionTimeout }; + TestConnectObjectTimeoutSuccessTimeout(connectionObj, 0, 5, "Checking the timeout between 0 to 5 seconds"); + + var connStrBuilder = new MySqlXConnectionStringBuilder(); + connStrBuilder.ConnectTimeout = (uint)connectionTimeout; + connStrBuilder.UserID = session.Settings.UserID; + connStrBuilder.Password = session.Settings.Password; + connStrBuilder.Port = Convert.ToUInt32(XPort); + connStrBuilder.Server = session.Settings.Server; + TestConnectStringTimeoutSuccessTimeout(connStrBuilder.ConnectionString, 0, 5, "Checking the timeout between 0 to 5 seconds"); + + connStr = ConnectionString + ";" + "connect-timeout=" + connectionTimeout; + connStrBuilder = new MySqlXConnectionStringBuilder(connStr); + TestConnectStringTimeoutSuccessTimeout(connStrBuilder.ConnectionString, 0, 5, "Checking the timeout between 0 to 5 seconds"); + + } + + [Test, Description("scenario 1(connectionString,connectionUri,Anonymous Object,MysqlxStringBuilder with connect timeout option=0 for offline server)")] + public void TimeoutOfflineServerConnectOptionZero() + { + //, Ignore("Disabling the connection timeout will wait until the OS closes the socket, which can take several time.") + MockServer mServer = new MockServer(true); + mServer.StartServer(); + int connectionTimeout = 0; + + string connStr = $"server={mServer.Address.ToString()};user={session.Settings.UserID};port={mServer.Port.ToString()};password={session.Settings.Password};connect-timeout={connectionTimeout}"; + TestConnectStringTimeoutFailureNoConnectTimeout(connStr, 0, 50000, "Checking the timeout between 0 to 50000 milliseconds"); + mServer.StopServer(); + mServer.DisposeListener(); + + mServer = new MockServer(true); + mServer.StartServer(); + connStr = $"mysqlx://{session.Settings.UserID}:{session.Settings.Password}@[{mServer.Address.ToString()}:{mServer.Port.ToString()}]/?connect-timeout=" + connectionTimeout; + if (Uri.TryCreate(connStr,UriKind.Absolute, out _)) + TestConnectStringTimeoutFailureNoConnectTimeout(connStr, 0, 50000, "Checking the timeout between 0 to 50000 milliseconds"); + + mServer.StopServer(); + mServer.DisposeListener(); + + mServer = new MockServer(true); + mServer.StartServer(); + var connObj = new { server = mServer.Address.ToString(), port = mServer.Port.ToString(), user = session.Settings.UserID, password = session.Settings.Password, connecttimeout = connectionTimeout }; + TestConnectObjTimeoutFailureNoTimeout(connObj, 0, 50000, "Checking the timeout between 0 to 50000 milliseconds"); + mServer.StopServer(); + mServer.DisposeListener(); + + mServer = new MockServer(true); + mServer.StartServer(); + var connStrBuilder = new MySqlXConnectionStringBuilder(); + connStrBuilder.ConnectTimeout = (uint)connectionTimeout; + connStrBuilder.UserID = session.Settings.UserID; + connStrBuilder.Password = session.Settings.Password; + connStrBuilder.Port = (uint)mServer.Port; + connStrBuilder.Server = mServer.Address.ToString(); + TestConnectStringTimeoutFailureNoConnectTimeout(connStrBuilder.ConnectionString, 0, 50000, "Checking the timeout between 0 to 50000 milliseconds"); + mServer.StopServer(); + mServer.DisposeListener(); + + mServer = new MockServer(true); + mServer.StartServer(); + connStr = $"server={mServer.Address.ToString()};user={session.Settings.UserID};port={mServer.Port.ToString()};password={session.Settings.Password};connect-timeout={connectionTimeout}"; + connStrBuilder = new MySqlXConnectionStringBuilder(connStr); + TestConnectStringTimeoutFailureNoConnectTimeout(connStr, 0, 50000, "Checking the timeout between 0 to 50000 milliseconds"); + + mServer.StopServer(); + mServer.DisposeListener(); + } + + [Test, Description("(connectionString,connectionUri,Anonymous Object.Test that the timeout will be reset for each connection attempt in a failover scenario")] + public void ConnectTimeoutSeveralAddreses() + { + StringBuilder hostList = new StringBuilder(); + int connectionTimeout = 1000; + var priority = 100; + for (var i = 1; i <= 101; i++) + { + hostList.Append("(address=server" + i + ".example,priority=" + (priority != 0 ? priority-- : 0) + "),"); + if (i == 101) hostList.Append($"(address={Host},priority=0)"); + } + + using (var session1 = MySQLX.GetSession("server=" + hostList + ";port=" + XPort + ";uid=" + + session.Settings.UserID + ";password=" + session.Settings.Password + ";connect-timeout=" + + connectionTimeout + ";ssl-mode=required")) + { + Assert.That(session1.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + var schema = session1.GetSchema("test"); + Assert.That(schema, Is.Not.Null); + } + + var connStr = "mysqlx://" + session.Settings.UserID + ":" + session.Settings.Password + "@[" + hostList + "]/?connect-timeout=" + connectionTimeout; + using (var session1 = MySQLX.GetSession(connStr)) + { + Assert.That(session1.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + var schema = session1.GetSchema("test"); + Assert.That(schema, Is.Not.Null); + } + + using (var session1 = MySQLX.GetSession(new + { + server = hostList.ToString(), + port = XPort, + user = session.Settings.UserID, + password = session.Settings.Password, + sslmode = MySqlSslMode.Required + })) + { + Assert.That(session1.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + var schema = session1.GetSchema("test"); + Assert.That(schema, Is.Not.Null); + } + + var strList = "(address=143.24.20.36,priority=0),(address=10.172.165.157,priority=1)"; + connectionTimeout = 2000; + var connString = "server=" + strList + ";port=" + XPort + ";uid=" + + session.Settings.UserID + ";password=" + session.Settings.Password + ";connect-timeout=" + + connectionTimeout + ";ssl-mode=required"; + Stopwatch sw = new Stopwatch(); + sw.Start(); + Assert.Throws(() => MySQLX.GetSession(connString)); + sw.Stop(); + Assert.That(sw.Elapsed.Seconds > 0 && sw.Elapsed.Seconds < 21); + + connStr = "mysqlx://" + session.Settings.UserID + ":" + session.Settings.Password + "@[" + strList + "]" + "/?connect-timeout=" + connectionTimeout; + sw = new Stopwatch(); + sw.Start(); + Assert.Throws(() => MySQLX.GetSession(connString)); + sw.Stop(); + Assert.That(sw.Elapsed.Seconds > 0 && sw.Elapsed.Seconds < 21); + + var connObj1 = new + { + server = strList, + port = XPort, + user = session.Settings.UserID, + password = session.Settings.Password, + connecttimeout = connectionTimeout + }; + sw = new Stopwatch(); + sw.Start(); + Assert.Throws(() => MySQLX.GetSession(connString)); + sw.Stop(); + Assert.That(sw.Elapsed.Seconds > 0 && sw.Elapsed.Seconds < 21); + } + + [Test, Description("(connectionString,connectionUri,Anonymous Object.Test that the timeout will be reset for each connection attempt in a failover scenario")] + public void ConnectTimeoutWithFailoverAndNotValidHost() + { + string hostList = "(address=143.24.20.36,priority=0),(address=143.24.70.98,priority=1)"; + int connectionTimeout = 2000; + // URL + var connString = "server=" + hostList + ";port=" + XPort + ";uid=" + + session.Settings.UserID + ";password=" + session.Settings.Password + ";connect-timeout=" + + connectionTimeout; + Stopwatch sw = new Stopwatch(); + sw.Start(); + Assert.Throws(() => MySQLX.GetSession(connString)); + sw.Stop(); + Assert.That(sw.Elapsed.Seconds > 0 && sw.Elapsed.Seconds < 10); + // URI + var connStr = "mysqlx://" + session.Settings.UserID + ":" + session.Settings.Password + "@[" + hostList + "]" + "/?connect-timeout=" + connectionTimeout; + sw = new Stopwatch(); + sw.Start(); + Assert.Throws(() => MySQLX.GetSession(connString)); + sw.Stop(); + Assert.That(sw.Elapsed.Seconds > 0 && sw.Elapsed.Seconds < 10); + + // Object + var connObj = new + { + server = hostList, + port = XPort, + user = session.Settings.UserID, + password = session.Settings.Password, + connecttimeout = connectionTimeout + }; + sw = new Stopwatch(); + sw.Start(); + Assert.Throws(() => MySQLX.GetSession(connString)); + sw.Stop(); + Assert.That(sw.Elapsed.Seconds > 0 && sw.Elapsed.Seconds < 10); + } + + [Test, Description("Confirm that the timeout is only applied to the connection process, not to any subsequent operation after the connection is established")] + public void ValidateConnectTimeoutScope() + { + if (!Platform.IsWindows()) return; + string connStr = null; + connStr = "server=" + session.Settings.Server + ";user=" + session.Settings.UserID + ";port=" + XPort + ";password=" + + session.Settings.Password + ";" + "connect-timeout=10000;"; + using (var conn = MySQLX.GetSession(connStr)) + { + conn.SQL("SELECT SLEEP(10)").Execute(); + var res = conn.SQL("select @@port").Execute().FirstOrDefault(); + Assert.That(res, Is.Not.Null); + } + + connStr = "mysqlx://" + session.Settings.UserID + ":" + session.Settings.Password + "@" + session.Settings.Server + ":" + XPort + "?connect-timeout=10000;"; + using (var conn = MySQLX.GetSession(connStr)) + { + conn.SQL("SELECT SLEEP(10)").Execute(); + var res = conn.SQL("select @@port").Execute().FirstOrDefault(); + Assert.That(res, Is.Not.Null); + } + + var connObj = new + { + server = session.Settings.Server, + port = XPort, + user = session.Settings.UserID, + password = session.Settings.Password, + connecttimeout = 10000 + }; + using (var conn = MySQLX.GetSession(connObj)) + { + conn.SQL("SELECT SLEEP(10)").Execute(); + var res = conn.SQL("select @@port").Execute().FirstOrDefault(); + Assert.That(res, Is.Not.Null); + } + + var connStrBuilder = new MySqlXConnectionStringBuilder(); + connStrBuilder.ConnectTimeout = 10000; + connStrBuilder.UserID = session.Settings.UserID; + connStrBuilder.Password = session.Settings.Password; + connStrBuilder.Port = Convert.ToUInt32(XPort); + connStrBuilder.Server = session.Settings.Server; + using (var conn = MySQLX.GetSession(connStrBuilder.ConnectionString)) + { + conn.SQL("SELECT SLEEP(10)").Execute(); + var res = conn.SQL("select @@port").Execute().FirstOrDefault(); + Assert.That(res, Is.Not.Null); + } + + connStr = "server=" + session.Settings.Server + ";user=" + session.Settings.UserID + ";port=" + XPort + ";password=" + + session.Settings.Password + ";" + "connect-timeout=10000;"; + connStrBuilder = new MySqlXConnectionStringBuilder(connStr); + using (var conn = MySQLX.GetSession(connStrBuilder.ConnectionString)) + { + conn.SQL("SELECT SLEEP(10)").Execute(); + var res = conn.SQL("select @@port").Execute().FirstOrDefault(); + Assert.That(res, Is.Not.Null); + } + + connStr = ConnectionString + ";protocol=Socket;" + + "database=" + schemaName + ";characterset=utf8mb4;sslmode=Required;ssl-ca=" + + sslCa + $";certificatepassword={sslCertificatePassword};certificatestorelocation=LocalMachine;" + + ";keepalive =10;auth=PLAIN;certificatethumbprint=;" + + "connect-timeout=" + 10000; + var mysqlx0 = new MySqlXConnectionStringBuilder(connStr); + using (var conn = MySQLX.GetSession(mysqlx0.ConnectionString)) + { + conn.SQL("SELECT SLEEP(10)").Execute(); + var res = conn.SQL("select @@port").Execute().FirstOrDefault(); + Assert.That(res, Is.Not.Null); + } + + mysqlx0 = new MySqlXConnectionStringBuilder(); + mysqlx0.UserID = session.Settings.UserID; + mysqlx0.Password = session.Settings.Password; + mysqlx0.Port = Convert.ToUInt32(XPort); + mysqlx0.Server = session.Settings.Server; + mysqlx0.ConnectionProtocol = MySqlConnectionProtocol.Tcp; + mysqlx0.Database = schemaName; + mysqlx0.CharacterSet = "utf8mb4"; + mysqlx0.SslMode = MySqlSslMode.Required; + mysqlx0.SslCa = sslCa; + mysqlx0.CertificatePassword = sslCertificatePassword; + mysqlx0.CertificateStoreLocation = MySqlCertificateStoreLocation.LocalMachine; + mysqlx0.Keepalive = 10; + mysqlx0.Auth = MySqlAuthenticationMode.PLAIN; + mysqlx0.CertificateThumbprint = ""; + mysqlx0.ConnectTimeout = (uint)10000; + + using (var conn = MySQLX.GetSession(mysqlx0.ConnectionString)) + { + conn.SQL("SELECT SLEEP(10)").Execute(); + var res = conn.SQL("select @@port").Execute().FirstOrDefault(); + Assert.That(res, Is.Not.Null); + } + } + + [Test, Description("Test that if an unexpected error occurs during the specified time frame, the execution should stop and the error must be reported to the user")] + public void WrongPasswordException() + { + string connStr = null; + string password = "wrongpassword"; + Object[] ConnectTimeout = new Object[] { 10000 }; + for (int i = 0; i < ConnectTimeout.Length; i++) + { + // Connection String + connStr = "server=" + session.Settings.Server + ";user=" + session.Settings.UserID + ";port=" + XPort + ";password=" + + password + ";" + "connect-timeout=" + ConnectTimeout[i]; + Assert.Throws(() => MySQLX.GetSession(connStr)); + //String Builder + var connStrBuilder = new MySqlXConnectionStringBuilder(connStr); + Assert.Throws(() => MySQLX.GetSession(connStrBuilder.ConnectionString)); + // Uri + connStr = "mysqlx://" + session.Settings.UserID + ":" + password + "@" + session.Settings.Server + ":" + XPort + "?connect-timeout=" + ConnectTimeout[i]; + Assert.Throws(() => MySQLX.GetSession(connStr)); + // Anonymous Object + var connObj = new { server = session.Settings.Server, port = XPort, user = session.Settings.UserID, password = password, connecttimeout = ConnectTimeout[i] }; + Assert.Throws(() => MySQLX.GetSession(connStr)); + } + } + + [Test, Description("Test the default connect timeout with mock server with concurrent connections")] + public async Task ConnectTimeoutConcurrentConnections() + { + MockServer mServer = new MockServer(false); + mServer.StartServer(); + + await Task.Run(() => SubThread1(mServer.Address.ToString(), mServer.Port.ToString())); + await Task.Run(() => SubThread2(mServer.Address.ToString(), mServer.Port.ToString())); + + mServer.StopServer(); + mServer.DisposeListener(); + } + + private void SubThread1(string address, string port) + { + for (int i = 0; i < 5; i++) + { + string connStr = "server=" + address + ";user=" + session.Settings.UserID + ";port=" + port + ";password=" + + session.Settings.Password + ";" + "connect-timeout=2000;"; + TestConnectStringTimeoutFailureTimeout(connStr, 1, 5, "Timeout value between 1 and 3 second"); + } + } + + private void SubThread2(string address, string port) + { + for (int i = 0; i < 5; i++) + { + string connStr = "server=" + address + ";user=" + session.Settings.UserID + ";port=" + port + ";password=" + + session.Settings.Password + ";" + "connect-timeout=2000;"; + TestConnectStringTimeoutFailureTimeout(connStr, 1, 5, "Timeout value between 1 and 3 second"); + } + } + + + [Test, Description("CONNECT-TIMEOUT WORKS WITH BLANK VALUES FOR CONNECTION STRING AND URI")] + public void ConnectTimeoutBlankValues() + { + var connObj = new { server = session.Settings.Server, port = XPort, user = session.Settings.UserID, password = session.Settings.Password, connecttimeout = "" }; + Assert.Throws(() => MySQLX.GetSession(connObj)); + + connObj = new { server = session.Settings.Server, port = XPort, user = session.Settings.UserID, password = session.Settings.Password, connecttimeout = " " }; + Assert.Throws(() => MySQLX.GetSession(connObj)); + + var connStr = $"server={session.Settings.Server};user={session.Settings.UserID};port={XPort};password={session.Settings.Password};connect-timeout=''"; + Assert.Throws(() => MySQLX.GetSession(connStr)); + + connStr = $"server={session.Settings.Server};user={session.Settings.UserID};port={XPort};password={session.Settings.Password};connect-timeout=' '"; + Assert.Throws(() => MySQLX.GetSession(connStr)); + + connStr = $"server={session.Settings.Server};user={session.Settings.UserID};port={XPort};password={session.Settings.Password};connect-timeout="; + Assert.Throws(() => MySQLX.GetSession(connStr)); + + connStr = $"server={session.Settings.Server};user={session.Settings.UserID};port={XPort};password={session.Settings.Password};connect-timeout= "; + Assert.Throws(() => MySQLX.GetSession(connStr)); + + connStr = $"mysqlx://{session.Settings.UserID}:{session.Settings.Password}@{session.Settings.Server}:{XPort}?connect-timeout="; + Assert.Throws(() => MySQLX.GetSession(connStr)); + + connStr = $"mysqlx://{session.Settings.UserID}:{session.Settings.Password}@{session.Settings.Server}:{XPort}?connect-timeout= "; + Assert.Throws(() => MySQLX.GetSession(connStr)); + } + + /// + /// Bug28624010 + /// + [Test, Description("CONNECTIONTIMEOUT OPT WORKS WITH XPLUGN IF A CLASSIC CONN IS ESTABLISD")] + public void TimeoutWithClassicConnection() + { + int connectionTimeout = 10; + var connStr1 = $"server={session.Settings.Server};user={session.Settings.UserID};port={Port};password={session.Settings.Password};sslmode={MySqlSslMode.Required}"; + var conn = new MySqlConnection(connStr1); + conn.Open(); + conn.Close(); + var connStr = $"server={session.Settings.Server};user={session.Settings.UserID};port={XPort};password={session.Settings.Password};connectiontimeout={connectionTimeout}"; + Assert.Throws(() => MySQLX.GetSession(connStr)); + + connStr = $"mysqlx://{session.Settings.UserID}:{session.Settings.Password}@{session.Settings.Server}:{XPort}?connectiontimeout={connectionTimeout} "; + Assert.Throws(() => MySQLX.GetSession(connStr)); + + var connObj = new { server = session.Settings.Server, port = XPort, user = session.Settings.UserID, password = session.Settings.Password, connectiontimeout = connectionTimeout }; + Assert.Throws(() => MySQLX.GetSession(connObj)); + } + + [Test, Description("MySQLX Session Stress test")] + public void SessionStressTest() + { + for (int i = 0; i < 1000; i++) + { + using (Session session1 = MySQLX.GetSession(ConnectionString)) + { + Assert.That(session1.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + session1.Close(); + } + } + } + + [Test, Description("Getsession using Anonymous Type-Positive")] + public void GetSessionAnonymousTypePositiveStress() + { + for (int i = 0; i < 200; i++) + { + var connectionStringObject = new { connection = $"server={Host};user={session.Settings.UserID};port={XPort};password={session.Settings.Password};sslmode={MySqlSslMode.Required};" }; + using (Session sessionPlain = MySQLX.GetSession(connectionStringObject.connection)) + { + var db = sessionPlain.GetSchema(schemaName); + var col = CreateCollection("my_collection_123456789"); + sessionPlain.Close(); + } + } + } + + [Test, Description("Test Audit Plugin")] + public void SessionAuditPluginTest() + { + using (var mysqlx = MySQLX.GetSession(ConnectionString)) + { + Assert.That(mysqlx.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + mysqlx.Close(); + } + using (var mysql = new MySqlConnection($"server={Host};user={session.Settings.UserID};port={Port};password={session.Settings.Password}")) + { + mysql.Open(); + Assert.That(mysql.connectionState, Is.EqualTo(ConnectionState.Open)); + mysql.Close(); + } + Assert.Throws(() => MySQLX.GetSession($"server={Host};user={session.Settings.UserID};port={XPort};password=wrong")); + } + + [Test, Description("Classic Client with xprotocol server")] + public void ClassicClientXProtocol() + { + Assume.That(Platform.IsWindows(), "This test is only for Windows OS."); + Assume.That(session.Version.isAtLeast(5, 7, 0), "This test is for MySql 5.7 or higher"); + + string connectionString = $"server={Host};user={session.Settings.UserID};port={XPort};password={session.Settings.Password}"; + using (var session1 = new MySqlConnection(connectionString)) + { + Exception ex = Assert.Throws(() => session1.Open()); + Assert.That(ex.Message, Is.EqualTo("Unsupported protocol version.")); + } + } + + #region Methods + + public void TestConnectObjectTimeoutSuccessTimeout(object connString, int minTime, int maxTime, string test) + { + Stopwatch sw = new Stopwatch(); + sw.Start(); + var conn = MySQLX.GetSession(connString); + sw.Stop(); + Assert.That(sw.Elapsed.Seconds >= minTime && sw.Elapsed.Seconds <= maxTime, String.Format("Timeout exceeded ({0}). Actual time: {1}", test, sw.Elapsed)); + } + + public void TestConnectStringTimeoutSuccessTimeout(String connString, int minTime, int maxTime, string test) + { + Stopwatch sw = new Stopwatch(); + sw.Start(); + var conn = MySQLX.GetSession(connString); + sw.Stop(); + Assert.That(sw.Elapsed.Seconds >= minTime && sw.Elapsed.Seconds <= maxTime, String.Format("Timeout exceeded ({0}). Actual time: {1}", test, sw.Elapsed)); + } + + public void TestConnectObjTimeoutFailureTimeout(object connString, int minTime, int maxTime, string test) + { + Stopwatch sw = new Stopwatch(); + sw.Start(); + Assert.Throws(() => MySQLX.GetSession(connString)); + sw.Stop(); + Assert.That(sw.Elapsed.Seconds >= minTime && sw.Elapsed.Seconds < maxTime, String.Format("Timeout exceeded ({0}). Actual time: {1}", test, sw.Elapsed)); + } + + public void TestConnectObjTimeoutFailureNoTimeout(object connString, int minTime, int maxTime, string test) + { + Stopwatch sw = new Stopwatch(); + sw.Start(); + Assert.Throws(() => MySQLX.GetSession(connString)); + sw.Stop(); + Assert.That(sw.Elapsed.Seconds >= minTime && sw.Elapsed.Seconds < maxTime, String.Format("Timeout exceeded ({0}). Actual time: {1}", test, sw.Elapsed)); + } + + public void TestConnectStringTimeoutFailureTimeout(String connString, int minTime, int maxTime, string test) + { + Stopwatch sw = new Stopwatch(); + sw.Start(); + Assert.Throws(() => MySQLX.GetSession(connString)); + sw.Stop(); + Assert.That(sw.Elapsed.Seconds >= minTime && sw.Elapsed.Seconds < maxTime, String.Format("Timeout exceeded ({0}). Actual time: {1}", test, sw.Elapsed)); + } + + public void TestConnectStringTimeoutFailureNoConnectTimeout(String connString, int minTime, int maxTime, string test) + { + Stopwatch sw = new Stopwatch(); + sw.Start(); + Assert.Throws(() => MySQLX.GetSession(connString)); + sw.Stop(); + Assert.That(sw.Elapsed.Seconds >= minTime && sw.Elapsed.Seconds < maxTime, String.Format("Timeout exceeded ({0}). Actual time: {1}", test, sw.Elapsed)); + } + + public void TestClientQueueTimeout(Client client, int minTime, int maxTime, string test) + { + Stopwatch sw = new Stopwatch(); + sw.Start(); + Assert.Throws(() => client.GetSession()); + sw.Stop(); + Assert.That(sw.Elapsed.Seconds >= minTime && sw.Elapsed.Seconds < maxTime, + String.Format("Timeout exceeded ({0}). Actual time: {1}", test, sw.Elapsed)); + } + + public void TestClientSuccessTimeout(int minTime, int maxTime, string test, string connectionString, object poolingObject) + { + using (var client = MySQLX.GetClient(connectionString, poolingObject)) + { + Stopwatch sw = new Stopwatch(); + sw.Start(); + client.GetSession(); + sw.Stop(); + Assert.That(sw.Elapsed.Seconds >= minTime && sw.Elapsed.Seconds < maxTime, String.Format("Timeout exceeded ({0}). Actual time: {1}", test, sw.Elapsed)); + } + } + + public void TestClientSuccessTimeout(int minTime, int maxTime, string test, object connectionObject, object poolingObject) + { + using (var client = MySQLX.GetClient(connectionObject, poolingObject)) + { + Stopwatch sw = new Stopwatch(); + sw.Start(); + client.GetSession(); + sw.Stop(); + Assert.That(sw.Elapsed.Seconds >= minTime && sw.Elapsed.Seconds < maxTime, String.Format("Timeout exceeded ({0}). Actual time: {1}", test, sw.Elapsed)); + } + } + public void TestFailureTimeout(Client client, int minTime, int maxTime, string test) + { + DateTime start = DateTime.Now; + Assert.Catch(() => client.GetSession()); + TimeSpan diff = DateTime.Now.Subtract(start); + Assert.That(diff.TotalSeconds >= minTime && diff.TotalSeconds < maxTime, String.Format("Timeout exceeded ({0}). Actual time: {1}", test, diff)); + } + + private void MeasureConnectionString(string connStr, int maxTime, string test, int iteration) + { + Stopwatch sw = new Stopwatch(); + sw.Start(); + + for (int i = 0; i < iteration; i++) + { + using Session conn = MySQLX.GetSession(connStr); + } + + sw.Stop(); + Assert.That(sw.Elapsed.Seconds < maxTime, String.Format("Timeout exceeded ({0}). Actual time: {1}", test, sw.Elapsed)); + } + + private void MeasureConnectionObject(object connStr, int maxTime, string test, int iteration) + { + Stopwatch sw = new Stopwatch(); + sw.Start(); + + for (int i = 0; i < iteration; i++) + { + using Session conn = MySQLX.GetSession(connStr); + } + + sw.Stop(); + Assert.That(sw.Elapsed.Seconds < maxTime, String.Format("Timeout exceeded ({0}). Actual time: {1}", test, sw.Elapsed)); + } + + public long NanoTime() + { + long nano = 10000L * Stopwatch.GetTimestamp(); + nano /= TimeSpan.TicksPerMillisecond; + nano *= 100L; + return nano; + } + + public long DoConnectString(string connectionString) + { + long queryStartTime, queryRunTime = 0; + queryStartTime = NanoTime(); + var session = MySQLX.GetSession(connectionString); + queryRunTime = NanoTime() - queryStartTime; + session.Close(); + session.Dispose(); + return queryRunTime; + } + + public long DoConnectObject(object connectionString) + { + long queryStartTime, queryRunTime = 0; + queryStartTime = NanoTime(); + var session = MySQLX.GetSession(connectionString); + queryRunTime = NanoTime() - queryStartTime; + session.Close(); + session.Dispose(); + return queryRunTime; + } + + /// + /// Calculate the Connection per second + /// Total execution time.(Connection+query execution time) + /// Query execution time + public float CalculateTPS(long elapsedTime, long transactions) + { + float tps = 0; + if (elapsedTime > 0.0) + { + tps = (float)transactions / elapsedTime; + tps = tps * 1000; + } + return tps; + } + + #endregion Methods + + } +} diff --git a/MySQL.Data/tests/MySqlX.Data.Tests/SslTests.cs b/MySQL.Data/tests/MySqlX.Data.Tests/SslTests.cs index f445b4cc9..f424c85d4 100644 --- a/MySQL.Data/tests/MySqlX.Data.Tests/SslTests.cs +++ b/MySQL.Data/tests/MySqlX.Data.Tests/SslTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2018, 2022, Oracle and/or its affiliates. +// Copyright © 2018, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -30,6 +30,7 @@ using MySql.Data.MySqlClient; using MySqlX.XDevAPI; using NUnit.Framework; +using NUnit.Framework.Legacy; using System; using System.Collections.Generic; @@ -44,9 +45,9 @@ public void SslSession() { using (var s3 = MySQLX.GetSession(ConnectionStringUri)) { - Assert.AreEqual(SessionState.Open, s3.InternalSession.SessionState); + Assert.That(s3.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); var result = ExecuteSQLStatement(s3.SQL("SHOW SESSION STATUS LIKE 'Mysqlx_ssl_version';")).FetchAll(); - StringAssert.StartsWith("TLSv1", result[0][1].ToString()); + Assert.That(result[0][1].ToString(), Does.StartWith("TLSv1")); } } @@ -57,9 +58,9 @@ public void SslEmptyCertificate() // if certificate is empty, it connects without a certificate using (var s1 = MySQLX.GetSession(connstring)) { - Assert.AreEqual(SessionState.Open, s1.InternalSession.SessionState); + Assert.That(s1.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); var result = ExecuteSQLStatement(s1.SQL("SHOW SESSION STATUS LIKE 'Mysqlx_ssl_version';")).FetchAll(); - StringAssert.StartsWith("TLSv1", result[0][1].ToString()); + Assert.That(result[0][1].ToString(), Does.StartWith("TLSv1")); } } @@ -70,12 +71,12 @@ public void SslOptions() // sslmode is valid. using (var connection = MySQLX.GetSession(connectionUri + "?sslmode=required")) { - Assert.AreEqual(SessionState.Open, connection.InternalSession.SessionState); + Assert.That(connection.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } using (var connection = MySQLX.GetSession(connectionUri + "?ssl-mode=required")) { - Assert.AreEqual(SessionState.Open, connection.InternalSession.SessionState); + Assert.That(connection.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } // sslenable is invalid. @@ -85,17 +86,17 @@ public void SslOptions() // sslmode=Required is default value. using (var connection = MySQLX.GetSession(connectionUri)) { - Assert.AreEqual(connection.Settings.SslMode, MySqlSslMode.Required); + Assert.That(MySqlSslMode.Required, Is.EqualTo(connection.Settings.SslMode)); } // sslmode case insensitive. using (var connection = MySQLX.GetSession(connectionUri + "?SsL-mOdE=required")) { - Assert.AreEqual(SessionState.Open, connection.InternalSession.SessionState); + Assert.That(connection.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } using (var connection = MySQLX.GetSession(connectionUri + "?SsL-mOdE=VeRiFyca&ssl-ca=../../../../MySql.Data.Tests/client.pfx&ssl-ca-pwd=pass")) { - Assert.AreEqual(SessionState.Open, connection.InternalSession.SessionState); + Assert.That(connection.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); var uri = connection.Uri; } @@ -114,7 +115,7 @@ public void SslRequiredByDefault() { using (var connection = MySQLX.GetSession(ConnectionStringUri)) { - Assert.AreEqual(MySqlSslMode.Required, connection.Settings.SslMode); + Assert.That(connection.Settings.SslMode, Is.EqualTo(MySqlSslMode.Required)); } } @@ -122,16 +123,16 @@ public void SslRequiredByDefault() public void SslPreferredIsInvalid() { string prefered = "Prefered"; -#if NET7_0 +#if NET8_0_OR_GREATER prefered = "Preferred"; #endif - var expectedErrorMessage = "Value '{0}' is not of the correct type."; + var expectedErrorMessage = "Value '{0}' is not of the correct type"; // In connection string. var exception = Assert.Throws(() => MySQLX.GetSession(ConnectionStringUri + "?ssl-mode=Preferred")); - Assert.AreEqual(string.Format(expectedErrorMessage, "Preferred"), exception.Message); + Assert.That(exception.Message, Is.EqualTo(string.Format(expectedErrorMessage, "Preferred"))); exception = Assert.Throws(() => MySQLX.GetSession(ConnectionStringUri + "?ssl-mode=Prefered")); - Assert.AreEqual(string.Format(expectedErrorMessage, "Prefered"), exception.Message); + Assert.That(exception.Message, Is.EqualTo(string.Format(expectedErrorMessage, "Prefered"))); // In anonymous object. var builder = new MySqlXConnectionStringBuilder(ConnectionString); @@ -144,18 +145,18 @@ public void SslPreferredIsInvalid() sslmode = MySqlSslMode.Prefered }; exception = Assert.Throws(() => MySQLX.GetSession(connectionObject)); - Assert.AreEqual(string.Format(expectedErrorMessage, prefered), exception.Message); + Assert.That(exception.Message, Is.EqualTo(string.Format(expectedErrorMessage, prefered))); // In MySqlXConnectionStringBuilder. builder = new MySqlXConnectionStringBuilder(ConnectionString); builder.SslMode = MySqlSslMode.Prefered; exception = Assert.Throws(() => MySQLX.GetSession(connectionObject)); - Assert.AreEqual(string.Format(expectedErrorMessage, prefered), exception.Message); + Assert.That(exception.Message, Is.EqualTo(string.Format(expectedErrorMessage, prefered))); builder = new MySqlXConnectionStringBuilder(ConnectionString); builder.SslMode = MySqlSslMode.Preferred; exception = Assert.Throws(() => MySQLX.GetSession(connectionObject)); - Assert.AreEqual(string.Format(expectedErrorMessage, prefered), exception.Message); + Assert.That(exception.Message, Is.EqualTo(string.Format(expectedErrorMessage, prefered))); } [Test] @@ -199,9 +200,9 @@ public void GetUriWithSSLParameters() // Authentication mode AUTO/DEFAULT is internally assigned, hence it is expected to be different in this scenario. if (connectionOption == "auth") - Assert.AreEqual(MySqlAuthenticationMode.PLAIN, internalSession.Settings[connectionOption]); + Assert.That(internalSession.Settings[connectionOption], Is.EqualTo(MySqlAuthenticationMode.PLAIN)); else - Assert.AreEqual(builder[connectionOption], internalSession.Settings[connectionOption]); + Assert.That(internalSession.Settings[connectionOption], Is.EqualTo(builder[connectionOption])); } } } @@ -237,17 +238,17 @@ public void GetUriKeepsSSLMode() using (var internalSession = MySQLX.GetSession(uri)) { - Assert.AreEqual(builder.Server, internalSession.Settings.Server); - Assert.AreEqual(builder.UserID, internalSession.Settings.UserID); - Assert.AreEqual(builder.Password, internalSession.Settings.Password); - Assert.AreEqual(builder.Port, internalSession.Settings.Port); - Assert.AreEqual(builder.Database, internalSession.Settings.Database); - Assert.AreEqual(builder.CharacterSet, internalSession.Settings.CharacterSet); - Assert.AreEqual(builder.SslMode, internalSession.Settings.SslMode); - Assert.AreEqual(builder.SslCa, internalSession.Settings.SslCa); - Assert.AreEqual(builder.CertificatePassword, internalSession.Settings.CertificatePassword); - Assert.AreEqual(builder.ConnectTimeout, internalSession.Settings.ConnectTimeout); - Assert.AreEqual(MySqlAuthenticationMode.PLAIN, internalSession.Settings.Auth); + Assert.That(internalSession.Settings.Server, Is.EqualTo(builder.Server)); + Assert.That(internalSession.Settings.UserID, Is.EqualTo(builder.UserID)); + Assert.That(internalSession.Settings.Password, Is.EqualTo(builder.Password)); + Assert.That(internalSession.Settings.Port, Is.EqualTo(builder.Port)); + Assert.That(internalSession.Settings.Database, Is.EqualTo(builder.Database)); + Assert.That(internalSession.Settings.CharacterSet, Is.EqualTo(builder.CharacterSet)); + Assert.That(internalSession.Settings.SslMode, Is.EqualTo(builder.SslMode)); + Assert.That(internalSession.Settings.SslCa, Is.EqualTo(builder.SslCa)); + Assert.That(internalSession.Settings.CertificatePassword, Is.EqualTo(builder.CertificatePassword)); + Assert.That(internalSession.Settings.ConnectTimeout, Is.EqualTo(builder.ConnectTimeout)); + Assert.That(internalSession.Settings.Auth, Is.EqualTo(MySqlAuthenticationMode.PLAIN)); } } @@ -291,15 +292,15 @@ public void TlsVersionTest(string tlsVersion, int error) { case 1: ex = Assert.Throws(SetTlsVersion).Message; - StringAssert.AreEqualIgnoringCase(MySql.Data.Resources.TlsVersionsEmpty, ex); + Assert.That(ex, Is.EqualTo(MySql.Data.Resources.TlsVersionsEmpty).IgnoreCase); break; case 2: ex = Assert.Throws(SetTlsVersion).Message; - StringAssert.AreEqualIgnoringCase(MySql.Data.Resources.TlsUnsupportedVersions, ex); + Assert.That(ex, Is.EqualTo(MySql.Data.Resources.TlsUnsupportedVersions).IgnoreCase); break; case 3: ex = Assert.Throws(SetTlsVersion).Message; - StringAssert.AreEqualIgnoringCase(MySql.Data.Resources.TlsNonValidProtocols, ex); + Assert.That(ex, Is.EqualTo(MySql.Data.Resources.TlsNonValidProtocols).IgnoreCase); break; case 4: SetTlsVersion(); @@ -312,13 +313,13 @@ public void TlsVersionTest(string tlsVersion, int error) using (var internalSession = MySQLX.GetSession(builder.ConnectionString)) { uri = internalSession.Uri; - Assert.AreEqual(SessionState.Open, internalSession.InternalSession.SessionState); - StringAssert.StartsWith(tls, internalSession.SQL("SHOW SESSION STATUS LIKE 'mysqlx_ssl_version'").Execute().FetchAll()[0][1].ToString()); + Assert.That(internalSession.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + Assert.That(internalSession.SQL("SHOW SESSION STATUS LIKE 'mysqlx_ssl_version'").Execute().FetchAll()[0][1].ToString(), Does.StartWith(tls)); } using (var internalSession = MySQLX.GetSession(uri)) { - Assert.AreEqual(SessionState.Open, internalSession.InternalSession.SessionState); - StringAssert.StartsWith(tls, internalSession.SQL("SHOW SESSION STATUS LIKE 'mysqlx_ssl_version'").Execute().FetchAll()[0][1].ToString()); + Assert.That(internalSession.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + Assert.That(internalSession.SQL("SHOW SESSION STATUS LIKE 'mysqlx_ssl_version'").Execute().FetchAll()[0][1].ToString(), Does.StartWith(tls)); } break; @@ -349,13 +350,13 @@ public void TlsVersionNoSslTest(string tlsVersion) using (var internalSession = MySQLX.GetSession(builder.ConnectionString)) { uri = internalSession.Uri; - Assert.AreEqual(SessionState.Open, internalSession.InternalSession.SessionState); - Assert.IsEmpty(internalSession.SQL("SHOW SESSION STATUS LIKE 'mysqlx_ssl_version'").Execute().FetchAll()[0][1].ToString()); + Assert.That(internalSession.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + Assert.That(internalSession.SQL("SHOW SESSION STATUS LIKE 'mysqlx_ssl_version'").Execute().FetchAll()[0][1].ToString(), Is.Empty); } using (var internalSession = MySQLX.GetSession(uri)) { - Assert.AreEqual(SessionState.Open, internalSession.InternalSession.SessionState); - Assert.IsEmpty(internalSession.SQL("SHOW SESSION STATUS LIKE 'mysqlx_ssl_version'").Execute().FetchAll()[0][1].ToString()); + Assert.That(internalSession.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + Assert.That(internalSession.SQL("SHOW SESSION STATUS LIKE 'mysqlx_ssl_version'").Execute().FetchAll()[0][1].ToString(), Is.Empty); } } @@ -370,9 +371,9 @@ public void SslCertificate() string connstring = ConnectionStringUri + $"/?ssl-ca={path}client.pfx&ssl-ca-pwd=pass"; using (var s3 = MySQLX.GetSession(connstring)) { - Assert.AreEqual(SessionState.Open, s3.InternalSession.SessionState); + Assert.That(s3.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); var result = ExecuteSQLStatement(s3.SQL("SHOW SESSION STATUS LIKE 'Mysqlx_ssl_version';")).FetchAll(); - StringAssert.StartsWith("TLSv1", result[0][1].ToString()); + Assert.That(result[0][1].ToString(), Does.StartWith("TLSv1")); } } @@ -390,21 +391,21 @@ public void SslCertificatePathKeepsCase() // Connection string in basic format. string connString = ConnectionString + ";ssl-ca=" + certificatePath + ";ssl-ca-pwd=pass;"; var stringBuilder = new MySqlXConnectionStringBuilder(connString); - Assert.AreEqual(certificatePath, stringBuilder.CertificateFile); - Assert.AreEqual(certificatePath, stringBuilder.SslCa); - Assert.True(stringBuilder.ConnectionString.Contains(certificatePath)); + Assert.That(stringBuilder.CertificateFile, Is.EqualTo(certificatePath)); + Assert.That(stringBuilder.SslCa, Is.EqualTo(certificatePath)); + Assert.That(stringBuilder.ConnectionString.Contains(certificatePath)); connString = stringBuilder.ToString(); - Assert.True(connString.Contains(certificatePath)); + Assert.That(connString.Contains(certificatePath)); // Connection string in uri format. string connStringUri = ConnectionStringUri + "/?ssl-ca=" + certificatePath + "& ssl-ca-pwd=pass;"; using (var session = MySQLX.GetSession(connStringUri)) { - Assert.AreEqual(certificatePath, session.Settings.CertificateFile); - Assert.AreEqual(certificatePath, session.Settings.SslCa); - Assert.True(session.Settings.ConnectionString.Contains(certificatePath)); + Assert.That(session.Settings.CertificateFile, Is.EqualTo(certificatePath)); + Assert.That(session.Settings.SslCa, Is.EqualTo(certificatePath)); + Assert.That(session.Settings.ConnectionString.Contains(certificatePath)); connString = session.Settings.ToString(); - Assert.True(connString.Contains(certificatePath)); + Assert.That(connString.Contains(certificatePath)); } } @@ -419,7 +420,7 @@ public void SslCertificatePathVariations(string certificatePath) using (var session = MySQLX.GetSession(connStringUri)) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } } @@ -434,20 +435,20 @@ public void SslCertificateConnectionOptionsExistAndDefaultToNull() var builder = new MySqlXConnectionStringBuilder(); // Options exist. - Assert.True(builder.values.ContainsKey("sslca")); - Assert.True(builder.values.ContainsKey("sslcert")); - Assert.True(builder.values.ContainsKey("sslkey")); + Assert.That(builder.values.ContainsKey("sslca")); + Assert.That(builder.values.ContainsKey("sslcert")); + Assert.That(builder.values.ContainsKey("sslkey")); // Options default to null. - Assert.Null(builder["sslca"]); - Assert.Null(builder["sslcert"]); - Assert.Null(builder["sslkey"]); - Assert.Null(builder["ssl-ca"]); - Assert.Null(builder["ssl-cert"]); - Assert.Null(builder["ssl-key"]); - Assert.Null(builder.SslCa); - Assert.Null(builder.SslCert); - Assert.Null(builder.SslKey); + Assert.That(builder["sslca"], Is.Null); + Assert.That(builder["sslcert"], Is.Null); + Assert.That(builder["sslkey"], Is.Null); + Assert.That(builder["ssl-ca"], Is.Null); + Assert.That(builder["ssl-cert"], Is.Null); + Assert.That(builder["ssl-key"], Is.Null); + Assert.That(builder.SslCa, Is.Null); + Assert.That(builder.SslCert, Is.Null); + Assert.That(builder.SslKey, Is.Null); // Null or whitespace options are ignored. builder = new MySqlXConnectionStringBuilder(ConnectionString); @@ -456,18 +457,18 @@ public void SslCertificateConnectionOptionsExistAndDefaultToNull() builder.SslKey = " "; using (var session = MySQLX.GetSession(builder.ConnectionString)) { - Assert.Null(session.Settings.SslCa); - Assert.Null(session.Settings.SslCert); - Assert.AreEqual(" ", session.Settings.SslKey); + Assert.That(session.Settings.SslCa, Is.Null); + Assert.That(session.Settings.SslCert, Is.Null); + Assert.That(session.Settings.SslKey, Is.EqualTo(" ")); session.Close(); } // Failing to provide a value defaults to null. using (var session = MySQLX.GetSession($"{ConnectionString};sslca=;sslcert=;sslkey=")) { - Assert.Null(session.Settings.SslCa); - Assert.Null(session.Settings.SslCert); - Assert.Null(session.Settings.SslKey); + Assert.That(session.Settings.SslCa, Is.Null); + Assert.That(session.Settings.SslCert, Is.Null); + Assert.That(session.Settings.SslKey, Is.Null); session.Close(); } } @@ -479,13 +480,13 @@ public void MissingSslCaConnectionOption() var builder = new MySqlXConnectionStringBuilder(ConnectionString); builder.SslMode = MySqlSslMode.VerifyCA; var exception = Assert.Throws(() => MySQLX.GetSession(builder.ConnectionString)); - Assert.AreEqual(MySql.Data.Resources.SslConnectionError, exception.Message); - Assert.AreEqual(string.Format(MySql.Data.Resources.FilePathNotSet, nameof(builder.SslCa)), exception.InnerException.Message); + Assert.That(exception.Message, Is.EqualTo(MySql.Data.Resources.SslConnectionError)); + Assert.That(exception.InnerException.Message, Is.EqualTo(string.Format(MySql.Data.Resources.FilePathNotSet, nameof(builder.SslCa)))); builder.SslMode = MySqlSslMode.VerifyFull; exception = Assert.Throws(() => MySQLX.GetSession(builder.ConnectionString)); - Assert.AreEqual(MySql.Data.Resources.SslConnectionError, exception.Message); - Assert.AreEqual(string.Format(MySql.Data.Resources.FilePathNotSet, nameof(builder.SslCa)), exception.InnerException.Message); + Assert.That(exception.Message, Is.EqualTo(MySql.Data.Resources.SslConnectionError)); + Assert.That(exception.InnerException.Message, Is.EqualTo(string.Format(MySql.Data.Resources.FilePathNotSet, nameof(builder.SslCa)))); } [Test] @@ -497,8 +498,8 @@ public void MissingSslCertConnectionOption() builder.SslCert = string.Empty; builder.SslMode = MySqlSslMode.VerifyFull; var exception = Assert.Throws(() => MySQLX.GetSession(builder.ConnectionString)); - Assert.AreEqual(MySql.Data.Resources.SslConnectionError, exception.Message); - Assert.AreEqual(string.Format(MySql.Data.Resources.FilePathNotSet, nameof(builder.SslCert)), exception.InnerException.Message); + Assert.That(exception.Message, Is.EqualTo(MySql.Data.Resources.SslConnectionError)); + Assert.That(exception.InnerException.Message, Is.EqualTo(string.Format(MySql.Data.Resources.FilePathNotSet, nameof(builder.SslCert)))); } [Test] @@ -511,8 +512,8 @@ public void MissingSslKeyConnectionOption() builder.SslKey = " "; builder.SslMode = MySqlSslMode.VerifyFull; var exception = Assert.Throws(() => MySQLX.GetSession(builder.ConnectionString)); - Assert.AreEqual(MySql.Data.Resources.SslConnectionError, exception.Message); - Assert.AreEqual(string.Format(MySql.Data.Resources.FilePathNotSet, nameof(builder.SslKey)), exception.InnerException.Message); + Assert.That(exception.Message, Is.EqualTo(MySql.Data.Resources.SslConnectionError)); + Assert.That(exception.InnerException.Message, Is.EqualTo(string.Format(MySql.Data.Resources.FilePathNotSet, nameof(builder.SslKey)))); } [Test] @@ -523,8 +524,8 @@ public void InvalidFileNameForSslCaConnectionOption() builder.SslCa = "C:\\certs\\ca.pema"; builder.SslMode = MySqlSslMode.VerifyCA; var exception = Assert.Throws(() => MySQLX.GetSession(builder.ConnectionString)); - Assert.AreEqual(MySql.Data.Resources.SslConnectionError, exception.Message); - Assert.AreEqual(MySql.Data.Resources.FileNotFound, exception.InnerException.Message); + Assert.That(exception.Message, Is.EqualTo(MySql.Data.Resources.SslConnectionError)); + Assert.That(exception.InnerException.Message, Is.EqualTo(MySql.Data.Resources.FileNotFound)); } [Test] @@ -536,8 +537,8 @@ public void InvalidFileNameForSslCertConnectionOption() builder.SslCert = "C:\\certs\\client-cert"; builder.SslMode = MySqlSslMode.VerifyFull; var exception = Assert.Throws(() => MySQLX.GetSession(builder.ConnectionString)); - Assert.AreEqual(MySql.Data.Resources.SslConnectionError, exception.Message); - Assert.AreEqual(MySql.Data.Resources.FileNotFound, exception.InnerException.Message); + Assert.That(exception.Message, Is.EqualTo(MySql.Data.Resources.SslConnectionError)); + Assert.That(exception.InnerException.Message, Is.EqualTo(MySql.Data.Resources.FileNotFound)); } [Test] @@ -550,8 +551,8 @@ public void InvalidFileNameForSslKeyConnectionOption() builder.SslKey = "file"; builder.SslMode = MySqlSslMode.VerifyFull; var exception = Assert.Throws(() => MySQLX.GetSession(builder.ConnectionString)); - Assert.AreEqual(MySql.Data.Resources.SslConnectionError, exception.Message); - Assert.AreEqual(MySql.Data.Resources.FileNotFound, exception.InnerException.Message); + Assert.That(exception.Message, Is.EqualTo(MySql.Data.Resources.SslConnectionError)); + Assert.That(exception.InnerException.Message, Is.EqualTo(MySql.Data.Resources.FileNotFound)); } [Test] @@ -625,23 +626,23 @@ public void AttemptConnectionWithDummyPemCertificates() builder.SslCa = sslCa.Replace("ca.pem", "ca_dummy.pem"); builder.SslMode = MySqlSslMode.VerifyCA; var exception = Assert.Throws(() => MySQLX.GetSession(builder.ConnectionString)); - Assert.AreEqual(MySql.Data.Resources.SslConnectionError, exception.Message); - Assert.AreEqual(MySql.Data.Resources.FileIsNotACertificate, exception.InnerException.Message); + Assert.That(exception.Message, Is.EqualTo(MySql.Data.Resources.SslConnectionError)); + Assert.That(exception.InnerException.Message, Is.EqualTo(MySql.Data.Resources.FileIsNotACertificate)); builder.SslCa = sslCa; builder.SslCert = sslCert.Replace("client-cert.pem", "client-cert_dummy.pem"); builder.SslMode = MySqlSslMode.VerifyFull; exception = Assert.Throws(() => MySQLX.GetSession(builder.ConnectionString)); - Assert.AreEqual(MySql.Data.Resources.SslConnectionError, exception.Message); - Assert.AreEqual(MySql.Data.Resources.FileIsNotACertificate, exception.InnerException.Message); + Assert.That(exception.Message, Is.EqualTo(MySql.Data.Resources.SslConnectionError)); + Assert.That(exception.InnerException.Message, Is.EqualTo(MySql.Data.Resources.FileIsNotACertificate)); builder.SslCa = sslCa; builder.SslCert = sslCert; builder.SslKey = sslKey.Replace("client-key.pem", "client-key_dummy.pem"); builder.SslMode = MySqlSslMode.VerifyFull; exception = Assert.Throws(() => MySQLX.GetSession(builder.ConnectionString)); - Assert.AreEqual(MySql.Data.Resources.SslConnectionError, exception.Message); - Assert.AreEqual(MySql.Data.Resources.FileIsNotAKey, exception.InnerException.Message); + Assert.That(exception.Message, Is.EqualTo(MySql.Data.Resources.SslConnectionError)); + Assert.That(exception.InnerException.Message, Is.EqualTo(MySql.Data.Resources.FileIsNotAKey)); } [Test] @@ -652,28 +653,28 @@ public void AttemptConnectionWitSwitchedPemCertificates() builder.SslCa = sslCert; builder.SslMode = MySqlSslMode.VerifyCA; var exception = Assert.Throws(() => MySQLX.GetSession(builder.ConnectionString)); - Assert.AreEqual(MySql.Data.Resources.SslConnectionError, exception.Message); - Assert.AreEqual(MySql.Data.Resources.SslCertificateIsNotCA, exception.InnerException.Message); + Assert.That(exception.Message, Is.EqualTo(MySql.Data.Resources.SslConnectionError)); + Assert.That(exception.InnerException.Message, Is.EqualTo(MySql.Data.Resources.SslCertificateIsNotCA)); builder.SslCa = sslKey; builder.SslMode = MySqlSslMode.VerifyCA; exception = Assert.Throws(() => MySQLX.GetSession(builder.ConnectionString)); - Assert.AreEqual(MySql.Data.Resources.SslConnectionError, exception.Message); - Assert.AreEqual(MySql.Data.Resources.FileIsNotACertificate, exception.InnerException.Message); + Assert.That(exception.Message, Is.EqualTo(MySql.Data.Resources.SslConnectionError)); + Assert.That(exception.InnerException.Message, Is.EqualTo(MySql.Data.Resources.FileIsNotACertificate)); builder.SslCa = sslCa; builder.SslCert = sslCa; builder.SslMode = MySqlSslMode.VerifyFull; exception = Assert.Throws(() => MySQLX.GetSession(builder.ConnectionString)); - Assert.AreEqual(MySql.Data.Resources.SslConnectionError, exception.Message); - Assert.AreEqual(MySql.Data.Resources.InvalidSslCertificate, exception.InnerException.Message); + Assert.That(exception.Message, Is.EqualTo(MySql.Data.Resources.SslConnectionError)); + Assert.That(exception.InnerException.Message, Is.EqualTo(MySql.Data.Resources.InvalidSslCertificate)); builder.SslCert = sslCert; builder.SslKey = sslCa; builder.SslMode = MySqlSslMode.VerifyFull; exception = Assert.Throws(() => MySQLX.GetSession(builder.ConnectionString)); - Assert.AreEqual(MySql.Data.Resources.SslConnectionError, exception.Message); - Assert.AreEqual(MySql.Data.Resources.FileIsNotAKey, exception.InnerException.Message); + Assert.That(exception.Message, Is.EqualTo(MySql.Data.Resources.SslConnectionError)); + Assert.That(exception.InnerException.Message, Is.EqualTo(MySql.Data.Resources.FileIsNotAKey)); } #endregion @@ -681,9 +682,7 @@ public void AttemptConnectionWitSwitchedPemCertificates() [Test, Description("Wrong Certificate with TLS with URI")] public void PfxCertificateWithUri() { - if (!session.Version.isAtLeast(8, 0, 0)) Assert.Ignore("This test is for MySql 8.0 or higher."); - var result = session.SQL("show variables like '%ave_ssl%'").Execute().FetchOne(); - if (result[1].ToString() != "YES") return; + Assume.That(session.Version.isAtLeast(8, 0, 0), "This test is for MySql 8.0 or higher"); var connStr = ConnectionStringUri + $"?ssl-mode=VerifyCA&ssl-ca={clientPfxIncorrect}&ssl-ca-pwd={sslCertificatePassword}"; Assert.That(() => MySQLX.GetSession(connStr), Throws.Exception); @@ -694,25 +693,23 @@ public void PfxCertificateWithUri() connStr = ConnectionStringUri + $"?ssl-mode=Required&ssl-ca={clientPfx}&ssl-ca-pwd={sslCertificatePassword}"; using (var c = MySQLX.GetSession(connStr)) { - Assert.AreEqual(SessionState.Open, c.InternalSession.SessionState); + Assert.That(c.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); var res = ExecuteSQLStatement(c.SQL("SHOW SESSION STATUS LIKE 'Mysqlx_ssl_version';")).FetchAll(); - StringAssert.StartsWith("TLSv1", res[0][1].ToString()); + Assert.That(res[0][1].ToString(), Does.StartWith("TLSv1")); } } [Test, Description("MySQLX ran with Automation for server with TLS")] public void PfxCertificateWithConnectionString() { - if (!session.Version.isAtLeast(8, 0, 0)) Assert.Ignore("This test is for MySql 8.0 or higher."); - var result = session.SQL("show variables like '%ave_ssl%'").Execute().FetchOne(); - if (result[1].ToString() != "YES") return; + Assume.That(session.Version.isAtLeast(8, 0, 0), "This test is for MySql 8.0 or higher"); var connStr = ConnectionString + $";ssl-mode=Required;ssl-ca={clientPfx};ssl-ca-pwd={sslCertificatePassword};"; using (Session c = MySQLX.GetSession(connStr)) { - Assert.AreEqual(SessionState.Open, c.InternalSession.SessionState); + Assert.That(c.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); var res = ExecuteSQLStatement(c.SQL("SHOW SESSION STATUS LIKE 'Mysqlx_ssl_version';")).FetchAll(); - StringAssert.StartsWith("TLSv1", res[0][1].ToString()); + Assert.That(res[0][1].ToString(), Does.StartWith("TLSv1")); } //wrong certificate @@ -726,7 +723,7 @@ public void PfxCertificateWithConnectionString() [Test] public void ConnectUsingCertificateFileAndTlsVersionXplugin() { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher."); + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); var builder = new MySqlConnectionStringBuilder(ConnectionString); builder.SslMode = MySqlSslMode.Required; @@ -736,37 +733,35 @@ public void ConnectUsingCertificateFileAndTlsVersionXplugin() using (var session1 = MySQLX.GetSession(builder.ConnectionString)) { var result = session1.SQL("show variables like '%tls_version%'").Execute().FetchOne(); - StringAssert.Contains("TLSv1", result[1].ToString()); + Assert.That(result[1].ToString(), Does.Contain("TLSv1")); result = session1.SQL("show status like 'Mysqlx_ssl_cipher'").Execute().FetchOne(); - Assert.True(result[1].ToString().Trim().Length > 0); + Assert.That(result[1].ToString().Trim().Length > 0); result = session1.SQL("show status like 'Mysqlx_ssl_version'").Execute().FetchOne(); - StringAssert.AreEqualIgnoringCase("TLSv1.2", result[1].ToString()); + Assert.That(result[1].ToString(), Is.EqualTo("TLSv1.2").IgnoreCase); } } [TestCase("TLSv1.2")] public void TlsVersionInConnectionStringXplugin(string tlsVersion) { - if (!Platform.IsWindows()) Assert.Ignore("This test is for Windows OS only"); - if (!session.Version.isAtLeast(8, 0, 16)) Assert.Ignore("This test is for MySql 8.0.16 or higher."); - var result = session.SQL("show variables like '%ave_ssl%'").Execute().FetchOne(); - if (result[1].ToString() != "YES") return; + Assume.That(Platform.IsWindows(), "This test is only for Windows OS."); + Assume.That(session.Version.isAtLeast(8, 0, 16), "This test is for MySql 8.0.16 or higher"); var connStr = ConnectionString + $";sslmode=Required;tls-version={tlsVersion}"; using (var c = MySQLX.GetSession(connStr)) { - Assert.AreEqual(SessionState.Open, c.InternalSession.SessionState); + Assert.That(c.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); var res = c.SQL("SHOW SESSION STATUS LIKE 'Mysqlx_ssl_version';").Execute().FetchAll(); - StringAssert.AreEqualIgnoringCase(tlsVersion, res[0][1].ToString()); + Assert.That(res[0][1].ToString(), Is.EqualTo(tlsVersion).IgnoreCase); } } [Test, Description("Verify PEM options (SslCa,SslCert,SslKey) with different SSL modes")] public void PemCertDifferentSSLmodes() { - if (!session.Version.isAtLeast(8, 0, 16)) Assert.Ignore("This test is for MySql 8.0.16 or higher."); + Assume.That(session.Version.isAtLeast(8, 0, 16), "This test is for MySql 8.0.16 or higher"); string CommandText1 = "SHOW STATUS LIKE '%Ssl_cipher%';"; string CommandText2 = "show status like '%Ssl_version%';"; string connStr = null; @@ -784,7 +779,7 @@ public void PemCertDifferentSSLmodes() { using (var session1 = MySQLX.GetSession(connStr)) { - Assert.AreEqual(SessionState.Open, session1.InternalSession.SessionState); + Assert.That(session1.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } } else @@ -803,9 +798,9 @@ public void PemCertDifferentSSLmodes() using (var session1 = MySQLX.GetSession(connStr)) { var result = session1.SQL(CommandText1).Execute().FetchAll(); - Assert.AreEqual(result[0][1].ToString(), result[0][1].ToString(), "Matching the Cipher"); + Assert.That(result[0][1].ToString(), Is.EqualTo(result[0][1].ToString()), "Matching the Cipher"); result = session1.SQL(CommandText2).Execute().FetchAll(); - Assert.AreEqual(tls, result[0][1].ToString(), "Matching the TLS version"); + Assert.That(result[0][1].ToString(), Is.EqualTo(tls), "Matching the TLS version"); } } } @@ -816,7 +811,7 @@ public void PemCertDifferentSSLmodes() { using (var session1 = MySQLX.GetSession(connStr)) { - Assert.AreEqual(SessionState.Open, session1.InternalSession.SessionState); + Assert.That(session1.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } } else @@ -835,9 +830,9 @@ public void PemCertDifferentSSLmodes() using (var session1 = MySQLX.GetSession(connStr)) { var result = session1.SQL(CommandText1).Execute().FetchAll(); - Assert.AreEqual(result[0][1].ToString(), result[0][1].ToString(), "Matching the Cipher"); + Assert.That(result[0][1].ToString(), Is.EqualTo(result[0][1].ToString()), "Matching the Cipher"); result = session1.SQL(CommandText2).Execute().FetchAll(); - Assert.AreEqual(tls, result[0][1].ToString(), "Matching the TLS version"); + Assert.That(result[0][1].ToString(), Is.EqualTo(tls), "Matching the TLS version"); } } } @@ -860,7 +855,7 @@ public void PemCertDifferentSSLmodes() { using (var session1 = MySQLX.GetSession(connStr)) { - Assert.AreEqual(SessionState.Open, session1.InternalSession.SessionState); + Assert.That(session1.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } } else @@ -879,9 +874,9 @@ public void PemCertDifferentSSLmodes() using (var session1 = MySQLX.GetSession(connObject)) { var result = session1.SQL(CommandText1).Execute().FetchAll(); - Assert.AreEqual(result[0][1].ToString(), result[0][1].ToString(), "Matching the Cipher"); + Assert.That(result[0][1].ToString(), Is.EqualTo(result[0][1].ToString()), "Matching the Cipher"); result = session1.SQL(CommandText2).Execute().FetchAll(); - Assert.AreEqual(tls, result[0][1].ToString(), "Matching the TLS version"); + Assert.That(result[0][1].ToString(), Is.EqualTo(tls), "Matching the TLS version"); } } } @@ -907,9 +902,9 @@ public void PemCertDifferentSSLmodes() using (var session1 = MySQLX.GetSession(conn.ConnectionString)) { var result = session1.SQL(CommandText1).Execute().FetchAll(); - Assert.AreEqual(result[0][1].ToString(), result[0][1].ToString(), "Matching the Cipher"); + Assert.That(result[0][1].ToString(), Is.EqualTo(result[0][1].ToString()), "Matching the Cipher"); result = session1.SQL(CommandText2).Execute().FetchAll(); - Assert.AreEqual(tls, result[0][1].ToString(), "Matching the TLS version"); + Assert.That(result[0][1].ToString(), Is.EqualTo(tls), "Matching the TLS version"); } } } @@ -918,8 +913,8 @@ public void PemCertDifferentSSLmodes() [Test, Description("MySQLX-scenario (wrong/no ssl-ca,correct ssl-key/ssl-cert,ssl-mode VerifyCA)")] public void IncorrectSslCAVerifyCAMode() { - if (!Platform.IsWindows()) Assert.Ignore("This test is for Windows OS only"); - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher."); + Assume.That(Platform.IsWindows(), "This test is only for Windows OS."); + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); string sslmode = "VerifyCA"; string[] sslcalist = new string[] { "ca_dummy.pem", "", " ", null, "file", "file.pem" }; for (int i = 0; i < sslcalist.Length; i++) @@ -988,8 +983,8 @@ public void IncorrectSslCAVerifyCAMode() [Test, Description("MySQLX-Scenario (correct ssl-ca,wrong/no ssl-key/ssl-cert,ssl-mode VerifyCA)")] public void IncorrectSslkeyAndSslcertVerifyCAMode() { - if (!Platform.IsWindows()) Assert.Ignore("This test is for Windows OS only"); - if (!session.Version.isAtLeast(8, 0, 0)) Assert.Ignore("This test is for MySql 8.0 or higher."); + Assume.That(Platform.IsWindows(), "This test is only for Windows OS."); + Assume.That(session.Version.isAtLeast(8, 0, 0), "This test is for MySql 8.0 or higher"); string sslmode = "VerifyCA"; string[] sslcertlist = new string[] { "", " ", null, "file", "file.pem" }; string[] sslkeylist = new string[] { "", " ", null, "file", "file.pem" }; @@ -1065,8 +1060,8 @@ public void IncorrectSslkeyAndSslcertVerifyCAMode() [Test, Description("MySQLX-Scenario (wrong ssl-ca,correct ssl-key/ssl-cert,ssl-mode required and default)")] public void IncorrectSslCACorrectKeyAndCertRequiredMode() { - if (!Platform.IsWindows()) Assert.Ignore("This test is for Windows OS only"); - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher."); + Assume.That(Platform.IsWindows(), "This test is only for Windows OS."); + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); string sslmode = "Required"; string[] sslcalist = new string[] { "ca_dummy.pem", "", " ", null, "file", "file.pem" }; List csAndUriList = new List(); @@ -1131,8 +1126,8 @@ public void IncorrectSslCACorrectKeyAndCertRequiredMode() [Test, Description("MySQLX-Scenario (no ssl-ca,correct ssl-key/ssl-cert,ssl-mode required and default)")] public void NoSslcaWithSslkeySslcertRequiredMode() { - if (!Platform.IsWindows()) Assert.Ignore("This test is for Windows OS only"); - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("This test is for MySql 8.0.11 or higher."); + Assume.That(Platform.IsWindows(), "This test is only for Windows OS."); + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); string sslmode = "Required"; List csAndUriList = new List(); List connObjectList = new List(); @@ -1176,7 +1171,7 @@ public void NoSslcaWithSslkeySslcertRequiredMode() [Test, Description("MySQLX-Scenario (correct ssl-ca,wrong ssl-key/ssl-cert,ssl-mode required and default)")] public void CorrectSslcaWrongSslkeySslcertRequiredMode() { - if (!Platform.IsWindows()) Assert.Ignore("This test is for Windows OS only"); + Assume.That(Platform.IsWindows(), "This test is only for Windows OS."); string sslmode = "Required"; string[] sslcertlist = new string[] { "", " ", null, "file", "file.pem" }; string[] sslkeylist = new string[] { "", " ", null, "file", "file.pem" }; @@ -1256,8 +1251,8 @@ public void CorrectSslcaWrongSslkeySslcertRequiredMode() [Test, Description("MySQLX-Scenario (correct ssl-ca,no ssl-key/ssl-cert,ssl-mode required and default)")] public void CorrectSslcaNoSslkeyorCertRequiredMode() { - if (!Platform.IsWindows()) Assert.Ignore("This test is for Windows OS only"); - if (!session.Version.isAtLeast(8, 0, 0)) Assert.Ignore("This test is for MySql 8.0 or higher."); + Assume.That(Platform.IsWindows(), "This test is only for Windows OS."); + Assume.That(session.Version.isAtLeast(8, 0, 0), "This test is for MySql 8.0 or higher"); string sslmode = "Required"; List csAndUriList = new List(); //Connection string and Uris @@ -1318,8 +1313,8 @@ public void CorrectSslcaNoSslkeyorCertRequiredMode() [Test, Description("mixed spelling ssl-ca, ssl-key/ssl-cert, ssl-mode VerifyCA and Required)")] public void MixedspellingSslcaSslkeySslcert() { - if (!Platform.IsWindows()) Assert.Ignore("This test is for Windows OS only"); - if (!session.Version.isAtLeast(8, 0, 0)) Assert.Ignore("This test is for MySql 8.0 or higher."); + Assume.That(Platform.IsWindows(), "This test is only for Windows OS."); + Assume.That(session.Version.isAtLeast(8, 0, 0), "This test is for MySql 8.0.0 or higher"); string[] sslmode = new string[] { "VerifyCA", "Required" }; for (int i = 0; i < sslmode.Length; i++) { @@ -1383,7 +1378,7 @@ public void RepeatedTlsOption() [Test, Description("checking different versions of TLS")] public void SecurityTlsCheck() { - if (!Platform.IsWindows()) Assert.Ignore("This test is for Windows OS only"); + Assume.That(Platform.IsWindows(), "This test is only for Windows OS."); MySqlSslMode[] modes = { MySqlSslMode.Required, MySqlSslMode.VerifyCA, MySqlSslMode.VerifyFull }; String[] version, ver1Tls; var conStrX = $"{ConnectionString};SslCa={sslCa};SslCert={sslCert};SslKey={sslKey};ssl-ca-pwd={sslCertificatePassword}"; @@ -1392,7 +1387,7 @@ public void SecurityTlsCheck() using (Session session1 = MySQLX.GetSession(conStrX + $";ssl-mode={mode};tls-version=TLSv1.2")) { var sess = session1.SQL("select variable_value from performance_schema.session_status where variable_name='mysqlx_ssl_version'").Execute().FetchOne()[0]; - Assert.AreEqual("TLSv1.2", sess); + Assert.That(sess, Is.EqualTo("TLSv1.2")); } version = new string[] { "[TLSv1.1,TLSv1.2]", "[TLSv1,TLSv1.2]" }; @@ -1402,7 +1397,7 @@ public void SecurityTlsCheck() using (Session session1 = MySQLX.GetSession(conStrX + ";ssl-mode=" + mode + ";tls-version=" + version[i])) { var sess = session1.SQL("select variable_value from performance_schema.session_status where variable_name='mysqlx_ssl_version'").Execute().FetchOne()[0]; - Assert.AreEqual(ver1Tls[i], sess); + Assert.That(sess, Is.EqualTo(ver1Tls[i])); } } } @@ -1418,19 +1413,19 @@ public void Tlsv13Bug() using (session1 = MySQLX.GetSession(conStr + ";tls-version=TLSv1.3")) { var sess1 = session1.SQL("select variable_value from performance_schema.session_status where variable_name='mysqlx_ssl_version'").Execute().FetchOne()[0]; - Assert.AreEqual("TLSv1.3", sess1); + Assert.That(sess1, Is.EqualTo("TLSv1.3")); } using (session1 = MySQLX.GetSession(conStr + ";tls-version=TLSv1.2")) { var sess1 = session1.SQL("select variable_value from performance_schema.session_status where variable_name='mysqlx_ssl_version'").Execute().FetchOne()[0]; - Assert.AreEqual("TLSv1.2", sess1); + Assert.That(sess1, Is.EqualTo("TLSv1.2")); } using (session1 = MySQLX.GetSession(conStr + ";tls-version=TLSv1.2,TLSv1.3")) { var sess1 = session1.SQL("select variable_value from performance_schema.session_status where variable_name='mysqlx_ssl_version'").Execute().FetchOne()[0]; - Assert.AreEqual("TLSv1.3", sess1); + Assert.That(sess1, Is.EqualTo("TLSv1.3")); } } @@ -1438,7 +1433,7 @@ public void Tlsv13Bug() [Ignore("Fix this")] public void Tlsv13Linux() { - if (Platform.IsWindows()) Assert.Ignore("This test is for Linux OS only"); + Assume.That(!Platform.IsWindows(), "This test is only for Linux OS."); MySqlSslMode[] modes = { MySqlSslMode.Required, MySqlSslMode.VerifyCA, MySqlSslMode.VerifyFull }; var conStr = $"{ConnectionString};SslCa={sslCa};SslCert={sslCert};SslKey={sslKey};ssl-ca-pwd={sslCertificatePassword}"; @@ -1448,7 +1443,7 @@ public void Tlsv13Linux() foreach (string tlsVersion in version) { - Assert.AreEqual(SessionState.Open, MySQLX.GetSession(conStr + ";ssl-mode=" + mode + ";tls-version=" + tlsVersion).InternalSession.SessionState); + Assert.That(MySQLX.GetSession(conStr + ";ssl-mode=" + mode + ";tls-version=" + tlsVersion).InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } version = new string[] { "[TLSv1,TLSv1.3]", "[TLSv1.1,TLSv1.3]", "[TLSv1,TLSv1.2,TLSv1.3]", "[TLSv1.2,TLSv1.3]", "[TLSv1,TLSv1.1,TLSv1.2,TLSv1.3]" }; @@ -1458,7 +1453,7 @@ public void Tlsv13Linux() using (var session1 = MySQLX.GetSession(conStr + ";ssl-mode=" + mode + ";tls-version=" + version[i])) { var sess = session1.SQL("select variable_value from performance_schema.session_status where variable_name='mysqlx_ssl_version'").Execute().FetchOne()[0]; - Assert.True(sess.ToString().Contains("TLSv1")); + Assert.That(sess.ToString().Contains("TLSv1")); } } } @@ -1468,14 +1463,20 @@ private void AssertTlsConnection(string inputString) { string CommandText1 = "SHOW STATUS LIKE '%Ssl_cipher%';"; string CommandText2 = "show status like '%Ssl_version%';"; - string cipher = "ECDHE-RSA-AES256-GCM-SHA384"; + + string cipher = ""; + if (session.Version.isAtLeast(9, 2, 0)) + cipher = "ECDHE-RSA-AES128-GCM-SHA256"; + else + cipher = "ECDHE-RSA-AES256-GCM-SHA384"; + string tls = "TLSv1.2"; using (var session1 = MySQLX.GetSession(inputString)) { var result = session1.SQL(CommandText1).Execute().FetchAll(); - Assert.AreEqual(cipher, result[0][1].ToString(), "Matching the Cipher"); + Assert.That(result[0][1].ToString(), Is.EqualTo(cipher), "Matching the Cipher"); result = session1.SQL(CommandText2).Execute().FetchAll(); - Assert.AreEqual(tls, result[0][1].ToString(), "Matching the TLS version"); + Assert.That(result[0][1].ToString(), Is.EqualTo(tls), "Matching the TLS version"); } } @@ -1483,14 +1484,20 @@ private void AssertTlsConnection(object inputObject) { string CommandText1 = "SHOW STATUS LIKE '%Ssl_cipher%';"; string CommandText2 = "show status like '%Ssl_version%';"; - string cipher = "ECDHE-RSA-AES256-GCM-SHA384"; + + string cipher = ""; + if (session.Version.isAtLeast(9, 2, 0)) + cipher = "ECDHE-RSA-AES128-GCM-SHA256"; + else + cipher = "ECDHE-RSA-AES256-GCM-SHA384"; + string tls = "TLSv1.2"; using (var session1 = MySQLX.GetSession(inputObject)) { var result = session1.SQL(CommandText1).Execute().FetchAll(); - Assert.AreEqual(cipher, result[0][1].ToString(), "Matching the Cipher"); + Assert.That(result[0][1].ToString(), Is.EqualTo(cipher), "Matching the Cipher"); result = session1.SQL(CommandText2).Execute().FetchAll(); - Assert.AreEqual(tls, result[0][1].ToString(), "Matching the TLS version"); + Assert.That(result[0][1].ToString(), Is.EqualTo(tls), "Matching the TLS version"); } } @@ -1511,8 +1518,8 @@ public void SslOptionsCombinedWhenDisabled(MySqlSslMode sslMode, string sslOptio using var session = MySQLX.GetSession(connStr); var encryption = session.SQL("SHOW SESSION STATUS LIKE 'mysqlx_ssl_cipher'").Execute().FetchAll()[0][1].ToString(); - Assert.IsEmpty(encryption); - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); + Assert.That(encryption, Is.Empty); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); // ConnectionString Uri var connStrUri = ConnectionStringUri + $"?ssl-mode={sslMode}&{sslOption}"; @@ -1520,8 +1527,8 @@ public void SslOptionsCombinedWhenDisabled(MySqlSslMode sslMode, string sslOptio using var sessionUri = MySQLX.GetSession(connStrUri); encryption = sessionUri.SQL("SHOW SESSION STATUS LIKE 'mysqlx_ssl_cipher'").Execute().FetchAll()[0][1].ToString(); - Assert.IsEmpty(encryption); - Assert.AreEqual(SessionState.Open, sessionUri.InternalSession.SessionState); + Assert.That(encryption, Is.Empty); + Assert.That(sessionUri.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } [Test] @@ -1532,16 +1539,16 @@ public void SslRequiredAndDisabled() using var sessionUriDisabled = MySQLX.GetSession(connStrUri); var encryption = sessionUriDisabled.SQL("SHOW SESSION STATUS LIKE 'mysqlx_ssl_cipher'").Execute().FetchAll()[0][1].ToString(); - Assert.IsEmpty(encryption); - Assert.AreEqual(SessionState.Open, sessionUriDisabled.InternalSession.SessionState); + Assert.That(encryption, Is.Empty); + Assert.That(sessionUriDisabled.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); connStrUri = ConnectionStringUri + $"?ssl-mode={MySqlSslMode.Disabled}&ssl-mode={MySqlSslMode.Required}"; using var sessionUriRequired = MySQLX.GetSession(connStrUri); encryption = sessionUriRequired.SQL("SHOW SESSION STATUS LIKE 'mysqlx_ssl_cipher'").Execute().FetchAll()[0][1].ToString(); - Assert.IsNotEmpty(encryption); - Assert.AreEqual(SessionState.Open, sessionUriRequired.InternalSession.SessionState); + Assert.That(encryption, Is.Not.Empty); + Assert.That(sessionUriRequired.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } } -} \ No newline at end of file +} diff --git a/MySQL.Data/tests/MySqlX.Data.Tests/TransactionTests.cs b/MySQL.Data/tests/MySqlX.Data.Tests/TransactionTests.cs index 03394d22a..778a06428 100644 --- a/MySQL.Data/tests/MySqlX.Data.Tests/TransactionTests.cs +++ b/MySQL.Data/tests/MySqlX.Data.Tests/TransactionTests.cs @@ -1,996 +1,997 @@ -// Copyright (c) 2015, 2023, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data.MySqlClient; -using MySqlX.XDevAPI; -using MySqlX.XDevAPI.Common; -using MySqlX.XDevAPI.CRUD; -using MySqlX.XDevAPI.Relational; -using NUnit.Framework; -using System; -using System.Linq; - -namespace MySqlX.Data.Tests -{ - public class TransactionTests : BaseTest - { - private string collName = "collSp"; - - [TearDown] - public void TearDown() => session.Schema.DropCollection(collName); - - [Test] - public void Commit() - { - Collection coll = CreateCollection("test"); - var docs = new[] - { - new { _id = 1, title = "Book 1", pages = 20 }, - new { _id = 2, title = "Book 2", pages = 30 }, - new { _id = 3, title = "Book 3", pages = 40 }, - new { _id = 4, title = "Book 4", pages = 50 }, - }; - - // start the transaction - coll.Session.StartTransaction(); - - Result r = ExecuteAddStatement(coll.Add(docs)); - Assert.AreEqual(4, r.AffectedItemsCount); - - // now roll it back - coll.Session.Commit(); - - var foundDocs = ExecuteFindStatement(coll.Find()); - Assert.True(foundDocs.Next()); - Assert.True(foundDocs.Next()); - Assert.True(foundDocs.Next()); - Assert.True(foundDocs.Next()); - Assert.False(foundDocs.Next()); - } - - [Test] - public void Rollback() - { - Collection coll = CreateCollection("test"); - var docs = new[] - { - new { _id = 1, title = "Book 1", pages = 20 }, - new { _id = 2, title = "Book 2", pages = 30 }, - new { _id = 3, title = "Book 3", pages = 40 }, - new { _id = 4, title = "Book 4", pages = 50 }, - }; - - // start the transaction - coll.Session.StartTransaction(); - - Result r = ExecuteAddStatement(coll.Add(docs)); - Assert.AreEqual(4, r.AffectedItemsCount); - - // now roll it back - coll.Session.Rollback(); - - var foundDocs = ExecuteFindStatement(coll.Find()); - Assert.False(foundDocs.Next()); - } - - #region Savepoints - - [Test] - public void CreateUnnamedSavepoint() - { - using (var session = MySQLX.GetSession(ConnectionString)) - { - session.StartTransaction(); - - string spName = session.SetSavepoint(); - Assert.False(string.IsNullOrWhiteSpace(spName)); - - session.Rollback(); - } - } - - [Test] - public void RollbackToSavepoint() - { - using (var session = MySQLX.GetSession(ConnectionString)) - { - var schema = session.GetSchema("test"); - schema.DropCollection("collSP"); - var coll = schema.CreateCollection("collSP"); - - session.StartTransaction(); - - ExecuteAddStatement(coll.Add("{ \"test\": \"test\" }")); - var sp = session.SetSavepoint(); - ExecuteAddStatement(coll.Add("{ \"test\": \"test\" }")); - Assert.AreEqual(2, ExecuteFindStatement(coll.Find()).FetchAll().Count); - session.RollbackTo(sp); - Assert.That(ExecuteFindStatement(coll.Find()).FetchAll(), Has.One.Items); - - session.Rollback(); - } - } - - [Test] - public void ReleaseSavepoint() - { - using (var sessionTest = MySQLX.GetSession(ConnectionString)) - { - var coll = CreateCollection("test"); - sessionTest.StartTransaction(); - ExecuteAddStatement(coll.Add("{ \"test\": \"test\" }")); - var sp = sessionTest.SetSavepoint(); - ExecuteAddStatement(coll.Add("{ \"test2\": \"test2\" }")); - Assert.AreEqual(2, ExecuteFindStatement(coll.Find()).FetchAll().Count); - sessionTest.ReleaseSavepoint(sp); - Assert.AreEqual(2, ExecuteFindStatement(coll.Find()).FetchAll().Count); - sessionTest.Rollback(); - } - } - - [Test] - public void CreateNamedSavepoint() - { - using (var session = MySQLX.GetSession(ConnectionString)) - { - session.StartTransaction(); - - string spName = session.SetSavepoint("mySavedPoint"); - Assert.False(string.IsNullOrWhiteSpace(spName)); - - session.Rollback(); - } - } - - [Test] - public void RollbackToNamedSavepoint() - { - using (var session = MySQLX.GetSession(ConnectionString)) - { - var schema = session.GetSchema("test"); - schema.DropCollection("collSP"); - var coll = schema.CreateCollection("collSP"); - session.StartTransaction(); - ExecuteAddStatement(coll.Add("{ \"test\": \"test\" }")); - var sp = session.SetSavepoint("mySavedPoint"); - ExecuteAddStatement(coll.Add("{ \"test2\": \"test2\" }")); - Assert.AreEqual(2, ExecuteFindStatement(coll.Find()).FetchAll().Count); - session.RollbackTo(sp); - Assert.That(ExecuteFindStatement(coll.Find()).FetchAll(), Has.One.Items); - session.Rollback(); - } - } - - [Test] - public void ReleaseNamedSavepoint() - { - using (var session = MySQLX.GetSession(ConnectionString)) - { - var schema = session.GetSchema("test"); - schema.DropCollection("test"); - var coll = schema.CreateCollection("test"); - session.StartTransaction(); - ExecuteAddStatement(coll.Add("{ \"test\": \"test\" }")); - var sp = session.SetSavepoint("mySavedPoint"); - ExecuteAddStatement(coll.Add("{ \"test2\": \"test2\" }")); - Assert.AreEqual(2, ExecuteFindStatement(coll.Find()).FetchAll().Count); - session.ReleaseSavepoint(sp); - Assert.AreEqual(2, ExecuteFindStatement(coll.Find()).FetchAll().Count); - session.Rollback(); - } - } - - [Test] - public void NonExistentSavepoint() - { - using (var session = MySQLX.GetSession(ConnectionString)) - { - session.StartTransaction(); - - Exception exception = Assert.Throws(() => session.RollbackTo("nonExistentSavePoint")); - Assert.AreEqual("SAVEPOINT nonExistentSavePoint does not exist", exception.Message); - - exception = Assert.Throws(() => session.ReleaseSavepoint("nonExistentSavePoint")); - Assert.AreEqual("SAVEPOINT nonExistentSavePoint does not exist", exception.Message); - - session.Rollback(); - } - } - - [Test] - public void CreateSavepointWithWeirdNames() - { - using (var session = MySQLX.GetSession(ConnectionString)) - { - string errorMessage = "You have an error in your SQL syntax"; - session.StartTransaction(); - - Exception ex = Assert.Throws(() => session.SetSavepoint("")); - StringAssert.StartsWith(errorMessage, ex.Message); - ex = Assert.Throws(() => session.SetSavepoint(" ")); - StringAssert.StartsWith(errorMessage, ex.Message); - ex = Assert.Throws(() => session.SetSavepoint(null)); - StringAssert.StartsWith(errorMessage, ex.Message); - ex = Assert.Throws(() => session.SetSavepoint("-")); - StringAssert.StartsWith(errorMessage, ex.Message); - ex = Assert.Throws(() => session.SetSavepoint("mysp+")); - StringAssert.StartsWith(errorMessage, ex.Message); - ex = Assert.Throws(() => session.SetSavepoint("3306")); - StringAssert.StartsWith(errorMessage, ex.Message); - - var sp = session.SetSavepoint("_"); - session.RollbackTo(sp); - sp = session.SetSavepoint("mysql3306"); - session.RollbackTo(sp); - - session.Rollback(); - } - } - - [Test] - public void OverwriteSavepoint() - { - using (var session = MySQLX.GetSession(ConnectionString)) - { - var schema = session.GetSchema("test"); - var coll = schema.CreateCollection(collName); - - session.StartTransaction(); - - ExecuteAddStatement(coll.Add("{ \"test\": \"test\" }")); - var sp = session.SetSavepoint("mySP"); - ExecuteAddStatement(coll.Add("{ \"test2\": \"test2\" }")); - sp = session.SetSavepoint("mySP"); - ExecuteAddStatement(coll.Add("{ \"test3\": \"test3\" }")); - sp = session.SetSavepoint("mySP"); - ExecuteAddStatement(coll.Add("{ \"test4\": \"test4\" }")); - sp = session.SetSavepoint("mySP"); - session.RollbackTo(sp); - Assert.AreEqual(4, ExecuteFindStatement(coll.Find()).FetchAll().Count); - - session.Rollback(); - } - } - - [Test] - public void MultipleReleasesForSavepoint() - { - using (var session = MySQLX.GetSession(ConnectionString)) - { - session.StartTransaction(); - - var sp = session.SetSavepoint("mySP"); - session.ReleaseSavepoint(sp); - Exception exception = Assert.Throws(() => session.ReleaseSavepoint(sp)); - Assert.AreEqual(string.Format("SAVEPOINT {0} does not exist", sp), exception.Message); - - session.Rollback(); - } - } - - [Test] - public void RollbackAndReleaseAfterTransactionCommit() - { - using (var sessionTest = MySQLX.GetSession(ConnectionString)) - { - var coll = CreateCollection("collSP"); - sessionTest.StartTransaction(); - var sp = sessionTest.SetSavepoint("mySP"); - ExecuteAddStatement(coll.Add("{ \"test\": \"test\" }")); - sessionTest.Commit(); - Exception exception = Assert.Throws(() => sessionTest.RollbackTo(sp)); - Assert.AreEqual(string.Format("SAVEPOINT {0} does not exist", sp), exception.Message); - exception = Assert.Throws(() => sessionTest.ReleaseSavepoint(sp)); - Assert.AreEqual(string.Format("SAVEPOINT {0} does not exist", sp), exception.Message); - } - } - - [Test] - public void RollbackAndReleaseAfterTransactionRollback() - { - using (var sessionTest = MySQLX.GetSession(ConnectionString)) - { - var coll = CreateCollection("collSP"); - sessionTest.StartTransaction(); - - var sp = sessionTest.SetSavepoint("mySP"); - ExecuteAddStatement(coll.Add("{ \"test\": \"test\" }")); - - sessionTest.Rollback(); - - Exception exception = Assert.Throws(() => sessionTest.RollbackTo(sp)); - Assert.AreEqual(string.Format("SAVEPOINT {0} does not exist", sp), exception.Message); - - exception = Assert.Throws(() => sessionTest.ReleaseSavepoint(sp)); - Assert.AreEqual(string.Format("SAVEPOINT {0} does not exist", sp), exception.Message); - } - } - - #endregion - - #region WL14389 - - [Test, Description("Session Close Transaction")] - public void SessionCloseTransaction() - { - if (!session.Version.isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher."); - using (Session sessionTest = MySQLX.GetSession(ConnectionString)) - { - Schema db = null; - db = sessionTest.GetSchema("test"); - sessionTest.StartTransaction(); - - if (db.GetCollection("my_collection_1").ExistsInDatabase()) - { - db.DropCollection("my_collection_1"); - } - Collection col = db.CreateCollection("my_collection_1"); - sessionTest.Close(); - Assert.Throws(() => sessionTest.Rollback()); - } - } - - [Test, Description("Valid Commit and Check Warning ")] - public void CommitValidWarning() - { - if (!session.Version.isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher."); - using (Session sessionPlain = MySQLX.GetSession(ConnectionString)) - { - sessionPlain.SetCurrentSchema("test"); - sessionPlain.SQL("drop table if exists temp").Execute(); - sessionPlain.SQL("CREATE TABLE temp(id INT primary key)").Execute(); - Table table = sessionPlain.Schema.GetTable("temp"); - sessionPlain.StartTransaction(); - table.Insert().Values(5).Execute(); - sessionPlain.Commit(); - Assert.AreEqual(1, table.Count()); - } - } - - /// - /// Bug 23542005 - /// - [Test, Description("Invalid Commit and Check Warning ")] - public void CommitInvalidWarning() - { - if (!session.Version.isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher."); - using (Session sessionPlain = MySQLX.GetSession(ConnectionString)) - { - sessionPlain.SetCurrentSchema("test"); - sessionPlain.SQL("CREATE TABLE temp(v VARCHAR(4))").Execute(); - Table table = sessionPlain.Schema.GetTable("temp"); - sessionPlain.StartTransaction(); - Assert.Throws(() => sessionPlain.GetSchema("test").GetTable("temp").Insert().Values("abcdef").Execute()); - sessionPlain.Commit(); - Assert.AreEqual(0, table.Count()); - var warnings = sessionPlain.SQL("DROP TABLE IF EXISTS temp1").Execute().Warnings; - Assert.IsTrue(warnings.Count > 0); - sessionPlain.Commit(); - } - } - - - [Test, Description("Valid Rollback and Check Warning ")] - public void RollbackValidWarning() - { - if (!session.Version.isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher."); - using (Session sessionPlain = MySQLX.GetSession(ConnectionString)) - { - sessionPlain.SetCurrentSchema("test"); - sessionPlain.SQL("DROP TABLE IF EXISTS temp").Execute(); - sessionPlain.SQL("CREATE TABLE temp(id INT primary key)").Execute(); - Table table = sessionPlain.Schema.GetTable("temp"); - sessionPlain.StartTransaction(); - var res = table.Insert().Values(5).Execute(); - sessionPlain.Rollback(); - Assert.AreEqual(0, table.Count()); - Assert.AreEqual(0, res.Warnings.Count); - } - } - - /// - /// Bug 23542005 - /// - [Test, Description("Invalid Rollback and Check Warning ")] - public void RollbackInvalidWarning() - { - if (!session.Version.isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher."); - using (Session sessionPlain = MySQLX.GetSession(ConnectionString)) - { - sessionPlain.SetCurrentSchema("test"); - sessionPlain.SQL("DROP TABLE IF EXISTS temp").Execute(); - sessionPlain.SQL("CREATE TABLE temp(v VARCHAR(4))").Execute(); - Table table = sessionPlain.Schema.GetTable("temp"); - sessionPlain.StartTransaction(); - Assert.Throws(() => sessionPlain.GetSchema("test").GetTable("temp").Insert().Values("abcdef").Execute()); - sessionPlain.Rollback(); - Assert.AreEqual(0, table.Count()); - var res = sessionPlain.SQL("DROP TABLE IF EXISTS temp1").Execute(); - Assert.IsTrue(res.Warnings.Count > 0); - } - } - - /// - /// Bug 23542005 - /// - [Test, Description("Commit Rollback Invalid Warning")] - public void CommitRollbackInvalidWarning() - { - if (!session.Version.isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher."); - Collection coll = CreateCollection("test"); - var docs1 = new[] - { - new { _id = 1, title = "Book 1", pages = 20 }, - new { _id = 2, title = "Book 2", pages = 30 }, - }; - - var docs2 = new[] - { - new { _id = 3, title = "Book 3", pages = 40 }, - new { _id = 4, title = "Book 4", pages = 50 }, - }; - - var docs3 = new[] - - { - new { _id = 5, title = "Book 5", pages = 60 }, - new { _id = 6, title = "Book 6", pages = 70 }, - }; - - // start the transaction - coll.Session.StartTransaction(); - - Result r = coll.Add(docs1).Execute(); - Assert.AreEqual(2, r.AffectedItemsCount); - - r = coll.Add(docs2).Execute(); - Assert.AreEqual(2, r.AffectedItemsCount); - - r = coll.Add(docs3).Execute(); - Assert.Throws(() => coll.Add(docs3).Execute()); - coll.Session.Commit(); - Assert.AreEqual(6, coll.Count()); - // now Rollback - coll.Session.Rollback(); - Assert.AreEqual(6, coll.Count()); - - var foundDocs = coll.Find().Execute(); - Assert.IsNotNull(foundDocs); - } - - [Test, Description("MySQLX plugin Warnings")] - public void Warnings() - { - if (!session.Version.isAtLeast(8, 0, 0)) return; - using (Session sessionTest = MySQLX.GetSession(ConnectionString)) - { - Schema schema = sessionTest.GetSchema("test"); - Collection coll = CreateCollection("test"); - - Result r = coll.Add("{ \"foo\": 1 }").Execute(); - Assert.AreEqual(1, r.AffectedItemsCount); - Assert.AreEqual(1, coll.Count()); - r = coll.Add("{ \"fool\": 2 }").Execute(); - Assert.AreEqual(0, r.Warnings.Count); - r = coll.Add("{ \"fool\": 10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 }").Execute(); - Assert.AreEqual(0, r.Warnings.Count); - - sessionTest.SQL("use test").Execute(); - sessionTest.SQL("CREATE TABLE nontrac(id INT primary key) ENGINE=MyISAM;").Execute(); - Table table = schema.GetTable("nontrac"); - sessionTest.StartTransaction(); - table.Insert().Values(5).Execute(); - - schema = sessionTest.GetSchema(schemaName); - sessionTest.StartTransaction(); - - var res = sessionTest.SQL("drop table if exists t1, t2").Execute(); - Assert.AreEqual(2, res.Warnings.Count); - Assert.AreEqual(1051, res.Warnings[0].Code); - - Assert.AreEqual(1051, res.Warnings[1].Code); - - res = sessionTest.SQL("create table t1 (a int) engine=innodb").Execute(); - Assert.AreEqual(0, res.Warnings.Count); - res = sessionTest.SQL("create table t2 (a int) engine=myisam").Execute(); - Assert.AreEqual(0, res.Warnings.Count); - res = sessionTest.SQL("insert into t1 values(1)").Execute(); - Assert.AreEqual(0, res.Warnings.Count); - res = sessionTest.SQL("insert into t2 select * from t1").Execute(); - Assert.AreEqual(1, res.Warnings.Count); - sessionTest.Commit(); - - } - } - - //Savepoints - [Test, Description("Rollback to same savepoint multiple times")] - public void RollbackToSameSavepoint() - { - if (!session.Version.isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher."); - - var col = CreateCollection("my_collection"); - session.StartTransaction(); - object[] data = new object[] - { - new { _id = 1, title = "Book 1", pages = 30 }, - new { _id = 2, title = "Book 2", pages = 50 }, - }; - Result result = col.Add(data).Execute(); - var sp = session.SetSavepoint("SavePoint1"); - data = new object[] - { - new { _id = 3, title = "Book 3", pages = 30 }, - new { _id = 4, title = "Book 4", pages = 50 }, - }; - result = col.Add(data).Execute(); - var sp1 = session.SetSavepoint("SavePoint2"); - - session.RollbackTo(sp); - data = new object[] - { - new { _id = 5, title = "Book 5", pages = 30 }, - new { _id = 6, title = "Book 6", pages = 50 }, - }; - result = col.Add(data).Execute(); - session.RollbackTo(sp); - var doc = col.Find().Execute(); - var docs = doc.FetchAll().Count(); - Assert.AreEqual(2, docs); - } - - - [Test, Description("Releasing a savepoint multiple times")] - public void ReleaseSavepointMoreThanOnce() - { - if (!session.Version.isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher."); - using (Session sessionTest = MySQLX.GetSession(ConnectionString)) - { - var col = CreateCollection("my_collection"); - sessionTest.StartTransaction(); - object[] data = new object[] - { - new { _id = 1, title = "Book 1", pages = 30 }, - new { _id = 2, title = "Book 2", pages = 50 }, - }; - Result result = col.Add(data).Execute(); - var sp = sessionTest.SetSavepoint("SavePoint1"); - data = new object[] - { - new { _id = 3, title = "Book 3", pages = 30 }, - new { _id = 4, title = "Book 4", pages = 50 }, - }; - result = col.Add(data).Execute(); - sessionTest.ReleaseSavepoint(sp); - data = new object[] - { - new { _id = 5, title = "Book 5", pages = 30 }, - new { _id = 6, title = "Book 6", pages = 50 }, - }; - result = col.Add(data).Execute(); - var ex = Assert.Throws(() => sessionTest.ReleaseSavepoint(sp)); - sessionTest.Rollback(); - } - } - - [TestCase("Savepoint1", "Savepoint2")] - [TestCase("", "")] - [Description("Creating multiple savepoints with SetSavepoint([name]) and rolling back to a specific one")] - public void MultipleSavepointsAndRollback(string savePoint1, string savePoint2) - { - if (!session.Version.isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher."); - var col = CreateCollection("my_collection"); - session.StartTransaction(); - object[] data = new object[] - { - new { _id = 1, title = "Book 1", pages = 30 }, - new { _id = 2, title = "Book 2", pages = 50 }, - }; - Result result = col.Add(data).Execute(); - var sp = string.IsNullOrEmpty(savePoint1) ? session.SetSavepoint() : session.SetSavepoint(savePoint1); - data = new object[] - { - new { _id = 3, title = "Book 3", pages = 30 }, - new { _id = 4, title = "Book 4", pages = 50 }, - }; - result = col.Add(data).Execute(); - var sp2 = string.IsNullOrEmpty(savePoint2) ? session.SetSavepoint() : session.SetSavepoint(savePoint2); - session.RollbackTo(sp); - var doc = col.Find().Execute(); - var docs = doc.FetchAll().Count(); - Assert.AreEqual(2, docs); - } - - [Test, Description("Test creating a savepoint without starting a transaction")] - public void SavepointWithoutTransaction() - { - if (!session.Version.isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher."); - var col = CreateCollection("my_collection"); - object[] data = new object[] - { - new { _id = 1, title = "Book 1", pages = 30 }, - new { _id = 2, title = "Book 2", pages = 50 }, - }; - Result result = col.Add(data).Execute(); - var sp = ""; - sp = session.SetSavepoint("SP"); - data = new object[] - { - new { _id =3, title = "Book 3", pages = 30 }, - new { _id =4, title = "Book 4", pages = 50 }, - }; - result = col.Add(data).Execute(); - var sp1 = session.SetSavepoint("SP"); - Assert.Throws(() => session.ReleaseSavepoint(sp1)); - } - - [Test, Description("Validate that further savepoints get released once you release a preceding savepoint")] - public void ValidateSavepointsReleased() - { - if (!session.Version.isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher."); - var col = CreateCollection("my_collection"); - session.StartTransaction(); - - object[] data = new object[] - { - new { _id = 1, title = "Book 1", pages = 30 }, - new { _id = 2, title = "Book 2", pages = 50 }, - }; - Result result = col.Add(data).Execute(); - var sp = session.SetSavepoint("SavePoint1"); - data = new object[] - { - new { _id = 3, title = "Book 3", pages = 30 }, - new { _id = 4, title = "Book 4", pages = 50 }, - }; - result = col.Add(data).Execute(); - var sp1 = session.SetSavepoint("SavePoint2"); - session.ReleaseSavepoint(sp); - Assert.Throws(() => session.ReleaseSavepoint(sp1)); - - var doc = col.Find().Execute(); - var docs = doc.FetchAll().Count(); - Assert.AreEqual(4, docs); - - } - - - [Test, Description("Validate Nested-transactions with multiple savepoints")] - public void NestedTransactions() - { - if (!session.Version.isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher."); - var col = CreateCollection("my_collection"); - session.StartTransaction(); - object[] data = new object[] - { - new { _id = 1, title = "Book 1", pages = 30 }, - new { _id = 2, title = "Book 2", pages = 50 }, - }; - Result result = col.Add(data).Execute(); - var sp = session.SetSavepoint("Savepoint1"); - session.StartTransaction(); - - data = new object[] - { - new { _id = 3, title = "Book 3", pages = 30 }, - new { _id = 4, title = "Book 4", pages = 50 }, - }; - result = col.Add(data).Execute(); - var sp1 = session.SetSavepoint("Savepoint2"); - session.Rollback(); - var doc = col.Find().Execute(); - var docs = doc.FetchAll().Count(); - Assert.AreEqual(2, docs); - } - - [Test, Description("Test the behaviour of Savepoints created immediately after one another")] - public void SavepointsCreatedImmediately() - { - if (!session.Version.isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher."); - var col = CreateCollection("my_collection"); - session.StartTransaction(); - object[] data = new object[] - { - new { _id = 1, title = "Book 1", pages = 30 }, - new { _id = 2, title = "Book 2", pages = 50 }, - }; - Result result = col.Add(data).Execute(); - var sp = session.SetSavepoint("Savepoint1"); - var sp1 = session.SetSavepoint("Savepoint2"); - session.RollbackTo(sp); - var doc = col.Find().Execute(); - var docs = doc.FetchAll().Count(); - Assert.AreEqual(2, docs); - } - - [Test, Description("Test MySQLX plugin Commit After Commit")] - public void CommitAfterCommit() - { - if (!session.Version.isAtLeast(5, 7, 0)) Assert.Ignore("This test is for MySql 5.7 or higher."); - Collection coll = CreateCollection("test"); - var docs1 = new[] - { - new { _id = 1, title = "Book 1", pages = 20 }, - new { _id = 2, title = "Book 2", pages = 30 }, - }; - - var docs2 = new[] - { - new { _id = 3, title = "Book 3", pages = 40 }, - new { _id = 4, title = "Book 4", pages = 50 }, - }; - - var docs3 = new[] - { - new { _id = 5, title = "Book 5", pages = 60 }, - new { _id = 6, title = "Book 6", pages = 70 }, - }; - - var docs4 = new[] - { - new { _id = 7, title = "Book 7", pages = 80 }, - new { _id = 8, title = "Book 8", pages = 90 }, - }; - - // start the transaction - coll.Session.StartTransaction(); - - Result r = coll.Add(docs1).Execute(); - Assert.AreEqual(2, r.AffectedItemsCount, "Matching"); - - r = coll.Add(docs2).Execute(); - Assert.AreEqual(2, r.AffectedItemsCount, "Matching"); - - r = coll.Add(docs3).Execute(); - Assert.AreEqual(2, r.AffectedItemsCount, "Matching"); - - // now Commit - coll.Session.Commit(); - // start the transaction - coll.Session.StartTransaction(); - r = coll.Add(docs4).Execute(); - Assert.AreEqual(2, r.AffectedItemsCount, "Matching"); - // now Commit Again - coll.Session.Commit(); - - var foundDocs = coll.Find().Execute(); - Assert.AreEqual(true, foundDocs.Next(), "Matching"); - Assert.AreEqual(true, foundDocs.Next(), "Matching"); - Assert.AreEqual(true, foundDocs.Next(), "Matching"); - Assert.AreEqual(true, foundDocs.Next(), "Matching"); - Assert.AreEqual(true, foundDocs.Next(), "Matching"); - Assert.AreEqual(true, foundDocs.Next(), "Matching"); - Assert.AreEqual(true, foundDocs.Next(), "Matching"); - Assert.AreEqual(true, foundDocs.Next(), "Matching"); - Assert.AreEqual(false, foundDocs.Next(), "Matching"); - - } - - [Test, Description("Test MySQLX plugin Rollback Multiple")] - public void RollBackMultiple() - { - if (!session.Version.isAtLeast(5, 7, 0)) Assert.Ignore("This test is for MySql 5.7 or higher."); - Collection coll = CreateCollection("test"); - var docs1 = new[] - { - new { _id = 1, title = "Book 1", pages = 20 }, - new { _id = 2, title = "Book 2", pages = 30 }, - }; - - var docs2 = new[] - { - new { _id = 3, title = "Book 3", pages = 40 }, - new { _id = 4, title = "Book 4", pages = 50 }, - }; - - var docs3 = new[] - { - new { _id = 5, title = "Book 5", pages = 60 }, - new { _id = 6, title = "Book 6", pages = 70 }, - }; - - // start the transaction - coll.Session.StartTransaction(); - - Result r = coll.Add(docs1).Execute(); - Assert.AreEqual(2, r.AffectedItemsCount, "Matching"); - - r = coll.Add(docs2).Execute(); - Assert.AreEqual(2, r.AffectedItemsCount, "Matching"); - - r = coll.Add(docs3).Execute(); - Assert.AreEqual(2, r.AffectedItemsCount, "Matching"); - - // now Rollback - coll.Session.Rollback(); - - var foundDocs = coll.Find().Execute(); - Assert.AreEqual(false, foundDocs.Next(), "Matching"); - - } - - [Test, Description("Test MySQLX plugin Rollback after RollBack")] - public void RollBackAfterRollBack() - { - if (!session.Version.isAtLeast(8, 0, 3)) Assert.Ignore("This test is for MySql 8.0.3 or higher."); - Collection coll = CreateCollection("test"); - var docs1 = new[] - { - new { _id = 1, title = "Book 1", pages = 20 }, - new { _id = 2, title = "Book 2", pages = 30 }, - }; - - var docs2 = new[] - { - new { _id = 3, title = "Book 3", pages = 40 }, - new { _id = 4, title = "Book 4", pages = 50 }, - }; - - var docs3 = new[] - { - new { _id = 5, title = "Book 5", pages = 60 }, - new { _id = 6, title = "Book 6", pages = 70 }, - }; - - var docs4 = new[] - { - new { _id = 7, title = "Book 7", pages = 80 }, - new { _id = 8, title = "Book 8", pages = 90 }, - }; - - // start the transaction - coll.Session.StartTransaction(); - - Result r = coll.Add(docs1).Execute(); - //WL11843-Core API v1 alignment Changes - Assert.AreEqual(2, r.AffectedItemsCount, "Matching"); - - r = coll.Add(docs2).Execute(); - Assert.AreEqual(2, r.AffectedItemsCount, "Matching"); - - r = coll.Add(docs3).Execute(); - Assert.AreEqual(2, r.AffectedItemsCount, "Matching"); - - // now Rollback - coll.Session.Rollback(); - - // start the transaction - coll.Session.StartTransaction(); - - r = coll.Add(docs4).Execute(); - Assert.AreEqual(2, r.AffectedItemsCount, "Matching"); - - // now Rollback Again - coll.Session.Rollback(); - - var foundDocs = coll.Find().Execute(); - Assert.AreEqual(false, foundDocs.Next(), "Matching"); - - } - - [Test, Description("Test MySQLX plugin Commit Rollback")] - public void CommitRollBack() - { - if (!session.Version.isAtLeast(5, 7, 0)) Assert.Ignore("This test is for MySql 5.7 or higher."); - Collection coll = CreateCollection("test"); - var docs1 = new[] - { - new { _id = 1, title = "Book 1", pages = 20 }, - new { _id = 2, title = "Book 2", pages = 30 }, - }; - - var docs2 = new[] - { - new { _id = 3, title = "Book 3", pages = 40 }, - new { _id = 4, title = "Book 4", pages = 50 }, - }; - - var docs3 = new[] - { - new { _id = 5, title = "Book 5", pages = 60 }, - new { _id = 6, title = "Book 6", pages = 70 }, - }; - - // start the transaction - coll.Session.StartTransaction(); - - Result r = coll.Add(docs1).Execute(); - //WL11843-Core API v1 alignment Changes - Assert.AreEqual(2, r.AffectedItemsCount, "Matching"); - - r = coll.Add(docs2).Execute(); - Assert.AreEqual(2, r.AffectedItemsCount, "Matching"); - - r = coll.Add(docs3).Execute(); - Assert.AreEqual(2, r.AffectedItemsCount, "Matching"); - - //now Commit - coll.Session.Commit(); - // now Rollback - coll.Session.Rollback(); - - var foundDocs = coll.Find().Execute(); - Assert.AreEqual(true, foundDocs.Next(), "Matching"); - Assert.AreEqual(true, foundDocs.Next(), "Matching"); - Assert.AreEqual(true, foundDocs.Next(), "Matching"); - Assert.AreEqual(true, foundDocs.Next(), "Matching"); - Assert.AreEqual(true, foundDocs.Next(), "Matching"); - Assert.AreEqual(true, foundDocs.Next(), "Matching"); - Assert.AreEqual(false, foundDocs.Next(), "Matching"); - - } - - [Test, Description("Test MySQLX plugin RollBack Commit")] - public void RollBackCommit() - { - if (!session.Version.isAtLeast(5, 7, 0)) Assert.Ignore("This test is for MySql 5.7 or higher."); - Collection coll = CreateCollection("test"); - var docs1 = new[] - { - new { _id = 1, title = "Book 1", pages = 20 }, - new { _id = 2, title = "Book 2", pages = 30 }, - }; - - var docs2 = new[] - { - new { _id = 3, title = "Book 3", pages = 40 }, - new { _id = 4, title = "Book 4", pages = 50 }, - }; - - var docs3 = new[] - { - new { _id = 5, title = "Book 5", pages = 60 }, - new { _id = 6, title = "Book 6", pages = 70 }, - }; - - // start the transaction - coll.Session.StartTransaction(); - Result r = coll.Add(docs1).Execute(); - Assert.AreEqual(2, r.AffectedItemsCount, "Matching"); - - // now Rollback - coll.Session.Rollback(); - r = coll.Add(docs2).Execute(); - Assert.AreEqual(2, r.AffectedItemsCount, "Matching"); - r = coll.Add(docs3).Execute(); - Assert.AreEqual(2, r.AffectedItemsCount, "Matching"); - //now Commit - coll.Session.Commit(); - var foundDocs = coll.Find().Execute(); - Assert.AreEqual(true, foundDocs.Next(), "Matching"); - Assert.AreEqual(true, foundDocs.Next(), "Matching"); - Assert.AreEqual(true, foundDocs.Next(), "Matching"); - Assert.AreEqual(true, foundDocs.Next(), "Matching"); - Assert.AreEqual(false, foundDocs.Next(), "Matching"); - - } - - #endregion - - } -} +// Copyright © 2015, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data.MySqlClient; +using MySqlX.XDevAPI; +using MySqlX.XDevAPI.Common; +using MySqlX.XDevAPI.CRUD; +using MySqlX.XDevAPI.Relational; +using NUnit.Framework; +using NUnit.Framework.Legacy; +using System; +using System.Linq; + +namespace MySqlX.Data.Tests +{ + public class TransactionTests : BaseTest + { + private string collName = "collSp"; + + [TearDown] + public void TearDown() => session.Schema.DropCollection(collName); + + [Test] + public void Commit() + { + Collection coll = CreateCollection("test"); + var docs = new[] + { + new { _id = 1, title = "Book 1", pages = 20 }, + new { _id = 2, title = "Book 2", pages = 30 }, + new { _id = 3, title = "Book 3", pages = 40 }, + new { _id = 4, title = "Book 4", pages = 50 }, + }; + + // start the transaction + coll.Session.StartTransaction(); + + Result r = ExecuteAddStatement(coll.Add(docs)); + Assert.That(r.AffectedItemsCount, Is.EqualTo(4)); + + // now roll it back + coll.Session.Commit(); + + var foundDocs = ExecuteFindStatement(coll.Find()); + Assert.That(foundDocs.Next()); + Assert.That(foundDocs.Next()); + Assert.That(foundDocs.Next()); + Assert.That(foundDocs.Next()); + Assert.That(foundDocs.Next(), Is.False); + } + + [Test] + public void Rollback() + { + Collection coll = CreateCollection("test"); + var docs = new[] + { + new { _id = 1, title = "Book 1", pages = 20 }, + new { _id = 2, title = "Book 2", pages = 30 }, + new { _id = 3, title = "Book 3", pages = 40 }, + new { _id = 4, title = "Book 4", pages = 50 }, + }; + + // start the transaction + coll.Session.StartTransaction(); + + Result r = ExecuteAddStatement(coll.Add(docs)); + Assert.That(r.AffectedItemsCount, Is.EqualTo(4)); + + // now roll it back + coll.Session.Rollback(); + + var foundDocs = ExecuteFindStatement(coll.Find()); + Assert.That(foundDocs.Next(), Is.False); + } + + #region Savepoints + + [Test] + public void CreateUnnamedSavepoint() + { + using (var session = MySQLX.GetSession(ConnectionString)) + { + session.StartTransaction(); + + string spName = session.SetSavepoint(); + Assert.That(string.IsNullOrWhiteSpace(spName), Is.False); + + session.Rollback(); + } + } + + [Test] + public void RollbackToSavepoint() + { + using (var session = MySQLX.GetSession(ConnectionString)) + { + var schema = session.GetSchema("test"); + schema.DropCollection("collSP"); + var coll = schema.CreateCollection("collSP"); + + session.StartTransaction(); + + ExecuteAddStatement(coll.Add("{ \"test\": \"test\" }")); + var sp = session.SetSavepoint(); + ExecuteAddStatement(coll.Add("{ \"test\": \"test\" }")); + Assert.That(ExecuteFindStatement(coll.Find()).FetchAll().Count, Is.EqualTo(2)); + session.RollbackTo(sp); + Assert.That(ExecuteFindStatement(coll.Find()).FetchAll(), Has.One.Items); + + session.Rollback(); + } + } + + [Test] + public void ReleaseSavepoint() + { + using (var sessionTest = MySQLX.GetSession(ConnectionString)) + { + var coll = CreateCollection("test"); + sessionTest.StartTransaction(); + ExecuteAddStatement(coll.Add("{ \"test\": \"test\" }")); + var sp = sessionTest.SetSavepoint(); + ExecuteAddStatement(coll.Add("{ \"test2\": \"test2\" }")); + Assert.That(ExecuteFindStatement(coll.Find()).FetchAll().Count, Is.EqualTo(2)); + sessionTest.ReleaseSavepoint(sp); + Assert.That(ExecuteFindStatement(coll.Find()).FetchAll().Count, Is.EqualTo(2)); + sessionTest.Rollback(); + } + } + + [Test] + public void CreateNamedSavepoint() + { + using (var session = MySQLX.GetSession(ConnectionString)) + { + session.StartTransaction(); + + string spName = session.SetSavepoint("mySavedPoint"); + Assert.That(string.IsNullOrWhiteSpace(spName), Is.False); + + session.Rollback(); + } + } + + [Test] + public void RollbackToNamedSavepoint() + { + using (var session = MySQLX.GetSession(ConnectionString)) + { + var schema = session.GetSchema("test"); + schema.DropCollection("collSP"); + var coll = schema.CreateCollection("collSP"); + session.StartTransaction(); + ExecuteAddStatement(coll.Add("{ \"test\": \"test\" }")); + var sp = session.SetSavepoint("mySavedPoint"); + ExecuteAddStatement(coll.Add("{ \"test2\": \"test2\" }")); + Assert.That(ExecuteFindStatement(coll.Find()).FetchAll().Count, Is.EqualTo(2)); + session.RollbackTo(sp); + Assert.That(ExecuteFindStatement(coll.Find()).FetchAll(), Has.One.Items); + session.Rollback(); + } + } + + [Test] + public void ReleaseNamedSavepoint() + { + using (var session = MySQLX.GetSession(ConnectionString)) + { + var schema = session.GetSchema("test"); + schema.DropCollection("test"); + var coll = schema.CreateCollection("test"); + session.StartTransaction(); + ExecuteAddStatement(coll.Add("{ \"test\": \"test\" }")); + var sp = session.SetSavepoint("mySavedPoint"); + ExecuteAddStatement(coll.Add("{ \"test2\": \"test2\" }")); + Assert.That(ExecuteFindStatement(coll.Find()).FetchAll().Count, Is.EqualTo(2)); + session.ReleaseSavepoint(sp); + Assert.That(ExecuteFindStatement(coll.Find()).FetchAll().Count, Is.EqualTo(2)); + session.Rollback(); + } + } + + [Test] + public void NonExistentSavepoint() + { + using (var session = MySQLX.GetSession(ConnectionString)) + { + session.StartTransaction(); + + Exception exception = Assert.Throws(() => session.RollbackTo("nonExistentSavePoint")); + Assert.That(exception.Message, Is.EqualTo("SAVEPOINT nonExistentSavePoint does not exist")); + + exception = Assert.Throws(() => session.ReleaseSavepoint("nonExistentSavePoint")); + Assert.That(exception.Message, Is.EqualTo("SAVEPOINT nonExistentSavePoint does not exist")); + + session.Rollback(); + } + } + + [Test] + public void CreateSavepointWithWeirdNames() + { + using (var session = MySQLX.GetSession(ConnectionString)) + { + string errorMessage = "You have an error in your SQL syntax"; + session.StartTransaction(); + + Exception ex = Assert.Throws(() => session.SetSavepoint("")); + Assert.That(ex.Message, Does.StartWith(errorMessage)); + ex = Assert.Throws(() => session.SetSavepoint(" ")); + Assert.That(ex.Message, Does.StartWith(errorMessage)); + ex = Assert.Throws(() => session.SetSavepoint(null)); + Assert.That(ex.Message, Does.StartWith(errorMessage)); + ex = Assert.Throws(() => session.SetSavepoint("-")); + Assert.That(ex.Message, Does.StartWith(errorMessage)); + ex = Assert.Throws(() => session.SetSavepoint("mysp+")); + Assert.That(ex.Message, Does.StartWith(errorMessage)); + ex = Assert.Throws(() => session.SetSavepoint("3306")); + Assert.That(ex.Message, Does.StartWith(errorMessage)); + + var sp = session.SetSavepoint("_"); + session.RollbackTo(sp); + sp = session.SetSavepoint("mysql3306"); + session.RollbackTo(sp); + + session.Rollback(); + } + } + + [Test] + public void OverwriteSavepoint() + { + using (var session = MySQLX.GetSession(ConnectionString)) + { + var schema = session.GetSchema("test"); + var coll = schema.CreateCollection(collName); + + session.StartTransaction(); + + ExecuteAddStatement(coll.Add("{ \"test\": \"test\" }")); + var sp = session.SetSavepoint("mySP"); + ExecuteAddStatement(coll.Add("{ \"test2\": \"test2\" }")); + sp = session.SetSavepoint("mySP"); + ExecuteAddStatement(coll.Add("{ \"test3\": \"test3\" }")); + sp = session.SetSavepoint("mySP"); + ExecuteAddStatement(coll.Add("{ \"test4\": \"test4\" }")); + sp = session.SetSavepoint("mySP"); + session.RollbackTo(sp); + Assert.That(ExecuteFindStatement(coll.Find()).FetchAll().Count, Is.EqualTo(4)); + + session.Rollback(); + } + } + + [Test] + public void MultipleReleasesForSavepoint() + { + using (var session = MySQLX.GetSession(ConnectionString)) + { + session.StartTransaction(); + + var sp = session.SetSavepoint("mySP"); + session.ReleaseSavepoint(sp); + Exception exception = Assert.Throws(() => session.ReleaseSavepoint(sp)); + Assert.That(exception.Message, Is.EqualTo(string.Format("SAVEPOINT {0} does not exist", sp))); + + session.Rollback(); + } + } + + [Test] + public void RollbackAndReleaseAfterTransactionCommit() + { + using (var sessionTest = MySQLX.GetSession(ConnectionString)) + { + var coll = CreateCollection("collSP"); + sessionTest.StartTransaction(); + var sp = sessionTest.SetSavepoint("mySP"); + ExecuteAddStatement(coll.Add("{ \"test\": \"test\" }")); + sessionTest.Commit(); + Exception exception = Assert.Throws(() => sessionTest.RollbackTo(sp)); + Assert.That(exception.Message, Is.EqualTo(string.Format("SAVEPOINT {0} does not exist", sp))); + exception = Assert.Throws(() => sessionTest.ReleaseSavepoint(sp)); + Assert.That(exception.Message, Is.EqualTo(string.Format("SAVEPOINT {0} does not exist", sp))); + } + } + + [Test] + public void RollbackAndReleaseAfterTransactionRollback() + { + using (var sessionTest = MySQLX.GetSession(ConnectionString)) + { + var coll = CreateCollection("collSP"); + sessionTest.StartTransaction(); + + var sp = sessionTest.SetSavepoint("mySP"); + ExecuteAddStatement(coll.Add("{ \"test\": \"test\" }")); + + sessionTest.Rollback(); + + Exception exception = Assert.Throws(() => sessionTest.RollbackTo(sp)); + Assert.That(exception.Message, Is.EqualTo(string.Format("SAVEPOINT {0} does not exist", sp))); + + exception = Assert.Throws(() => sessionTest.ReleaseSavepoint(sp)); + Assert.That(exception.Message, Is.EqualTo(string.Format("SAVEPOINT {0} does not exist", sp))); + } + } + + #endregion + + #region WL14389 + + [Test, Description("Session Close Transaction")] + public void SessionCloseTransaction() + { + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); + using (Session sessionTest = MySQLX.GetSession(ConnectionString)) + { + Schema db = null; + db = sessionTest.GetSchema("test"); + sessionTest.StartTransaction(); + + if (db.GetCollection("my_collection_1").ExistsInDatabase()) + { + db.DropCollection("my_collection_1"); + } + Collection col = db.CreateCollection("my_collection_1"); + sessionTest.Close(); + Assert.Throws(() => sessionTest.Rollback()); + } + } + + [Test, Description("Valid Commit and Check Warning ")] + public void CommitValidWarning() + { + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); + using (Session sessionPlain = MySQLX.GetSession(ConnectionString)) + { + sessionPlain.SetCurrentSchema("test"); + sessionPlain.SQL("drop table if exists temp").Execute(); + sessionPlain.SQL("CREATE TABLE temp(id INT primary key)").Execute(); + Table table = sessionPlain.Schema.GetTable("temp"); + sessionPlain.StartTransaction(); + table.Insert().Values(5).Execute(); + sessionPlain.Commit(); + Assert.That(table.Count(), Is.EqualTo(1)); + } + } + + /// + /// Bug 23542005 + /// + [Test, Description("Invalid Commit and Check Warning ")] + public void CommitInvalidWarning() + { + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); + using (Session sessionPlain = MySQLX.GetSession(ConnectionString)) + { + sessionPlain.SetCurrentSchema("test"); + sessionPlain.SQL("CREATE TABLE temp(v VARCHAR(4))").Execute(); + Table table = sessionPlain.Schema.GetTable("temp"); + sessionPlain.StartTransaction(); + Assert.Throws(() => sessionPlain.GetSchema("test").GetTable("temp").Insert().Values("abcdef").Execute()); + sessionPlain.Commit(); + Assert.That(table.Count(), Is.EqualTo(0)); + var warnings = sessionPlain.SQL("DROP TABLE IF EXISTS temp1").Execute().Warnings; + Assert.That(warnings.Count > 0); + sessionPlain.Commit(); + } + } + + + [Test, Description("Valid Rollback and Check Warning ")] + public void RollbackValidWarning() + { + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); + using (Session sessionPlain = MySQLX.GetSession(ConnectionString)) + { + sessionPlain.SetCurrentSchema("test"); + sessionPlain.SQL("DROP TABLE IF EXISTS temp").Execute(); + sessionPlain.SQL("CREATE TABLE temp(id INT primary key)").Execute(); + Table table = sessionPlain.Schema.GetTable("temp"); + sessionPlain.StartTransaction(); + var res = table.Insert().Values(5).Execute(); + sessionPlain.Rollback(); + Assert.That(table.Count(), Is.EqualTo(0)); + Assert.That(res.Warnings.Count, Is.EqualTo(0)); + } + } + + /// + /// Bug 23542005 + /// + [Test, Description("Invalid Rollback and Check Warning ")] + public void RollbackInvalidWarning() + { + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); + using (Session sessionPlain = MySQLX.GetSession(ConnectionString)) + { + sessionPlain.SetCurrentSchema("test"); + sessionPlain.SQL("DROP TABLE IF EXISTS temp").Execute(); + sessionPlain.SQL("CREATE TABLE temp(v VARCHAR(4))").Execute(); + Table table = sessionPlain.Schema.GetTable("temp"); + sessionPlain.StartTransaction(); + Assert.Throws(() => sessionPlain.GetSchema("test").GetTable("temp").Insert().Values("abcdef").Execute()); + sessionPlain.Rollback(); + Assert.That(table.Count(), Is.EqualTo(0)); + var res = sessionPlain.SQL("DROP TABLE IF EXISTS temp1").Execute(); + Assert.That(res.Warnings.Count > 0); + } + } + + /// + /// Bug 23542005 + /// + [Test, Description("Commit Rollback Invalid Warning")] + public void CommitRollbackInvalidWarning() + { + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); + Collection coll = CreateCollection("test"); + var docs1 = new[] + { + new { _id = 1, title = "Book 1", pages = 20 }, + new { _id = 2, title = "Book 2", pages = 30 }, + }; + + var docs2 = new[] + { + new { _id = 3, title = "Book 3", pages = 40 }, + new { _id = 4, title = "Book 4", pages = 50 }, + }; + + var docs3 = new[] + + { + new { _id = 5, title = "Book 5", pages = 60 }, + new { _id = 6, title = "Book 6", pages = 70 }, + }; + + // start the transaction + coll.Session.StartTransaction(); + + Result r = coll.Add(docs1).Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(2)); + + r = coll.Add(docs2).Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(2)); + + r = coll.Add(docs3).Execute(); + Assert.Throws(() => coll.Add(docs3).Execute()); + coll.Session.Commit(); + Assert.That(coll.Count(), Is.EqualTo(6)); + // now Rollback + coll.Session.Rollback(); + Assert.That(coll.Count(), Is.EqualTo(6)); + + var foundDocs = coll.Find().Execute(); + Assert.That(foundDocs, Is.Not.Null); + } + + [Test, Description("MySQLX plugin Warnings")] + public void Warnings() + { + if (!session.Version.isAtLeast(8, 0, 0)) return; + using (Session sessionTest = MySQLX.GetSession(ConnectionString)) + { + Schema schema = sessionTest.GetSchema("test"); + Collection coll = CreateCollection("test"); + + Result r = coll.Add("{ \"foo\": 1 }").Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(1)); + Assert.That(coll.Count(), Is.EqualTo(1)); + r = coll.Add("{ \"fool\": 2 }").Execute(); + Assert.That(r.Warnings.Count, Is.EqualTo(0)); + r = coll.Add("{ \"fool\": 10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 }").Execute(); + Assert.That(r.Warnings.Count, Is.EqualTo(0)); + + sessionTest.SQL("use test").Execute(); + sessionTest.SQL("CREATE TABLE nontrac(id INT primary key) ENGINE=MyISAM;").Execute(); + Table table = schema.GetTable("nontrac"); + sessionTest.StartTransaction(); + table.Insert().Values(5).Execute(); + + schema = sessionTest.GetSchema(schemaName); + sessionTest.StartTransaction(); + + var res = sessionTest.SQL("drop table if exists t1, t2").Execute(); + Assert.That(res.Warnings.Count, Is.EqualTo(2)); + Assert.That(res.Warnings[0].Code, Is.EqualTo(1051)); + + Assert.That(res.Warnings[1].Code, Is.EqualTo(1051)); + + res = sessionTest.SQL("create table t1 (a int) engine=innodb").Execute(); + Assert.That(res.Warnings.Count, Is.EqualTo(0)); + res = sessionTest.SQL("create table t2 (a int) engine=myisam").Execute(); + Assert.That(res.Warnings.Count, Is.EqualTo(0)); + res = sessionTest.SQL("insert into t1 values(1)").Execute(); + Assert.That(res.Warnings.Count, Is.EqualTo(0)); + res = sessionTest.SQL("insert into t2 select * from t1").Execute(); + Assert.That(res.Warnings.Count, Is.EqualTo(1)); + sessionTest.Commit(); + + } + } + + //Savepoints + [Test, Description("Rollback to same savepoint multiple times")] + public void RollbackToSameSavepoint() + { + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); + + var col = CreateCollection("my_collection"); + session.StartTransaction(); + object[] data = new object[] + { + new { _id = 1, title = "Book 1", pages = 30 }, + new { _id = 2, title = "Book 2", pages = 50 }, + }; + Result result = col.Add(data).Execute(); + var sp = session.SetSavepoint("SavePoint1"); + data = new object[] + { + new { _id = 3, title = "Book 3", pages = 30 }, + new { _id = 4, title = "Book 4", pages = 50 }, + }; + result = col.Add(data).Execute(); + var sp1 = session.SetSavepoint("SavePoint2"); + + session.RollbackTo(sp); + data = new object[] + { + new { _id = 5, title = "Book 5", pages = 30 }, + new { _id = 6, title = "Book 6", pages = 50 }, + }; + result = col.Add(data).Execute(); + session.RollbackTo(sp); + var doc = col.Find().Execute(); + var docs = doc.FetchAll().Count(); + Assert.That(docs, Is.EqualTo(2)); + } + + + [Test, Description("Releasing a savepoint multiple times")] + public void ReleaseSavepointMoreThanOnce() + { + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); + using (Session sessionTest = MySQLX.GetSession(ConnectionString)) + { + var col = CreateCollection("my_collection"); + sessionTest.StartTransaction(); + object[] data = new object[] + { + new { _id = 1, title = "Book 1", pages = 30 }, + new { _id = 2, title = "Book 2", pages = 50 }, + }; + Result result = col.Add(data).Execute(); + var sp = sessionTest.SetSavepoint("SavePoint1"); + data = new object[] + { + new { _id = 3, title = "Book 3", pages = 30 }, + new { _id = 4, title = "Book 4", pages = 50 }, + }; + result = col.Add(data).Execute(); + sessionTest.ReleaseSavepoint(sp); + data = new object[] + { + new { _id = 5, title = "Book 5", pages = 30 }, + new { _id = 6, title = "Book 6", pages = 50 }, + }; + result = col.Add(data).Execute(); + var ex = Assert.Throws(() => sessionTest.ReleaseSavepoint(sp)); + sessionTest.Rollback(); + } + } + + [TestCase("Savepoint1", "Savepoint2")] + [TestCase("", "")] + [Description("Creating multiple savepoints with SetSavepoint([name]) and rolling back to a specific one")] + public void MultipleSavepointsAndRollback(string savePoint1, string savePoint2) + { + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); + var col = CreateCollection("my_collection"); + session.StartTransaction(); + object[] data = new object[] + { + new { _id = 1, title = "Book 1", pages = 30 }, + new { _id = 2, title = "Book 2", pages = 50 }, + }; + Result result = col.Add(data).Execute(); + var sp = string.IsNullOrEmpty(savePoint1) ? session.SetSavepoint() : session.SetSavepoint(savePoint1); + data = new object[] + { + new { _id = 3, title = "Book 3", pages = 30 }, + new { _id = 4, title = "Book 4", pages = 50 }, + }; + result = col.Add(data).Execute(); + var sp2 = string.IsNullOrEmpty(savePoint2) ? session.SetSavepoint() : session.SetSavepoint(savePoint2); + session.RollbackTo(sp); + var doc = col.Find().Execute(); + var docs = doc.FetchAll().Count(); + Assert.That(docs, Is.EqualTo(2)); + } + + [Test, Description("Test creating a savepoint without starting a transaction")] + public void SavepointWithoutTransaction() + { + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); + var col = CreateCollection("my_collection"); + object[] data = new object[] + { + new { _id = 1, title = "Book 1", pages = 30 }, + new { _id = 2, title = "Book 2", pages = 50 }, + }; + Result result = col.Add(data).Execute(); + var sp = ""; + sp = session.SetSavepoint("SP"); + data = new object[] + { + new { _id =3, title = "Book 3", pages = 30 }, + new { _id =4, title = "Book 4", pages = 50 }, + }; + result = col.Add(data).Execute(); + var sp1 = session.SetSavepoint("SP"); + Assert.Throws(() => session.ReleaseSavepoint(sp1)); + } + + [Test, Description("Validate that further savepoints get released once you release a preceding savepoint")] + public void ValidateSavepointsReleased() + { + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); + var col = CreateCollection("my_collection"); + session.StartTransaction(); + + object[] data = new object[] + { + new { _id = 1, title = "Book 1", pages = 30 }, + new { _id = 2, title = "Book 2", pages = 50 }, + }; + Result result = col.Add(data).Execute(); + var sp = session.SetSavepoint("SavePoint1"); + data = new object[] + { + new { _id = 3, title = "Book 3", pages = 30 }, + new { _id = 4, title = "Book 4", pages = 50 }, + }; + result = col.Add(data).Execute(); + var sp1 = session.SetSavepoint("SavePoint2"); + session.ReleaseSavepoint(sp); + Assert.Throws(() => session.ReleaseSavepoint(sp1)); + + var doc = col.Find().Execute(); + var docs = doc.FetchAll().Count(); + Assert.That(docs, Is.EqualTo(4)); + + } + + + [Test, Description("Validate Nested-transactions with multiple savepoints")] + public void NestedTransactions() + { + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); + var col = CreateCollection("my_collection"); + session.StartTransaction(); + object[] data = new object[] + { + new { _id = 1, title = "Book 1", pages = 30 }, + new { _id = 2, title = "Book 2", pages = 50 }, + }; + Result result = col.Add(data).Execute(); + var sp = session.SetSavepoint("Savepoint1"); + session.StartTransaction(); + + data = new object[] + { + new { _id = 3, title = "Book 3", pages = 30 }, + new { _id = 4, title = "Book 4", pages = 50 }, + }; + result = col.Add(data).Execute(); + var sp1 = session.SetSavepoint("Savepoint2"); + session.Rollback(); + var doc = col.Find().Execute(); + var docs = doc.FetchAll().Count(); + Assert.That(docs, Is.EqualTo(2)); + } + + [Test, Description("Test the behaviour of Savepoints created immediately after one another")] + public void SavepointsCreatedImmediately() + { + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); + var col = CreateCollection("my_collection"); + session.StartTransaction(); + object[] data = new object[] + { + new { _id = 1, title = "Book 1", pages = 30 }, + new { _id = 2, title = "Book 2", pages = 50 }, + }; + Result result = col.Add(data).Execute(); + var sp = session.SetSavepoint("Savepoint1"); + var sp1 = session.SetSavepoint("Savepoint2"); + session.RollbackTo(sp); + var doc = col.Find().Execute(); + var docs = doc.FetchAll().Count(); + Assert.That(docs, Is.EqualTo(2)); + } + + [Test, Description("Test MySQLX plugin Commit After Commit")] + public void CommitAfterCommit() + { + Assume.That(session.Version.isAtLeast(5, 7, 0), "This test is for MySql 5.7 or higher"); + Collection coll = CreateCollection("test"); + var docs1 = new[] + { + new { _id = 1, title = "Book 1", pages = 20 }, + new { _id = 2, title = "Book 2", pages = 30 }, + }; + + var docs2 = new[] + { + new { _id = 3, title = "Book 3", pages = 40 }, + new { _id = 4, title = "Book 4", pages = 50 }, + }; + + var docs3 = new[] + { + new { _id = 5, title = "Book 5", pages = 60 }, + new { _id = 6, title = "Book 6", pages = 70 }, + }; + + var docs4 = new[] + { + new { _id = 7, title = "Book 7", pages = 80 }, + new { _id = 8, title = "Book 8", pages = 90 }, + }; + + // start the transaction + coll.Session.StartTransaction(); + + Result r = coll.Add(docs1).Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(2), "Matching"); + + r = coll.Add(docs2).Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(2), "Matching"); + + r = coll.Add(docs3).Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(2), "Matching"); + + // now Commit + coll.Session.Commit(); + // start the transaction + coll.Session.StartTransaction(); + r = coll.Add(docs4).Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(2), "Matching"); + // now Commit Again + coll.Session.Commit(); + + var foundDocs = coll.Find().Execute(); + Assert.That(foundDocs.Next(), Is.EqualTo(true), "Matching"); + Assert.That(foundDocs.Next(), Is.EqualTo(true), "Matching"); + Assert.That(foundDocs.Next(), Is.EqualTo(true), "Matching"); + Assert.That(foundDocs.Next(), Is.EqualTo(true), "Matching"); + Assert.That(foundDocs.Next(), Is.EqualTo(true), "Matching"); + Assert.That(foundDocs.Next(), Is.EqualTo(true), "Matching"); + Assert.That(foundDocs.Next(), Is.EqualTo(true), "Matching"); + Assert.That(foundDocs.Next(), Is.EqualTo(true), "Matching"); + Assert.That(foundDocs.Next(), Is.EqualTo(false), "Matching"); + + } + + [Test, Description("Test MySQLX plugin Rollback Multiple")] + public void RollBackMultiple() + { + Assume.That(session.Version.isAtLeast(5, 7, 0), "This test is for MySql 5.7 or higher"); + Collection coll = CreateCollection("test"); + var docs1 = new[] + { + new { _id = 1, title = "Book 1", pages = 20 }, + new { _id = 2, title = "Book 2", pages = 30 }, + }; + + var docs2 = new[] + { + new { _id = 3, title = "Book 3", pages = 40 }, + new { _id = 4, title = "Book 4", pages = 50 }, + }; + + var docs3 = new[] + { + new { _id = 5, title = "Book 5", pages = 60 }, + new { _id = 6, title = "Book 6", pages = 70 }, + }; + + // start the transaction + coll.Session.StartTransaction(); + + Result r = coll.Add(docs1).Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(2), "Matching"); + + r = coll.Add(docs2).Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(2), "Matching"); + + r = coll.Add(docs3).Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(2), "Matching"); + + // now Rollback + coll.Session.Rollback(); + + var foundDocs = coll.Find().Execute(); + Assert.That(foundDocs.Next(), Is.EqualTo(false), "Matching"); + + } + + [Test, Description("Test MySQLX plugin Rollback after RollBack")] + public void RollBackAfterRollBack() + { + Assume.That(session.Version.isAtLeast(8, 0, 3), "This test is for MySql 8.0.3 or higher"); + Collection coll = CreateCollection("test"); + var docs1 = new[] + { + new { _id = 1, title = "Book 1", pages = 20 }, + new { _id = 2, title = "Book 2", pages = 30 }, + }; + + var docs2 = new[] + { + new { _id = 3, title = "Book 3", pages = 40 }, + new { _id = 4, title = "Book 4", pages = 50 }, + }; + + var docs3 = new[] + { + new { _id = 5, title = "Book 5", pages = 60 }, + new { _id = 6, title = "Book 6", pages = 70 }, + }; + + var docs4 = new[] + { + new { _id = 7, title = "Book 7", pages = 80 }, + new { _id = 8, title = "Book 8", pages = 90 }, + }; + + // start the transaction + coll.Session.StartTransaction(); + + Result r = coll.Add(docs1).Execute(); + //WL11843-Core API v1 alignment Changes + Assert.That(r.AffectedItemsCount, Is.EqualTo(2), "Matching"); + + r = coll.Add(docs2).Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(2), "Matching"); + + r = coll.Add(docs3).Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(2), "Matching"); + + // now Rollback + coll.Session.Rollback(); + + // start the transaction + coll.Session.StartTransaction(); + + r = coll.Add(docs4).Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(2), "Matching"); + + // now Rollback Again + coll.Session.Rollback(); + + var foundDocs = coll.Find().Execute(); + Assert.That(foundDocs.Next(), Is.EqualTo(false), "Matching"); + + } + + [Test, Description("Test MySQLX plugin Commit Rollback")] + public void CommitRollBack() + { + Assume.That(session.Version.isAtLeast(5, 7, 0), "This test is for MySql 5.7 or higher"); + Collection coll = CreateCollection("test"); + var docs1 = new[] + { + new { _id = 1, title = "Book 1", pages = 20 }, + new { _id = 2, title = "Book 2", pages = 30 }, + }; + + var docs2 = new[] + { + new { _id = 3, title = "Book 3", pages = 40 }, + new { _id = 4, title = "Book 4", pages = 50 }, + }; + + var docs3 = new[] + { + new { _id = 5, title = "Book 5", pages = 60 }, + new { _id = 6, title = "Book 6", pages = 70 }, + }; + + // start the transaction + coll.Session.StartTransaction(); + + Result r = coll.Add(docs1).Execute(); + //WL11843-Core API v1 alignment Changes + Assert.That(r.AffectedItemsCount, Is.EqualTo(2), "Matching"); + + r = coll.Add(docs2).Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(2), "Matching"); + + r = coll.Add(docs3).Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(2), "Matching"); + + //now Commit + coll.Session.Commit(); + // now Rollback + coll.Session.Rollback(); + + var foundDocs = coll.Find().Execute(); + Assert.That(foundDocs.Next(), Is.EqualTo(true), "Matching"); + Assert.That(foundDocs.Next(), Is.EqualTo(true), "Matching"); + Assert.That(foundDocs.Next(), Is.EqualTo(true), "Matching"); + Assert.That(foundDocs.Next(), Is.EqualTo(true), "Matching"); + Assert.That(foundDocs.Next(), Is.EqualTo(true), "Matching"); + Assert.That(foundDocs.Next(), Is.EqualTo(true), "Matching"); + Assert.That(foundDocs.Next(), Is.EqualTo(false), "Matching"); + + } + + [Test, Description("Test MySQLX plugin RollBack Commit")] + public void RollBackCommit() + { + Assume.That(session.Version.isAtLeast(5, 7, 0), "This test is for MySql 5.7 or higher"); + Collection coll = CreateCollection("test"); + var docs1 = new[] + { + new { _id = 1, title = "Book 1", pages = 20 }, + new { _id = 2, title = "Book 2", pages = 30 }, + }; + + var docs2 = new[] + { + new { _id = 3, title = "Book 3", pages = 40 }, + new { _id = 4, title = "Book 4", pages = 50 }, + }; + + var docs3 = new[] + { + new { _id = 5, title = "Book 5", pages = 60 }, + new { _id = 6, title = "Book 6", pages = 70 }, + }; + + // start the transaction + coll.Session.StartTransaction(); + Result r = coll.Add(docs1).Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(2), "Matching"); + + // now Rollback + coll.Session.Rollback(); + r = coll.Add(docs2).Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(2), "Matching"); + r = coll.Add(docs3).Execute(); + Assert.That(r.AffectedItemsCount, Is.EqualTo(2), "Matching"); + //now Commit + coll.Session.Commit(); + var foundDocs = coll.Find().Execute(); + Assert.That(foundDocs.Next(), Is.EqualTo(true), "Matching"); + Assert.That(foundDocs.Next(), Is.EqualTo(true), "Matching"); + Assert.That(foundDocs.Next(), Is.EqualTo(true), "Matching"); + Assert.That(foundDocs.Next(), Is.EqualTo(true), "Matching"); + Assert.That(foundDocs.Next(), Is.EqualTo(false), "Matching"); + + } + + #endregion + + } +} diff --git a/MySQL.Data/tests/MySqlX.Data.Tests/UnixSocketsTests.cs b/MySQL.Data/tests/MySqlX.Data.Tests/UnixSocketsTests.cs index c0c2bda15..58ff81014 100644 --- a/MySQL.Data/tests/MySqlX.Data.Tests/UnixSocketsTests.cs +++ b/MySQL.Data/tests/MySqlX.Data.Tests/UnixSocketsTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2017, 2022, Oracle and/or its affiliates. +// Copyright © 2017, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -30,6 +30,7 @@ using MySql.Data.MySqlClient; using MySqlX.XDevAPI; using NUnit.Framework; +using NUnit.Framework.Legacy; using System; namespace MySqlX.Data.Tests @@ -51,14 +52,14 @@ public void ConnectionWithUriConnectionString() using (var session = MySQLX.GetSession("mysqlx://root:@" + defaultUnixSocket + "?protocol=unix&sslmode=none")) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); - Assert.AreEqual(defaultUnixSocket, session.Settings.Server); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + Assert.That(session.Settings.Server, Is.EqualTo(defaultUnixSocket)); } using (var session = MySQLX.GetSession("mysqlx://root:@" + defaultUnixSocket.Replace("/", "%2F") + "?protocol=unix&sslmode=none")) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); - Assert.AreEqual(defaultUnixSocket, session.Settings.Server); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + Assert.That(session.Settings.Server, Is.EqualTo(defaultUnixSocket)); } } @@ -70,8 +71,8 @@ public void ConnectionWithUriConnectionStringIncludingSchema() using (var session = MySQLX.GetSession($"mysqlx://root:@({defaultUnixSocket})/mysql?protocol=unix&sslmode=none")) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); - Assert.AreEqual(defaultUnixSocket, session.Settings.Server); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + Assert.That(session.Settings.Server, Is.EqualTo(defaultUnixSocket)); } } @@ -83,14 +84,14 @@ public void ConnectionWithParenthesisEnclosedSockets() using (var session = MySQLX.GetSession($"mysqlx://{RootUser}:@({defaultUnixSocket})?protocol=unix&sslmode=none")) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); - Assert.AreEqual(defaultUnixSocket, session.Settings.Server); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + Assert.That(session.Settings.Server, Is.EqualTo(defaultUnixSocket)); } using (var session = MySQLX.GetSession($"server=({defaultUnixSocket});uid={RootUser};protocol=unix;sslmode=none")) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); - Assert.AreEqual(defaultUnixSocket, session.Settings.Server); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + Assert.That(session.Settings.Server, Is.EqualTo(defaultUnixSocket)); } using (var session = MySQLX.GetSession(new @@ -101,8 +102,8 @@ public void ConnectionWithParenthesisEnclosedSockets() sslmode = MySqlSslMode.Disabled })) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); - Assert.AreEqual(defaultUnixSocket, session.Settings.Server); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + Assert.That(session.Settings.Server, Is.EqualTo(defaultUnixSocket)); } } @@ -114,8 +115,8 @@ public void ConnectionWithBasicConnectionString() using (var session = MySQLX.GetSession($"server={defaultUnixSocket};uid={RootUser};protocol=unixsocket;sslmode=none")) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); - Assert.AreEqual(defaultUnixSocket, session.Settings.Server); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + Assert.That(session.Settings.Server, Is.EqualTo(defaultUnixSocket)); } } @@ -133,8 +134,8 @@ public void ConnectionWithAnonymousObject() sslmode = MySqlSslMode.Disabled })) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); - Assert.AreEqual(defaultUnixSocket, session.Settings.Server); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + Assert.That(session.Settings.Server, Is.EqualTo(defaultUnixSocket)); } } @@ -155,50 +156,50 @@ public void Failover() using (var session = MySQLX.GetSession($"server=/tmp/mysql.sock1, (/tmp/mysql.sock2) ,(%2Ftmp%2Fmysql.sock3) ,{defaultUnixSocket};uid={RootUser};protocol=unix;sslmode=none;")) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); - Assert.AreEqual(defaultUnixSocket, session.Settings.Server); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + Assert.That(session.Settings.Server, Is.EqualTo(defaultUnixSocket)); } using (var session = MySQLX.GetSession($"server=(address=/tmp/mysql.sock1, priority=100),(address=(/tmp/mysql.sock2),priority=99),(address=(%2tmp%2mysql.sock3),priority=98),(address={defaultUnixSocket},priority=97);uid={RootUser};protocol=unix;sslmode=none;")) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); - Assert.AreEqual(defaultUnixSocket, session.Settings.Server); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + Assert.That(session.Settings.Server, Is.EqualTo(defaultUnixSocket)); } using (var session = MySQLX.GetSession($"server=(address={defaultUnixSocket},priority=100);uid={RootUser};protocol=unix;sslmode=none;")) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); - Assert.AreEqual(defaultUnixSocket, session.Settings.Server); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + Assert.That(session.Settings.Server, Is.EqualTo(defaultUnixSocket)); } using (var session = MySQLX.GetSession($"server=(address=({defaultUnixSocket}),priority=100);uid={RootUser};protocol=unix;sslmode=none;")) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); - Assert.AreEqual(defaultUnixSocket, session.Settings.Server); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + Assert.That(session.Settings.Server, Is.EqualTo(defaultUnixSocket)); } using (var session = MySQLX.GetSession($"mysqlx://{RootUser}:@[./tmp/mysql.sock, (../tmp/mysql.sock) ,(%2Ftmpsocket%2Fmysql.sock) , {defaultUnixSocket}]?protocol=unix&sslmode=none")) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); - Assert.AreEqual(defaultUnixSocket, session.Settings.Server); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + Assert.That(session.Settings.Server, Is.EqualTo(defaultUnixSocket)); } using (var session = MySQLX.GetSession($"mysqlx://{RootUser}:@[(address=./tmp/mysql.sock,priority=100),(address=(../tmp/mysql.sock),priority=99),(address=(%2tmpsocket%2mysql.sock),priority=98),(address={defaultUnixSocket},priority=97)]?protocol=unix&sslmode=none")) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); - Assert.AreEqual(defaultUnixSocket, session.Settings.Server); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + Assert.That(session.Settings.Server, Is.EqualTo(defaultUnixSocket)); } using (var session = MySQLX.GetSession($"mysqlx://{RootUser}:@[(address={defaultUnixSocket},priority=100)]?protocol=unix&sslmode=none")) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); - Assert.AreEqual(defaultUnixSocket, session.Settings.Server); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + Assert.That(session.Settings.Server, Is.EqualTo(defaultUnixSocket)); } using (var session = MySQLX.GetSession($"mysqlx://{RootUser}:@[(address=({defaultUnixSocket}),priority=100)]?protocol=unix&sslmode=none")) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); - Assert.AreEqual(defaultUnixSocket, session.Settings.Server); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + Assert.That(session.Settings.Server, Is.EqualTo(defaultUnixSocket)); } using (var session = MySQLX.GetSession(new @@ -209,8 +210,8 @@ public void Failover() sslmode = MySqlSslMode.Disabled })) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); - Assert.AreEqual(defaultUnixSocket, session.Settings.Server); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + Assert.That(session.Settings.Server, Is.EqualTo(defaultUnixSocket)); } using (var session = MySQLX.GetSession(new @@ -221,8 +222,8 @@ public void Failover() sslmode = MySqlSslMode.Disabled })) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); - Assert.AreEqual(defaultUnixSocket, session.Settings.Server); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + Assert.That(session.Settings.Server, Is.EqualTo(defaultUnixSocket)); } using (var session = MySQLX.GetSession(new @@ -233,8 +234,8 @@ public void Failover() sslmode = MySqlSslMode.Disabled })) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); - Assert.AreEqual(defaultUnixSocket, session.Settings.Server); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + Assert.That(session.Settings.Server, Is.EqualTo(defaultUnixSocket)); } using (var session = MySQLX.GetSession(new @@ -245,8 +246,8 @@ public void Failover() sslmode = MySqlSslMode.Disabled })) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); - Assert.AreEqual(defaultUnixSocket, session.Settings.Server); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + Assert.That(session.Settings.Server, Is.EqualTo(defaultUnixSocket)); } } } diff --git a/MySQL.Data/tests/MySqlX.Data.Tests/XAuth.cs b/MySQL.Data/tests/MySqlX.Data.Tests/XAuth.cs index 1dd754717..71d5c655f 100644 --- a/MySQL.Data/tests/MySqlX.Data.Tests/XAuth.cs +++ b/MySQL.Data/tests/MySqlX.Data.Tests/XAuth.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2021, 2022, Oracle and/or its affiliates. +// Copyright © 2021, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -30,6 +30,7 @@ using MySql.Data.MySqlClient; using MySqlX.XDevAPI; using NUnit.Framework; +using NUnit.Framework.Legacy; using System; namespace MySqlX.Data.Tests @@ -41,33 +42,33 @@ public class XAuth : BaseTest [Property("Category", "Security")] public void DefaultAuthNullPlugin() { - if (!Platform.IsWindows()) Assert.Ignore("Check for Linux OS"); - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("Test available only to MySQL Server +8.0.11"); + Assume.That(Platform.IsWindows(), "Check For Linux OS"); + Assume.That(session.Version.isAtLeast(8, 4, 0), "This test is for MySql 8.4.0 or higher"); - string pluginName = null;//default plugin + string pluginName = "caching_sha2_password";//default plugin MySqlConnectionStringBuilder builder = new MySqlConnectionStringBuilder(ConnectionString); builder.UserID = "testDefaultPlugin"; builder.Password = "test"; CreateUser(builder.UserID, builder.Password, pluginName); string connectionString = null, connectionStringUri = null; - string defaultAuthPlugin = session.SQL("SHOW VARIABLES LIKE 'default_authentication_plugin'").Execute().FetchAll()[0][1].ToString(); + string defaultAuthPlugin = session.SQL("SHOW VARIABLES LIKE 'authentication_policy'").Execute().FetchAll()[0][1].ToString().Split(',')[0] == "*" ? "caching_sha2_password" : ""; //Connection String connectionString = $"server={Host};user={builder.UserID};port={XPort};password={builder.Password}"; using (var session1 = MySQLX.GetSession(connectionString)) { - Assert.AreEqual(MySqlAuthenticationMode.PLAIN, session1.Settings.Auth); + Assert.That(session1.Settings.Auth, Is.EqualTo(MySqlAuthenticationMode.PLAIN)); var result = session1.SQL("SHOW SESSION STATUS LIKE 'Mysqlx_ssl_version';").Execute().FetchAll(); - Assert.True(result[0][1].ToString().Contains("TLSv1")); + Assert.That(result[0][1].ToString().Contains("TLSv1")); } - connectionString = connectionString + ";ssl-mode=none"; + connectionString = connectionString + ";sslmode=none;"; using (var session1 = MySQLX.GetSession(connectionString)) - Assert.AreEqual(defaultAuthPlugin == "mysql_native_password" ? MySqlAuthenticationMode.MYSQL41 : MySqlAuthenticationMode.SHA256_MEMORY, session1.Settings.Auth); + Assert.That(session1.Settings.Auth, Is.EqualTo(defaultAuthPlugin == "mysql_native_password" ? MySqlAuthenticationMode.MYSQL41 : MySqlAuthenticationMode.SHA256_MEMORY)); connectionString = $"server={Host};user={builder.UserID};port={XPort};password={builder.Password};ssl-mode=VerifyCA;ssl-ca={sslCa};ssl-ca-pwd=pass;"; using (var session1 = MySQLX.GetSession(connectionString)) - Assert.AreEqual(MySqlAuthenticationMode.PLAIN, session1.Settings.Auth); + Assert.That(session1.Settings.Auth, Is.EqualTo(MySqlAuthenticationMode.PLAIN)); //invalid values connectionString = $"server={Host};user={builder.UserID};port={XPort};password={builder.Password};ssl-mode=required;auth=shaa256memory"; @@ -78,21 +79,21 @@ public void DefaultAuthNullPlugin() builder.Server + ":" + XPort; using (var session1 = MySQLX.GetSession(connectionStringUri)) { - Assert.AreEqual(MySqlAuthenticationMode.PLAIN, session1.Settings.Auth); + Assert.That(session1.Settings.Auth, Is.EqualTo(MySqlAuthenticationMode.PLAIN)); var result = session1.SQL("SHOW SESSION STATUS LIKE 'Mysqlx_ssl_version';").Execute().FetchAll(); - Assert.True(result[0][1].ToString().Contains("TLSv1")); + Assert.That(result[0][1].ToString().Contains("TLSv1")); } connectionStringUri = connectionStringUri + "?sslmode=none"; using (var session1 = MySQLX.GetSession(connectionStringUri)) - Assert.AreEqual(defaultAuthPlugin == "mysql_native_password" ? MySqlAuthenticationMode.MYSQL41 : MySqlAuthenticationMode.SHA256_MEMORY, session1.Settings.Auth); + Assert.That(session1.Settings.Auth, Is.EqualTo(defaultAuthPlugin == "mysql_native_password" ? MySqlAuthenticationMode.MYSQL41 : MySqlAuthenticationMode.SHA256_MEMORY)); //Anonymous Object using (var session1 = MySQLX.GetSession(new { server = builder.Server, port = XPort, user = builder.UserID, password = builder.Password })) { - Assert.AreEqual(MySqlAuthenticationMode.PLAIN, session1.Settings.Auth); + Assert.That(session1.Settings.Auth, Is.EqualTo(MySqlAuthenticationMode.PLAIN)); var result = session1.SQL("SHOW SESSION STATUS LIKE 'Mysqlx_ssl_version';").Execute().FetchAll(); - Assert.True(result[0][1].ToString().Contains("TLSv1")); + Assert.That(result[0][1].ToString().Contains("TLSv1")); } using (var session1 = MySQLX.GetSession( @@ -104,32 +105,32 @@ public void DefaultAuthNullPlugin() sslmode = MySqlSslMode.Disabled, password = builder.Password })) - Assert.AreEqual(defaultAuthPlugin == "mysql_native_password" ? MySqlAuthenticationMode.MYSQL41 : MySqlAuthenticationMode.SHA256_MEMORY, session1.Settings.Auth); + Assert.That(session1.Settings.Auth, Is.EqualTo(defaultAuthPlugin == "mysql_native_password" ? MySqlAuthenticationMode.MYSQL41 : MySqlAuthenticationMode.SHA256_MEMORY)); ExecuteSQL("flush privileges"); connectionString = $"server={Host};user={builder.UserID};port={XPort};password={builder.Password};ssl-mode=none"; if (defaultAuthPlugin == "mysql_native_password") - Assert.NotNull(MySQLX.GetSession(connectionString)); + Assert.That(MySQLX.GetSession(connectionString), Is.Not.Null); else Assert.Throws(() => MySQLX.GetSession(connectionString)); //URI connectionStringUri = $"mysqlx://{builder.UserID}:{builder.Password}@{builder.Server}:{XPort}?sslmode=none"; if (defaultAuthPlugin == "mysql_native_password") - Assert.NotNull(MySQLX.GetSession(connectionStringUri)); + Assert.That(MySQLX.GetSession(connectionStringUri), Is.Not.Null); else Assert.Throws(() => MySQLX.GetSession(connectionStringUri)); //Anonymous Object if (defaultAuthPlugin == "mysql_native_password") - Assert.NotNull(MySQLX.GetSession(new + Assert.That(MySQLX.GetSession(new { server = Host, port = XPort, user = builder.UserID, sslmode = MySqlSslMode.Disabled, password = builder.Password - })); + }), Is.Not.Null); else Assert.Throws(() => MySQLX.GetSession(new { @@ -145,7 +146,7 @@ public void DefaultAuthNullPlugin() [Property("Category", "Security")] public void DefaultAuthPublicKeyRetrieval() { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("Test available only to MySQL Server +8.0.11"); + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); string pluginName = "caching_sha2_password";//default plugin MySqlConnectionStringBuilder builder = new MySqlConnectionStringBuilder(ConnectionString); @@ -197,11 +198,9 @@ public void DefaultAuthPublicKeyRetrieval() [Test, Description("User selects DEFAULT as authentication mechanism-mysql_native_password user,ssl mode default,fresh connection")] public void MySqlNativePlugin() { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("Test available only to MySQL Server +8.0.11"); - - var counter = session.SQL("SELECT count(*) FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME = 'caching_sha2_password'").Execute().FetchOne(); - if (Convert.ToInt32(counter[0]) <= 0) - Assert.Ignore("The caching_sha2_password plugin isn't available."); + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); + Assume.That(Check_Plugin_Enabled("mysql_native_password"), "mysql_native_password plugin must be enabled on the server to run this test."); + Assume.That(Check_Plugin_Enabled("caching_sha2_password"), "The caching_sha2_password plugin isn't available."); string pluginName = "mysql_native_password";//mysql_native_password plugin MySqlConnectionStringBuilder builder = new MySqlConnectionStringBuilder(ConnectionString); @@ -212,29 +211,29 @@ public void MySqlNativePlugin() //Connection String connectionString = $"server={Host};user={builder.UserID};port={XPort};password={builder.Password}"; using (var session1 = MySQLX.GetSession(connectionString)) - Assert.AreEqual(MySqlAuthenticationMode.PLAIN, session1.Settings.Auth); + Assert.That(session1.Settings.Auth, Is.EqualTo(MySqlAuthenticationMode.PLAIN)); connectionString += ";ssl-mode=VerifyCA;ssl-ca=" + sslCa + ";ssl-ca-pwd=pass;"; using (var session1 = MySQLX.GetSession(connectionString)) - Assert.AreEqual(MySqlAuthenticationMode.PLAIN, session1.Settings.Auth); + Assert.That(session1.Settings.Auth, Is.EqualTo(MySqlAuthenticationMode.PLAIN)); connectionString = $"server={Host};user={builder.UserID};port={XPort};password={builder.Password};ssl-mode=none"; using (var session1 = MySQLX.GetSession(connectionString)) - Assert.AreEqual(MySqlAuthenticationMode.MYSQL41, session1.Settings.Auth); + Assert.That(session1.Settings.Auth, Is.EqualTo(MySqlAuthenticationMode.MYSQL41)); connectionString = $"server={Host};user={builder.UserID};port={XPort};password={builder.Password};ssl-mode=Required;ssl-ca={sslCa};ssl-ca-pwd=pass;"; using (var session1 = MySQLX.GetSession(connectionString)) - Assert.AreEqual(MySqlAuthenticationMode.PLAIN, session1.Settings.Auth); + Assert.That(session1.Settings.Auth, Is.EqualTo(MySqlAuthenticationMode.PLAIN)); //URI ExecuteSQL("flush privileges"); connectionStringUri = $"mysqlx://{builder.UserID}:{builder.Password}@{builder.Server}:{XPort}"; using (var session1 = MySQLX.GetSession(connectionStringUri)) - Assert.AreEqual(MySqlAuthenticationMode.PLAIN, session1.Settings.Auth); + Assert.That(session1.Settings.Auth, Is.EqualTo(MySqlAuthenticationMode.PLAIN)); connectionStringUri = connectionStringUri + "?ssl-mode=none"; using (var session1 = MySQLX.GetSession(connectionStringUri)) - Assert.AreEqual(MySqlAuthenticationMode.MYSQL41, session1.Settings.Auth); + Assert.That(session1.Settings.Auth, Is.EqualTo(MySqlAuthenticationMode.MYSQL41)); //Anonymous Object ExecuteSQL("flush privileges"); @@ -245,7 +244,7 @@ public void MySqlNativePlugin() user = builder.UserID, password = builder.Password })) - Assert.AreEqual(MySqlAuthenticationMode.PLAIN, session1.Settings.Auth); + Assert.That(session1.Settings.Auth, Is.EqualTo(MySqlAuthenticationMode.PLAIN)); using (var session1 = MySQLX.GetSession(new { @@ -255,13 +254,16 @@ public void MySqlNativePlugin() sslmode = MySqlSslMode.Disabled, password = builder.Password })) - Assert.AreEqual(MySqlAuthenticationMode.MYSQL41, session1.Settings.Auth); + Assert.That(session1.Settings.Auth, Is.EqualTo(MySqlAuthenticationMode.MYSQL41)); } [Test] [Property("Category", "Security")] public void ConnectUsingMySQL41Auth() { + Assume.That(Check_Plugin_Enabled("mysql_native_password"), "mysql_native_password plugin must be enabled on the server to run this test."); + ExecuteSqlAsRoot("CREATE USER IF NOT EXISTS 'testNative'@'%' identified with mysql_native_password by 'test';"); + var connectionStringUri = ConnectionStringUri; if (session.InternalSession.GetServerVersion().isAtLeast(8, 0, 4)) { @@ -271,14 +273,14 @@ public void ConnectUsingMySQL41Auth() using (var session = MySQLX.GetSession(connectionStringUri + "?auth=MySQL41")) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); - Assert.AreEqual(MySqlAuthenticationMode.MYSQL41, session.Settings.Auth); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + Assert.That(session.Settings.Auth, Is.EqualTo(MySqlAuthenticationMode.MYSQL41)); } using (var session = MySQLX.GetSession(connectionStringUri + "?auth=mysql41&sslmode=none")) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); - Assert.AreEqual(MySqlAuthenticationMode.MYSQL41, session.Settings.Auth); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + Assert.That(session.Settings.Auth, Is.EqualTo(MySqlAuthenticationMode.MYSQL41)); } } @@ -297,17 +299,17 @@ public void DefaultAuth() // Default to PLAIN when TLS is enabled. using (var session = MySQLX.GetSession(connString)) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); - Assert.AreEqual(MySqlAuthenticationMode.PLAIN, session.Settings.Auth); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + Assert.That(session.Settings.Auth, Is.EqualTo(MySqlAuthenticationMode.PLAIN)); var result = ExecuteSQLStatement(session.SQL("SHOW SESSION STATUS LIKE 'Mysqlx_ssl_version';")).FetchAll(); - StringAssert.StartsWith("TLSv1", result[0][1].ToString()); + Assert.That(result[0][1].ToString(), Does.StartWith("TLSv1")); } // Default to SHA256_MEMORY when TLS is not enabled. using (var session = MySQLX.GetSession(connString + "?sslmode=none")) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); - Assert.AreEqual(MySqlAuthenticationMode.SHA256_MEMORY, session.Settings.Auth); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + Assert.That(session.Settings.Auth, Is.EqualTo(MySqlAuthenticationMode.SHA256_MEMORY)); } } @@ -319,16 +321,16 @@ public void ConnectUsingSha256Memory() using (var session = MySQLX.GetSession(ConnectionStringUri + "?auth=SHA256_MEMORY")) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); - Assert.AreEqual(MySqlAuthenticationMode.SHA256_MEMORY, session.Settings.Auth); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + Assert.That(session.Settings.Auth, Is.EqualTo(MySqlAuthenticationMode.SHA256_MEMORY)); var result = session.SQL("SHOW SESSION STATUS LIKE 'Mysqlx_ssl_version';").Execute().FetchAll(); - Assert.True(result[0][1].ToString().Contains("TLSv1")); + Assert.That(result[0][1].ToString().Contains("TLSv1")); } using (var session = MySQLX.GetSession(ConnectionStringUri + "?auth=SHA256_MEMORY&sslmode=none")) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); - Assert.AreEqual(MySqlAuthenticationMode.SHA256_MEMORY, session.Settings.Auth); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + Assert.That(session.Settings.Auth, Is.EqualTo(MySqlAuthenticationMode.SHA256_MEMORY)); } using (var session1 = MySQLX.GetSession( @@ -342,8 +344,8 @@ public void ConnectUsingSha256Memory() auth = MySqlAuthenticationMode.SHA256_MEMORY })) { - Assert.AreEqual(SessionState.Open, session1.InternalSession.SessionState); - Assert.AreEqual(MySqlAuthenticationMode.SHA256_MEMORY, session1.Settings.Auth); + Assert.That(session1.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + Assert.That(session1.Settings.Auth, Is.EqualTo(MySqlAuthenticationMode.SHA256_MEMORY)); } //Exceptions @@ -368,8 +370,9 @@ public void ConnectUsingSha256Memory() [Property("Category", "Security")] public void Sha256MemoryAuthWithDifferentPlugin(string pluginName) { - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("Test available only to MySQL Server +8.0.11"); - + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); + Assume.That(Check_Plugin_Enabled("mysql_native_password"), "mysql_native_password plugin must be enabled on the server to run this test."); + MySqlConnectionStringBuilder builder = new MySqlConnectionStringBuilder(ConnectionString); builder.UserID = "testDefaultPlugin"; builder.Password = "test"; @@ -414,39 +417,41 @@ public void Sha256MemoryAuthWithDifferentPlugin(string pluginName) [Property("Category", "Security")] public void NativeAuthValidAndInvalidConnection() { - if (!Platform.IsWindows()) Assert.Ignore("Check for Linux OS"); - if (!session.Version.isAtLeast(8, 0, 11)) Assert.Ignore("Test available only to MySQL Server +8.0.11"); + Assume.That(Platform.IsWindows(), "Check for Linux OS"); + Assume.That(session.Version.isAtLeast(8, 0, 11), "This test is for MySql 8.0.11 or higher"); + Assume.That(Check_Plugin_Enabled("mysql_native_password"), "mysql_native_password plugin must be enabled on the server to run this test."); + ExecuteSqlAsRoot("CREATE USER IF NOT EXISTS 'testNative'@'%' identified with mysql_native_password by 'test';"); var user = "testNative"; var pwd = "test"; var cs = $"server={Host};user={user};port={XPort};password={pwd}"; //Connection String using (var session1 = MySQLX.GetSession(ConnectionString)) - Assert.AreEqual(MySqlAuthenticationMode.PLAIN, session1.Settings.Auth); + Assert.That(session1.Settings.Auth, Is.EqualTo(MySqlAuthenticationMode.PLAIN)); using (var session1 = MySQLX.GetSession(cs + ";auth=mysql41")) - Assert.AreEqual(MySqlAuthenticationMode.MYSQL41, session1.Settings.Auth); + Assert.That(session1.Settings.Auth, Is.EqualTo(MySqlAuthenticationMode.MYSQL41)); using (var session1 = MySQLX.GetSession(cs + ";auth=mysql41;ssl-mode=none")) - Assert.AreEqual(MySqlAuthenticationMode.MYSQL41, session1.Settings.Auth); + Assert.That(session1.Settings.Auth, Is.EqualTo(MySqlAuthenticationMode.MYSQL41)); using (var session1 = MySQLX.GetSession(cs + ";auth=mysql41;ssl-mode=Required")) - Assert.AreEqual(MySqlAuthenticationMode.MYSQL41, session1.Settings.Auth); + Assert.That(session1.Settings.Auth, Is.EqualTo(MySqlAuthenticationMode.MYSQL41)); using (var session1 = MySQLX.GetSession(ConnectionString + ";auth=PLAIN")) - Assert.AreEqual(MySqlAuthenticationMode.PLAIN, session1.Settings.Auth); + Assert.That(session1.Settings.Auth, Is.EqualTo(MySqlAuthenticationMode.PLAIN)); using (var session1 = MySQLX.GetSession(ConnectionString + ";auth=plain;ssl-mode=Required")) - Assert.AreEqual(MySqlAuthenticationMode.PLAIN, session1.Settings.Auth); + Assert.That(session1.Settings.Auth, Is.EqualTo(MySqlAuthenticationMode.PLAIN)); using (var session1 = MySQLX.GetSession(cs + ";ssl-mode=none")) - Assert.AreEqual(MySqlAuthenticationMode.MYSQL41, session1.Settings.Auth); + Assert.That(session1.Settings.Auth, Is.EqualTo(MySqlAuthenticationMode.MYSQL41)); using (var session1 = MySQLX.GetSession(ConnectionString + ";ssl-mode=Required")) { - Assert.AreEqual(MySqlAuthenticationMode.PLAIN, session1.Settings.Auth); + Assert.That(session1.Settings.Auth, Is.EqualTo(MySqlAuthenticationMode.PLAIN)); var result = session.SQL("SHOW SESSION STATUS LIKE 'Mysqlx_ssl_version';").Execute().FetchAll(); - Assert.True(result[0][1].ToString().Contains("TLSv1")); + Assert.That(result[0][1].ToString().Contains("TLSv1")); } Assert.Throws(() => MySQLX.GetSession(ConnectionString + ";auth=PLAIN;ssl-mode=none")); @@ -458,33 +463,33 @@ public void NativeAuthValidAndInvalidConnection() Assert.Throws(() => MySQLX.GetSession(ConnectionString + ";auth=INVALID;ssl-mode=Required")); //Uri using (var session1 = MySQLX.GetSession(ConnectionStringUriNative)) - Assert.AreEqual(MySqlAuthenticationMode.PLAIN, session1.Settings.Auth); + Assert.That(session1.Settings.Auth, Is.EqualTo(MySqlAuthenticationMode.PLAIN)); using (var session1 = MySQLX.GetSession(ConnectionStringUriNative + "?auth=MySQL41")) - Assert.AreEqual(MySqlAuthenticationMode.MYSQL41, session1.Settings.Auth); + Assert.That(session1.Settings.Auth, Is.EqualTo(MySqlAuthenticationMode.MYSQL41)); using (var session1 = MySQLX.GetSession(ConnectionStringUriNative + "?auth=MySQL41&ssl-mode=none")) - Assert.AreEqual(MySqlAuthenticationMode.MYSQL41, session1.Settings.Auth); + Assert.That(session1.Settings.Auth, Is.EqualTo(MySqlAuthenticationMode.MYSQL41)); using (var session1 = MySQLX.GetSession(ConnectionStringUriNative + "?auth=MySQL41&ssl-mode=Required")) - Assert.AreEqual(MySqlAuthenticationMode.MYSQL41, session1.Settings.Auth); + Assert.That(session1.Settings.Auth, Is.EqualTo(MySqlAuthenticationMode.MYSQL41)); using (var session1 = MySQLX.GetSession(ConnectionStringUriNative + "?auth=PLAIN")) - Assert.AreEqual(MySqlAuthenticationMode.PLAIN, session1.Settings.Auth); + Assert.That(session1.Settings.Auth, Is.EqualTo(MySqlAuthenticationMode.PLAIN)); Assert.Throws(() => MySQLX.GetSession(ConnectionStringUriNative + "?auth=PLAIN&ssl-mode=none")); using (var session1 = MySQLX.GetSession(ConnectionStringUriNative + "?auth=PLAIN&ssl-mode=Required")) - Assert.AreEqual(MySqlAuthenticationMode.PLAIN, session1.Settings.Auth); + Assert.That(session1.Settings.Auth, Is.EqualTo(MySqlAuthenticationMode.PLAIN)); using (var session1 = MySQLX.GetSession(ConnectionStringUriNative + "?ssl-mode=none")) - Assert.AreEqual(MySqlAuthenticationMode.MYSQL41, session1.Settings.Auth); + Assert.That(session1.Settings.Auth, Is.EqualTo(MySqlAuthenticationMode.MYSQL41)); using (var session1 = MySQLX.GetSession(ConnectionStringUriNative + "?ssl-mode=Required")) { - Assert.AreEqual(MySqlAuthenticationMode.PLAIN, session1.Settings.Auth); + Assert.That(session1.Settings.Auth, Is.EqualTo(MySqlAuthenticationMode.PLAIN)); var result = session.SQL("SHOW SESSION STATUS LIKE 'Mysqlx_ssl_version';").Execute().FetchAll(); - Assert.True(result[0][1].ToString().Contains("TLSv1")); + Assert.That(result[0][1].ToString().Contains("TLSv1")); } Assert.Throws(() => MySQLX.GetSession(ConnectionStringUriNative + "?auth=EXTERNAL")); @@ -501,7 +506,7 @@ public void NativeAuthValidAndInvalidConnection() user = user, password = pwd })) - Assert.AreEqual(MySqlAuthenticationMode.PLAIN, session1.Settings.Auth); + Assert.That(session1.Settings.Auth, Is.EqualTo(MySqlAuthenticationMode.PLAIN)); using (var session1 = MySQLX.GetSession(new { @@ -511,7 +516,7 @@ public void NativeAuthValidAndInvalidConnection() password = pwd, auth = MySqlAuthenticationMode.MYSQL41 })) - Assert.AreEqual(MySqlAuthenticationMode.MYSQL41, session1.Settings.Auth); + Assert.That(session1.Settings.Auth, Is.EqualTo(MySqlAuthenticationMode.MYSQL41)); using (var session1 = MySQLX.GetSession(new { @@ -522,7 +527,7 @@ public void NativeAuthValidAndInvalidConnection() auth = MySqlAuthenticationMode.MYSQL41, sslmode = MySqlSslMode.Disabled })) - Assert.AreEqual(MySqlAuthenticationMode.MYSQL41, session1.Settings.Auth); + Assert.That(session1.Settings.Auth, Is.EqualTo(MySqlAuthenticationMode.MYSQL41)); using (var session1 = MySQLX.GetSession(new { @@ -533,7 +538,7 @@ public void NativeAuthValidAndInvalidConnection() auth = MySqlAuthenticationMode.MYSQL41, sslmode = MySqlSslMode.Required })) - Assert.AreEqual(MySqlAuthenticationMode.MYSQL41, session1.Settings.Auth); + Assert.That(session1.Settings.Auth, Is.EqualTo(MySqlAuthenticationMode.MYSQL41)); using (var session1 = MySQLX.GetSession(new { @@ -543,7 +548,7 @@ public void NativeAuthValidAndInvalidConnection() password = pwd, auth = MySqlAuthenticationMode.PLAIN })) - Assert.AreEqual(MySqlAuthenticationMode.PLAIN, session1.Settings.Auth); + Assert.That(session1.Settings.Auth, Is.EqualTo(MySqlAuthenticationMode.PLAIN)); Assert.Throws(() => MySQLX.GetSession(new { @@ -564,7 +569,7 @@ public void NativeAuthValidAndInvalidConnection() auth = MySqlAuthenticationMode.PLAIN, sslmode = MySqlSslMode.Required })) - Assert.AreEqual(MySqlAuthenticationMode.PLAIN, session1.Settings.Auth); + Assert.That(session1.Settings.Auth, Is.EqualTo(MySqlAuthenticationMode.PLAIN)); using (var session1 = MySQLX.GetSession(new { @@ -574,7 +579,7 @@ public void NativeAuthValidAndInvalidConnection() password = pwd, sslmode = MySqlSslMode.Disabled })) - Assert.AreEqual(MySqlAuthenticationMode.MYSQL41, session1.Settings.Auth); + Assert.That(session1.Settings.Auth, Is.EqualTo(MySqlAuthenticationMode.MYSQL41)); using (var session1 = MySQLX.GetSession(new { @@ -585,9 +590,9 @@ public void NativeAuthValidAndInvalidConnection() sslmode = MySqlSslMode.Required })) { - Assert.AreEqual(MySqlAuthenticationMode.PLAIN, session1.Settings.Auth); + Assert.That(session1.Settings.Auth, Is.EqualTo(MySqlAuthenticationMode.PLAIN)); var result = session1.SQL("SHOW SESSION STATUS LIKE 'Mysqlx_ssl_version';").Execute().FetchAll(); - Assert.True(result[0][1].ToString().Contains("TLSv1")); + Assert.That(result[0][1].ToString().Contains("TLSv1")); } Assert.Throws(() => MySQLX.GetSession(new @@ -607,10 +612,10 @@ public void ConnectUsingExternalAuth() { // Should fail since EXTERNAL is currently not supported by X Plugin. Exception ex = Assert.Throws(() => MySQLX.GetSession(ConnectionString + ";auth=EXTERNAL")); - Assert.AreEqual("Invalid authentication method EXTERNAL", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Invalid authentication method EXTERNAL")); ex = Assert.Throws(() => MySQLX.GetSession(ConnectionStringUri + "?auth=EXTERNAL")); - Assert.AreEqual("Invalid authentication method EXTERNAL", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Invalid authentication method EXTERNAL")); } [Test] @@ -619,14 +624,14 @@ public void ConnectUsingPlainAuth() { using (var session = MySQLX.GetSession(ConnectionString + ";auth=pLaIn")) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); - Assert.AreEqual(MySqlAuthenticationMode.PLAIN, session.Settings.Auth); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + Assert.That(session.Settings.Auth, Is.EqualTo(MySqlAuthenticationMode.PLAIN)); } using (var session = MySQLX.GetSession(ConnectionStringUri + "?auth=pLaIn")) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); - Assert.AreEqual(MySqlAuthenticationMode.PLAIN, session.Settings.Auth); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + Assert.That(session.Settings.Auth, Is.EqualTo(MySqlAuthenticationMode.PLAIN)); } // Should fail since PLAIN requires TLS to be enabled. @@ -649,29 +654,29 @@ public void ConnectUsingSha256PasswordPlugin() // User with password over TLS connection. using (var session = MySQLX.GetSession(connectionStringUri)) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); var result = ExecuteSQLStatement(session.SQL(string.Format("SELECT `User`, `plugin` FROM `mysql`.`user` WHERE `User` = '{0}';", userName))).FetchAll(); - Assert.AreEqual(userName, session.Settings.UserID); - Assert.AreEqual(session.Settings.UserID, result[0][0].ToString()); - Assert.AreEqual(pluginName, result[0][1].ToString()); + Assert.That(session.Settings.UserID, Is.EqualTo(userName)); + Assert.That(result[0][0].ToString(), Is.EqualTo(session.Settings.UserID)); + Assert.That(result[0][1].ToString(), Is.EqualTo(pluginName)); } // Connect over non-TLS connection. using (var session = MySQLX.GetSession(connectionStringUri + "?sslmode=none")) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); - Assert.AreEqual(MySqlAuthenticationMode.SHA256_MEMORY, session.Settings.Auth); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); + Assert.That(session.Settings.Auth, Is.EqualTo(MySqlAuthenticationMode.SHA256_MEMORY)); } // User without password over TLS connection. ExecuteSQL($"ALTER USER {userName}@'%' IDENTIFIED BY ''"); using (var session = MySQLX.GetSession(ConnectionStringUri.Replace("test:test", string.Format("{0}:{1}", userName, "")))) { - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); var result = ExecuteSQLStatement(session.SQL(string.Format("SELECT `User`, `plugin` FROM `mysql`.`user` WHERE `User` = '{0}';", userName))).FetchAll(); - Assert.AreEqual(userName, session.Settings.UserID); - Assert.AreEqual(session.Settings.UserID, result[0][0].ToString()); - Assert.AreEqual(pluginName, result[0][1].ToString()); + Assert.That(session.Settings.UserID, Is.EqualTo(userName)); + Assert.That(result[0][0].ToString(), Is.EqualTo(session.Settings.UserID)); + Assert.That(result[0][1].ToString(), Is.EqualTo(pluginName)); } } diff --git a/MySQL.Data/tests/MySqlX.Data.Tests/XConnectionStringBuilderTests.cs b/MySQL.Data/tests/MySqlX.Data.Tests/XConnectionStringBuilderTests.cs index 711d0e338..616f67d33 100644 --- a/MySQL.Data/tests/MySqlX.Data.Tests/XConnectionStringBuilderTests.cs +++ b/MySQL.Data/tests/MySqlX.Data.Tests/XConnectionStringBuilderTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2018, 2022, Oracle and/or its affiliates. +// Copyright © 2018, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -30,6 +30,7 @@ using MySql.Data.MySqlClient; using MySqlX.XDevAPI; using NUnit.Framework; +using NUnit.Framework.Legacy; using System; using System.Data; @@ -56,25 +57,25 @@ static XConnectionStringBuilderTests() public void SessionCanBeOpened() { using (var session = MySQLX.GetSession(_xConnectionURI)) - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } [Test] public void ConnectionAfterSessionCanBeOpened() { - if (!Platform.IsWindows()) Assert.Ignore("Check for Linux OS"); + Assume.That(Platform.IsWindows(), "Check for Linux OS"); using (var session = MySQLX.GetSession(_xConnectionURI)) - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); using (var connection = new MySqlConnection(_connectionStringWithSslMode)) { connection.Open(); - Assert.AreEqual(ConnectionState.Open, connection.State); + Assert.That(connection.State, Is.EqualTo(ConnectionState.Open)); } using (var session = MySQLX.GetSession(_xConnectionURI + "?sslca=client.pfx&certificatepassword=pass")) - Assert.AreEqual(SessionState.Open, session.InternalSession.SessionState); + Assert.That(session.InternalSession.SessionState, Is.EqualTo(SessionState.Open)); } #if !NET452 @@ -86,7 +87,7 @@ public void ConnectionAfterSessionCanBeOpened() public void ValidateTlsVersionOptionAsString(string options, string result) { MySqlXConnectionStringBuilder builder = new MySqlXConnectionStringBuilder(_connectionString + options); - Assert.AreEqual(result, builder.TlsVersion); + Assert.That(builder.TlsVersion, Is.EqualTo(result)); } #if !NET452 @@ -100,7 +101,7 @@ public void ValidateTlsVersionOptionAsProperty(string options, string result) MySqlXConnectionStringBuilder builder = new MySqlXConnectionStringBuilder(_connectionString); builder.TlsVersion = options; - Assert.AreEqual(result, builder.TlsVersion); + Assert.That(builder.TlsVersion, Is.EqualTo(result)); } #if !NET452 @@ -121,7 +122,7 @@ public void ValidateTlsVersionOptionAndSslMode(MySqlSslMode? sslMode1, string op if (result != null) { builder.TlsVersion = options; - StringAssert.AreEqualIgnoringCase(result, builder.TlsVersion); + Assert.That(builder.TlsVersion, Is.EqualTo(result).IgnoreCase); } else Assert.Throws(() => { builder.TlsVersion = options; }); @@ -141,7 +142,7 @@ public void CaseInsensitiveAuthOption() for (int j = 0; j < values.GetLength(1); j++) { var builder = new MySqlXConnectionStringBuilder(String.Format("server=localhost;auth={0}", values[i, j])); - Assert.AreEqual((MySqlAuthenticationMode)(i + 1), builder.Auth); + Assert.That(builder.Auth, Is.EqualTo((MySqlAuthenticationMode)(i + 1))); } } } @@ -153,7 +154,7 @@ public void IncorrectAuthOptionThrowsArgumentException() foreach (var value in values) { Exception ex = Assert.Throws(() => new MySqlXConnectionStringBuilder(String.Format("server=localhost;aUth={0}", value))); - Assert.AreEqual(String.Format("Value '{0}' is not of the correct type.", value), ex.Message); + Assert.That(ex.Message, Is.EqualTo(String.Format("Value '{0}' is not of the correct type", value))); } } @@ -170,21 +171,21 @@ public void TryGetValue() CompressionAlgorithm = "deflate, lz4", }; - Assert.IsTrue(connStringBuilder.ContainsKey("dnssrv")); - Assert.IsTrue(connStringBuilder.TryGetValue("dns-srv", out var dnssrv)); - Assert.AreEqual(connStringBuilder.DnsSrv, (bool)dnssrv); + Assert.That(connStringBuilder.ContainsKey("dnssrv")); + Assert.That(connStringBuilder.TryGetValue("dns-srv", out var dnssrv)); + Assert.That((bool)dnssrv, Is.EqualTo(connStringBuilder.DnsSrv)); - Assert.IsTrue(connStringBuilder.ContainsKey("compressionAlgorithms")); - Assert.IsTrue(connStringBuilder.TryGetValue("Compression-Algorithms", out var compressionAlgorithm)); - StringAssert.AreEqualIgnoringCase(connStringBuilder.CompressionAlgorithm, (string)compressionAlgorithm); + Assert.That(connStringBuilder.ContainsKey("compressionAlgorithms")); + Assert.That(connStringBuilder.TryGetValue("Compression-Algorithms", out var compressionAlgorithm)); + Assert.That((string)compressionAlgorithm, Is.EqualTo(connStringBuilder.CompressionAlgorithm).IgnoreCase); // Default value - Assert.IsTrue(connStringBuilder.TryGetValue("connection-attributes", out var connectionattributes)); - Assert.AreEqual(connStringBuilder.GetOption("connection-attributes").DefaultValue, connectionattributes); + Assert.That(connStringBuilder.TryGetValue("connection-attributes", out var connectionattributes)); + Assert.That(connectionattributes, Is.EqualTo(connStringBuilder.GetOption("connection-attributes").DefaultValue)); // Non existing option - Assert.IsFalse(connStringBuilder.TryGetValue("foo", out var nonexistingoption)); - Assert.IsNull(nonexistingoption); + Assert.That(connStringBuilder.TryGetValue("foo", out var nonexistingoption), Is.False); + Assert.That(nonexistingoption, Is.Null); } } } diff --git a/MySql.Web/src/Application.cs b/MySql.Web/src/Application.cs index 69b8e074c..fcfc033ea 100644 --- a/MySql.Web/src/Application.cs +++ b/MySql.Web/src/Application.cs @@ -1,94 +1,94 @@ -// Copyright (c) 2009, 2020, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data.MySqlClient; -using System; -using System.Configuration.Provider; - -namespace MySql.Web.General -{ - internal class Application - { - private long _id; - private string _desc; - - public Application(string name, string desc) - { - Id = -1; - Name = name; - Description = desc; - } - public long Id - { - get { return _id; } - private set { _id = value; } - } - public string Name; - - public string Description - { - get { return _desc; } - private set { _desc = value; } - } - - public long FetchId(MySqlConnection connection) - { - if (Id == -1) - { - MySqlCommand cmd = new MySqlCommand( - @"SELECT id FROM my_aspnet_applications WHERE name=@name", connection); - cmd.Parameters.AddWithValue("@name", Name); - object id = cmd.ExecuteScalar(); - Id = id == null ? -1 : Convert.ToInt64(id); - } - return Id; - } - - /// - /// Creates the or fetch application id. - /// - /// The connection. - public long EnsureId(MySqlConnection connection) - { - // first try and retrieve the existing id - if (FetchId(connection) <= 0) - { - MySqlCommand cmd = new MySqlCommand( - "INSERT INTO my_aspnet_applications VALUES (NULL, @appName, @appDesc)", connection); - cmd.Parameters.AddWithValue("@appName", Name); - cmd.Parameters.AddWithValue("@appDesc", Description); - int recordsAffected = cmd.ExecuteNonQuery(); - if (recordsAffected != 1) - throw new ProviderException(Properties.Resources.UnableToCreateApplication); - - Id = cmd.LastInsertedId; - } - return Id; - } - } -} +// Copyright © 2009, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data.MySqlClient; +using System; +using System.Configuration.Provider; + +namespace MySql.Web.General +{ + internal class Application + { + private long _id; + private string _desc; + + public Application(string name, string desc) + { + Id = -1; + Name = name; + Description = desc; + } + public long Id + { + get { return _id; } + private set { _id = value; } + } + public string Name; + + public string Description + { + get { return _desc; } + private set { _desc = value; } + } + + public long FetchId(MySqlConnection connection) + { + if (Id == -1) + { + MySqlCommand cmd = new MySqlCommand( + @"SELECT id FROM my_aspnet_applications WHERE name=@name", connection); + cmd.Parameters.AddWithValue("@name", Name); + object id = cmd.ExecuteScalar(); + Id = id == null ? -1 : Convert.ToInt64(id); + } + return Id; + } + + /// + /// Creates the or fetch application id. + /// + /// The connection. + public long EnsureId(MySqlConnection connection) + { + // first try and retrieve the existing id + if (FetchId(connection) <= 0) + { + MySqlCommand cmd = new MySqlCommand( + "INSERT INTO my_aspnet_applications VALUES (NULL, @appName, @appDesc)", connection); + cmd.Parameters.AddWithValue("@appName", Name); + cmd.Parameters.AddWithValue("@appDesc", Description); + int recordsAffected = cmd.ExecuteNonQuery(); + if (recordsAffected != 1) + throw new ProviderException(Properties.Resources.UnableToCreateApplication); + + Id = cmd.LastInsertedId; + } + return Id; + } + } +} diff --git a/MySql.Web/src/ConfigUtility.cs b/MySql.Web/src/ConfigUtility.cs index 28a094812..6bb236523 100644 --- a/MySql.Web/src/ConfigUtility.cs +++ b/MySql.Web/src/ConfigUtility.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2017, 2020, Oracle and/or its affiliates. +// Copyright © 2017, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySql.Web/src/MembershipProvider.cs b/MySql.Web/src/MembershipProvider.cs index 400dc8ea3..d3b82785a 100644 --- a/MySql.Web/src/MembershipProvider.cs +++ b/MySql.Web/src/MembershipProvider.cs @@ -1,1727 +1,1727 @@ -// Copyright (c) 2004, 2021, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -// This code was contributed by Sean Wright (srwright@alcor.concordia.ca) on 2007-01-12 -// The copyright was assigned and transferred under the terms of -// the MySQL Contributor License Agreement (CLA) - -using MySql.Data.MySqlClient; -using MySql.Web.Common; -using MySql.Web.General; -using MySql.Web.Profile; -using System; -using System.Collections.Specialized; -using System.Configuration.Provider; -using System.Data; -using System.Diagnostics; -using System.Security.Cryptography; -using System.Text; -using System.Text.RegularExpressions; -using System.Web.Hosting; -using System.Web.Security; - -namespace MySql.Web.Security -{ - /// - /// Manages storage of membership information for an ASP.NET application in a MySQL database. - /// - /// - /// - /// This class is used by the and classes - /// to provide membership services for ASP.NET applications using a MySQL database. - /// - /// - /// - /// - /// configuration> - /// connectionStrings> - /// add name = "LocalMySqlService" connectionString="server=localhost;user id=myuser;password=mypass;database=test" /> - /// /connectionStrings> - /// system.web> - /// authentication mode = "Forms" > - /// forms loginUrl="login.aspx" name=".ASPXFORMSAUTH" /> - /// /authentication> - /// authorization> - /// deny users = "?" /> - /// /authorization> - /// membership defaultProvider="MySQLProvider" userIsOnlineTimeWindow="15"> - /// providers> - /// add - /// name = "MySQLProvider" - /// type="MySql.Web.Security.MySQLMembershipProvider" - /// connectionStringName="LocalMySqlService" - /// applicationName="MyApplication" - /// enablePasswordRetrieval="false" - /// enablePasswordReset="true" - /// requiresQuestionAndAnswer="true" - /// requiresUniqueEmail="false" - /// passwordFormat="Hashed" - /// maxInvalidPasswordAttempts="5" - /// passwordAttemptWindow="10" /> - /// /providers> - /// /membership> - /// /system.web> - /// /configuration> - /// - /// - public sealed class MySQLMembershipProvider : MembershipProvider - { - private int newPasswordLength = 8; - private string eventSource = "MySQLMembershipProvider"; - private string eventLog = "Application"; - private string exceptionMessage = "An exception occurred. Please check the Event Log."; - private string connectionString; - private int minRequiredPasswordLength; - private bool writeExceptionsToEventLog; - private bool enablePasswordReset; - private bool enablePasswordRetrieval; - private bool requiresQuestionAndAnswer; - private bool requiresUniqueEmail; - private int maxInvalidPasswordAttempts; - private int passwordAttemptWindow; - private MembershipPasswordFormat passwordFormat; - private int minRequiredNonAlphanumericCharacters; - private string passwordStrengthRegularExpression; - private Application app; - - /// - /// Initializes the MySQL membership provider with the property values specified in the - /// ASP.NET application's configuration file. This method is not intended to be used directly - /// from your code. - /// - /// The name of the instance to initialize. - /// A collection of the name/value pairs representing the - /// provider-specific attributes specified in the configuration for this provider. - /// config is a null reference. - /// An attempt is made to call on a provider after the provider has already been initialized. - /// - public override void Initialize(string name, NameValueCollection config) - { - if (config == null) - { - throw new ArgumentNullException("config"); - } - if (name == null || name.Length == 0) - { - name = "MySQLMembershipProvider"; - } - if (string.IsNullOrEmpty(config["description"])) - { - config.Remove("description"); - config.Add("description", "MySQL default application"); - } - base.Initialize(name, config); - - string applicationName = GetConfigValue(config["applicationName"], - HostingEnvironment.ApplicationVirtualPath); - maxInvalidPasswordAttempts = Convert.ToInt32(GetConfigValue(config["maxInvalidPasswordAttempts"], "5")); - passwordAttemptWindow = Convert.ToInt32(GetConfigValue(config["passwordAttemptWindow"], "10")); - minRequiredNonAlphanumericCharacters = - Convert.ToInt32(GetConfigValue(config["minRequiredNonalphanumericCharacters"], "1")); - minRequiredPasswordLength = Convert.ToInt32(GetConfigValue(config["minRequiredPasswordLength"], "7")); - passwordStrengthRegularExpression = - Convert.ToString(GetConfigValue(config["passwordStrengthRegularExpression"], "")); - enablePasswordReset = Convert.ToBoolean(GetConfigValue(config["enablePasswordReset"], "True")); - enablePasswordRetrieval = Convert.ToBoolean( - GetConfigValue(config["enablePasswordRetrieval"], "False")); - requiresQuestionAndAnswer = Convert.ToBoolean(GetConfigValue(config["requiresQuestionAndAnswer"], "False")); - requiresUniqueEmail = Convert.ToBoolean(GetConfigValue(config["requiresUniqueEmail"], "True")); - writeExceptionsToEventLog = Convert.ToBoolean(GetConfigValue(config["writeExceptionsToEventLog"], "True")); - string temp_format = config["passwordFormat"]; - - if (temp_format == null) - temp_format = "hashed"; - else - temp_format = temp_format.ToLowerInvariant(); - - if (temp_format == "hashed") - passwordFormat = MembershipPasswordFormat.Hashed; - else if (temp_format == "encrypted") - passwordFormat = MembershipPasswordFormat.Encrypted; - else if (temp_format == "clear") - passwordFormat = MembershipPasswordFormat.Clear; - else - throw new ProviderException("Password format not supported."); - - // if the user is asking for the ability to retrieve hashed passwords, then let - // them know we can't - if (PasswordFormat == MembershipPasswordFormat.Hashed) - { - if (EnablePasswordRetrieval) - throw new ProviderException(Properties.Resources.CannotRetrieveHashedPasswords); - } - - connectionString = ConfigUtility.GetConnectionString(config); - if (String.IsNullOrEmpty(connectionString)) return; - - // make sure we have the correct schema - SchemaManager.CheckSchema(connectionString, config); - - app = new Application(applicationName, base.Description); - } - - private static string GetConfigValue(string configValue, string defaultValue) - { - if (string.IsNullOrEmpty(configValue)) - { - return defaultValue; - } - return configValue; - } - - #region Properties - - /// - /// The name of the application using the MySQL membership provider. - /// - /// The name of the application using the MySQL membership provider. The default is the - /// application virtual path. - /// The ApplicationName is used by the MySqlMembershipProvider to separate - /// membership information for multiple applications. Using different application names, - /// applications can use the same membership database. - /// Likewise, multiple applications can make use of the same membership data by simply using - /// the same application name. - /// Caution should be taken with multiple applications as the ApplicationName property is not - /// thread safe during writes. - /// - /// - /// The following example shows the membership element being used in an applications web.config file. - /// The application name setting is being used. - /// - /// membership defaultProvider="MySQLMembershipProvider"> - /// providers> - /// add name="MySqlMembershipProvider" - /// type="MySql.Web.Security.MySQLMembershipProvider" - /// connectionStringName="LocalMySqlServer" - /// enablePasswordRetrieval="true" - /// enablePasswordReset="false" - /// requiresQuestionAndAnswer="true" - /// requiresUniqueEmail="false" - /// passwordFormat="Encrypted" - /// maxInvalidPasswordAttempts="3" - /// passwordAttemptWindow="20" - /// minRequiredNonAlphanumericCharacters="1" - /// minRequiredPasswordLength="11" - /// applicationName="MyApplication" /> - /// /providers> - /// /membership> - /// - /// - public override string ApplicationName - { - get { return app.Name; } - set - { - lock (this) - { - if (value.ToLowerInvariant() == app.Name.ToLowerInvariant()) return; - app = new Application(value, String.Empty); - } - } - } - - /// - /// Indicates whether the membership provider is configured to allow users to reset their passwords. - /// - /// true if the membership provider supports password reset; otherwise, false. The default is true. - /// Allows the user to replace their password with a new, randomly generated password. - /// This can be especially handy when using hashed passwords since hashed passwords cannot be - /// retrieved. - /// - /// The following example shows the membership element being used in an applications web.config file. - /// - /// membership defaultProvider="MySQLMembershipProvider"> - /// providers> - /// add name="MySqlMembershipProvider" - /// type="MySql.Web.Security.MySQLMembershipProvider" - /// connectionStringName="LocalMySqlServer" - /// enablePasswordRetrieval="true" - /// enablePasswordReset="false" - /// requiresQuestionAndAnswer="true" - /// requiresUniqueEmail="false" - /// passwordFormat="Encrypted" - /// maxInvalidPasswordAttempts="3" - /// passwordAttemptWindow="20" - /// minRequiredNonAlphanumericCharacters="1" - /// minRequiredPasswordLength="11" - /// applicationName="MyApplication" /> - /// /providers> - /// /membership> - /// - /// - public override bool EnablePasswordReset - { - get { return enablePasswordReset; } - } - - /// - /// Indicates whether the membership provider is configured to allow users to retrieve - /// their passwords. - /// - /// true if the membership provider is configured to support password retrieval; - /// otherwise, false. The default is false. - /// If the system is configured to use hashed passwords, then retrieval is not possible. - /// If the user attempts to initialize the provider with hashed passwords and enable password retrieval - /// set to true then a is thrown. - /// - /// The following example shows the membership element being used in an applications web.config file. - /// - /// membership defaultProvider="MySQLMembershipProvider"> - /// providers> - /// add name="MySqlMembershipProvider" - /// type="MySql.Web.Security.MySQLMembershipProvider" - /// connectionStringName="LocalMySqlServer" - /// enablePasswordRetrieval="true" - /// enablePasswordReset="false" - /// requiresQuestionAndAnswer="true" - /// requiresUniqueEmail="false" - /// passwordFormat="Encrypted" - /// maxInvalidPasswordAttempts="3" - /// passwordAttemptWindow="20" - /// minRequiredNonAlphanumericCharacters="1" - /// minRequiredPasswordLength="11" - /// applicationName="MyApplication" /> - /// /providers> - /// /membership> - /// - /// - public override bool EnablePasswordRetrieval - { - get { return enablePasswordRetrieval; } - } - - /// - /// Gets a value indicating whether the membership provider is - /// configured to require the user to answer a password question - /// for password reset and retrieval. - /// - /// true if a password answer is required for password - /// reset and retrieval; otherwise, false. The default is false. - /// - /// The following example shows the membership element being used in an applications web.config file. - /// - /// membership defaultProvider="MySQLMembershipProvider"> - /// providers> - /// add name="MySqlMembershipProvider" - /// type="MySql.Web.Security.MySQLMembershipProvider" - /// connectionStringName="LocalMySqlServer" - /// enablePasswordRetrieval="true" - /// enablePasswordReset="false" - /// requiresQuestionAndAnswer="true" - /// requiresUniqueEmail="false" - /// passwordFormat="Encrypted" - /// maxInvalidPasswordAttempts="3" - /// passwordAttemptWindow="20" - /// minRequiredNonAlphanumericCharacters="1" - /// minRequiredPasswordLength="11" - /// applicationName="MyApplication" /> - /// /providers> - /// /membership> - /// - /// - public override bool RequiresQuestionAndAnswer - { - get { return requiresQuestionAndAnswer; } - } - - /// - /// Gets a value indicating whether the membership provider is configured - /// to require a unique e-mail address for each user name. - /// - /// true if the membership provider requires a unique e-mail address; - /// otherwise, false. The default is true. - /// - /// The following example shows the membership element being used in an applications web.config file. - /// - /// membership defaultProvider="MySQLMembershipProvider"> - /// providers> - /// add name="MySqlMembershipProvider" - /// type="MySql.Web.Security.MySQLMembershipProvider" - /// connectionStringName="LocalMySqlServer" - /// enablePasswordRetrieval="true" - /// enablePasswordReset="false" - /// requiresQuestionAndAnswer="true" - /// requiresUniqueEmail="false" - /// passwordFormat="Encrypted" - /// maxInvalidPasswordAttempts="3" - /// passwordAttemptWindow="20" - /// minRequiredNonAlphanumericCharacters="1" - /// minRequiredPasswordLength="11" - /// applicationName="MyApplication" /> - /// /providers> - /// /membership> - /// - /// - public override bool RequiresUniqueEmail - { - get { return requiresUniqueEmail; } - } - - /// - /// Gets the number of invalid password or password-answer attempts allowed - /// before the membership user is locked out. - /// - /// The number of invalid password or password-answer attempts allowed - /// before the membership user is locked out. - /// - /// The following example shows the membership element being used in an applications web.config file. - /// - /// membership defaultProvider="MySQLMembershipProvider"> - /// providers> - /// add name="MySqlMembershipProvider" - /// type="MySql.Web.Security.MySQLMembershipProvider" - /// connectionStringName="LocalMySqlServer" - /// enablePasswordRetrieval="true" - /// enablePasswordReset="false" - /// requiresQuestionAndAnswer="true" - /// requiresUniqueEmail="false" - /// passwordFormat="Encrypted" - /// maxInvalidPasswordAttempts="3" - /// passwordAttemptWindow="20" - /// minRequiredNonAlphanumericCharacters="1" - /// minRequiredPasswordLength="11" - /// applicationName="MyApplication" /> - /// /providers> - /// /membership> - /// - /// - public override int MaxInvalidPasswordAttempts - { - get { return maxInvalidPasswordAttempts; } - } - - /// - /// Gets the number of minutes in which a maximum number of invalid password or - /// password-answer attempts are allowed before the membership user is locked out. - /// - /// The number of minutes in which a maximum number of invalid password or - /// password-answer attempts are allowed before the membership user is locked out. - /// - /// The following example shows the membership element being used in an applications web.config file. - /// - /// membership defaultProvider="MySQLMembershipProvider"> - /// providers> - /// add name="MySqlMembershipProvider" - /// type="MySql.Web.Security.MySQLMembershipProvider" - /// connectionStringName="LocalMySqlServer" - /// enablePasswordRetrieval="true" - /// enablePasswordReset="false" - /// requiresQuestionAndAnswer="true" - /// requiresUniqueEmail="false" - /// passwordFormat="Encrypted" - /// maxInvalidPasswordAttempts="3" - /// passwordAttemptWindow="20" - /// minRequiredNonAlphanumericCharacters="1" - /// minRequiredPasswordLength="11" - /// applicationName="MyApplication" /> - /// /providers> - /// /membership> - /// - /// - public override int PasswordAttemptWindow - { - get { return passwordAttemptWindow; } - } - - /// - /// Gets a value indicating the format for storing passwords in the membership data store. - /// - /// One of the - /// values indicating the format for storing passwords in the data store. - /// - /// The following example shows the membership element being used in an applications web.config file. - /// - /// membership defaultProvider="MySQLMembershipProvider"> - /// providers> - /// add name="MySqlMembershipProvider" - /// type="MySql.Web.Security.MySQLMembershipProvider" - /// connectionStringName="LocalMySqlServer" - /// enablePasswordRetrieval="true" - /// enablePasswordReset="false" - /// requiresQuestionAndAnswer="true" - /// requiresUniqueEmail="false" - /// passwordFormat="Encrypted" - /// maxInvalidPasswordAttempts="3" - /// passwordAttemptWindow="20" - /// minRequiredNonAlphanumericCharacters="1" - /// minRequiredPasswordLength="11" - /// applicationName="MyApplication" /> - /// /providers> - /// /membership> - /// - /// - public override MembershipPasswordFormat PasswordFormat - { - get { return passwordFormat; } - } - - /// - /// Gets the minimum number of special characters that must be present in a valid password. - /// - /// The minimum number of special characters that must be present - /// in a valid password. - /// - /// The following example shows the membership element being used in an applications web.config file. - /// - /// membership defaultProvider="MySQLMembershipProvider"> - /// providers> - /// add name="MySqlMembershipProvider" - /// type="MySql.Web.Security.MySQLMembershipProvider" - /// connectionStringName="LocalMySqlServer" - /// enablePasswordRetrieval="true" - /// enablePasswordReset="false" - /// requiresQuestionAndAnswer="true" - /// requiresUniqueEmail="false" - /// passwordFormat="Encrypted" - /// maxInvalidPasswordAttempts="3" - /// passwordAttemptWindow="20" - /// minRequiredNonAlphanumericCharacters="1" - /// minRequiredPasswordLength="11" - /// applicationName="MyApplication" /> - /// /providers> - /// /membership> - /// - /// - public override int MinRequiredNonAlphanumericCharacters - { - get { return minRequiredNonAlphanumericCharacters; } - } - - /// - /// Gets the minimum length required for a password. - /// - /// The minimum length required for a password. - /// - /// The following example shows the membership element being used in an applications web.config file. - /// - /// membership defaultProvider="MySQLMembershipProvider"> - /// providers> - /// add name="MySqlMembershipProvider" - /// type="MySql.Web.Security.MySQLMembershipProvider" - /// connectionStringName="LocalMySqlServer" - /// enablePasswordRetrieval="true" - /// enablePasswordReset="false" - /// requiresQuestionAndAnswer="true" - /// requiresUniqueEmail="false" - /// passwordFormat="Encrypted" - /// maxInvalidPasswordAttempts="3" - /// passwordAttemptWindow="20" - /// minRequiredNonAlphanumericCharacters="1" - /// minRequiredPasswordLength="11" - /// applicationName="MyApplication" /> - /// /providers> - /// /membership> - /// - /// - public override int MinRequiredPasswordLength - { - get { return minRequiredPasswordLength; } - } - - /// - /// Gets the regular expression used to evaluate a password. - /// - /// A regular expression used to evaluate a password. - /// - /// The following example shows the membership element being used in an applications web.config file. - /// In this example, the regular expression specifies that the password must meet the following - /// criteria: - /// * Is at least seven characters. - /// * Contains at least one digit. - /// * Contains at least one special (non-alphanumeric) character. - /// - /// membership defaultProvider="MySQLMembershipProvider"> - /// providers> - /// add name="MySqlMembershipProvider" - /// type="MySql.Web.Security.MySQLMembershipProvider" - /// connectionStringName="LocalMySqlServer" - /// enablePasswordRetrieval="true" - /// enablePasswordReset="false" - /// requiresQuestionAndAnswer="true" - /// requiresUniqueEmail="false" - /// passwordFormat="Encrypted" - /// maxInvalidPasswordAttempts="3" - /// passwordAttemptWindow="20" - /// minRequiredNonAlphanumericCharacters="1" - /// minRequiredPasswordLength="11" - /// applicationName="MyApplication" /> - /// /providers> - /// /membership> - /// - /// - public override string PasswordStrengthRegularExpression - { - get { return passwordStrengthRegularExpression; } - } - - /// - /// Gets or sets a value indicating whether exceptions are written to the event log. - /// - /// - /// true if exceptions should be written to the log; otherwise, false. - /// - public bool WriteExceptionsToEventLog - { - get { return writeExceptionsToEventLog; } - set { writeExceptionsToEventLog = value; } - } - - #endregion - - #region Public Methods - - /// - /// Changes the password. - /// - /// The username. - /// The old password. - /// The new password. - /// true if the password was updated successfully; false if the supplied old password - /// is invalid, the user is locked out, or the user does not exist in the database. - public override bool ChangePassword(string username, string oldPassword, string newPassword) - { - // this will return false if the username doesn't exist - if (!(ValidateUser(username, oldPassword))) - return false; - - ValidatePasswordEventArgs args = new ValidatePasswordEventArgs(username, newPassword, true); - OnValidatingPassword(args); - if (args.Cancel) - { - if (!(args.FailureInformation == null)) - throw args.FailureInformation; - else - throw new ProviderException(Properties.Resources.ChangePasswordCanceled); - } - - // validate the password according to current guidelines - if (!ValidatePassword(newPassword, "newPassword", true)) - return false; - - try - { - using (MySqlConnection connection = new MySqlConnection(connectionString)) - { - connection.Open(); - - // retrieve the existing key and format for this user - string passwordKey; - MembershipPasswordFormat passwordFormat; - int userId = GetUserId(connection, username); - - GetPasswordInfo(connection, userId, out passwordKey, out passwordFormat); - - MySqlCommand cmd = new MySqlCommand( - @"UPDATE my_aspnet_membership - SET Password = @pass, LastPasswordChangedDate = @lastPasswordChangedDate - WHERE userId=@userId", connection); - cmd.Parameters.AddWithValue("@pass", - EncodePassword(newPassword, passwordKey, passwordFormat)); - cmd.Parameters.AddWithValue("@lastPasswordChangedDate", DateTime.Now); - cmd.Parameters.AddWithValue("@userId", userId); - return cmd.ExecuteNonQuery() > 0; - } - } - catch (MySqlException e) - { - if (WriteExceptionsToEventLog) - WriteToEventLog(e, "ChangePassword"); - throw new ProviderException(exceptionMessage, e); - } - } - - /// - /// Changes the password question and answer. - /// - /// The user name. - /// The password. - /// The new password question. - /// The new password answer. - /// true if the update was successful; otherwise, false. A value of false is - /// also returned if the password is incorrect, the user is locked out, or the user - /// does not exist in the database. - public override bool ChangePasswordQuestionAndAnswer(string username, - string password, string newPwdQuestion, string newPwdAnswer) - { - // this handles the case where the username doesn't exist - if (!(ValidateUser(username, password))) - return false; - - try - { - using (MySqlConnection connection = new MySqlConnection(connectionString)) - { - connection.Open(); - - string passwordKey; - MembershipPasswordFormat passwordFormat; - int userId = GetUserId(connection, username); - - GetPasswordInfo(connection, userId, out passwordKey, out passwordFormat); - - - MySqlCommand cmd = new MySqlCommand( - @"UPDATE my_aspnet_membership - SET PasswordQuestion = @passwordQuestion, PasswordAnswer = @passwordAnswer - WHERE userId=@userId", connection); - cmd.Parameters.AddWithValue("@passwordQuestion", newPwdQuestion); - cmd.Parameters.AddWithValue("@passwordAnswer", - EncodePassword(newPwdAnswer, passwordKey, passwordFormat)); - cmd.Parameters.AddWithValue("@userId", userId); - return cmd.ExecuteNonQuery() > 0; - } - } - catch (MySqlException e) - { - if (WriteExceptionsToEventLog) - WriteToEventLog(e, "ChangePasswordQuestionAndAnswer"); - throw new ProviderException(exceptionMessage, e); - } - } - - /// - /// Adds a new membership user to the data source. - /// - /// The user name for the new user. - /// The password for the new user. - /// The e-mail address for the new user. - /// The password question for the new user. - /// The password answer for the new user - /// Whether or not the new user is approved to be validated. - /// The unique identifier from the membership data source for the user. - /// A enumeration value indicating whether the user was created successfully. - /// - /// A object populated with the information for the newly created user. - /// - public override MembershipUser CreateUser(string username, string password, - string email, string passwordQuestion, string passwordAnswer, - bool isApproved, object providerUserKey, out MembershipCreateStatus status) - { - //basis on MSDN documentation we should trim all the paramater values: http://msdn.microsoft.com/en-us/library/d8t4h2es%28v=vs.110%29.aspx - TrimParametersValues(ref username, ref password, ref email, ref passwordQuestion, ref passwordAnswer); - - ValidatePasswordEventArgs Args = new ValidatePasswordEventArgs(username, password, true); - OnValidatingPassword(Args); - if (Args.Cancel) - { - status = MembershipCreateStatus.InvalidPassword; - return null; - } - if (RequiresUniqueEmail && !String.IsNullOrEmpty(GetUserNameByEmail(email))) - { - status = MembershipCreateStatus.DuplicateEmail; - return null; - } - - ValidateQA(passwordQuestion, passwordAnswer); - - // now try to validate the password - if (!ValidatePassword(password, "password", false)) - { - status = MembershipCreateStatus.InvalidPassword; - return null; - } - - // now check to see if we already have a member by this name - MembershipUser u = GetUser(username, false); - if (u != null) - { - status = MembershipCreateStatus.DuplicateUserName; - return null; - } - - string passwordKey = GetPasswordKey(); - DateTime createDate = DateTime.Now; - MySqlTransaction transaction = null; - - using (MySqlConnection connection = new MySqlConnection(connectionString)) - { - try - { - connection.Open(); - transaction = connection.BeginTransaction(); - - // either create a new user or fetch the existing user id - long userId = SchemaManager.CreateOrFetchUserId(connection, username, - app.EnsureId(connection), true); - - MySqlCommand cmd = new MySqlCommand( - @"INSERT INTO my_aspnet_membership - VALUES(@userId, @email, @comment, @password, @passwordKey, - @passwordFormat, @passwordQuestion, @passwordAnswer, - @isApproved, @lastActivityDate, @lastLoginDate, - @lastPasswordChangedDate, @creationDate, - @isLockedOut, @lastLockedOutDate, @failedPasswordAttemptCount, - @failedPasswordAttemptWindowStart, @failedPasswordAnswerAttemptCount, - @failedPasswordAnswerAttemptWindowStart)", - connection); - cmd.Parameters.AddWithValue("@userId", userId); - cmd.Parameters.AddWithValue("@email", email); - cmd.Parameters.AddWithValue("@comment", ""); - cmd.Parameters.AddWithValue("@password", - EncodePassword(password, passwordKey, PasswordFormat)); - cmd.Parameters.AddWithValue("@passwordKey", passwordKey); - cmd.Parameters.AddWithValue("@passwordFormat", PasswordFormat); - cmd.Parameters.AddWithValue("@passwordQuestion", passwordQuestion); - cmd.Parameters.AddWithValue("@passwordAnswer", - EncodePassword(passwordAnswer, passwordKey, PasswordFormat)); - cmd.Parameters.AddWithValue("@isApproved", isApproved); - cmd.Parameters.AddWithValue("@lastActivityDate", createDate); - cmd.Parameters.AddWithValue("@lastLoginDate", createDate); - cmd.Parameters.AddWithValue("@lastPasswordChangedDate", createDate); - cmd.Parameters.AddWithValue("@creationDate", createDate); - cmd.Parameters.AddWithValue("@isLockedOut", false); - cmd.Parameters.AddWithValue("@lastLockedOutDate", createDate); - cmd.Parameters.AddWithValue("@failedPasswordAttemptCount", 0); - cmd.Parameters.AddWithValue("@failedPasswordAttemptWindowStart", createDate); - cmd.Parameters.AddWithValue("@failedPasswordAnswerAttemptCount", 0); - cmd.Parameters.AddWithValue("@failedPasswordAnswerAttemptWindowStart", createDate); - - int recAdded = cmd.ExecuteNonQuery(); - if (recAdded > 0) - status = MembershipCreateStatus.Success; - else - status = MembershipCreateStatus.UserRejected; - transaction.Commit(); - } - catch (MySqlException e) - { - if (WriteExceptionsToEventLog) - WriteToEventLog(e, "CreateUser"); - status = MembershipCreateStatus.ProviderError; - if (transaction != null) - transaction.Rollback(); - return null; - } - } - - return GetUser(username, false); - } - - /// - /// Removes a user from the membership data source. - /// - /// The name of the user to delete. - /// true to delete data related to the user from the database; false to leave data related to the user in the database. - /// - /// true if the user was successfully deleted; otherwise, false. - /// - public override bool DeleteUser(string username, bool deleteAllRelatedData) - { - try - { - using (MySqlConnection conn = new MySqlConnection(connectionString)) - { - conn.Open(); - - int userId = GetUserId(conn, username); - if (-1 == userId) return false; - - // if we are supposed to delete all related data, then delegate that to those providers - if (deleteAllRelatedData) - { - MySQLRoleProvider.DeleteUserData(conn, userId); - MySQLProfileProvider.DeleteUserData(conn, userId); - } - - string sql = @"DELETE {0}m - FROM my_aspnet_users u, my_aspnet_membership m - WHERE u.id=m.userId AND u.id=@userId"; - - MySqlCommand cmd = new MySqlCommand( - String.Format(sql, deleteAllRelatedData ? "u," : ""), conn); - cmd.Parameters.AddWithValue("@appId", app.FetchId(conn)); - cmd.Parameters.AddWithValue("@userId", userId); - return cmd.ExecuteNonQuery() > 0; - } - } - catch (MySqlException e) - { - if (WriteExceptionsToEventLog) - WriteToEventLog(e, "DeleteUser"); - throw new ProviderException(exceptionMessage, e); - } - } - - /// - /// Gets a collection of all the users in the data source in pages of data. - /// - /// The index of the page of results to return. is zero-based. - /// The size of the page of results to return. - /// The total number of matched users. - /// - /// A collection that contains a page of objects beginning at the page specified by . - /// - public override MembershipUserCollection GetAllUsers(int pageIndex, - int pageSize, out int totalRecords) - { - return GetUsers(null, null, pageIndex, pageSize, out totalRecords); - } - - /// - /// Gets the number of users currently accessing the application. - /// - /// - /// The number of users currently accessing the application. - /// - public override int GetNumberOfUsersOnline() - { - TimeSpan onlineSpan = new TimeSpan(0, Membership.UserIsOnlineTimeWindow, 0); - DateTime compareTime = DateTime.Now.Subtract(onlineSpan); - - try - { - using (MySqlConnection connection = new MySqlConnection(connectionString)) - { - connection.Open(); - MySqlCommand cmd = new MySqlCommand( - @"SELECT COUNT(*) FROM my_aspnet_membership m JOIN my_aspnet_users u - ON m.userId=u.id WHERE m.LastActivityDate > @date AND u.applicationId=@appId", - connection); - cmd.Parameters.AddWithValue("@date", compareTime); - cmd.Parameters.AddWithValue("@appId", app.FetchId(connection)); - return Convert.ToInt32(cmd.ExecuteScalar()); - } - } - catch (MySqlException e) - { - if (WriteExceptionsToEventLog) - WriteToEventLog(e, "GetNumberOfUsersOnline"); - throw new ProviderException(exceptionMessage, e); - } - } - - /// - /// Gets the password for the specified user name from the data source. - /// - /// The user to retrieve the password for. - /// The password answer for the user. - /// - /// The password for the specified user name. - /// - public override string GetPassword(string username, string answer) - { - if (!EnablePasswordRetrieval) - throw new ProviderException(Properties.Resources.PasswordRetrievalNotEnabled); - - try - { - using (MySqlConnection connection = new MySqlConnection(connectionString)) - { - connection.Open(); - - int userId = GetUserId(connection, username); - if (-1 == userId) - throw new ProviderException("Username not found."); - - string sql = @"SELECT Password, PasswordAnswer, PasswordKey, PasswordFormat, - IsLockedOut FROM my_aspnet_membership WHERE userId=@userId"; - MySqlCommand cmd = new MySqlCommand(sql, connection); - cmd.Parameters.AddWithValue("@userId", userId); - - using (MySqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SingleRow)) - { - reader.Read(); - if (reader.GetBoolean("IsLockedOut")) - throw new MembershipPasswordException(Properties.Resources.UserIsLockedOut); - - string password = reader.GetString("Password"); - string passwordAnswer = reader.GetValue(reader.GetOrdinal("PasswordAnswer")).ToString(); - string passwordKey = reader.GetString("PasswordKey"); - MembershipPasswordFormat format = (MembershipPasswordFormat)reader.GetInt32(3); - reader.Close(); - - if (RequiresQuestionAndAnswer && - !(CheckPassword(answer, passwordAnswer, passwordKey, format))) - { - UpdateFailureCount(userId, "PasswordAnswer", connection); - throw new MembershipPasswordException(Properties.Resources.IncorrectPasswordAnswer); - } - if (PasswordFormat == MembershipPasswordFormat.Encrypted) - { - password = UnEncodePassword(password, format); - } - return password; - } - } - } - catch (MySqlException e) - { - if (WriteExceptionsToEventLog) - WriteToEventLog(e, "GetPassword"); - throw new ProviderException(exceptionMessage, e); - } - } - - /// - /// Gets information from the data source for a user. Provides an option to update the last-activity date/time stamp for the user. - /// - /// The name of the user to get information for. - /// true to update the last-activity date/time stamp for the user; false to return user information without updating the last-activity date/time stamp for the user. - /// - /// A object populated with the specified user's information from the data source. - /// - public override MembershipUser GetUser(string username, bool userIsOnline) - { - try - { - int userId = -1; - using (MySqlConnection connection = new MySqlConnection(connectionString)) - { - connection.Open(); - - userId = GetUserId(connection, username); - if (-1 == userId) return null; - } - - return GetUser(userId, userIsOnline); - } - catch (MySqlException e) - { - if (WriteExceptionsToEventLog) - WriteToEventLog(e, "GetUser(String, Boolean)"); - throw new ProviderException(exceptionMessage, e); - } - } - - /// - /// Gets user information from the data source based on the unique identifier for the membership user. Provides an option to update the last-activity date/time stamp for the user. - /// - /// The unique identifier for the membership user to get information for. - /// true to update the last-activity date/time stamp for the user; false to return user information without updating the last-activity date/time stamp for the user. - /// - /// A object populated with the specified user's information from the data source. - /// - public override MembershipUser GetUser(object providerUserKey, bool userIsOnline) - { - MySqlTransaction txn = null; - - try - { - using (MySqlConnection connection = new MySqlConnection(connectionString)) - { - connection.Open(); - - txn = connection.BeginTransaction(); - MySqlCommand cmd = new MySqlCommand("", connection); - cmd.Parameters.AddWithValue("@userId", providerUserKey); - - if (userIsOnline) - { - cmd.CommandText = - @"UPDATE my_aspnet_users SET lastActivityDate = @date WHERE id=@userId"; - cmd.Parameters.AddWithValue("@date", DateTime.Now); - cmd.ExecuteNonQuery(); - - cmd.CommandText = "UPDATE my_aspnet_membership SET LastActivityDate=@date WHERE userId=@userId"; - cmd.ExecuteNonQuery(); - } - - cmd.CommandText = @"SELECT m.*,u.name - FROM my_aspnet_membership m JOIN my_aspnet_users u ON m.userId=u.id - WHERE u.id=@userId"; - - MembershipUser user; - using (MySqlDataReader reader = cmd.ExecuteReader()) - { - if (!reader.Read()) return null; - user = GetUserFromReader(reader); - } - txn.Commit(); - return user; - } - } - catch (MySqlException e) - { - if (txn != null) - txn.Rollback(); - if (WriteExceptionsToEventLog) - WriteToEventLog(e, "GetUser(Object, Boolean)"); - throw new ProviderException(exceptionMessage); - } - } - - /// - /// Unlocks the user. - /// - /// The username. - /// true if the membership user was successfully unlocked; - /// otherwise, false. A value of false is also returned if the user - /// does not exist in the database. - public override bool UnlockUser(string username) - { - try - { - using (MySqlConnection conn = new MySqlConnection(connectionString)) - { - conn.Open(); - - int userId = GetUserId(conn, username); - if (-1 == userId) return false; - - string sql = @"UPDATE my_aspnet_membership - SET IsLockedOut = false, LastLockedOutDate = @lastDate - WHERE userId=@userId"; - - MySqlCommand cmd = new MySqlCommand(sql, conn); - cmd.Parameters.AddWithValue("@lastDate", DateTime.Now); - cmd.Parameters.AddWithValue("@userId", userId); - return cmd.ExecuteNonQuery() > 0; - } - } - catch (MySqlException e) - { - if (WriteExceptionsToEventLog) - WriteToEventLog(e, "UnlockUser"); - throw new ProviderException(exceptionMessage, e); - } - } - - /// - /// Gets the user name associated with the specified e-mail address. - /// - /// The e-mail address to search for. - /// - /// The user name associated with the specified e-mail address. If no match is found, return null. - /// - public override string GetUserNameByEmail(string email) - { - try - { - using (MySqlConnection conn = new MySqlConnection(connectionString)) - { - conn.Open(); - - string sql = @"SELECT u.name FROM my_aspnet_users u - JOIN my_aspnet_membership m ON m.userid=u.id - WHERE m.Email = @email AND u.applicationId=@appId"; - MySqlCommand cmd = new MySqlCommand(sql, conn); - cmd.Parameters.AddWithValue("@email", email); - cmd.Parameters.AddWithValue("@appId", app.FetchId(conn)); - return (string)cmd.ExecuteScalar(); - } - } - catch (MySqlException e) - { - if (WriteExceptionsToEventLog) - WriteToEventLog(e, "GetUserNameByEmail"); - throw new ProviderException(exceptionMessage); - } - } - - /// - /// Resets a user's password to a new, automatically generated password. - /// - /// The user to reset the password for. - /// The password answer for the specified user. - /// The new password for the specified user. - public override string ResetPassword(string username, string answer) - { - if (!(EnablePasswordReset)) - throw new NotSupportedException(Properties.Resources.PasswordResetNotEnabled); - - try - { - using (MySqlConnection connection = new MySqlConnection(connectionString)) - { - connection.Open(); - - // fetch the userid first - int userId = GetUserId(connection, username); - if (-1 == userId) - throw new ProviderException(Properties.Resources.UsernameNotFound); - - if (answer == null && RequiresQuestionAndAnswer) - { - UpdateFailureCount(userId, "PasswordAnswer", connection); - throw new ProviderException(Properties.Resources.PasswordRequiredForReset); - } - - string newPassword = Membership.GeneratePassword(newPasswordLength, MinRequiredNonAlphanumericCharacters); - ValidatePasswordEventArgs Args = new ValidatePasswordEventArgs(username, newPassword, true); - OnValidatingPassword(Args); - if (Args.Cancel) - { - if (!(Args.FailureInformation == null)) - throw Args.FailureInformation; - else - throw new MembershipPasswordException(Properties.Resources.PasswordResetCanceledNotValid); - } - - MySqlCommand cmd = new MySqlCommand(@"SELECT PasswordAnswer, - PasswordKey, PasswordFormat, IsLockedOut - FROM my_aspnet_membership WHERE userId=@userId", connection); - cmd.Parameters.AddWithValue("@userId", userId); - - string passwordKey = String.Empty; - MembershipPasswordFormat format; - using (MySqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SingleRow)) - { - reader.Read(); - if (reader.GetBoolean("IsLockedOut")) - throw new MembershipPasswordException(Properties.Resources.UserIsLockedOut); - - object passwordAnswer = reader.GetValue(reader.GetOrdinal("PasswordAnswer")); - passwordKey = reader.GetString("PasswordKey"); - format = (MembershipPasswordFormat)reader.GetByte("PasswordFormat"); - reader.Close(); - - if (RequiresQuestionAndAnswer) - { - if (!CheckPassword(answer, (string)passwordAnswer, passwordKey, format)) - { - UpdateFailureCount(userId, "PasswordAnswer", connection); - throw new MembershipPasswordException(Properties.Resources.IncorrectPasswordAnswer); - } - } - } - - cmd.CommandText = @"UPDATE my_aspnet_membership - SET Password = @pass, LastPasswordChangedDate = @lastPassChange - WHERE userId=@userId"; - - cmd.Parameters.AddWithValue("@pass", - EncodePassword(newPassword, passwordKey, format)); - cmd.Parameters.AddWithValue("@lastPassChange", DateTime.Now); - int rowsAffected = cmd.ExecuteNonQuery(); - if (rowsAffected != 1) - throw new MembershipPasswordException(Properties.Resources.ErrorResettingPassword); - return newPassword; - } - } - catch (MySqlException e) - { - if (WriteExceptionsToEventLog) - WriteToEventLog(e, "ResetPassword"); - throw new ProviderException(exceptionMessage, e); - } - } - - /// - /// Updates information about a user in the data source. - /// - /// A object - /// that represents the user to update and the updated information for the user. - public override void UpdateUser(MembershipUser user) - { - try - { - using (MySqlConnection conn = new MySqlConnection(connectionString)) - { - conn.Open(); - - int userId = GetUserId(conn, user.UserName); - if (-1 == userId) - throw new ProviderException(Properties.Resources.UsernameNotFound); - - string sql = @"UPDATE my_aspnet_membership m, my_aspnet_users u - SET m.Email=@email, m.Comment=@comment, m.IsApproved=@isApproved, - m.LastLoginDate=@lastLoginDate, u.lastActivityDate=@lastActivityDate, - m.LastActivityDate=@lastActivityDate - WHERE m.userId=u.id AND u.name LIKE @name AND u.applicationId=@appId"; - MySqlCommand cmd = new MySqlCommand(sql, conn); - cmd.Parameters.AddWithValue("@Email", user.Email); - cmd.Parameters.AddWithValue("@Comment", user.Comment); - cmd.Parameters.AddWithValue("@isApproved", user.IsApproved); - cmd.Parameters.AddWithValue("@lastLoginDate", user.LastLoginDate); - cmd.Parameters.AddWithValue("@lastActivityDate", user.LastActivityDate); - cmd.Parameters.AddWithValue("@name", user.UserName); - cmd.Parameters.AddWithValue("@appId", app.FetchId(conn)); - cmd.ExecuteNonQuery(); - } - } - catch (MySqlException e) - { - if (WriteExceptionsToEventLog) - WriteToEventLog(e, "UpdateUser"); - throw new ProviderException(exceptionMessage); - } - } - - /// - /// Verifies that the specified user name and password exist in the data source. - /// - /// The name of the user to validate. - /// The password for the specified user. - /// - /// true if the specified username and password are valid; otherwise, false. - /// - public override bool ValidateUser(string username, string password) - { - bool isValid = false; - try - { - using (MySqlConnection connection = new MySqlConnection(connectionString)) - { - connection.Open(); - - // first get the user id. If that is -1, then the user doesn't exist - // so we just return false since we can't bump any counters - int userId = GetUserId(connection, username); - if (-1 == userId) return false; - - string sql = @"SELECT Password, PasswordKey, PasswordFormat, IsApproved, - Islockedout FROM my_aspnet_membership WHERE userId=@userId"; - MySqlCommand cmd = new MySqlCommand(sql, connection); - cmd.Parameters.AddWithValue("@userId", userId); - - using (MySqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SingleRow)) - { - if (!reader.HasRows) return false; - reader.Read(); - if (reader.GetBoolean("IsLockedOut")) return false; - - string pwd = reader.GetString(0); - string passwordKey = reader.GetString(1); - MembershipPasswordFormat format = (MembershipPasswordFormat) - reader.GetInt32(2); - bool isApproved = reader.GetBoolean(3); - reader.Close(); - - if (!CheckPassword(password, pwd, passwordKey, format)) - UpdateFailureCount(userId, "Password", connection); - else if (isApproved) - { - isValid = true; - DateTime currentDate = DateTime.Now; - MySqlCommand updateCmd = new MySqlCommand( - @"UPDATE my_aspnet_membership m, my_aspnet_users u - SET m.LastLoginDate = @lastLoginDate, u.lastActivityDate = @date, - m.LastActivityDate=@date - WHERE m.userId=@userid AND u.id=@userid", connection); - updateCmd.Parameters.AddWithValue("@lastLoginDate", currentDate); - updateCmd.Parameters.AddWithValue("@date", currentDate); - updateCmd.Parameters.AddWithValue("@userid", userId); - updateCmd.ExecuteNonQuery(); - } - } - return isValid; - } - } - catch (MySqlException e) - { - if (WriteExceptionsToEventLog) - WriteToEventLog(e, "ValidateUser"); - throw new ProviderException(exceptionMessage, e); - } - } - - /// - /// Gets a collection of membership users where the user name contains the specified user name to match. - /// - /// The user name to search for. - /// The index of the page of results to return. is zero-based. - /// The size of the page of results to return. - /// The total number of matched users. - /// - /// A collection that contains a page of objects beginning at the page specified by . - /// - public override MembershipUserCollection FindUsersByName(string usernameToMatch, - int pageIndex, int pageSize, out int totalRecords) - { - return GetUsers(usernameToMatch, null, pageIndex, pageSize, out totalRecords); - } - - /// - /// Gets a collection of membership users where the e-mail address contains the specified e-mail address to match. - /// - /// The e-mail address to search for. - /// The index of the page of results to return. is zero-based. - /// The size of the page of results to return. - /// The total number of matched users. - /// - /// A collection that contains a page of objects beginning at the page specified by . - /// - public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, - int pageSize, out int totalRecords) - { - return GetUsers(null, emailToMatch, pageIndex, pageSize, out totalRecords); - } - - #endregion - - #region Private Methods - - private int GetUserId(MySqlConnection connection, string username) - { - MySqlCommand cmd = new MySqlCommand( - "SELECT id FROM my_aspnet_users WHERE name = @name AND applicationId=@appId", connection); - cmd.Parameters.AddWithValue("@name", username); - cmd.Parameters.AddWithValue("@appId", app.FetchId(connection)); - object id = cmd.ExecuteScalar(); - if (id == null) return -1; - return (int)id; - } - - private void WriteToEventLog(Exception e, string action) - { - using (EventLog log = new EventLog()) - { - log.Source = eventSource; - log.Log = eventLog; - string message = "An exception occurred communicating with the data source." + - Environment.NewLine + Environment.NewLine; - message += "Action: " + action + Environment.NewLine + Environment.NewLine; - message += "Exception: " + e; - log.WriteEntry(message); - } - } - - private MembershipUser GetUserFromReader(MySqlDataReader reader) - { - object providerUserKey = reader.GetInt32("userId"); - string username = reader.GetString("name"); - - string email = null; - if (!reader.IsDBNull(reader.GetOrdinal("Email"))) - email = reader.GetString("Email"); - - string passwordQuestion = ""; - if (!(reader.GetValue(reader.GetOrdinal("PasswordQuestion")) == DBNull.Value)) - passwordQuestion = reader.GetString("PasswordQuestion"); - - string comment = ""; - if (!(reader.GetValue(reader.GetOrdinal("Comment")) == DBNull.Value)) - comment = reader.GetString("Comment"); - - bool isApproved = reader.GetBoolean("IsApproved"); - bool isLockedOut = reader.GetBoolean("IsLockedOut"); - DateTime creationDate = reader.GetDateTime("CreationDate"); - DateTime lastLoginDate = new DateTime(); - if (!(reader.GetValue(reader.GetOrdinal("LastLoginDate")) == DBNull.Value)) - lastLoginDate = reader.GetDateTime("LastLoginDate"); - - DateTime lastActivityDate = reader.GetDateTime("LastActivityDate"); - DateTime lastPasswordChangedDate = reader.GetDateTime("LastPasswordChangedDate"); - DateTime lastLockedOutDate = new DateTime(); - if (!(reader.GetValue(reader.GetOrdinal("LastLockedoutDate")) == DBNull.Value)) - lastLockedOutDate = reader.GetDateTime("LastLockedoutDate"); - - MembershipUser u = - new MembershipUser(Name, username, providerUserKey, email, passwordQuestion, comment, isApproved, - isLockedOut, creationDate, lastLoginDate, lastActivityDate, lastPasswordChangedDate, - lastLockedOutDate); - return u; - } - - private string UnEncodePassword(string encodedPassword, MembershipPasswordFormat format) - { - string password = encodedPassword; - if (format == MembershipPasswordFormat.Clear) - return encodedPassword; - else if (format == MembershipPasswordFormat.Encrypted) - return Encoding.Unicode.GetString(DecryptPassword( - Convert.FromBase64String(password))); - else if (format == MembershipPasswordFormat.Hashed) - throw new ProviderException(Properties.Resources.CannotUnencodeHashedPwd); - else - throw new ProviderException(Properties.Resources.UnsupportedPasswordFormat); - } - - private string GetPasswordKey() - { - RNGCryptoServiceProvider cryptoProvider = - new RNGCryptoServiceProvider(); - byte[] key = new byte[16]; - cryptoProvider.GetBytes(key); - return Convert.ToBase64String(key); - } - - /// - /// this method is only necessary because early versions of Mono did not support - /// the HashAlgorithmType property - /// - /// - /// - /// - private string HashPasswordBytes(byte[] key, byte[] bytes) - { - HashAlgorithm hash = HashAlgorithm.Create(Membership.HashAlgorithmType); - - if (hash is KeyedHashAlgorithm) - { - KeyedHashAlgorithm keyedHash = hash as KeyedHashAlgorithm; - keyedHash.Key = key; - } - return Convert.ToBase64String(hash.ComputeHash(bytes)); - } - - private string EncodePassword(string password, string passwordKey, - MembershipPasswordFormat format) - { - if (password == null) - return null; - if (format == MembershipPasswordFormat.Clear) - return password; - - byte[] passwordBytes = Encoding.Unicode.GetBytes(password); - byte[] keyBytes = Convert.FromBase64String(passwordKey); - byte[] keyedBytes = new byte[passwordBytes.Length + keyBytes.Length]; - Array.Copy(keyBytes, keyedBytes, keyBytes.Length); - Array.Copy(passwordBytes, 0, keyedBytes, keyBytes.Length, passwordBytes.Length); - - if (format == MembershipPasswordFormat.Encrypted) - { - byte[] encryptedBytes = EncryptPassword(passwordBytes); - return Convert.ToBase64String(encryptedBytes); - } - else if (format == MembershipPasswordFormat.Hashed) - return HashPasswordBytes(keyBytes, keyedBytes); - else - throw new ProviderException(Properties.Resources.UnsupportedPasswordFormat); - } - - private void UpdateFailureCount(int userId, string failureType, MySqlConnection connection) - { - MySqlCommand cmd = new MySqlCommand( - @"SELECT FailedPasswordAttemptCount, - FailedPasswordAttemptWindowStart, FailedPasswordAnswerAttemptCount, - FailedPasswordAnswerAttemptWindowStart FROM my_aspnet_membership - WHERE userId=@userId", connection); - cmd.Parameters.AddWithValue("@userId", userId); - - DateTime windowStart = new DateTime(); - int failureCount = 0; - try - { - using (MySqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SingleRow)) - { - if (!reader.HasRows) - throw new ProviderException(Properties.Resources.UnableToUpdateFailureCount); - - reader.Read(); - if (failureType == "Password") - { - failureCount = reader.GetInt32(0); - windowStart = reader.GetDateTime(1); - } - if (failureType == "PasswordAnswer") - { - failureCount = reader.GetInt32(2); - windowStart = reader.GetDateTime(3); - } - } - - DateTime windowEnd = windowStart.AddMinutes(PasswordAttemptWindow); - if (failureCount == 0 || DateTime.Now > windowEnd) - { - if (failureType == "Password") - { - cmd.CommandText = - @"UPDATE my_aspnet_membership - SET FailedPasswordAttemptCount = @count, - FailedPasswordAttemptWindowStart = @windowStart - WHERE userId=@userId"; - } - if (failureType == "PasswordAnswer") - { - cmd.CommandText = - @"UPDATE my_aspnet_membership - SET FailedPasswordAnswerAttemptCount = @count, - FailedPasswordAnswerAttemptWindowStart = @windowStart - WHERE userId = @userId"; - } - cmd.Parameters.Clear(); - cmd.Parameters.AddWithValue("@count", 1); - cmd.Parameters.AddWithValue("@windowStart", DateTime.Now); - cmd.Parameters.AddWithValue("@userId", userId); - if (cmd.ExecuteNonQuery() < 0) - throw new ProviderException(Properties.Resources.UnableToUpdateFailureCount); - } - else - { - failureCount += 1; - if (failureCount >= MaxInvalidPasswordAttempts) - { - cmd.CommandText = - @"UPDATE my_aspnet_membership SET IsLockedOut = @isLockedOut, - LastLockedOutDate = @lastLockedOutDate WHERE userId=@userId"; - cmd.Parameters.Clear(); - cmd.Parameters.AddWithValue("@isLockedOut", true); - cmd.Parameters.AddWithValue("@lastLockedOutDate", DateTime.Now); - cmd.Parameters.AddWithValue("@userId", userId); - if (cmd.ExecuteNonQuery() < 0) - throw new ProviderException(Properties.Resources.UnableToLockOutUser); - } - else - { - if (failureType == "Password") - { - cmd.CommandText = - @"UPDATE my_aspnet_membership - SET FailedPasswordAttemptCount = @count WHERE userId=@userId"; - } - if (failureType == "PasswordAnswer") - { - cmd.CommandText = - @"UPDATE my_aspnet_membership - SET FailedPasswordAnswerAttemptCount = @count - WHERE userId=@userId"; - } - cmd.Parameters.Clear(); - cmd.Parameters.AddWithValue("@count", failureCount); - cmd.Parameters.AddWithValue("@userId", userId); - if (cmd.ExecuteNonQuery() < 0) - throw new ProviderException("Unable to update failure count."); - } - } - } - catch (MySqlException e) - { - if (WriteExceptionsToEventLog) - WriteToEventLog(e, "UpdateFailureCount"); - throw new ProviderException(exceptionMessage, e); - } - } - - private bool CheckPassword(string password, string dbpassword, - string passwordKey, MembershipPasswordFormat format) - { - password = EncodePassword(password, passwordKey, format); - return password == dbpassword; - } - - private void GetPasswordInfo(MySqlConnection connection, int userId, - out string passwordKey, out MembershipPasswordFormat passwordFormat) - { - MySqlCommand cmd = new MySqlCommand( - @"SELECT PasswordKey, PasswordFormat FROM my_aspnet_membership WHERE - userId=@userId", connection); - cmd.Parameters.AddWithValue("@userId", userId); - using (MySqlDataReader reader = cmd.ExecuteReader()) - { - reader.Read(); - passwordKey = reader.GetString(reader.GetOrdinal("PasswordKey")); - passwordFormat = (MembershipPasswordFormat)reader.GetByte( - reader.GetOrdinal("PasswordFormat")); - } - } - - private MembershipUserCollection GetUsers(string username, string email, - int pageIndex, int pageSize, out int totalRecords) - { - MembershipUserCollection users = new MembershipUserCollection(); - try - { - using (MySqlConnection connection = new MySqlConnection(connectionString)) - { - connection.Open(); - MySqlCommand cmd = new MySqlCommand(); - cmd.Connection = connection; - - string sql = @"SELECT SQL_CALC_FOUND_ROWS u.name,m.* FROM my_aspnet_users u - JOIN my_aspnet_membership m ON m.userId=u.id - WHERE u.applicationId=@appId"; - - if (username != null) - { - sql += " AND u.name LIKE @name"; - cmd.Parameters.AddWithValue("@name", username); - } - else if (email != null) - { - sql += " AND m.Email LIKE @email"; - cmd.Parameters.AddWithValue("@email", email); - } - sql += " ORDER BY u.id ASC LIMIT {0},{1}"; - cmd.CommandText = String.Format(sql, pageIndex * pageSize, pageSize); - cmd.Parameters.AddWithValue("@appId", app.FetchId(connection)); - using (MySqlDataReader reader = cmd.ExecuteReader()) - { - while (reader.Read()) - users.Add(GetUserFromReader(reader)); - } - cmd.CommandText = "SELECT FOUND_ROWS()"; - cmd.Parameters.Clear(); - totalRecords = Convert.ToInt32(cmd.ExecuteScalar()); - } - return users; - } - catch (MySqlException e) - { - if (WriteExceptionsToEventLog) - WriteToEventLog(e, "GetUsers"); - throw new ProviderException(exceptionMessage); - } - } - - private void ValidateQA(string question, string answer) - { - if (RequiresQuestionAndAnswer && String.IsNullOrEmpty(question)) - throw new ArgumentException(Properties.Resources.PasswordQuestionInvalid); - if (RequiresQuestionAndAnswer && String.IsNullOrEmpty(answer)) - throw new ArgumentException(Properties.Resources.PasswordAnswerInvalid); - } - - private bool ValidatePassword(string password, string argumentName, bool throwExceptions) - { - string exceptionString = null; - object correctValue = MinRequiredPasswordLength; - - if (password.Length < MinRequiredPasswordLength) - exceptionString = Properties.Resources.PasswordNotLongEnough; - else - { - int count = 0; - foreach (char c in password) - if (!char.IsLetterOrDigit(c)) - count++; - if (count < MinRequiredNonAlphanumericCharacters) - exceptionString = Properties.Resources.NotEnoughNonAlphaNumericInPwd; - correctValue = MinRequiredNonAlphanumericCharacters; - } - - if (exceptionString != null) - { - if (throwExceptions) - throw new ArgumentException( - string.Format(exceptionString, argumentName, correctValue), - argumentName); - else - return false; - } - - if (PasswordStrengthRegularExpression.Length > 0) - if (!Regex.IsMatch(password, PasswordStrengthRegularExpression)) - return false; - - return true; - } - - private void TrimParametersValues(ref string username, ref string password, ref string email, ref string passwordQuestion, ref string passwordAnswer) - { - username = string.IsNullOrEmpty(username) ? username : username.Trim(); - password = string.IsNullOrEmpty(password) ? password : password.Trim(); - email = string.IsNullOrEmpty(email) ? email : email.Trim(); - passwordQuestion = string.IsNullOrEmpty(passwordQuestion) ? passwordQuestion : passwordQuestion.Trim(); - passwordAnswer = string.IsNullOrEmpty(passwordAnswer) ? passwordAnswer : passwordAnswer.Trim(); - } - - #endregion - } -} +// Copyright © 2004, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +// This code was contributed by Sean Wright (srwright@alcor.concordia.ca) on 2007-01-12 +// The copyright was assigned and transferred under the terms of +// the MySQL Contributor License Agreement (CLA) + +using MySql.Data.MySqlClient; +using MySql.Web.Common; +using MySql.Web.General; +using MySql.Web.Profile; +using System; +using System.Collections.Specialized; +using System.Configuration.Provider; +using System.Data; +using System.Diagnostics; +using System.Security.Cryptography; +using System.Text; +using System.Text.RegularExpressions; +using System.Web.Hosting; +using System.Web.Security; + +namespace MySql.Web.Security +{ + /// + /// Manages storage of membership information for an ASP.NET application in a MySQL database. + /// + /// + /// + /// This class is used by the and classes + /// to provide membership services for ASP.NET applications using a MySQL database. + /// + /// + /// + /// + /// configuration> + /// connectionStrings> + /// add name = "LocalMySqlService" connectionString="server=localhost;user id=myuser;password=mypass;database=test" /> + /// /connectionStrings> + /// system.web> + /// authentication mode = "Forms" > + /// forms loginUrl="login.aspx" name=".ASPXFORMSAUTH" /> + /// /authentication> + /// authorization> + /// deny users = "?" /> + /// /authorization> + /// membership defaultProvider="MySQLProvider" userIsOnlineTimeWindow="15"> + /// providers> + /// add + /// name = "MySQLProvider" + /// type="MySql.Web.Security.MySQLMembershipProvider" + /// connectionStringName="LocalMySqlService" + /// applicationName="MyApplication" + /// enablePasswordRetrieval="false" + /// enablePasswordReset="true" + /// requiresQuestionAndAnswer="true" + /// requiresUniqueEmail="false" + /// passwordFormat="Hashed" + /// maxInvalidPasswordAttempts="5" + /// passwordAttemptWindow="10" /> + /// /providers> + /// /membership> + /// /system.web> + /// /configuration> + /// + /// + public sealed class MySQLMembershipProvider : MembershipProvider + { + private int newPasswordLength = 8; + private string eventSource = "MySQLMembershipProvider"; + private string eventLog = "Application"; + private string exceptionMessage = "An exception occurred. Please check the Event Log."; + private string connectionString; + private int minRequiredPasswordLength; + private bool writeExceptionsToEventLog; + private bool enablePasswordReset; + private bool enablePasswordRetrieval; + private bool requiresQuestionAndAnswer; + private bool requiresUniqueEmail; + private int maxInvalidPasswordAttempts; + private int passwordAttemptWindow; + private MembershipPasswordFormat passwordFormat; + private int minRequiredNonAlphanumericCharacters; + private string passwordStrengthRegularExpression; + private Application app; + + /// + /// Initializes the MySQL membership provider with the property values specified in the + /// ASP.NET application's configuration file. This method is not intended to be used directly + /// from your code. + /// + /// The name of the instance to initialize. + /// A collection of the name/value pairs representing the + /// provider-specific attributes specified in the configuration for this provider. + /// config is a null reference. + /// An attempt is made to call on a provider after the provider has already been initialized. + /// + public override void Initialize(string name, NameValueCollection config) + { + if (config == null) + { + throw new ArgumentNullException("config"); + } + if (name == null || name.Length == 0) + { + name = "MySQLMembershipProvider"; + } + if (string.IsNullOrEmpty(config["description"])) + { + config.Remove("description"); + config.Add("description", "MySQL default application"); + } + base.Initialize(name, config); + + string applicationName = GetConfigValue(config["applicationName"], + HostingEnvironment.ApplicationVirtualPath); + maxInvalidPasswordAttempts = Convert.ToInt32(GetConfigValue(config["maxInvalidPasswordAttempts"], "5")); + passwordAttemptWindow = Convert.ToInt32(GetConfigValue(config["passwordAttemptWindow"], "10")); + minRequiredNonAlphanumericCharacters = + Convert.ToInt32(GetConfigValue(config["minRequiredNonalphanumericCharacters"], "1")); + minRequiredPasswordLength = Convert.ToInt32(GetConfigValue(config["minRequiredPasswordLength"], "7")); + passwordStrengthRegularExpression = + Convert.ToString(GetConfigValue(config["passwordStrengthRegularExpression"], "")); + enablePasswordReset = Convert.ToBoolean(GetConfigValue(config["enablePasswordReset"], "True")); + enablePasswordRetrieval = Convert.ToBoolean( + GetConfigValue(config["enablePasswordRetrieval"], "False")); + requiresQuestionAndAnswer = Convert.ToBoolean(GetConfigValue(config["requiresQuestionAndAnswer"], "False")); + requiresUniqueEmail = Convert.ToBoolean(GetConfigValue(config["requiresUniqueEmail"], "True")); + writeExceptionsToEventLog = Convert.ToBoolean(GetConfigValue(config["writeExceptionsToEventLog"], "True")); + string temp_format = config["passwordFormat"]; + + if (temp_format == null) + temp_format = "hashed"; + else + temp_format = temp_format.ToLowerInvariant(); + + if (temp_format == "hashed") + passwordFormat = MembershipPasswordFormat.Hashed; + else if (temp_format == "encrypted") + passwordFormat = MembershipPasswordFormat.Encrypted; + else if (temp_format == "clear") + passwordFormat = MembershipPasswordFormat.Clear; + else + throw new ProviderException("Password format not supported."); + + // if the user is asking for the ability to retrieve hashed passwords, then let + // them know we can't + if (PasswordFormat == MembershipPasswordFormat.Hashed) + { + if (EnablePasswordRetrieval) + throw new ProviderException(Properties.Resources.CannotRetrieveHashedPasswords); + } + + connectionString = ConfigUtility.GetConnectionString(config); + if (String.IsNullOrEmpty(connectionString)) return; + + // make sure we have the correct schema + SchemaManager.CheckSchema(connectionString, config); + + app = new Application(applicationName, base.Description); + } + + private static string GetConfigValue(string configValue, string defaultValue) + { + if (string.IsNullOrEmpty(configValue)) + { + return defaultValue; + } + return configValue; + } + + #region Properties + + /// + /// The name of the application using the MySQL membership provider. + /// + /// The name of the application using the MySQL membership provider. The default is the + /// application virtual path. + /// The ApplicationName is used by the MySqlMembershipProvider to separate + /// membership information for multiple applications. Using different application names, + /// applications can use the same membership database. + /// Likewise, multiple applications can make use of the same membership data by simply using + /// the same application name. + /// Caution should be taken with multiple applications as the ApplicationName property is not + /// thread safe during writes. + /// + /// + /// The following example shows the membership element being used in an applications web.config file. + /// The application name setting is being used. + /// + /// membership defaultProvider="MySQLMembershipProvider"> + /// providers> + /// add name="MySqlMembershipProvider" + /// type="MySql.Web.Security.MySQLMembershipProvider" + /// connectionStringName="LocalMySqlServer" + /// enablePasswordRetrieval="true" + /// enablePasswordReset="false" + /// requiresQuestionAndAnswer="true" + /// requiresUniqueEmail="false" + /// passwordFormat="Encrypted" + /// maxInvalidPasswordAttempts="3" + /// passwordAttemptWindow="20" + /// minRequiredNonAlphanumericCharacters="1" + /// minRequiredPasswordLength="11" + /// applicationName="MyApplication" /> + /// /providers> + /// /membership> + /// + /// + public override string ApplicationName + { + get { return app.Name; } + set + { + lock (this) + { + if (value.ToLowerInvariant() == app.Name.ToLowerInvariant()) return; + app = new Application(value, String.Empty); + } + } + } + + /// + /// Indicates whether the membership provider is configured to allow users to reset their passwords. + /// + /// true if the membership provider supports password reset; otherwise, false. The default is true. + /// Allows the user to replace their password with a new, randomly generated password. + /// This can be especially handy when using hashed passwords since hashed passwords cannot be + /// retrieved. + /// + /// The following example shows the membership element being used in an applications web.config file. + /// + /// membership defaultProvider="MySQLMembershipProvider"> + /// providers> + /// add name="MySqlMembershipProvider" + /// type="MySql.Web.Security.MySQLMembershipProvider" + /// connectionStringName="LocalMySqlServer" + /// enablePasswordRetrieval="true" + /// enablePasswordReset="false" + /// requiresQuestionAndAnswer="true" + /// requiresUniqueEmail="false" + /// passwordFormat="Encrypted" + /// maxInvalidPasswordAttempts="3" + /// passwordAttemptWindow="20" + /// minRequiredNonAlphanumericCharacters="1" + /// minRequiredPasswordLength="11" + /// applicationName="MyApplication" /> + /// /providers> + /// /membership> + /// + /// + public override bool EnablePasswordReset + { + get { return enablePasswordReset; } + } + + /// + /// Indicates whether the membership provider is configured to allow users to retrieve + /// their passwords. + /// + /// true if the membership provider is configured to support password retrieval; + /// otherwise, false. The default is false. + /// If the system is configured to use hashed passwords, then retrieval is not possible. + /// If the user attempts to initialize the provider with hashed passwords and enable password retrieval + /// set to true then a is thrown. + /// + /// The following example shows the membership element being used in an applications web.config file. + /// + /// membership defaultProvider="MySQLMembershipProvider"> + /// providers> + /// add name="MySqlMembershipProvider" + /// type="MySql.Web.Security.MySQLMembershipProvider" + /// connectionStringName="LocalMySqlServer" + /// enablePasswordRetrieval="true" + /// enablePasswordReset="false" + /// requiresQuestionAndAnswer="true" + /// requiresUniqueEmail="false" + /// passwordFormat="Encrypted" + /// maxInvalidPasswordAttempts="3" + /// passwordAttemptWindow="20" + /// minRequiredNonAlphanumericCharacters="1" + /// minRequiredPasswordLength="11" + /// applicationName="MyApplication" /> + /// /providers> + /// /membership> + /// + /// + public override bool EnablePasswordRetrieval + { + get { return enablePasswordRetrieval; } + } + + /// + /// Gets a value indicating whether the membership provider is + /// configured to require the user to answer a password question + /// for password reset and retrieval. + /// + /// true if a password answer is required for password + /// reset and retrieval; otherwise, false. The default is false. + /// + /// The following example shows the membership element being used in an applications web.config file. + /// + /// membership defaultProvider="MySQLMembershipProvider"> + /// providers> + /// add name="MySqlMembershipProvider" + /// type="MySql.Web.Security.MySQLMembershipProvider" + /// connectionStringName="LocalMySqlServer" + /// enablePasswordRetrieval="true" + /// enablePasswordReset="false" + /// requiresQuestionAndAnswer="true" + /// requiresUniqueEmail="false" + /// passwordFormat="Encrypted" + /// maxInvalidPasswordAttempts="3" + /// passwordAttemptWindow="20" + /// minRequiredNonAlphanumericCharacters="1" + /// minRequiredPasswordLength="11" + /// applicationName="MyApplication" /> + /// /providers> + /// /membership> + /// + /// + public override bool RequiresQuestionAndAnswer + { + get { return requiresQuestionAndAnswer; } + } + + /// + /// Gets a value indicating whether the membership provider is configured + /// to require a unique e-mail address for each user name. + /// + /// true if the membership provider requires a unique e-mail address; + /// otherwise, false. The default is true. + /// + /// The following example shows the membership element being used in an applications web.config file. + /// + /// membership defaultProvider="MySQLMembershipProvider"> + /// providers> + /// add name="MySqlMembershipProvider" + /// type="MySql.Web.Security.MySQLMembershipProvider" + /// connectionStringName="LocalMySqlServer" + /// enablePasswordRetrieval="true" + /// enablePasswordReset="false" + /// requiresQuestionAndAnswer="true" + /// requiresUniqueEmail="false" + /// passwordFormat="Encrypted" + /// maxInvalidPasswordAttempts="3" + /// passwordAttemptWindow="20" + /// minRequiredNonAlphanumericCharacters="1" + /// minRequiredPasswordLength="11" + /// applicationName="MyApplication" /> + /// /providers> + /// /membership> + /// + /// + public override bool RequiresUniqueEmail + { + get { return requiresUniqueEmail; } + } + + /// + /// Gets the number of invalid password or password-answer attempts allowed + /// before the membership user is locked out. + /// + /// The number of invalid password or password-answer attempts allowed + /// before the membership user is locked out. + /// + /// The following example shows the membership element being used in an applications web.config file. + /// + /// membership defaultProvider="MySQLMembershipProvider"> + /// providers> + /// add name="MySqlMembershipProvider" + /// type="MySql.Web.Security.MySQLMembershipProvider" + /// connectionStringName="LocalMySqlServer" + /// enablePasswordRetrieval="true" + /// enablePasswordReset="false" + /// requiresQuestionAndAnswer="true" + /// requiresUniqueEmail="false" + /// passwordFormat="Encrypted" + /// maxInvalidPasswordAttempts="3" + /// passwordAttemptWindow="20" + /// minRequiredNonAlphanumericCharacters="1" + /// minRequiredPasswordLength="11" + /// applicationName="MyApplication" /> + /// /providers> + /// /membership> + /// + /// + public override int MaxInvalidPasswordAttempts + { + get { return maxInvalidPasswordAttempts; } + } + + /// + /// Gets the number of minutes in which a maximum number of invalid password or + /// password-answer attempts are allowed before the membership user is locked out. + /// + /// The number of minutes in which a maximum number of invalid password or + /// password-answer attempts are allowed before the membership user is locked out. + /// + /// The following example shows the membership element being used in an applications web.config file. + /// + /// membership defaultProvider="MySQLMembershipProvider"> + /// providers> + /// add name="MySqlMembershipProvider" + /// type="MySql.Web.Security.MySQLMembershipProvider" + /// connectionStringName="LocalMySqlServer" + /// enablePasswordRetrieval="true" + /// enablePasswordReset="false" + /// requiresQuestionAndAnswer="true" + /// requiresUniqueEmail="false" + /// passwordFormat="Encrypted" + /// maxInvalidPasswordAttempts="3" + /// passwordAttemptWindow="20" + /// minRequiredNonAlphanumericCharacters="1" + /// minRequiredPasswordLength="11" + /// applicationName="MyApplication" /> + /// /providers> + /// /membership> + /// + /// + public override int PasswordAttemptWindow + { + get { return passwordAttemptWindow; } + } + + /// + /// Gets a value indicating the format for storing passwords in the membership data store. + /// + /// One of the + /// values indicating the format for storing passwords in the data store. + /// + /// The following example shows the membership element being used in an applications web.config file. + /// + /// membership defaultProvider="MySQLMembershipProvider"> + /// providers> + /// add name="MySqlMembershipProvider" + /// type="MySql.Web.Security.MySQLMembershipProvider" + /// connectionStringName="LocalMySqlServer" + /// enablePasswordRetrieval="true" + /// enablePasswordReset="false" + /// requiresQuestionAndAnswer="true" + /// requiresUniqueEmail="false" + /// passwordFormat="Encrypted" + /// maxInvalidPasswordAttempts="3" + /// passwordAttemptWindow="20" + /// minRequiredNonAlphanumericCharacters="1" + /// minRequiredPasswordLength="11" + /// applicationName="MyApplication" /> + /// /providers> + /// /membership> + /// + /// + public override MembershipPasswordFormat PasswordFormat + { + get { return passwordFormat; } + } + + /// + /// Gets the minimum number of special characters that must be present in a valid password. + /// + /// The minimum number of special characters that must be present + /// in a valid password. + /// + /// The following example shows the membership element being used in an applications web.config file. + /// + /// membership defaultProvider="MySQLMembershipProvider"> + /// providers> + /// add name="MySqlMembershipProvider" + /// type="MySql.Web.Security.MySQLMembershipProvider" + /// connectionStringName="LocalMySqlServer" + /// enablePasswordRetrieval="true" + /// enablePasswordReset="false" + /// requiresQuestionAndAnswer="true" + /// requiresUniqueEmail="false" + /// passwordFormat="Encrypted" + /// maxInvalidPasswordAttempts="3" + /// passwordAttemptWindow="20" + /// minRequiredNonAlphanumericCharacters="1" + /// minRequiredPasswordLength="11" + /// applicationName="MyApplication" /> + /// /providers> + /// /membership> + /// + /// + public override int MinRequiredNonAlphanumericCharacters + { + get { return minRequiredNonAlphanumericCharacters; } + } + + /// + /// Gets the minimum length required for a password. + /// + /// The minimum length required for a password. + /// + /// The following example shows the membership element being used in an applications web.config file. + /// + /// membership defaultProvider="MySQLMembershipProvider"> + /// providers> + /// add name="MySqlMembershipProvider" + /// type="MySql.Web.Security.MySQLMembershipProvider" + /// connectionStringName="LocalMySqlServer" + /// enablePasswordRetrieval="true" + /// enablePasswordReset="false" + /// requiresQuestionAndAnswer="true" + /// requiresUniqueEmail="false" + /// passwordFormat="Encrypted" + /// maxInvalidPasswordAttempts="3" + /// passwordAttemptWindow="20" + /// minRequiredNonAlphanumericCharacters="1" + /// minRequiredPasswordLength="11" + /// applicationName="MyApplication" /> + /// /providers> + /// /membership> + /// + /// + public override int MinRequiredPasswordLength + { + get { return minRequiredPasswordLength; } + } + + /// + /// Gets the regular expression used to evaluate a password. + /// + /// A regular expression used to evaluate a password. + /// + /// The following example shows the membership element being used in an applications web.config file. + /// In this example, the regular expression specifies that the password must meet the following + /// criteria: + /// * Is at least seven characters. + /// * Contains at least one digit. + /// * Contains at least one special (non-alphanumeric) character. + /// + /// membership defaultProvider="MySQLMembershipProvider"> + /// providers> + /// add name="MySqlMembershipProvider" + /// type="MySql.Web.Security.MySQLMembershipProvider" + /// connectionStringName="LocalMySqlServer" + /// enablePasswordRetrieval="true" + /// enablePasswordReset="false" + /// requiresQuestionAndAnswer="true" + /// requiresUniqueEmail="false" + /// passwordFormat="Encrypted" + /// maxInvalidPasswordAttempts="3" + /// passwordAttemptWindow="20" + /// minRequiredNonAlphanumericCharacters="1" + /// minRequiredPasswordLength="11" + /// applicationName="MyApplication" /> + /// /providers> + /// /membership> + /// + /// + public override string PasswordStrengthRegularExpression + { + get { return passwordStrengthRegularExpression; } + } + + /// + /// Gets or sets a value indicating whether exceptions are written to the event log. + /// + /// + /// true if exceptions should be written to the log; otherwise, false. + /// + public bool WriteExceptionsToEventLog + { + get { return writeExceptionsToEventLog; } + set { writeExceptionsToEventLog = value; } + } + + #endregion + + #region Public Methods + + /// + /// Changes the password. + /// + /// The username. + /// The old password. + /// The new password. + /// true if the password was updated successfully; false if the supplied old password + /// is invalid, the user is locked out, or the user does not exist in the database. + public override bool ChangePassword(string username, string oldPassword, string newPassword) + { + // this will return false if the username doesn't exist + if (!(ValidateUser(username, oldPassword))) + return false; + + ValidatePasswordEventArgs args = new ValidatePasswordEventArgs(username, newPassword, true); + OnValidatingPassword(args); + if (args.Cancel) + { + if (!(args.FailureInformation == null)) + throw args.FailureInformation; + else + throw new ProviderException(Properties.Resources.ChangePasswordCanceled); + } + + // validate the password according to current guidelines + if (!ValidatePassword(newPassword, "newPassword", true)) + return false; + + try + { + using (MySqlConnection connection = new MySqlConnection(connectionString)) + { + connection.Open(); + + // retrieve the existing key and format for this user + string passwordKey; + MembershipPasswordFormat passwordFormat; + int userId = GetUserId(connection, username); + + GetPasswordInfo(connection, userId, out passwordKey, out passwordFormat); + + MySqlCommand cmd = new MySqlCommand( + @"UPDATE my_aspnet_membership + SET Password = @pass, LastPasswordChangedDate = @lastPasswordChangedDate + WHERE userId=@userId", connection); + cmd.Parameters.AddWithValue("@pass", + EncodePassword(newPassword, passwordKey, passwordFormat)); + cmd.Parameters.AddWithValue("@lastPasswordChangedDate", DateTime.Now); + cmd.Parameters.AddWithValue("@userId", userId); + return cmd.ExecuteNonQuery() > 0; + } + } + catch (MySqlException e) + { + if (WriteExceptionsToEventLog) + WriteToEventLog(e, "ChangePassword"); + throw new ProviderException(exceptionMessage, e); + } + } + + /// + /// Changes the password question and answer. + /// + /// The user name. + /// The password. + /// The new password question. + /// The new password answer. + /// true if the update was successful; otherwise, false. A value of false is + /// also returned if the password is incorrect, the user is locked out, or the user + /// does not exist in the database. + public override bool ChangePasswordQuestionAndAnswer(string username, + string password, string newPwdQuestion, string newPwdAnswer) + { + // this handles the case where the username doesn't exist + if (!(ValidateUser(username, password))) + return false; + + try + { + using (MySqlConnection connection = new MySqlConnection(connectionString)) + { + connection.Open(); + + string passwordKey; + MembershipPasswordFormat passwordFormat; + int userId = GetUserId(connection, username); + + GetPasswordInfo(connection, userId, out passwordKey, out passwordFormat); + + + MySqlCommand cmd = new MySqlCommand( + @"UPDATE my_aspnet_membership + SET PasswordQuestion = @passwordQuestion, PasswordAnswer = @passwordAnswer + WHERE userId=@userId", connection); + cmd.Parameters.AddWithValue("@passwordQuestion", newPwdQuestion); + cmd.Parameters.AddWithValue("@passwordAnswer", + EncodePassword(newPwdAnswer, passwordKey, passwordFormat)); + cmd.Parameters.AddWithValue("@userId", userId); + return cmd.ExecuteNonQuery() > 0; + } + } + catch (MySqlException e) + { + if (WriteExceptionsToEventLog) + WriteToEventLog(e, "ChangePasswordQuestionAndAnswer"); + throw new ProviderException(exceptionMessage, e); + } + } + + /// + /// Adds a new membership user to the data source. + /// + /// The user name for the new user. + /// The password for the new user. + /// The e-mail address for the new user. + /// The password question for the new user. + /// The password answer for the new user + /// Whether or not the new user is approved to be validated. + /// The unique identifier from the membership data source for the user. + /// A enumeration value indicating whether the user was created successfully. + /// + /// A object populated with the information for the newly created user. + /// + public override MembershipUser CreateUser(string username, string password, + string email, string passwordQuestion, string passwordAnswer, + bool isApproved, object providerUserKey, out MembershipCreateStatus status) + { + //basis on MSDN documentation we should trim all the paramater values: http://msdn.microsoft.com/en-us/library/d8t4h2es%28v=vs.110%29.aspx + TrimParametersValues(ref username, ref password, ref email, ref passwordQuestion, ref passwordAnswer); + + ValidatePasswordEventArgs Args = new ValidatePasswordEventArgs(username, password, true); + OnValidatingPassword(Args); + if (Args.Cancel) + { + status = MembershipCreateStatus.InvalidPassword; + return null; + } + if (RequiresUniqueEmail && !String.IsNullOrEmpty(GetUserNameByEmail(email))) + { + status = MembershipCreateStatus.DuplicateEmail; + return null; + } + + ValidateQA(passwordQuestion, passwordAnswer); + + // now try to validate the password + if (!ValidatePassword(password, "password", false)) + { + status = MembershipCreateStatus.InvalidPassword; + return null; + } + + // now check to see if we already have a member by this name + MembershipUser u = GetUser(username, false); + if (u != null) + { + status = MembershipCreateStatus.DuplicateUserName; + return null; + } + + string passwordKey = GetPasswordKey(); + DateTime createDate = DateTime.Now; + MySqlTransaction transaction = null; + + using (MySqlConnection connection = new MySqlConnection(connectionString)) + { + try + { + connection.Open(); + transaction = connection.BeginTransaction(); + + // either create a new user or fetch the existing user id + long userId = SchemaManager.CreateOrFetchUserId(connection, username, + app.EnsureId(connection), true); + + MySqlCommand cmd = new MySqlCommand( + @"INSERT INTO my_aspnet_membership + VALUES(@userId, @email, @comment, @password, @passwordKey, + @passwordFormat, @passwordQuestion, @passwordAnswer, + @isApproved, @lastActivityDate, @lastLoginDate, + @lastPasswordChangedDate, @creationDate, + @isLockedOut, @lastLockedOutDate, @failedPasswordAttemptCount, + @failedPasswordAttemptWindowStart, @failedPasswordAnswerAttemptCount, + @failedPasswordAnswerAttemptWindowStart)", + connection); + cmd.Parameters.AddWithValue("@userId", userId); + cmd.Parameters.AddWithValue("@email", email); + cmd.Parameters.AddWithValue("@comment", ""); + cmd.Parameters.AddWithValue("@password", + EncodePassword(password, passwordKey, PasswordFormat)); + cmd.Parameters.AddWithValue("@passwordKey", passwordKey); + cmd.Parameters.AddWithValue("@passwordFormat", PasswordFormat); + cmd.Parameters.AddWithValue("@passwordQuestion", passwordQuestion); + cmd.Parameters.AddWithValue("@passwordAnswer", + EncodePassword(passwordAnswer, passwordKey, PasswordFormat)); + cmd.Parameters.AddWithValue("@isApproved", isApproved); + cmd.Parameters.AddWithValue("@lastActivityDate", createDate); + cmd.Parameters.AddWithValue("@lastLoginDate", createDate); + cmd.Parameters.AddWithValue("@lastPasswordChangedDate", createDate); + cmd.Parameters.AddWithValue("@creationDate", createDate); + cmd.Parameters.AddWithValue("@isLockedOut", false); + cmd.Parameters.AddWithValue("@lastLockedOutDate", createDate); + cmd.Parameters.AddWithValue("@failedPasswordAttemptCount", 0); + cmd.Parameters.AddWithValue("@failedPasswordAttemptWindowStart", createDate); + cmd.Parameters.AddWithValue("@failedPasswordAnswerAttemptCount", 0); + cmd.Parameters.AddWithValue("@failedPasswordAnswerAttemptWindowStart", createDate); + + int recAdded = cmd.ExecuteNonQuery(); + if (recAdded > 0) + status = MembershipCreateStatus.Success; + else + status = MembershipCreateStatus.UserRejected; + transaction.Commit(); + } + catch (MySqlException e) + { + if (WriteExceptionsToEventLog) + WriteToEventLog(e, "CreateUser"); + status = MembershipCreateStatus.ProviderError; + if (transaction != null) + transaction.Rollback(); + return null; + } + } + + return GetUser(username, false); + } + + /// + /// Removes a user from the membership data source. + /// + /// The name of the user to delete. + /// true to delete data related to the user from the database; false to leave data related to the user in the database. + /// + /// true if the user was successfully deleted; otherwise, false. + /// + public override bool DeleteUser(string username, bool deleteAllRelatedData) + { + try + { + using (MySqlConnection conn = new MySqlConnection(connectionString)) + { + conn.Open(); + + int userId = GetUserId(conn, username); + if (-1 == userId) return false; + + // if we are supposed to delete all related data, then delegate that to those providers + if (deleteAllRelatedData) + { + MySQLRoleProvider.DeleteUserData(conn, userId); + MySQLProfileProvider.DeleteUserData(conn, userId); + } + + string sql = @"DELETE {0}m + FROM my_aspnet_users u, my_aspnet_membership m + WHERE u.id=m.userId AND u.id=@userId"; + + MySqlCommand cmd = new MySqlCommand( + String.Format(sql, deleteAllRelatedData ? "u," : ""), conn); + cmd.Parameters.AddWithValue("@appId", app.FetchId(conn)); + cmd.Parameters.AddWithValue("@userId", userId); + return cmd.ExecuteNonQuery() > 0; + } + } + catch (MySqlException e) + { + if (WriteExceptionsToEventLog) + WriteToEventLog(e, "DeleteUser"); + throw new ProviderException(exceptionMessage, e); + } + } + + /// + /// Gets a collection of all the users in the data source in pages of data. + /// + /// The index of the page of results to return. is zero-based. + /// The size of the page of results to return. + /// The total number of matched users. + /// + /// A collection that contains a page of objects beginning at the page specified by . + /// + public override MembershipUserCollection GetAllUsers(int pageIndex, + int pageSize, out int totalRecords) + { + return GetUsers(null, null, pageIndex, pageSize, out totalRecords); + } + + /// + /// Gets the number of users currently accessing the application. + /// + /// + /// The number of users currently accessing the application. + /// + public override int GetNumberOfUsersOnline() + { + TimeSpan onlineSpan = new TimeSpan(0, Membership.UserIsOnlineTimeWindow, 0); + DateTime compareTime = DateTime.Now.Subtract(onlineSpan); + + try + { + using (MySqlConnection connection = new MySqlConnection(connectionString)) + { + connection.Open(); + MySqlCommand cmd = new MySqlCommand( + @"SELECT COUNT(*) FROM my_aspnet_membership m JOIN my_aspnet_users u + ON m.userId=u.id WHERE m.LastActivityDate > @date AND u.applicationId=@appId", + connection); + cmd.Parameters.AddWithValue("@date", compareTime); + cmd.Parameters.AddWithValue("@appId", app.FetchId(connection)); + return Convert.ToInt32(cmd.ExecuteScalar()); + } + } + catch (MySqlException e) + { + if (WriteExceptionsToEventLog) + WriteToEventLog(e, "GetNumberOfUsersOnline"); + throw new ProviderException(exceptionMessage, e); + } + } + + /// + /// Gets the password for the specified user name from the data source. + /// + /// The user to retrieve the password for. + /// The password answer for the user. + /// + /// The password for the specified user name. + /// + public override string GetPassword(string username, string answer) + { + if (!EnablePasswordRetrieval) + throw new ProviderException(Properties.Resources.PasswordRetrievalNotEnabled); + + try + { + using (MySqlConnection connection = new MySqlConnection(connectionString)) + { + connection.Open(); + + int userId = GetUserId(connection, username); + if (-1 == userId) + throw new ProviderException("Username not found."); + + string sql = @"SELECT Password, PasswordAnswer, PasswordKey, PasswordFormat, + IsLockedOut FROM my_aspnet_membership WHERE userId=@userId"; + MySqlCommand cmd = new MySqlCommand(sql, connection); + cmd.Parameters.AddWithValue("@userId", userId); + + using (MySqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SingleRow)) + { + reader.Read(); + if (reader.GetBoolean("IsLockedOut")) + throw new MembershipPasswordException(Properties.Resources.UserIsLockedOut); + + string password = reader.GetString("Password"); + string passwordAnswer = reader.GetValue(reader.GetOrdinal("PasswordAnswer")).ToString(); + string passwordKey = reader.GetString("PasswordKey"); + MembershipPasswordFormat format = (MembershipPasswordFormat)reader.GetInt32(3); + reader.Close(); + + if (RequiresQuestionAndAnswer && + !(CheckPassword(answer, passwordAnswer, passwordKey, format))) + { + UpdateFailureCount(userId, "PasswordAnswer", connection); + throw new MembershipPasswordException(Properties.Resources.IncorrectPasswordAnswer); + } + if (PasswordFormat == MembershipPasswordFormat.Encrypted) + { + password = UnEncodePassword(password, format); + } + return password; + } + } + } + catch (MySqlException e) + { + if (WriteExceptionsToEventLog) + WriteToEventLog(e, "GetPassword"); + throw new ProviderException(exceptionMessage, e); + } + } + + /// + /// Gets information from the data source for a user. Provides an option to update the last-activity date/time stamp for the user. + /// + /// The name of the user to get information for. + /// true to update the last-activity date/time stamp for the user; false to return user information without updating the last-activity date/time stamp for the user. + /// + /// A object populated with the specified user's information from the data source. + /// + public override MembershipUser GetUser(string username, bool userIsOnline) + { + try + { + int userId = -1; + using (MySqlConnection connection = new MySqlConnection(connectionString)) + { + connection.Open(); + + userId = GetUserId(connection, username); + if (-1 == userId) return null; + } + + return GetUser(userId, userIsOnline); + } + catch (MySqlException e) + { + if (WriteExceptionsToEventLog) + WriteToEventLog(e, "GetUser(String, Boolean)"); + throw new ProviderException(exceptionMessage, e); + } + } + + /// + /// Gets user information from the data source based on the unique identifier for the membership user. Provides an option to update the last-activity date/time stamp for the user. + /// + /// The unique identifier for the membership user to get information for. + /// true to update the last-activity date/time stamp for the user; false to return user information without updating the last-activity date/time stamp for the user. + /// + /// A object populated with the specified user's information from the data source. + /// + public override MembershipUser GetUser(object providerUserKey, bool userIsOnline) + { + MySqlTransaction txn = null; + + try + { + using (MySqlConnection connection = new MySqlConnection(connectionString)) + { + connection.Open(); + + txn = connection.BeginTransaction(); + MySqlCommand cmd = new MySqlCommand("", connection); + cmd.Parameters.AddWithValue("@userId", providerUserKey); + + if (userIsOnline) + { + cmd.CommandText = + @"UPDATE my_aspnet_users SET lastActivityDate = @date WHERE id=@userId"; + cmd.Parameters.AddWithValue("@date", DateTime.Now); + cmd.ExecuteNonQuery(); + + cmd.CommandText = "UPDATE my_aspnet_membership SET LastActivityDate=@date WHERE userId=@userId"; + cmd.ExecuteNonQuery(); + } + + cmd.CommandText = @"SELECT m.*,u.name + FROM my_aspnet_membership m JOIN my_aspnet_users u ON m.userId=u.id + WHERE u.id=@userId"; + + MembershipUser user; + using (MySqlDataReader reader = cmd.ExecuteReader()) + { + if (!reader.Read()) return null; + user = GetUserFromReader(reader); + } + txn.Commit(); + return user; + } + } + catch (MySqlException e) + { + if (txn != null) + txn.Rollback(); + if (WriteExceptionsToEventLog) + WriteToEventLog(e, "GetUser(Object, Boolean)"); + throw new ProviderException(exceptionMessage); + } + } + + /// + /// Unlocks the user. + /// + /// The username. + /// true if the membership user was successfully unlocked; + /// otherwise, false. A value of false is also returned if the user + /// does not exist in the database. + public override bool UnlockUser(string username) + { + try + { + using (MySqlConnection conn = new MySqlConnection(connectionString)) + { + conn.Open(); + + int userId = GetUserId(conn, username); + if (-1 == userId) return false; + + string sql = @"UPDATE my_aspnet_membership + SET IsLockedOut = false, LastLockedOutDate = @lastDate + WHERE userId=@userId"; + + MySqlCommand cmd = new MySqlCommand(sql, conn); + cmd.Parameters.AddWithValue("@lastDate", DateTime.Now); + cmd.Parameters.AddWithValue("@userId", userId); + return cmd.ExecuteNonQuery() > 0; + } + } + catch (MySqlException e) + { + if (WriteExceptionsToEventLog) + WriteToEventLog(e, "UnlockUser"); + throw new ProviderException(exceptionMessage, e); + } + } + + /// + /// Gets the user name associated with the specified e-mail address. + /// + /// The e-mail address to search for. + /// + /// The user name associated with the specified e-mail address. If no match is found, return null. + /// + public override string GetUserNameByEmail(string email) + { + try + { + using (MySqlConnection conn = new MySqlConnection(connectionString)) + { + conn.Open(); + + string sql = @"SELECT u.name FROM my_aspnet_users u + JOIN my_aspnet_membership m ON m.userid=u.id + WHERE m.Email = @email AND u.applicationId=@appId"; + MySqlCommand cmd = new MySqlCommand(sql, conn); + cmd.Parameters.AddWithValue("@email", email); + cmd.Parameters.AddWithValue("@appId", app.FetchId(conn)); + return (string)cmd.ExecuteScalar(); + } + } + catch (MySqlException e) + { + if (WriteExceptionsToEventLog) + WriteToEventLog(e, "GetUserNameByEmail"); + throw new ProviderException(exceptionMessage); + } + } + + /// + /// Resets a user's password to a new, automatically generated password. + /// + /// The user to reset the password for. + /// The password answer for the specified user. + /// The new password for the specified user. + public override string ResetPassword(string username, string answer) + { + if (!(EnablePasswordReset)) + throw new NotSupportedException(Properties.Resources.PasswordResetNotEnabled); + + try + { + using (MySqlConnection connection = new MySqlConnection(connectionString)) + { + connection.Open(); + + // fetch the userid first + int userId = GetUserId(connection, username); + if (-1 == userId) + throw new ProviderException(Properties.Resources.UsernameNotFound); + + if (answer == null && RequiresQuestionAndAnswer) + { + UpdateFailureCount(userId, "PasswordAnswer", connection); + throw new ProviderException(Properties.Resources.PasswordRequiredForReset); + } + + string newPassword = Membership.GeneratePassword(newPasswordLength, MinRequiredNonAlphanumericCharacters); + ValidatePasswordEventArgs Args = new ValidatePasswordEventArgs(username, newPassword, true); + OnValidatingPassword(Args); + if (Args.Cancel) + { + if (!(Args.FailureInformation == null)) + throw Args.FailureInformation; + else + throw new MembershipPasswordException(Properties.Resources.PasswordResetCanceledNotValid); + } + + MySqlCommand cmd = new MySqlCommand(@"SELECT PasswordAnswer, + PasswordKey, PasswordFormat, IsLockedOut + FROM my_aspnet_membership WHERE userId=@userId", connection); + cmd.Parameters.AddWithValue("@userId", userId); + + string passwordKey = String.Empty; + MembershipPasswordFormat format; + using (MySqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SingleRow)) + { + reader.Read(); + if (reader.GetBoolean("IsLockedOut")) + throw new MembershipPasswordException(Properties.Resources.UserIsLockedOut); + + object passwordAnswer = reader.GetValue(reader.GetOrdinal("PasswordAnswer")); + passwordKey = reader.GetString("PasswordKey"); + format = (MembershipPasswordFormat)reader.GetByte("PasswordFormat"); + reader.Close(); + + if (RequiresQuestionAndAnswer) + { + if (!CheckPassword(answer, (string)passwordAnswer, passwordKey, format)) + { + UpdateFailureCount(userId, "PasswordAnswer", connection); + throw new MembershipPasswordException(Properties.Resources.IncorrectPasswordAnswer); + } + } + } + + cmd.CommandText = @"UPDATE my_aspnet_membership + SET Password = @pass, LastPasswordChangedDate = @lastPassChange + WHERE userId=@userId"; + + cmd.Parameters.AddWithValue("@pass", + EncodePassword(newPassword, passwordKey, format)); + cmd.Parameters.AddWithValue("@lastPassChange", DateTime.Now); + int rowsAffected = cmd.ExecuteNonQuery(); + if (rowsAffected != 1) + throw new MembershipPasswordException(Properties.Resources.ErrorResettingPassword); + return newPassword; + } + } + catch (MySqlException e) + { + if (WriteExceptionsToEventLog) + WriteToEventLog(e, "ResetPassword"); + throw new ProviderException(exceptionMessage, e); + } + } + + /// + /// Updates information about a user in the data source. + /// + /// A object + /// that represents the user to update and the updated information for the user. + public override void UpdateUser(MembershipUser user) + { + try + { + using (MySqlConnection conn = new MySqlConnection(connectionString)) + { + conn.Open(); + + int userId = GetUserId(conn, user.UserName); + if (-1 == userId) + throw new ProviderException(Properties.Resources.UsernameNotFound); + + string sql = @"UPDATE my_aspnet_membership m, my_aspnet_users u + SET m.Email=@email, m.Comment=@comment, m.IsApproved=@isApproved, + m.LastLoginDate=@lastLoginDate, u.lastActivityDate=@lastActivityDate, + m.LastActivityDate=@lastActivityDate + WHERE m.userId=u.id AND u.name LIKE @name AND u.applicationId=@appId"; + MySqlCommand cmd = new MySqlCommand(sql, conn); + cmd.Parameters.AddWithValue("@Email", user.Email); + cmd.Parameters.AddWithValue("@Comment", user.Comment); + cmd.Parameters.AddWithValue("@isApproved", user.IsApproved); + cmd.Parameters.AddWithValue("@lastLoginDate", user.LastLoginDate); + cmd.Parameters.AddWithValue("@lastActivityDate", user.LastActivityDate); + cmd.Parameters.AddWithValue("@name", user.UserName); + cmd.Parameters.AddWithValue("@appId", app.FetchId(conn)); + cmd.ExecuteNonQuery(); + } + } + catch (MySqlException e) + { + if (WriteExceptionsToEventLog) + WriteToEventLog(e, "UpdateUser"); + throw new ProviderException(exceptionMessage); + } + } + + /// + /// Verifies that the specified user name and password exist in the data source. + /// + /// The name of the user to validate. + /// The password for the specified user. + /// + /// true if the specified username and password are valid; otherwise, false. + /// + public override bool ValidateUser(string username, string password) + { + bool isValid = false; + try + { + using (MySqlConnection connection = new MySqlConnection(connectionString)) + { + connection.Open(); + + // first get the user id. If that is -1, then the user doesn't exist + // so we just return false since we can't bump any counters + int userId = GetUserId(connection, username); + if (-1 == userId) return false; + + string sql = @"SELECT Password, PasswordKey, PasswordFormat, IsApproved, + Islockedout FROM my_aspnet_membership WHERE userId=@userId"; + MySqlCommand cmd = new MySqlCommand(sql, connection); + cmd.Parameters.AddWithValue("@userId", userId); + + using (MySqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SingleRow)) + { + if (!reader.HasRows) return false; + reader.Read(); + if (reader.GetBoolean("IsLockedOut")) return false; + + string pwd = reader.GetString(0); + string passwordKey = reader.GetString(1); + MembershipPasswordFormat format = (MembershipPasswordFormat) + reader.GetInt32(2); + bool isApproved = reader.GetBoolean(3); + reader.Close(); + + if (!CheckPassword(password, pwd, passwordKey, format)) + UpdateFailureCount(userId, "Password", connection); + else if (isApproved) + { + isValid = true; + DateTime currentDate = DateTime.Now; + MySqlCommand updateCmd = new MySqlCommand( + @"UPDATE my_aspnet_membership m, my_aspnet_users u + SET m.LastLoginDate = @lastLoginDate, u.lastActivityDate = @date, + m.LastActivityDate=@date + WHERE m.userId=@userid AND u.id=@userid", connection); + updateCmd.Parameters.AddWithValue("@lastLoginDate", currentDate); + updateCmd.Parameters.AddWithValue("@date", currentDate); + updateCmd.Parameters.AddWithValue("@userid", userId); + updateCmd.ExecuteNonQuery(); + } + } + return isValid; + } + } + catch (MySqlException e) + { + if (WriteExceptionsToEventLog) + WriteToEventLog(e, "ValidateUser"); + throw new ProviderException(exceptionMessage, e); + } + } + + /// + /// Gets a collection of membership users where the user name contains the specified user name to match. + /// + /// The user name to search for. + /// The index of the page of results to return. is zero-based. + /// The size of the page of results to return. + /// The total number of matched users. + /// + /// A collection that contains a page of objects beginning at the page specified by . + /// + public override MembershipUserCollection FindUsersByName(string usernameToMatch, + int pageIndex, int pageSize, out int totalRecords) + { + return GetUsers(usernameToMatch, null, pageIndex, pageSize, out totalRecords); + } + + /// + /// Gets a collection of membership users where the e-mail address contains the specified e-mail address to match. + /// + /// The e-mail address to search for. + /// The index of the page of results to return. is zero-based. + /// The size of the page of results to return. + /// The total number of matched users. + /// + /// A collection that contains a page of objects beginning at the page specified by . + /// + public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, + int pageSize, out int totalRecords) + { + return GetUsers(null, emailToMatch, pageIndex, pageSize, out totalRecords); + } + + #endregion + + #region Private Methods + + private int GetUserId(MySqlConnection connection, string username) + { + MySqlCommand cmd = new MySqlCommand( + "SELECT id FROM my_aspnet_users WHERE name = @name AND applicationId=@appId", connection); + cmd.Parameters.AddWithValue("@name", username); + cmd.Parameters.AddWithValue("@appId", app.FetchId(connection)); + object id = cmd.ExecuteScalar(); + if (id == null) return -1; + return (int)id; + } + + private void WriteToEventLog(Exception e, string action) + { + using (EventLog log = new EventLog()) + { + log.Source = eventSource; + log.Log = eventLog; + string message = "An exception occurred communicating with the data source." + + Environment.NewLine + Environment.NewLine; + message += "Action: " + action + Environment.NewLine + Environment.NewLine; + message += "Exception: " + e; + log.WriteEntry(message); + } + } + + private MembershipUser GetUserFromReader(MySqlDataReader reader) + { + object providerUserKey = reader.GetInt32("userId"); + string username = reader.GetString("name"); + + string email = null; + if (!reader.IsDBNull(reader.GetOrdinal("Email"))) + email = reader.GetString("Email"); + + string passwordQuestion = ""; + if (!(reader.GetValue(reader.GetOrdinal("PasswordQuestion")) == DBNull.Value)) + passwordQuestion = reader.GetString("PasswordQuestion"); + + string comment = ""; + if (!(reader.GetValue(reader.GetOrdinal("Comment")) == DBNull.Value)) + comment = reader.GetString("Comment"); + + bool isApproved = reader.GetBoolean("IsApproved"); + bool isLockedOut = reader.GetBoolean("IsLockedOut"); + DateTime creationDate = reader.GetDateTime("CreationDate"); + DateTime lastLoginDate = new DateTime(); + if (!(reader.GetValue(reader.GetOrdinal("LastLoginDate")) == DBNull.Value)) + lastLoginDate = reader.GetDateTime("LastLoginDate"); + + DateTime lastActivityDate = reader.GetDateTime("LastActivityDate"); + DateTime lastPasswordChangedDate = reader.GetDateTime("LastPasswordChangedDate"); + DateTime lastLockedOutDate = new DateTime(); + if (!(reader.GetValue(reader.GetOrdinal("LastLockedoutDate")) == DBNull.Value)) + lastLockedOutDate = reader.GetDateTime("LastLockedoutDate"); + + MembershipUser u = + new MembershipUser(Name, username, providerUserKey, email, passwordQuestion, comment, isApproved, + isLockedOut, creationDate, lastLoginDate, lastActivityDate, lastPasswordChangedDate, + lastLockedOutDate); + return u; + } + + private string UnEncodePassword(string encodedPassword, MembershipPasswordFormat format) + { + string password = encodedPassword; + if (format == MembershipPasswordFormat.Clear) + return encodedPassword; + else if (format == MembershipPasswordFormat.Encrypted) + return Encoding.Unicode.GetString(DecryptPassword( + Convert.FromBase64String(password))); + else if (format == MembershipPasswordFormat.Hashed) + throw new ProviderException(Properties.Resources.CannotUnencodeHashedPwd); + else + throw new ProviderException(Properties.Resources.UnsupportedPasswordFormat); + } + + private string GetPasswordKey() + { + RNGCryptoServiceProvider cryptoProvider = + new RNGCryptoServiceProvider(); + byte[] key = new byte[16]; + cryptoProvider.GetBytes(key); + return Convert.ToBase64String(key); + } + + /// + /// this method is only necessary because early versions of Mono did not support + /// the HashAlgorithmType property + /// + /// + /// + /// + private string HashPasswordBytes(byte[] key, byte[] bytes) + { + HashAlgorithm hash = HashAlgorithm.Create(Membership.HashAlgorithmType); + + if (hash is KeyedHashAlgorithm) + { + KeyedHashAlgorithm keyedHash = hash as KeyedHashAlgorithm; + keyedHash.Key = key; + } + return Convert.ToBase64String(hash.ComputeHash(bytes)); + } + + private string EncodePassword(string password, string passwordKey, + MembershipPasswordFormat format) + { + if (password == null) + return null; + if (format == MembershipPasswordFormat.Clear) + return password; + + byte[] passwordBytes = Encoding.Unicode.GetBytes(password); + byte[] keyBytes = Convert.FromBase64String(passwordKey); + byte[] keyedBytes = new byte[passwordBytes.Length + keyBytes.Length]; + Array.Copy(keyBytes, keyedBytes, keyBytes.Length); + Array.Copy(passwordBytes, 0, keyedBytes, keyBytes.Length, passwordBytes.Length); + + if (format == MembershipPasswordFormat.Encrypted) + { + byte[] encryptedBytes = EncryptPassword(passwordBytes); + return Convert.ToBase64String(encryptedBytes); + } + else if (format == MembershipPasswordFormat.Hashed) + return HashPasswordBytes(keyBytes, keyedBytes); + else + throw new ProviderException(Properties.Resources.UnsupportedPasswordFormat); + } + + private void UpdateFailureCount(int userId, string failureType, MySqlConnection connection) + { + MySqlCommand cmd = new MySqlCommand( + @"SELECT FailedPasswordAttemptCount, + FailedPasswordAttemptWindowStart, FailedPasswordAnswerAttemptCount, + FailedPasswordAnswerAttemptWindowStart FROM my_aspnet_membership + WHERE userId=@userId", connection); + cmd.Parameters.AddWithValue("@userId", userId); + + DateTime windowStart = new DateTime(); + int failureCount = 0; + try + { + using (MySqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SingleRow)) + { + if (!reader.HasRows) + throw new ProviderException(Properties.Resources.UnableToUpdateFailureCount); + + reader.Read(); + if (failureType == "Password") + { + failureCount = reader.GetInt32(0); + windowStart = reader.GetDateTime(1); + } + if (failureType == "PasswordAnswer") + { + failureCount = reader.GetInt32(2); + windowStart = reader.GetDateTime(3); + } + } + + DateTime windowEnd = windowStart.AddMinutes(PasswordAttemptWindow); + if (failureCount == 0 || DateTime.Now > windowEnd) + { + if (failureType == "Password") + { + cmd.CommandText = + @"UPDATE my_aspnet_membership + SET FailedPasswordAttemptCount = @count, + FailedPasswordAttemptWindowStart = @windowStart + WHERE userId=@userId"; + } + if (failureType == "PasswordAnswer") + { + cmd.CommandText = + @"UPDATE my_aspnet_membership + SET FailedPasswordAnswerAttemptCount = @count, + FailedPasswordAnswerAttemptWindowStart = @windowStart + WHERE userId = @userId"; + } + cmd.Parameters.Clear(); + cmd.Parameters.AddWithValue("@count", 1); + cmd.Parameters.AddWithValue("@windowStart", DateTime.Now); + cmd.Parameters.AddWithValue("@userId", userId); + if (cmd.ExecuteNonQuery() < 0) + throw new ProviderException(Properties.Resources.UnableToUpdateFailureCount); + } + else + { + failureCount += 1; + if (failureCount >= MaxInvalidPasswordAttempts) + { + cmd.CommandText = + @"UPDATE my_aspnet_membership SET IsLockedOut = @isLockedOut, + LastLockedOutDate = @lastLockedOutDate WHERE userId=@userId"; + cmd.Parameters.Clear(); + cmd.Parameters.AddWithValue("@isLockedOut", true); + cmd.Parameters.AddWithValue("@lastLockedOutDate", DateTime.Now); + cmd.Parameters.AddWithValue("@userId", userId); + if (cmd.ExecuteNonQuery() < 0) + throw new ProviderException(Properties.Resources.UnableToLockOutUser); + } + else + { + if (failureType == "Password") + { + cmd.CommandText = + @"UPDATE my_aspnet_membership + SET FailedPasswordAttemptCount = @count WHERE userId=@userId"; + } + if (failureType == "PasswordAnswer") + { + cmd.CommandText = + @"UPDATE my_aspnet_membership + SET FailedPasswordAnswerAttemptCount = @count + WHERE userId=@userId"; + } + cmd.Parameters.Clear(); + cmd.Parameters.AddWithValue("@count", failureCount); + cmd.Parameters.AddWithValue("@userId", userId); + if (cmd.ExecuteNonQuery() < 0) + throw new ProviderException("Unable to update failure count."); + } + } + } + catch (MySqlException e) + { + if (WriteExceptionsToEventLog) + WriteToEventLog(e, "UpdateFailureCount"); + throw new ProviderException(exceptionMessage, e); + } + } + + private bool CheckPassword(string password, string dbpassword, + string passwordKey, MembershipPasswordFormat format) + { + password = EncodePassword(password, passwordKey, format); + return password == dbpassword; + } + + private void GetPasswordInfo(MySqlConnection connection, int userId, + out string passwordKey, out MembershipPasswordFormat passwordFormat) + { + MySqlCommand cmd = new MySqlCommand( + @"SELECT PasswordKey, PasswordFormat FROM my_aspnet_membership WHERE + userId=@userId", connection); + cmd.Parameters.AddWithValue("@userId", userId); + using (MySqlDataReader reader = cmd.ExecuteReader()) + { + reader.Read(); + passwordKey = reader.GetString(reader.GetOrdinal("PasswordKey")); + passwordFormat = (MembershipPasswordFormat)reader.GetByte( + reader.GetOrdinal("PasswordFormat")); + } + } + + private MembershipUserCollection GetUsers(string username, string email, + int pageIndex, int pageSize, out int totalRecords) + { + MembershipUserCollection users = new MembershipUserCollection(); + try + { + using (MySqlConnection connection = new MySqlConnection(connectionString)) + { + connection.Open(); + MySqlCommand cmd = new MySqlCommand(); + cmd.Connection = connection; + + string sql = @"SELECT SQL_CALC_FOUND_ROWS u.name,m.* FROM my_aspnet_users u + JOIN my_aspnet_membership m ON m.userId=u.id + WHERE u.applicationId=@appId"; + + if (username != null) + { + sql += " AND u.name LIKE @name"; + cmd.Parameters.AddWithValue("@name", username); + } + else if (email != null) + { + sql += " AND m.Email LIKE @email"; + cmd.Parameters.AddWithValue("@email", email); + } + sql += " ORDER BY u.id ASC LIMIT {0},{1}"; + cmd.CommandText = String.Format(sql, pageIndex * pageSize, pageSize); + cmd.Parameters.AddWithValue("@appId", app.FetchId(connection)); + using (MySqlDataReader reader = cmd.ExecuteReader()) + { + while (reader.Read()) + users.Add(GetUserFromReader(reader)); + } + cmd.CommandText = "SELECT FOUND_ROWS()"; + cmd.Parameters.Clear(); + totalRecords = Convert.ToInt32(cmd.ExecuteScalar()); + } + return users; + } + catch (MySqlException e) + { + if (WriteExceptionsToEventLog) + WriteToEventLog(e, "GetUsers"); + throw new ProviderException(exceptionMessage); + } + } + + private void ValidateQA(string question, string answer) + { + if (RequiresQuestionAndAnswer && String.IsNullOrEmpty(question)) + throw new ArgumentException(Properties.Resources.PasswordQuestionInvalid); + if (RequiresQuestionAndAnswer && String.IsNullOrEmpty(answer)) + throw new ArgumentException(Properties.Resources.PasswordAnswerInvalid); + } + + private bool ValidatePassword(string password, string argumentName, bool throwExceptions) + { + string exceptionString = null; + object correctValue = MinRequiredPasswordLength; + + if (password.Length < MinRequiredPasswordLength) + exceptionString = Properties.Resources.PasswordNotLongEnough; + else + { + int count = 0; + foreach (char c in password) + if (!char.IsLetterOrDigit(c)) + count++; + if (count < MinRequiredNonAlphanumericCharacters) + exceptionString = Properties.Resources.NotEnoughNonAlphaNumericInPwd; + correctValue = MinRequiredNonAlphanumericCharacters; + } + + if (exceptionString != null) + { + if (throwExceptions) + throw new ArgumentException( + string.Format(exceptionString, argumentName, correctValue), + argumentName); + else + return false; + } + + if (PasswordStrengthRegularExpression.Length > 0) + if (!Regex.IsMatch(password, PasswordStrengthRegularExpression)) + return false; + + return true; + } + + private void TrimParametersValues(ref string username, ref string password, ref string email, ref string passwordQuestion, ref string passwordAnswer) + { + username = string.IsNullOrEmpty(username) ? username : username.Trim(); + password = string.IsNullOrEmpty(password) ? password : password.Trim(); + email = string.IsNullOrEmpty(email) ? email : email.Trim(); + passwordQuestion = string.IsNullOrEmpty(passwordQuestion) ? passwordQuestion : passwordQuestion.Trim(); + passwordAnswer = string.IsNullOrEmpty(passwordAnswer) ? passwordAnswer : passwordAnswer.Trim(); + } + + #endregion + } +} diff --git a/MySql.Web/src/MySql.Web.csproj b/MySql.Web/src/MySql.Web.csproj index 46a3075e6..ed1ebd6ba 100644 --- a/MySql.Web/src/MySql.Web.csproj +++ b/MySql.Web/src/MySql.Web.csproj @@ -2,31 +2,40 @@ MySql.Web - Copyright (c) 2016, 2023, Oracle and/or its affiliates. + Copyright © 2004, 2025, Oracle and/or its affiliates. en-US - 8.2.0 - Oracle + 9.4.0 + Oracle Corporation net462;net48; $(NoWarn);CS1591 MySql.Web MySql.Web MySql;.NET Connector;MySql Connector/NET - http://www.mysql.com/common/logos/logo-mysql-170x115.png + logo-mysql-170x115.png + README.md https://dev.mysql.com/downloads/ - GPL-2.0-only + GPL-2.0-only WITH Universal-FOSS-exception-1.0 true - false - false - false - false - false - false + false False True True ..\..\ConnectorNetPublicKey.snk + + + + + + + + + + + + + @@ -44,8 +53,8 @@ - - + + diff --git a/MySql.Web/src/MySqlDatabaseWrapper.cs b/MySql.Web/src/MySqlDatabaseWrapper.cs index 54c0eeba7..5fa161e80 100644 --- a/MySql.Web/src/MySqlDatabaseWrapper.cs +++ b/MySql.Web/src/MySqlDatabaseWrapper.cs @@ -1,208 +1,208 @@ -// Copyright (c) 2014, 2020, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data.MySqlClient; -using System; -using System.Collections.Generic; -using System.Data; -using System.Linq; - -namespace MySql.Web.Security -{ - /// - /// Perform basic operations against a Database - /// - internal class MySqlDatabaseWrapper : IDisposable - { - private MySqlConnection _conn; - #region Public - /// - /// Initialize a new instance of the class - /// - /// Connection String - public MySqlDatabaseWrapper(string connectionString) - { - _conn = new MySqlConnection(connectionString); - } - ~MySqlDatabaseWrapper() - { - this.Dispose(true); - } - /// - /// Close the current instance - /// - public void Close() - { - this.Dispose(); - } - /// - /// Dispose the current instance - /// - public void Dispose() - { - this.Dispose(true); - GC.SuppressFinalize(this); - } - - /// - /// Execute given query on the database - /// - /// Query to exeute - /// Parameters used in the query - /// Query resultset - public IEnumerable ExecuteQuery(string cmdText, params object[] parametersValues) - { - CheckIsConnectionOpen(); - MySqlCommand cmd = _conn.CreateCommand(); - cmd.CommandText = cmdText; - AddParameters(cmd, parametersValues); - DataTable result = new DataTable(); - MySqlDataAdapter adapter = new MySqlDataAdapter(cmd); - adapter.Fill(result); - foreach (DataRow row in result.Rows) - { - yield return row; - } - } - - /// - /// Execute given query on the database - /// - /// Query to exeute - /// Parameters used in the query - /// First record in the Query resultset - public DataRow ExecuteQuerySingleRecord(string cmdText, params object[] parametersValues) - { - return ExecuteQuery(cmdText, parametersValues).FirstOrDefault(); - } - - /// - /// Execute given query on the database - /// - /// Query to exeute - /// Parameters used in the query - /// Rows affected by the query - public int ExecuteNonQuery(string cmdText, params object[] parametersValues) - { - CheckIsConnectionOpen(); - MySqlCommand cmd = _conn.CreateCommand(); - cmd.CommandText = cmdText; - AddParameters(cmd, parametersValues); - return cmd.ExecuteNonQuery(); - } - - /// - /// Execute given query on the database - /// - /// Query to exeute - /// Parameters used in the query - /// Value of the first column in the first row in the query resulset - public object ExecuteScalar(string cmdText, params object[] parametersValues) - { - CheckIsConnectionOpen(); - MySqlCommand cmd = _conn.CreateCommand(); - cmd.CommandText = cmdText; - AddParameters(cmd, parametersValues); - return cmd.ExecuteScalar(); - } - - /// - /// Execute all given queries on the database inside of a transaction - /// - /// Queries to exeute - /// If queries were successfully executed - public bool ExecuteInTransaction(IEnumerable> commands) - { - CheckIsConnectionOpen(); - MySqlTransaction tran = _conn.BeginTransaction(); - try - { - foreach (var command in commands) - { - MySqlCommand cmd = _conn.CreateCommand(); - cmd.CommandText = command.Item1; - AddParameters(cmd, command.Item2); - cmd.ExecuteNonQuery(); - } - tran.Commit(); - return true; - } - catch (Exception) - { - tran.Rollback(); - return false; - } - } - #endregion - - #region Protected - protected virtual void Dispose(bool disposing) - { - if (disposing && (this._conn != null)) - { - if (_conn.State != ConnectionState.Closed) - _conn.Close(); - - _conn = null; - } - } - #endregion - - #region Private - /// - /// Verifies if the current connection is open, if not is opened - /// - private void CheckIsConnectionOpen() - { - if (this._conn.State != ConnectionState.Open) - { - this._conn.Open(); - } - } - - /// - /// Add parameters to a command, nomenclature name used for the parameters are 'param[n]' - /// - /// Command that will stores the parameters - /// Parameters values - private void AddParameters(MySqlCommand cmd, object[] values) - { - int ctr = 1; - foreach (object value in values) - { - cmd.Parameters.Add(new MySqlParameter() - { - ParameterName = string.Format("param{0}", ctr), - Value = value ?? DBNull.Value - }); - ctr++; - } - } - #endregion - } -} +// Copyright © 2014, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data.MySqlClient; +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; + +namespace MySql.Web.Security +{ + /// + /// Perform basic operations against a Database + /// + internal class MySqlDatabaseWrapper : IDisposable + { + private MySqlConnection _conn; + #region Public + /// + /// Initialize a new instance of the class + /// + /// Connection String + public MySqlDatabaseWrapper(string connectionString) + { + _conn = new MySqlConnection(connectionString); + } + ~MySqlDatabaseWrapper() + { + this.Dispose(true); + } + /// + /// Close the current instance + /// + public void Close() + { + this.Dispose(); + } + /// + /// Dispose the current instance + /// + public void Dispose() + { + this.Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Execute given query on the database + /// + /// Query to exeute + /// Parameters used in the query + /// Query resultset + public IEnumerable ExecuteQuery(string cmdText, params object[] parametersValues) + { + CheckIsConnectionOpen(); + MySqlCommand cmd = _conn.CreateCommand(); + cmd.CommandText = cmdText; + AddParameters(cmd, parametersValues); + DataTable result = new DataTable(); + MySqlDataAdapter adapter = new MySqlDataAdapter(cmd); + adapter.Fill(result); + foreach (DataRow row in result.Rows) + { + yield return row; + } + } + + /// + /// Execute given query on the database + /// + /// Query to exeute + /// Parameters used in the query + /// First record in the Query resultset + public DataRow ExecuteQuerySingleRecord(string cmdText, params object[] parametersValues) + { + return ExecuteQuery(cmdText, parametersValues).FirstOrDefault(); + } + + /// + /// Execute given query on the database + /// + /// Query to exeute + /// Parameters used in the query + /// Rows affected by the query + public int ExecuteNonQuery(string cmdText, params object[] parametersValues) + { + CheckIsConnectionOpen(); + MySqlCommand cmd = _conn.CreateCommand(); + cmd.CommandText = cmdText; + AddParameters(cmd, parametersValues); + return cmd.ExecuteNonQuery(); + } + + /// + /// Execute given query on the database + /// + /// Query to exeute + /// Parameters used in the query + /// Value of the first column in the first row in the query resulset + public object ExecuteScalar(string cmdText, params object[] parametersValues) + { + CheckIsConnectionOpen(); + MySqlCommand cmd = _conn.CreateCommand(); + cmd.CommandText = cmdText; + AddParameters(cmd, parametersValues); + return cmd.ExecuteScalar(); + } + + /// + /// Execute all given queries on the database inside of a transaction + /// + /// Queries to exeute + /// If queries were successfully executed + public bool ExecuteInTransaction(IEnumerable> commands) + { + CheckIsConnectionOpen(); + MySqlTransaction tran = _conn.BeginTransaction(); + try + { + foreach (var command in commands) + { + MySqlCommand cmd = _conn.CreateCommand(); + cmd.CommandText = command.Item1; + AddParameters(cmd, command.Item2); + cmd.ExecuteNonQuery(); + } + tran.Commit(); + return true; + } + catch (Exception) + { + tran.Rollback(); + return false; + } + } + #endregion + + #region Protected + protected virtual void Dispose(bool disposing) + { + if (disposing && (this._conn != null)) + { + if (_conn.State != ConnectionState.Closed) + _conn.Close(); + + _conn = null; + } + } + #endregion + + #region Private + /// + /// Verifies if the current connection is open, if not is opened + /// + private void CheckIsConnectionOpen() + { + if (this._conn.State != ConnectionState.Open) + { + this._conn.Open(); + } + } + + /// + /// Add parameters to a command, nomenclature name used for the parameters are 'param[n]' + /// + /// Command that will stores the parameters + /// Parameters values + private void AddParameters(MySqlCommand cmd, object[] values) + { + int ctr = 1; + foreach (object value in values) + { + cmd.Parameters.Add(new MySqlParameter() + { + ParameterName = string.Format("param{0}", ctr), + Value = value ?? DBNull.Value + }); + ctr++; + } + } + #endregion + } +} diff --git a/MySql.Web/src/MySqlWebSecurity.cs b/MySql.Web/src/MySqlWebSecurity.cs index 39ecff096..4b5939251 100644 --- a/MySql.Web/src/MySqlWebSecurity.cs +++ b/MySql.Web/src/MySqlWebSecurity.cs @@ -1,577 +1,577 @@ -// Copyright (c) 2014, 2020, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Web.Properties; -using System; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.Configuration; -using System.Net; -using System.Web; -using System.Web.Routing; -using System.Web.Security; -using System.Web.WebPages; - -namespace MySql.Web.Security -{ - /// - /// Provides security features for web projects implementing a MySql database. - /// - public static class MySqlWebSecurity - { - /// - /// Name of the key required to enable simple membership. - /// - public static readonly string EnableSimpleMembershipKey = "enableSimpleMembership"; - private static readonly string MySqlMembershipProviderName = "MySqlMembershipProvider"; - private static readonly string MySqlRoleProviderName = "MySQLRoleProvider"; - - #region Public - /// - /// Changes the password for the user provided. - /// - /// The user name. - /// The current pasword. - /// The new Password. - /// - public static bool ChangePassword(string userName, string oldPassword, string newPassword) - { - ValidProvider(); - var user = Membership.GetUser(userName, true); - return user.ChangePassword(oldPassword, newPassword); - } - - /// - /// Confirms user by confirmation token. - /// - /// The confirmation token. - /// true if the user was confirmed; otherwise, false. - public static bool ConfirmAccount(string confirmationToken) - { - var provider = ValidProvider(); - return provider.ConfirmAccount(confirmationToken); - } - - /// - /// Confirms user by confirmation token and user name. - /// - /// The user name. - /// The confirmation token. - /// true if the user was confirmed; otherwise, false. - public static bool ConfirmAccount(string userName, string confirmationToken) - { - var provider = ValidProvider(); - return provider.ConfirmAccount(userName, confirmationToken); - } - - /// - /// Creates a user account. - /// - /// The user name. - /// The user password. - /// Flag to indicate if a confirmation token is required. - /// A confirmation token if required. - public static string CreateAccount(string userName, string password, bool requireConfirmationToken = false) - { - var provider = ValidProvider(); - return provider.CreateAccount(userName, password, requireConfirmationToken); - } - - /// - /// Creates user and account. - /// - /// The user name. - /// The user password. - /// Additional data for user table. - /// Flag to indicate if a confirmation token is required. - /// A confirmation token if required. - public static string CreateUserAndAccount(string userName, string password, object additionalUserAttributes = null, bool requireConfirmationToken = false) - { - var provider = ValidProvider(); - IDictionary userAttrs = additionalUserAttributes as RouteValueDictionary; - - if (userAttrs == null && additionalUserAttributes != null) - { - var attrs = additionalUserAttributes as IDictionary; - userAttrs = attrs != null ? new RouteValueDictionary(attrs) : new RouteValueDictionary(additionalUserAttributes); - } - - return provider.CreateUserAndAccount(userName, password, requireConfirmationToken, userAttrs); - } - - /// - /// Gets the date when the specified user was created. - /// - /// The user name. - /// Date created or minimum date value if the user was not found. - public static DateTime GetCreateDate(string userName) - { - var provider = ValidProvider(); - return provider.GetCreateDate(userName); - } - - /// - /// Gets the last date when password fails. - /// - /// The user name. - /// Last failure date or minimum date value if the user was not found. - public static DateTime GetLastPasswordFailureDate(string userName) - { - var provider = ValidProvider(); - return provider.GetLastPasswordFailureDate(userName); - } - - /// - /// Gets the date when password was changed. - /// - /// The user name. - /// Last password changed date or minimum date value if the user was not found. - public static DateTime GetPasswordChangedDate(string userName) - { - var provider = ValidProvider(); - return provider.GetPasswordChangedDate(userName); - } - - /// - /// Gets the password failures since last success. - /// - /// The user name. - /// The number of failures since last success. - public static int GetPasswordFailuresSinceLastSuccess(string userName) - { - var provider = ValidProvider(); - return provider.GetPasswordFailuresSinceLastSuccess(userName); - } - - /// - /// Generates password reset token for a confirmed user. - /// - /// The user name. - /// The time that the token will be valid. - /// A generated token or null if the user is not confirmed or does not have a token. - public static string GeneratePasswordResetToken(string userName, int tokenExpirationInMinutesFromNow = 1440) - { - var provider = ValidProvider(); - return provider.GeneratePasswordResetToken(userName, tokenExpirationInMinutesFromNow); - } - - /// - /// Gets the user id. - /// - /// The user name. - /// The user id. -1 if the user doesn't exists - public static int GetUserId(string userName) - { - ValidProvider(); - var user = Membership.GetUser(userName); - return user != null ? (int)user.ProviderUserKey : -1; - } - - /// - /// Gets the user id from the password reset token. - /// - /// The reset token. - /// The user id. 0 if the user doesn't exists. - public static int GetUserIdFromPasswordResetToken(string resetToken) - { - var provider = ValidProvider(); - return provider.GetUserIdFromPasswordResetToken(resetToken); - } - - /// - /// Initializes the simple membership provider with the values given. - /// - /// The connection string name defined in the config file. - /// The table name defined to create new users. - /// The column name defined to store the user ids. - /// The column name defined to store the user name. - /// Flag indicating if the tables should be created. - /// Flag indicating to check if the database has been initialized. - public static void InitializeDatabaseConnection(string connectionStringName, string userTableName, string userIdColumn, string userNameColumn, bool createTables, bool checkIfInitialized = false) - { - InitializeMembershipProvider(connectionStringName, null, null, userTableName, userIdColumn, userNameColumn, createTables, checkIfInitialized); - InitializeRoleProvider(connectionStringName, null, null, userTableName, userIdColumn, userNameColumn, createTables, checkIfInitialized); - Initialized = true; - } - - /// - /// Initializes the simple membership provider with the values given. - /// - /// The connection string. - /// The name of the provider. - /// The table name defined to create new users. - /// The column name defined to store the user ids. - /// The column name defined to store the user name. - /// Flag indicating if the tables should be created. - /// Flag indicating to check if the database has been initialized. - public static void InitializeDatabaseConnection(string connectionString, string providerName, string userTableName, string userIdColumn, string userNameColumn, bool createTables, bool checkIfInitialized = false) - { - InitializeMembershipProvider(null, connectionString, providerName, userTableName, userIdColumn, userNameColumn, createTables, checkIfInitialized); - InitializeRoleProvider(null, connectionString, providerName, userTableName, userIdColumn, userNameColumn, createTables, checkIfInitialized); - Initialized = true; - } - - /// - /// Determines if the account is locked out. - /// - /// The name of the user. - /// The number of allowed password attempts. - /// true if the account is locked; otherwise, false. - public static bool IsAccountLockedOut(string userName, int allowedPasswordAttempts, int intervalInSeconds) - { - return IsAccountLockedOut(userName, allowedPasswordAttempts, TimeSpan.FromSeconds(intervalInSeconds)); - } - - /// - /// Determines if the account is locked out. - /// - /// The name of the user. - /// The number of allowed password attempts. - /// true if the account is locked; otherwise, false. - public static bool IsAccountLockedOut(string userName, int allowedPasswordAttempts, TimeSpan interval) - { - var provider = ValidProvider(); - return (provider.GetUser(userName, false) != null && provider.GetPasswordFailuresSinceLastSuccess(userName) > allowedPasswordAttempts && provider.GetLastPasswordFailureDate(userName).Add(interval) > DateTime.UtcNow); - } - - /// - /// Determines if the user has been confirmed. - /// - /// The user name. - /// true if the user is confirmed; otherwise false. - public static bool IsConfirmed(string userName) - { - var provider = ValidProvider(); - return provider.IsConfirmed(userName); - } - - /// - /// Determines if the is the same as the provided user name. - /// - /// The user name. - /// true if the user matches the ; otherwise, false. - public static bool IsCurrentUser(string userName) - { - ValidProvider(); - return string.Equals(CurrentUserName, userName, StringComparison.OrdinalIgnoreCase); - } - - /// - /// Determines if the matches the provided user id. - /// - /// The user id to match. - /// true if the id matches the ; otherwise, false. - public static bool IsUseLoggedOn(int userId) - { - ValidProvider(); - return CurrentUserId == userId; - } - - /// - /// Performs a login for the specified user. - /// - /// The user name. - /// The user password. - /// Flag to indicate if a persistent cookie should be created. - /// true if the login was successful; otherwise, false. - public static bool Login(string userName, string password, bool createPersistentCookie = false) - { - var curentProvider = ValidProvider(); - bool loginSuccessful = false; - if (curentProvider != null) - loginSuccessful = curentProvider.ValidateUser(userName, password); - else - loginSuccessful = Membership.ValidateUser(userName, password); - - if (loginSuccessful) - { - FormsAuthentication.SetAuthCookie(userName, createPersistentCookie); - } - return loginSuccessful; - } - - /// - /// Performs a logout for the current item. - /// - public static void Logout() - { - ValidProvider(); - FormsAuthentication.SignOut(); - } - - /// - /// Evalutes if the user is authenticated. - /// - public static void RequireAuthenticatedUser() - { - ValidProvider(); - var user = CurrentContext.User; - if (user == null || !user.Identity.IsAuthenticated) - { - CurrentContext.Response.SetStatus(HttpStatusCode.Unauthorized); - } - } - - /// - /// Evaluates if the user belongs to the specified roles. - /// - /// - public static void RequireRoles(params string[] roles) - { - ValidProvider(); - foreach (var role in roles) - { - if (!Roles.IsUserInRole(CurrentUserName, role)) - { - CurrentContext.Response.SetStatus(HttpStatusCode.Unauthorized); - } - } - } - - /// - /// Evaluates if the user is logged on. - /// - /// - public static void RequiresUser(int userId) - { - ValidProvider(); - if (!IsUseLoggedOn(userId)) - { - CurrentContext.Response.SetStatus(HttpStatusCode.Unauthorized); - } - } - - /// - /// Evaluates if the provided user name matches the . - /// - /// - public static void RequiresUser(string userName) - { - ValidProvider(); - if (!string.Equals(CurrentUserName, userName, StringComparison.OrdinalIgnoreCase)) - { - CurrentContext.Response.SetStatus(HttpStatusCode.Unauthorized); - } - } - - /// - /// Resets the password identified by the provided password reset token. - /// - /// The password reset token. - /// The new password. - /// true if the password reset was successful; otherwise, false. - public static bool ResetPassword(string passwordResetToken, string newPassword) - { - var provider = ValidProvider(); - return provider.ResetPasswordWithToken(passwordResetToken, newPassword); - } - - /// - /// Determines if the user exists. - /// - /// The user name. - /// true if the user exists; otherwise, false. - public static bool UserExists(string username) - { - var curentProvider = ValidProvider(); - if (curentProvider != null) - return curentProvider.GetUser(username, false) != null; - else - return Membership.GetUser(username) != null; - } - #endregion - - /// - /// Gets the initialized status. - /// - #region Properties - public static bool Initialized - { - get; - private set; - } - - /// - /// Gets the current user id. - /// - public static int CurrentUserId - { - get { return GetUserId(CurrentUserName); } - } - - /// - /// Gets the current user name. - /// - public static string CurrentUserName - { - get { return CurrentContext.User.Identity.Name; } - } - - /// - /// Gets a flag indicating if there is an associated user id. - /// - public static bool HasUserId - { - get { return CurrentUserId != -1; } - } - - /// - /// Gets a flag indicating if the user is authenticated. - /// - public static bool IsAuthenticated - { - get { return CurrentContext.Request.IsAuthenticated; } - } - #endregion - - #region Private_Internal - - private static MySqlSimpleMembershipProvider CreateSimpleMembershipProvider(string name, MySQLMembershipProvider currentDefault) - { - MySqlSimpleMembershipProvider simpleProvider = new MySqlSimpleMembershipProvider(currentDefault); - NameValueCollection config = new NameValueCollection(); - simpleProvider.Initialize(name, config); - return simpleProvider; - } - - private static MySqlSimpleRoleProvider CreateSimpleRoleProvider(string name, MySQLRoleProvider currentDefault) - { - MySqlSimpleRoleProvider simpleProvider = new MySqlSimpleRoleProvider(currentDefault); - NameValueCollection config = new NameValueCollection(); - simpleProvider.Initialize(name, config); - return simpleProvider; - } - - private static MySqlSimpleMembershipProvider ValidProvider() - { - if (_provider.Initialized) - return _provider; - - throw new Exception(Resources.SimpleMembershipNotInitialized); - } - - private static void InitializeMembershipProvider(string connectionStringName, string connectionString, string providerName, string userTableName, string userIdColumn, string userNameColumn, bool createTables, bool checkIfInitialized = false) - { - if (checkIfInitialized) - { - if (_provider != null) - return; - } - - MySqlSimpleMembershipProvider simpleMembership = new MySqlSimpleMembershipProvider(Membership.Provider); - if (_provider != null && _provider.Initialized) - { - throw new InvalidOperationException(Resources.SimpleMembershipAlreadyInitialized); - } - simpleMembership.ConnectionStringName = connectionStringName; - simpleMembership.ConnectionString = connectionString; - simpleMembership.ProviderName = providerName; - simpleMembership.UserTableName = userTableName; - simpleMembership.UserIdColumn = userIdColumn; - simpleMembership.UserNameColumn = userNameColumn; - if (createTables) - { - simpleMembership.CreateTables(); - } - else - { - simpleMembership.ValidateUserTable(); - } - simpleMembership.Initialized = true; - _provider = simpleMembership; - } - - private static void InitializeRoleProvider(string connectionStringName, string connectionString, string providerName, string userTableName, string userIdColumn, string userNameColumn, bool createTables, bool checkIfInitialized = false) - { - if (checkIfInitialized) - { - if (_roleprovider != null) - return; - } - - MySqlSimpleRoleProvider roleProvider = new MySqlSimpleRoleProvider(Roles.Provider); - if (_roleprovider != null && _roleprovider.Initialized) - { - throw new InvalidOperationException(Resources.SimpleRoleAlreadyInitialized); - } - roleProvider.ConnectionStringName = connectionStringName; - roleProvider.ConnectionString = connectionString; - roleProvider.UserTableName = userTableName; - roleProvider.UserIdColumn = userIdColumn; - roleProvider.UserNameColumn = userNameColumn; - if (createTables) - { - roleProvider.CreateTables(); - } - roleProvider.Initialized = true; - _roleprovider = roleProvider; - } - - private static bool IsSimpleMembershipEnabled() - { - string config = ConfigurationManager.AppSettings[EnableSimpleMembershipKey]; - bool isEnabled = false; - if (!string.IsNullOrEmpty(config)) - { - bool.TryParse(config, out isEnabled); - } - return isEnabled; - } - - internal static void PreAppStartInit() - { - if (IsSimpleMembershipEnabled()) - { - MembershipProvider provider = Membership.Providers[MySqlMembershipProviderName]; - if (provider != null) - { - MySqlSimpleMembershipProvider mysqlProvider = CreateSimpleMembershipProvider(MySqlMembershipProviderName, (MySQLMembershipProvider)provider); - Membership.Providers.Remove(MySqlMembershipProviderName); - Membership.Providers.Add(mysqlProvider); - } - Roles.Enabled = true; - RoleProvider roleProvider = Roles.Providers[MySqlRoleProviderName]; - if (roleProvider != null) - { - MySqlSimpleRoleProvider simpleRoleProv = CreateSimpleRoleProvider(MySqlRoleProviderName, (MySQLRoleProvider)roleProvider); - Roles.Providers.Remove(MySqlRoleProviderName); - Roles.Providers.Add(simpleRoleProv); - } - } - } - - internal static HttpContextBase CurrentContext - { - get { return new HttpContextWrapper(HttpContext.Current); } - } - - private static MySqlSimpleMembershipProvider _provider; - private static MySqlSimpleRoleProvider _roleprovider; - #endregion - } -} +// Copyright © 2014, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Web.Properties; +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Configuration; +using System.Net; +using System.Web; +using System.Web.Routing; +using System.Web.Security; +using System.Web.WebPages; + +namespace MySql.Web.Security +{ + /// + /// Provides security features for web projects implementing a MySql database. + /// + public static class MySqlWebSecurity + { + /// + /// Name of the key required to enable simple membership. + /// + public static readonly string EnableSimpleMembershipKey = "enableSimpleMembership"; + private static readonly string MySqlMembershipProviderName = "MySqlMembershipProvider"; + private static readonly string MySqlRoleProviderName = "MySQLRoleProvider"; + + #region Public + /// + /// Changes the password for the user provided. + /// + /// The user name. + /// The current pasword. + /// The new Password. + /// + public static bool ChangePassword(string userName, string oldPassword, string newPassword) + { + ValidProvider(); + var user = Membership.GetUser(userName, true); + return user.ChangePassword(oldPassword, newPassword); + } + + /// + /// Confirms user by confirmation token. + /// + /// The confirmation token. + /// true if the user was confirmed; otherwise, false. + public static bool ConfirmAccount(string confirmationToken) + { + var provider = ValidProvider(); + return provider.ConfirmAccount(confirmationToken); + } + + /// + /// Confirms user by confirmation token and user name. + /// + /// The user name. + /// The confirmation token. + /// true if the user was confirmed; otherwise, false. + public static bool ConfirmAccount(string userName, string confirmationToken) + { + var provider = ValidProvider(); + return provider.ConfirmAccount(userName, confirmationToken); + } + + /// + /// Creates a user account. + /// + /// The user name. + /// The user password. + /// Flag to indicate if a confirmation token is required. + /// A confirmation token if required. + public static string CreateAccount(string userName, string password, bool requireConfirmationToken = false) + { + var provider = ValidProvider(); + return provider.CreateAccount(userName, password, requireConfirmationToken); + } + + /// + /// Creates user and account. + /// + /// The user name. + /// The user password. + /// Additional data for user table. + /// Flag to indicate if a confirmation token is required. + /// A confirmation token if required. + public static string CreateUserAndAccount(string userName, string password, object additionalUserAttributes = null, bool requireConfirmationToken = false) + { + var provider = ValidProvider(); + IDictionary userAttrs = additionalUserAttributes as RouteValueDictionary; + + if (userAttrs == null && additionalUserAttributes != null) + { + var attrs = additionalUserAttributes as IDictionary; + userAttrs = attrs != null ? new RouteValueDictionary(attrs) : new RouteValueDictionary(additionalUserAttributes); + } + + return provider.CreateUserAndAccount(userName, password, requireConfirmationToken, userAttrs); + } + + /// + /// Gets the date when the specified user was created. + /// + /// The user name. + /// Date created or minimum date value if the user was not found. + public static DateTime GetCreateDate(string userName) + { + var provider = ValidProvider(); + return provider.GetCreateDate(userName); + } + + /// + /// Gets the last date when password fails. + /// + /// The user name. + /// Last failure date or minimum date value if the user was not found. + public static DateTime GetLastPasswordFailureDate(string userName) + { + var provider = ValidProvider(); + return provider.GetLastPasswordFailureDate(userName); + } + + /// + /// Gets the date when password was changed. + /// + /// The user name. + /// Last password changed date or minimum date value if the user was not found. + public static DateTime GetPasswordChangedDate(string userName) + { + var provider = ValidProvider(); + return provider.GetPasswordChangedDate(userName); + } + + /// + /// Gets the password failures since last success. + /// + /// The user name. + /// The number of failures since last success. + public static int GetPasswordFailuresSinceLastSuccess(string userName) + { + var provider = ValidProvider(); + return provider.GetPasswordFailuresSinceLastSuccess(userName); + } + + /// + /// Generates password reset token for a confirmed user. + /// + /// The user name. + /// The time that the token will be valid. + /// A generated token or null if the user is not confirmed or does not have a token. + public static string GeneratePasswordResetToken(string userName, int tokenExpirationInMinutesFromNow = 1440) + { + var provider = ValidProvider(); + return provider.GeneratePasswordResetToken(userName, tokenExpirationInMinutesFromNow); + } + + /// + /// Gets the user id. + /// + /// The user name. + /// The user id. -1 if the user doesn't exists + public static int GetUserId(string userName) + { + ValidProvider(); + var user = Membership.GetUser(userName); + return user != null ? (int)user.ProviderUserKey : -1; + } + + /// + /// Gets the user id from the password reset token. + /// + /// The reset token. + /// The user id. 0 if the user doesn't exists. + public static int GetUserIdFromPasswordResetToken(string resetToken) + { + var provider = ValidProvider(); + return provider.GetUserIdFromPasswordResetToken(resetToken); + } + + /// + /// Initializes the simple membership provider with the values given. + /// + /// The connection string name defined in the config file. + /// The table name defined to create new users. + /// The column name defined to store the user ids. + /// The column name defined to store the user name. + /// Flag indicating if the tables should be created. + /// Flag indicating to check if the database has been initialized. + public static void InitializeDatabaseConnection(string connectionStringName, string userTableName, string userIdColumn, string userNameColumn, bool createTables, bool checkIfInitialized = false) + { + InitializeMembershipProvider(connectionStringName, null, null, userTableName, userIdColumn, userNameColumn, createTables, checkIfInitialized); + InitializeRoleProvider(connectionStringName, null, null, userTableName, userIdColumn, userNameColumn, createTables, checkIfInitialized); + Initialized = true; + } + + /// + /// Initializes the simple membership provider with the values given. + /// + /// The connection string. + /// The name of the provider. + /// The table name defined to create new users. + /// The column name defined to store the user ids. + /// The column name defined to store the user name. + /// Flag indicating if the tables should be created. + /// Flag indicating to check if the database has been initialized. + public static void InitializeDatabaseConnection(string connectionString, string providerName, string userTableName, string userIdColumn, string userNameColumn, bool createTables, bool checkIfInitialized = false) + { + InitializeMembershipProvider(null, connectionString, providerName, userTableName, userIdColumn, userNameColumn, createTables, checkIfInitialized); + InitializeRoleProvider(null, connectionString, providerName, userTableName, userIdColumn, userNameColumn, createTables, checkIfInitialized); + Initialized = true; + } + + /// + /// Determines if the account is locked out. + /// + /// The name of the user. + /// The number of allowed password attempts. + /// true if the account is locked; otherwise, false. + public static bool IsAccountLockedOut(string userName, int allowedPasswordAttempts, int intervalInSeconds) + { + return IsAccountLockedOut(userName, allowedPasswordAttempts, TimeSpan.FromSeconds(intervalInSeconds)); + } + + /// + /// Determines if the account is locked out. + /// + /// The name of the user. + /// The number of allowed password attempts. + /// true if the account is locked; otherwise, false. + public static bool IsAccountLockedOut(string userName, int allowedPasswordAttempts, TimeSpan interval) + { + var provider = ValidProvider(); + return (provider.GetUser(userName, false) != null && provider.GetPasswordFailuresSinceLastSuccess(userName) > allowedPasswordAttempts && provider.GetLastPasswordFailureDate(userName).Add(interval) > DateTime.UtcNow); + } + + /// + /// Determines if the user has been confirmed. + /// + /// The user name. + /// true if the user is confirmed; otherwise false. + public static bool IsConfirmed(string userName) + { + var provider = ValidProvider(); + return provider.IsConfirmed(userName); + } + + /// + /// Determines if the is the same as the provided user name. + /// + /// The user name. + /// true if the user matches the ; otherwise, false. + public static bool IsCurrentUser(string userName) + { + ValidProvider(); + return string.Equals(CurrentUserName, userName, StringComparison.OrdinalIgnoreCase); + } + + /// + /// Determines if the matches the provided user id. + /// + /// The user id to match. + /// true if the id matches the ; otherwise, false. + public static bool IsUseLoggedOn(int userId) + { + ValidProvider(); + return CurrentUserId == userId; + } + + /// + /// Performs a login for the specified user. + /// + /// The user name. + /// The user password. + /// Flag to indicate if a persistent cookie should be created. + /// true if the login was successful; otherwise, false. + public static bool Login(string userName, string password, bool createPersistentCookie = false) + { + var curentProvider = ValidProvider(); + bool loginSuccessful = false; + if (curentProvider != null) + loginSuccessful = curentProvider.ValidateUser(userName, password); + else + loginSuccessful = Membership.ValidateUser(userName, password); + + if (loginSuccessful) + { + FormsAuthentication.SetAuthCookie(userName, createPersistentCookie); + } + return loginSuccessful; + } + + /// + /// Performs a logout for the current item. + /// + public static void Logout() + { + ValidProvider(); + FormsAuthentication.SignOut(); + } + + /// + /// Evalutes if the user is authenticated. + /// + public static void RequireAuthenticatedUser() + { + ValidProvider(); + var user = CurrentContext.User; + if (user == null || !user.Identity.IsAuthenticated) + { + CurrentContext.Response.SetStatus(HttpStatusCode.Unauthorized); + } + } + + /// + /// Evaluates if the user belongs to the specified roles. + /// + /// + public static void RequireRoles(params string[] roles) + { + ValidProvider(); + foreach (var role in roles) + { + if (!Roles.IsUserInRole(CurrentUserName, role)) + { + CurrentContext.Response.SetStatus(HttpStatusCode.Unauthorized); + } + } + } + + /// + /// Evaluates if the user is logged on. + /// + /// + public static void RequiresUser(int userId) + { + ValidProvider(); + if (!IsUseLoggedOn(userId)) + { + CurrentContext.Response.SetStatus(HttpStatusCode.Unauthorized); + } + } + + /// + /// Evaluates if the provided user name matches the . + /// + /// + public static void RequiresUser(string userName) + { + ValidProvider(); + if (!string.Equals(CurrentUserName, userName, StringComparison.OrdinalIgnoreCase)) + { + CurrentContext.Response.SetStatus(HttpStatusCode.Unauthorized); + } + } + + /// + /// Resets the password identified by the provided password reset token. + /// + /// The password reset token. + /// The new password. + /// true if the password reset was successful; otherwise, false. + public static bool ResetPassword(string passwordResetToken, string newPassword) + { + var provider = ValidProvider(); + return provider.ResetPasswordWithToken(passwordResetToken, newPassword); + } + + /// + /// Determines if the user exists. + /// + /// The user name. + /// true if the user exists; otherwise, false. + public static bool UserExists(string username) + { + var curentProvider = ValidProvider(); + if (curentProvider != null) + return curentProvider.GetUser(username, false) != null; + else + return Membership.GetUser(username) != null; + } + #endregion + + /// + /// Gets the initialized status. + /// + #region Properties + public static bool Initialized + { + get; + private set; + } + + /// + /// Gets the current user id. + /// + public static int CurrentUserId + { + get { return GetUserId(CurrentUserName); } + } + + /// + /// Gets the current user name. + /// + public static string CurrentUserName + { + get { return CurrentContext.User.Identity.Name; } + } + + /// + /// Gets a flag indicating if there is an associated user id. + /// + public static bool HasUserId + { + get { return CurrentUserId != -1; } + } + + /// + /// Gets a flag indicating if the user is authenticated. + /// + public static bool IsAuthenticated + { + get { return CurrentContext.Request.IsAuthenticated; } + } + #endregion + + #region Private_Internal + + private static MySqlSimpleMembershipProvider CreateSimpleMembershipProvider(string name, MySQLMembershipProvider currentDefault) + { + MySqlSimpleMembershipProvider simpleProvider = new MySqlSimpleMembershipProvider(currentDefault); + NameValueCollection config = new NameValueCollection(); + simpleProvider.Initialize(name, config); + return simpleProvider; + } + + private static MySqlSimpleRoleProvider CreateSimpleRoleProvider(string name, MySQLRoleProvider currentDefault) + { + MySqlSimpleRoleProvider simpleProvider = new MySqlSimpleRoleProvider(currentDefault); + NameValueCollection config = new NameValueCollection(); + simpleProvider.Initialize(name, config); + return simpleProvider; + } + + private static MySqlSimpleMembershipProvider ValidProvider() + { + if (_provider.Initialized) + return _provider; + + throw new Exception(Resources.SimpleMembershipNotInitialized); + } + + private static void InitializeMembershipProvider(string connectionStringName, string connectionString, string providerName, string userTableName, string userIdColumn, string userNameColumn, bool createTables, bool checkIfInitialized = false) + { + if (checkIfInitialized) + { + if (_provider != null) + return; + } + + MySqlSimpleMembershipProvider simpleMembership = new MySqlSimpleMembershipProvider(Membership.Provider); + if (_provider != null && _provider.Initialized) + { + throw new InvalidOperationException(Resources.SimpleMembershipAlreadyInitialized); + } + simpleMembership.ConnectionStringName = connectionStringName; + simpleMembership.ConnectionString = connectionString; + simpleMembership.ProviderName = providerName; + simpleMembership.UserTableName = userTableName; + simpleMembership.UserIdColumn = userIdColumn; + simpleMembership.UserNameColumn = userNameColumn; + if (createTables) + { + simpleMembership.CreateTables(); + } + else + { + simpleMembership.ValidateUserTable(); + } + simpleMembership.Initialized = true; + _provider = simpleMembership; + } + + private static void InitializeRoleProvider(string connectionStringName, string connectionString, string providerName, string userTableName, string userIdColumn, string userNameColumn, bool createTables, bool checkIfInitialized = false) + { + if (checkIfInitialized) + { + if (_roleprovider != null) + return; + } + + MySqlSimpleRoleProvider roleProvider = new MySqlSimpleRoleProvider(Roles.Provider); + if (_roleprovider != null && _roleprovider.Initialized) + { + throw new InvalidOperationException(Resources.SimpleRoleAlreadyInitialized); + } + roleProvider.ConnectionStringName = connectionStringName; + roleProvider.ConnectionString = connectionString; + roleProvider.UserTableName = userTableName; + roleProvider.UserIdColumn = userIdColumn; + roleProvider.UserNameColumn = userNameColumn; + if (createTables) + { + roleProvider.CreateTables(); + } + roleProvider.Initialized = true; + _roleprovider = roleProvider; + } + + private static bool IsSimpleMembershipEnabled() + { + string config = ConfigurationManager.AppSettings[EnableSimpleMembershipKey]; + bool isEnabled = false; + if (!string.IsNullOrEmpty(config)) + { + bool.TryParse(config, out isEnabled); + } + return isEnabled; + } + + internal static void PreAppStartInit() + { + if (IsSimpleMembershipEnabled()) + { + MembershipProvider provider = Membership.Providers[MySqlMembershipProviderName]; + if (provider != null) + { + MySqlSimpleMembershipProvider mysqlProvider = CreateSimpleMembershipProvider(MySqlMembershipProviderName, (MySQLMembershipProvider)provider); + Membership.Providers.Remove(MySqlMembershipProviderName); + Membership.Providers.Add(mysqlProvider); + } + Roles.Enabled = true; + RoleProvider roleProvider = Roles.Providers[MySqlRoleProviderName]; + if (roleProvider != null) + { + MySqlSimpleRoleProvider simpleRoleProv = CreateSimpleRoleProvider(MySqlRoleProviderName, (MySQLRoleProvider)roleProvider); + Roles.Providers.Remove(MySqlRoleProviderName); + Roles.Providers.Add(simpleRoleProv); + } + } + } + + internal static HttpContextBase CurrentContext + { + get { return new HttpContextWrapper(HttpContext.Current); } + } + + private static MySqlSimpleMembershipProvider _provider; + private static MySqlSimpleRoleProvider _roleprovider; + #endregion + } +} diff --git a/MySql.Web/src/PersonalizationConnectionHelper.cs b/MySql.Web/src/PersonalizationConnectionHelper.cs index e4b610583..027113ded 100644 --- a/MySql.Web/src/PersonalizationConnectionHelper.cs +++ b/MySql.Web/src/PersonalizationConnectionHelper.cs @@ -1,86 +1,86 @@ -// Copyright (c) 2014, 2020, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data.MySqlClient; -using System; -using System.Web.Hosting; - -namespace MySql.Web -{ - internal sealed class MySQLPersonalizationConnectionHelper - { - private MySqlConnection _connection; - - public MySqlConnection Connection - { - get { - return _connection; - } - } - - public bool Opened - { - get { - return _connection.State == System.Data.ConnectionState.Open; - } - } - - internal MySQLPersonalizationConnectionHelper(string connectionString) - { - if (string.IsNullOrEmpty(connectionString)) - { - throw new ArgumentNullException("connectionString"); - } - - _connection = new MySqlConnection(connectionString); - } - - internal void OpenConnection(bool impersonateContext) - { - if (_connection.State != System.Data.ConnectionState.Open) - { - if (impersonateContext) - { - using (HostingEnvironment.Impersonate()) - { - _connection.Open(); - } - } - else - _connection.Open(); - } - } - - internal void CloseConnection() - { - if (_connection.State != System.Data.ConnectionState.Closed) - _connection.Close(); - } - - } -} +// Copyright © 2014, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data.MySqlClient; +using System; +using System.Web.Hosting; + +namespace MySql.Web +{ + internal sealed class MySQLPersonalizationConnectionHelper + { + private MySqlConnection _connection; + + public MySqlConnection Connection + { + get { + return _connection; + } + } + + public bool Opened + { + get { + return _connection.State == System.Data.ConnectionState.Open; + } + } + + internal MySQLPersonalizationConnectionHelper(string connectionString) + { + if (string.IsNullOrEmpty(connectionString)) + { + throw new ArgumentNullException("connectionString"); + } + + _connection = new MySqlConnection(connectionString); + } + + internal void OpenConnection(bool impersonateContext) + { + if (_connection.State != System.Data.ConnectionState.Open) + { + if (impersonateContext) + { + using (HostingEnvironment.Impersonate()) + { + _connection.Open(); + } + } + else + _connection.Open(); + } + } + + internal void CloseConnection() + { + if (_connection.State != System.Data.ConnectionState.Closed) + _connection.Close(); + } + + } +} diff --git a/MySql.Web/src/PersonalizationProvider.cs b/MySql.Web/src/PersonalizationProvider.cs index a78fdb0f6..6c80f47f4 100644 --- a/MySql.Web/src/PersonalizationProvider.cs +++ b/MySql.Web/src/PersonalizationProvider.cs @@ -1,569 +1,569 @@ -// Copyright (c) 2014, 2020, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data.MySqlClient; -using MySql.Web.Common; -using MySql.Web.General; -using System; -using System.Diagnostics; -using System.Web.Hosting; -using System.Web.UI.WebControls.WebParts; - -namespace MySql.Web.Personalization -{ - /// - /// Implementation for Personalization Provider to use web parts in ASP.NET websites. - /// - public class MySqlPersonalizationProvider : PersonalizationProvider - { - - string connectionString; - - - string eventSource = "MySQLPersonalizationProvider"; - string eventLog = "Application"; - string exceptionMessage = "An exception occurred. Please check the event log."; - bool writeExceptionsToEventLog = false; - - Application app; - - /// - /// Gets or sets the application name. - /// - public override string ApplicationName - { - get { return app.Name; } - set { app.Name = value; } - } - - private long ApplicationId - { - get { return app.Id; } - } - - private enum ResetUserStateMode - { - PerInactiveDate, - PerPaths, - PerUsers - } - - - /// - /// Initializes settings values for Personalization Provider. - /// - /// The name of the provider. - /// A named value collection representing the configurations for this provider. - public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config) - { - if (config == null) - throw new ArgumentNullException("config"); - - if (string.IsNullOrEmpty(name)) - { - name = "MySqlPersonalizationProvider"; - } - - if (string.IsNullOrEmpty(config["description"])) - { - config.Remove("description"); - config.Add("description", "MySql Personalization provider"); - } - - base.Initialize(name, config); - - string applicationName = HostingEnvironment.ApplicationVirtualPath; - if (!String.IsNullOrEmpty(config["applicationName"])) - applicationName = config["applicationName"]; - - - if (!(config["writeExceptionsToEventLog"] == null)) - { - if (config["writeExceptionsToEventLog"].ToUpper() == "TRUE") - { - writeExceptionsToEventLog = true; - } - } - connectionString = ConfigUtility.GetConnectionString(config); - if (String.IsNullOrEmpty(connectionString)) return; - - // Make sure we have the correct schema. - SchemaManager.CheckSchema(connectionString, config); - - app = new Application(applicationName, base.Description); - - // Get the application id. - try - { - using (MySqlConnection conn = new MySqlConnection(connectionString)) - { - conn.Open(); - app.EnsureId(conn); - } - } - catch (Exception ex) - { - if (writeExceptionsToEventLog) - WriteToEventLog(ex, "MySQLPersonalizationProvider - Initialize"); - throw; - } - } - - /// - /// Returns a collection of PersonalizationStateInfo objects containing administrative information regarding records in the database that match the specified criteria. - /// - /// The personalization scope. - /// The set of query parameters. - /// The index of the page. - /// The size of the page. - /// The total number of records to return. - /// For example, records corresponding to users named Jeff* that have been modified since January 1, 2005. Wildcard support is provider-dependent. - public override PersonalizationStateInfoCollection FindState(PersonalizationScope scope, PersonalizationStateQuery query, int pageIndex, int pageSize, out int totalRecords) - { - - if (query == null) - throw new ArgumentNullException("query"); - - if (pageIndex < 0) - throw new ArgumentOutOfRangeException("pageIndex"); - - if (pageSize < 1) - throw new ArgumentOutOfRangeException("pageSize"); - - if (query.PathToMatch == null) - throw new ArgumentNullException("query.PathToMatch"); - - if (query.UsernameToMatch == null) - throw new ArgumentNullException("query.UserToMatch"); - - DateTime inactiveSinceDate = query.UserInactiveSinceDate; - - if (scope == PersonalizationScope.User) - { - return FindUserState(query.PathToMatch.Trim(), inactiveSinceDate, query.UsernameToMatch.Trim(), pageIndex, pageSize, out totalRecords); - } - else - { - return FindSharedState(query.PathToMatch.Trim(), pageIndex, pageSize, out totalRecords); - } - } - - - /// - /// Returns the number of records in the database that match the specified criteria. - /// - /// The personalization scope. - /// The set of query parameters. - /// For example, records corresponding to users named Jeff* that haven't been modified since January 1, 2005. Wildcard support is provider-dependent. - public override int GetCountOfState(PersonalizationScope scope, PersonalizationStateQuery query) - { - if (query == null) - throw new ArgumentNullException("query"); - - if (scope == PersonalizationScope.User) - { - return GetCountUserState(query.PathToMatch.Trim(), query.UserInactiveSinceDate, query.UsernameToMatch); - } - else - { - return GetCountOfSharedState(query.PathToMatch.Trim()); - } - } - - - /// - /// Retrieves personalization state as opaque blobs from the data source. - /// - /// The web part manager. - /// The path indicating where to save the data. - /// The user name. - /// A byte array containing the user shared data to loaded. - /// A byte array containing the user data to be loaded. - /// Retrieves both shared and user personalization state corresponding to a specified user and a specified page. - protected override void LoadPersonalizationBlobs(WebPartManager webPartManager, string path, string userName, ref Byte[] sharedDataBlob, ref Byte[] userDataBlob) - { - sharedDataBlob = null; - userDataBlob = null; - MySQLPersonalizationConnectionHelper connection = new MySQLPersonalizationConnectionHelper(connectionString); - connection.OpenConnection(true); - try - { - sharedDataBlob = PersonalizationProviderProcedures.my_aspnet_PersonalizationAllUsers_GetPageSettings( - ApplicationId, path, connection); - if (!String.IsNullOrEmpty(userName)) - { - userDataBlob = PersonalizationProviderProcedures.my_aspnet_PersonalizationPerUser_GetPageSettings( - ApplicationId, path, userName, DateTime.UtcNow, connection); - } - - connection.CloseConnection(); - } - catch (Exception ex) - { - if (writeExceptionsToEventLog) - WriteToEventLog(ex, "MySQLPersonalizationProvider - LoadPersonazalitionBlobs"); - throw; - } - finally - { - connection.CloseConnection(); - } - } - - /// - /// Deletes personalization state corresponding to a specified user and a specified page from the database. - /// - /// The web part manager. - /// The path indicating where to save the data. - /// The user name. - protected override void ResetPersonalizationBlob(WebPartManager webPartManager, string path, string userName) - { - MySQLPersonalizationConnectionHelper connection = new MySQLPersonalizationConnectionHelper(connectionString); - connection.OpenConnection(true); - try - { - if (string.IsNullOrEmpty(userName)) - { - PersonalizationProviderProcedures.my_aspnet_PersonalizationAllUsers_ResetPageSettings(ApplicationId, path, connection); - } - else - { - PersonalizationProviderProcedures.my_aspnet_PersonalizationPerUser_ResetPageSettings(ApplicationId, userName, path, DateTime.UtcNow, connection); - } - } - catch (Exception ex) - { - if (writeExceptionsToEventLog) - WriteToEventLog(ex, "MySQLPersonalizationProvider - ResetPersonalizationBlob"); - throw; - } - finally - { - connection.CloseConnection(); - } - } - - /// - /// Deletes personalization state corresponding to the specified users and specified pages from the database. - /// - /// The personalization scope. - /// The paths indicating where to save the data. - /// The user names. - /// - public override int ResetState(PersonalizationScope scope, string[] paths, string[] usernames) - { - - bool hasPaths = !(paths == null || paths.Length == 0); - bool hasUsers = !(usernames == null || usernames.Length == 0); - - var count = 0; - - var connection = new MySQLPersonalizationConnectionHelper(connectionString); - connection.OpenConnection(true); - - if (scope == PersonalizationScope.Shared) - { - try - { - if (paths == null) // reset all state - { - return PersonalizationProviderProcedures.my_aspnet_PersonalizationAdministration_DeleteAllState(true, ApplicationId, connection); - } - else - { - return PersonalizationProviderProcedures.my_aspnet_PersonalizationAdministration_ResetSharedState(ApplicationId, paths, connection); - } - } - catch (Exception ex) - { - if (writeExceptionsToEventLog) - WriteToEventLog(ex, "MySQLPersonalizationProvider - ResetState"); - throw; - } - finally - { - connection.CloseConnection(); - } - } - else - { - DateTime dateTime = Convert.ToDateTime("2038-01-19 03:14:07.999999"); // MySQL TimeStamp MaxValue - - if (!hasPaths && !hasUsers) - { - count = PersonalizationProviderProcedures.my_aspnet_PersonalizationAdministration_DeleteAllState(true, ApplicationId, connection); - } - else if (!hasUsers) - { - count = ResetUserState(ResetUserStateMode.PerPaths, dateTime, paths, null); - } - else - { - count = ResetUserState(ResetUserStateMode.PerUsers, dateTime, paths, usernames); - } - } - return count; - } - - - /// - /// Deletes user personalization state corresponding to the specified pages and that hasn't been updated since a specified date from the database. - /// - /// The path indicating where to retrieve the user state from. - /// A time and date indicating since when the user has been inactive. - /// - public override int ResetUserState(string path, DateTime userInactiveSinceDate) - { - if (string.IsNullOrEmpty(path)) - return 0; - - string[] paths = (path == null) ? null : new string[] { path }; - try - { - return ResetUserState(ResetUserStateMode.PerInactiveDate, userInactiveSinceDate, paths, null); - } - catch (Exception ex) - { - if (writeExceptionsToEventLog) - WriteToEventLog(ex, "MySQLPersonalizationProvider - ResetUserState"); - throw; - } - } - - /// - /// Writes personalization state corresponding to a specified user and a specified page as an opaque blob to the database. - /// - /// The web part manager. - /// The path indicating where to save the data. - /// The user name. - /// A byte array containing the data to be saved. - /// If userName is null, then the personalization state is shared state and is not keyed by user name. - protected override void SavePersonalizationBlob(WebPartManager webPartManager, string path, string userName, Byte[] dataBlob) - { - - MySQLPersonalizationConnectionHelper connection = new MySQLPersonalizationConnectionHelper(connectionString); - - try - { - MySqlCommand cmd = new MySqlCommand(); - connection.OpenConnection(true); - if (!string.IsNullOrEmpty(userName)) - { - PersonalizationProviderProcedures.my_aspnet_PersonalizationPerUser_SetPageSettings(ApplicationId, userName, path, dataBlob, DateTime.UtcNow, connection); - } - else - { - PersonalizationProviderProcedures.my_aspnet_PersonalizationAllUsers_SetPageSettings(ApplicationId, path, dataBlob, DateTime.UtcNow, connection); - } - } - catch (Exception ex) - { - if (writeExceptionsToEventLog) - WriteToEventLog(ex, "MySQLPersonalizationProvider - SavePersonalizationBlob"); - throw; - } - } - - private PersonalizationStateInfoCollection FindSharedState(string path, int pageIndex, int pageSize, out int totalRecords) - { - MySQLPersonalizationConnectionHelper connection = new MySQLPersonalizationConnectionHelper(connectionString); - - try - { - MySqlCommand cmd = new MySqlCommand(); - connection.OpenConnection(true); - totalRecords = PersonalizationProviderProcedures.myaspnet_PersonalizationAdministration_FindState(true, ApplicationId, ApplicationName, pageIndex, pageSize, - path, null, DateTime.MinValue, connection, ref cmd); - - PersonalizationStateInfoCollection sharedStateInfoCollection = new PersonalizationStateInfoCollection(); - - using (var reader = cmd.ExecuteReader()) - { - while (reader.Read()) - { - string pathQuery = reader.GetString("Path"); - DateTime lastUpdatedDate = (reader.IsDBNull(1)) ? DateTime.MinValue : - DateTime.SpecifyKind(reader.GetDateTime(1), DateTimeKind.Utc); - int size = (reader.IsDBNull(2)) ? 0 : reader.GetInt32("SharedDataLength"); - int userDataLength = (reader.IsDBNull(3)) ? 0 : reader.GetInt32("UserDataLength"); - int userCount = (reader.IsDBNull(4)) ? 0 : reader.GetInt32("UserCount"); - - sharedStateInfoCollection.Add(new SharedPersonalizationStateInfo( - pathQuery, lastUpdatedDate, size, userDataLength, userCount)); - } - } - connection.CloseConnection(); - return sharedStateInfoCollection; - } - catch (Exception ex) - { - if (writeExceptionsToEventLog) - WriteToEventLog(ex, "MySQLPersonalizationProvider - FindSharedState"); - throw; - } - finally - { - connection.CloseConnection(); - } - } - - private PersonalizationStateInfoCollection FindUserState(string path, DateTime inactiveSinceDate, string userName, int pageIndex, int pageSize, out int totalRecords) - { - MySQLPersonalizationConnectionHelper connection = new MySQLPersonalizationConnectionHelper(connectionString); - - try - { - - MySqlCommand cmd = new MySqlCommand(); - connection.OpenConnection(true); - totalRecords = PersonalizationProviderProcedures.myaspnet_PersonalizationAdministration_FindState(false, ApplicationId, ApplicationName, pageIndex, pageSize, - path, userName, inactiveSinceDate, connection, ref cmd); - - PersonalizationStateInfoCollection stateInfoCollection = new PersonalizationStateInfoCollection(); - - using (var reader = cmd.ExecuteReader()) - { - while (reader.Read()) - { - string pathQuery = reader.GetString("Path"); - DateTime lastUpdatedDate = DateTime.SpecifyKind(reader.GetDateTime("LastUpdatedDate"), DateTimeKind.Utc); - int size = reader.GetInt32("Size"); - string usernameQuery = reader.GetString("name"); - DateTime lastActivityDate = DateTime.SpecifyKind(reader.GetDateTime("LastActivityDate"), DateTimeKind.Utc); - stateInfoCollection.Add(new UserPersonalizationStateInfo(pathQuery, lastActivityDate, size, usernameQuery, lastActivityDate)); - } - } - connection.CloseConnection(); - - return stateInfoCollection; - } - catch (Exception ex) - { - if (writeExceptionsToEventLog) - WriteToEventLog(ex, "MySQLPersonalizationProvider - FindUserState"); - throw; - } - finally - { - connection.CloseConnection(); - } - } - - private int GetCountOfSharedState(string path) - { - MySQLPersonalizationConnectionHelper connection = new MySQLPersonalizationConnectionHelper(connectionString); - try - { - MySqlCommand cmd = new MySqlCommand(); - connection.OpenConnection(true); - return PersonalizationProviderProcedures.myaspnet_PersonalizationAdministration_GetCountOfState( - true, ApplicationName, ApplicationId, path, - null, DateTime.MinValue, connection); - } - catch (Exception ex) - { - if (writeExceptionsToEventLog) - WriteToEventLog(ex, "MySQLPersonalizationProvider - GetCountOfSharedState"); - throw; - } - finally - { - connection.CloseConnection(); - } - } - - private int GetCountUserState(string path, DateTime userInactiveSinceDate, string userName) - { - MySQLPersonalizationConnectionHelper connection = new MySQLPersonalizationConnectionHelper(connectionString); - try - { - MySqlCommand cmd = new MySqlCommand(); - connection.OpenConnection(true); - return PersonalizationProviderProcedures.myaspnet_PersonalizationAdministration_GetCountOfState( - false, ApplicationName, ApplicationId, path, - userName, userInactiveSinceDate, connection); - } - catch (Exception ex) - { - if (writeExceptionsToEventLog) - WriteToEventLog(ex, "MySQLPersonalizationProvider - GetCountUserState"); - throw; - } - finally - { - connection.CloseConnection(); - } - } - - private int ResetUserState(ResetUserStateMode mode, DateTime userInactiveSinceDate, string[] paths, string[] usernames) - { - var connection = new MySQLPersonalizationConnectionHelper(connectionString); - connection.OpenConnection(true); - - try - { - if (ResetUserStateMode.PerInactiveDate == mode) - { - return PersonalizationProviderProcedures.my_aspnet_PersonalizationAdministration_ResetUserState(ApplicationId, userInactiveSinceDate.ToUniversalTime(), null, null, connection); - } - if (ResetUserStateMode.PerPaths == mode) - { - return PersonalizationProviderProcedures.my_aspnet_PersonalizationAdministration_ResetUserState(ApplicationId, userInactiveSinceDate, null, paths, connection); - } - else - { - return PersonalizationProviderProcedures.my_aspnet_PersonalizationAdministration_ResetUserState(ApplicationId, userInactiveSinceDate, usernames, paths, connection); - } - } - catch (Exception ex) - { - if (writeExceptionsToEventLog) - WriteToEventLog(ex, "MySQLPersonalizationProvider - ResetUserState"); - throw; - } - finally - { - connection.CloseConnection(); - } - } - - private void WriteToEventLog(Exception e, string action) - { - using (EventLog log = new EventLog()) - { - log.Source = eventSource; - log.Log = eventLog; - string message = exceptionMessage + Environment.NewLine + Environment.NewLine; - message += "Action: " + action + Environment.NewLine + Environment.NewLine; - message += "Exception: " + e; - log.WriteEntry(message); - } - } - - } -} +// Copyright © 2014, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data.MySqlClient; +using MySql.Web.Common; +using MySql.Web.General; +using System; +using System.Diagnostics; +using System.Web.Hosting; +using System.Web.UI.WebControls.WebParts; + +namespace MySql.Web.Personalization +{ + /// + /// Implementation for Personalization Provider to use web parts in ASP.NET websites. + /// + public class MySqlPersonalizationProvider : PersonalizationProvider + { + + string connectionString; + + + string eventSource = "MySQLPersonalizationProvider"; + string eventLog = "Application"; + string exceptionMessage = "An exception occurred. Please check the event log."; + bool writeExceptionsToEventLog = false; + + Application app; + + /// + /// Gets or sets the application name. + /// + public override string ApplicationName + { + get { return app.Name; } + set { app.Name = value; } + } + + private long ApplicationId + { + get { return app.Id; } + } + + private enum ResetUserStateMode + { + PerInactiveDate, + PerPaths, + PerUsers + } + + + /// + /// Initializes settings values for Personalization Provider. + /// + /// The name of the provider. + /// A named value collection representing the configurations for this provider. + public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config) + { + if (config == null) + throw new ArgumentNullException("config"); + + if (string.IsNullOrEmpty(name)) + { + name = "MySqlPersonalizationProvider"; + } + + if (string.IsNullOrEmpty(config["description"])) + { + config.Remove("description"); + config.Add("description", "MySql Personalization provider"); + } + + base.Initialize(name, config); + + string applicationName = HostingEnvironment.ApplicationVirtualPath; + if (!String.IsNullOrEmpty(config["applicationName"])) + applicationName = config["applicationName"]; + + + if (!(config["writeExceptionsToEventLog"] == null)) + { + if (config["writeExceptionsToEventLog"].ToUpper() == "TRUE") + { + writeExceptionsToEventLog = true; + } + } + connectionString = ConfigUtility.GetConnectionString(config); + if (String.IsNullOrEmpty(connectionString)) return; + + // Make sure we have the correct schema. + SchemaManager.CheckSchema(connectionString, config); + + app = new Application(applicationName, base.Description); + + // Get the application id. + try + { + using (MySqlConnection conn = new MySqlConnection(connectionString)) + { + conn.Open(); + app.EnsureId(conn); + } + } + catch (Exception ex) + { + if (writeExceptionsToEventLog) + WriteToEventLog(ex, "MySQLPersonalizationProvider - Initialize"); + throw; + } + } + + /// + /// Returns a collection of PersonalizationStateInfo objects containing administrative information regarding records in the database that match the specified criteria. + /// + /// The personalization scope. + /// The set of query parameters. + /// The index of the page. + /// The size of the page. + /// The total number of records to return. + /// For example, records corresponding to users named Jeff* that have been modified since January 1, 2005. Wildcard support is provider-dependent. + public override PersonalizationStateInfoCollection FindState(PersonalizationScope scope, PersonalizationStateQuery query, int pageIndex, int pageSize, out int totalRecords) + { + + if (query == null) + throw new ArgumentNullException("query"); + + if (pageIndex < 0) + throw new ArgumentOutOfRangeException("pageIndex"); + + if (pageSize < 1) + throw new ArgumentOutOfRangeException("pageSize"); + + if (query.PathToMatch == null) + throw new ArgumentNullException("query.PathToMatch"); + + if (query.UsernameToMatch == null) + throw new ArgumentNullException("query.UserToMatch"); + + DateTime inactiveSinceDate = query.UserInactiveSinceDate; + + if (scope == PersonalizationScope.User) + { + return FindUserState(query.PathToMatch.Trim(), inactiveSinceDate, query.UsernameToMatch.Trim(), pageIndex, pageSize, out totalRecords); + } + else + { + return FindSharedState(query.PathToMatch.Trim(), pageIndex, pageSize, out totalRecords); + } + } + + + /// + /// Returns the number of records in the database that match the specified criteria. + /// + /// The personalization scope. + /// The set of query parameters. + /// For example, records corresponding to users named Jeff* that haven't been modified since January 1, 2005. Wildcard support is provider-dependent. + public override int GetCountOfState(PersonalizationScope scope, PersonalizationStateQuery query) + { + if (query == null) + throw new ArgumentNullException("query"); + + if (scope == PersonalizationScope.User) + { + return GetCountUserState(query.PathToMatch.Trim(), query.UserInactiveSinceDate, query.UsernameToMatch); + } + else + { + return GetCountOfSharedState(query.PathToMatch.Trim()); + } + } + + + /// + /// Retrieves personalization state as opaque blobs from the data source. + /// + /// The web part manager. + /// The path indicating where to save the data. + /// The user name. + /// A byte array containing the user shared data to loaded. + /// A byte array containing the user data to be loaded. + /// Retrieves both shared and user personalization state corresponding to a specified user and a specified page. + protected override void LoadPersonalizationBlobs(WebPartManager webPartManager, string path, string userName, ref Byte[] sharedDataBlob, ref Byte[] userDataBlob) + { + sharedDataBlob = null; + userDataBlob = null; + MySQLPersonalizationConnectionHelper connection = new MySQLPersonalizationConnectionHelper(connectionString); + connection.OpenConnection(true); + try + { + sharedDataBlob = PersonalizationProviderProcedures.my_aspnet_PersonalizationAllUsers_GetPageSettings( + ApplicationId, path, connection); + if (!String.IsNullOrEmpty(userName)) + { + userDataBlob = PersonalizationProviderProcedures.my_aspnet_PersonalizationPerUser_GetPageSettings( + ApplicationId, path, userName, DateTime.UtcNow, connection); + } + + connection.CloseConnection(); + } + catch (Exception ex) + { + if (writeExceptionsToEventLog) + WriteToEventLog(ex, "MySQLPersonalizationProvider - LoadPersonazalitionBlobs"); + throw; + } + finally + { + connection.CloseConnection(); + } + } + + /// + /// Deletes personalization state corresponding to a specified user and a specified page from the database. + /// + /// The web part manager. + /// The path indicating where to save the data. + /// The user name. + protected override void ResetPersonalizationBlob(WebPartManager webPartManager, string path, string userName) + { + MySQLPersonalizationConnectionHelper connection = new MySQLPersonalizationConnectionHelper(connectionString); + connection.OpenConnection(true); + try + { + if (string.IsNullOrEmpty(userName)) + { + PersonalizationProviderProcedures.my_aspnet_PersonalizationAllUsers_ResetPageSettings(ApplicationId, path, connection); + } + else + { + PersonalizationProviderProcedures.my_aspnet_PersonalizationPerUser_ResetPageSettings(ApplicationId, userName, path, DateTime.UtcNow, connection); + } + } + catch (Exception ex) + { + if (writeExceptionsToEventLog) + WriteToEventLog(ex, "MySQLPersonalizationProvider - ResetPersonalizationBlob"); + throw; + } + finally + { + connection.CloseConnection(); + } + } + + /// + /// Deletes personalization state corresponding to the specified users and specified pages from the database. + /// + /// The personalization scope. + /// The paths indicating where to save the data. + /// The user names. + /// + public override int ResetState(PersonalizationScope scope, string[] paths, string[] usernames) + { + + bool hasPaths = !(paths == null || paths.Length == 0); + bool hasUsers = !(usernames == null || usernames.Length == 0); + + var count = 0; + + var connection = new MySQLPersonalizationConnectionHelper(connectionString); + connection.OpenConnection(true); + + if (scope == PersonalizationScope.Shared) + { + try + { + if (paths == null) // reset all state + { + return PersonalizationProviderProcedures.my_aspnet_PersonalizationAdministration_DeleteAllState(true, ApplicationId, connection); + } + else + { + return PersonalizationProviderProcedures.my_aspnet_PersonalizationAdministration_ResetSharedState(ApplicationId, paths, connection); + } + } + catch (Exception ex) + { + if (writeExceptionsToEventLog) + WriteToEventLog(ex, "MySQLPersonalizationProvider - ResetState"); + throw; + } + finally + { + connection.CloseConnection(); + } + } + else + { + DateTime dateTime = Convert.ToDateTime("2038-01-19 03:14:07.999999"); // MySQL TimeStamp MaxValue + + if (!hasPaths && !hasUsers) + { + count = PersonalizationProviderProcedures.my_aspnet_PersonalizationAdministration_DeleteAllState(true, ApplicationId, connection); + } + else if (!hasUsers) + { + count = ResetUserState(ResetUserStateMode.PerPaths, dateTime, paths, null); + } + else + { + count = ResetUserState(ResetUserStateMode.PerUsers, dateTime, paths, usernames); + } + } + return count; + } + + + /// + /// Deletes user personalization state corresponding to the specified pages and that hasn't been updated since a specified date from the database. + /// + /// The path indicating where to retrieve the user state from. + /// A time and date indicating since when the user has been inactive. + /// + public override int ResetUserState(string path, DateTime userInactiveSinceDate) + { + if (string.IsNullOrEmpty(path)) + return 0; + + string[] paths = (path == null) ? null : new string[] { path }; + try + { + return ResetUserState(ResetUserStateMode.PerInactiveDate, userInactiveSinceDate, paths, null); + } + catch (Exception ex) + { + if (writeExceptionsToEventLog) + WriteToEventLog(ex, "MySQLPersonalizationProvider - ResetUserState"); + throw; + } + } + + /// + /// Writes personalization state corresponding to a specified user and a specified page as an opaque blob to the database. + /// + /// The web part manager. + /// The path indicating where to save the data. + /// The user name. + /// A byte array containing the data to be saved. + /// If userName is null, then the personalization state is shared state and is not keyed by user name. + protected override void SavePersonalizationBlob(WebPartManager webPartManager, string path, string userName, Byte[] dataBlob) + { + + MySQLPersonalizationConnectionHelper connection = new MySQLPersonalizationConnectionHelper(connectionString); + + try + { + MySqlCommand cmd = new MySqlCommand(); + connection.OpenConnection(true); + if (!string.IsNullOrEmpty(userName)) + { + PersonalizationProviderProcedures.my_aspnet_PersonalizationPerUser_SetPageSettings(ApplicationId, userName, path, dataBlob, DateTime.UtcNow, connection); + } + else + { + PersonalizationProviderProcedures.my_aspnet_PersonalizationAllUsers_SetPageSettings(ApplicationId, path, dataBlob, DateTime.UtcNow, connection); + } + } + catch (Exception ex) + { + if (writeExceptionsToEventLog) + WriteToEventLog(ex, "MySQLPersonalizationProvider - SavePersonalizationBlob"); + throw; + } + } + + private PersonalizationStateInfoCollection FindSharedState(string path, int pageIndex, int pageSize, out int totalRecords) + { + MySQLPersonalizationConnectionHelper connection = new MySQLPersonalizationConnectionHelper(connectionString); + + try + { + MySqlCommand cmd = new MySqlCommand(); + connection.OpenConnection(true); + totalRecords = PersonalizationProviderProcedures.myaspnet_PersonalizationAdministration_FindState(true, ApplicationId, ApplicationName, pageIndex, pageSize, + path, null, DateTime.MinValue, connection, ref cmd); + + PersonalizationStateInfoCollection sharedStateInfoCollection = new PersonalizationStateInfoCollection(); + + using (var reader = cmd.ExecuteReader()) + { + while (reader.Read()) + { + string pathQuery = reader.GetString("Path"); + DateTime lastUpdatedDate = (reader.IsDBNull(1)) ? DateTime.MinValue : + DateTime.SpecifyKind(reader.GetDateTime(1), DateTimeKind.Utc); + int size = (reader.IsDBNull(2)) ? 0 : reader.GetInt32("SharedDataLength"); + int userDataLength = (reader.IsDBNull(3)) ? 0 : reader.GetInt32("UserDataLength"); + int userCount = (reader.IsDBNull(4)) ? 0 : reader.GetInt32("UserCount"); + + sharedStateInfoCollection.Add(new SharedPersonalizationStateInfo( + pathQuery, lastUpdatedDate, size, userDataLength, userCount)); + } + } + connection.CloseConnection(); + return sharedStateInfoCollection; + } + catch (Exception ex) + { + if (writeExceptionsToEventLog) + WriteToEventLog(ex, "MySQLPersonalizationProvider - FindSharedState"); + throw; + } + finally + { + connection.CloseConnection(); + } + } + + private PersonalizationStateInfoCollection FindUserState(string path, DateTime inactiveSinceDate, string userName, int pageIndex, int pageSize, out int totalRecords) + { + MySQLPersonalizationConnectionHelper connection = new MySQLPersonalizationConnectionHelper(connectionString); + + try + { + + MySqlCommand cmd = new MySqlCommand(); + connection.OpenConnection(true); + totalRecords = PersonalizationProviderProcedures.myaspnet_PersonalizationAdministration_FindState(false, ApplicationId, ApplicationName, pageIndex, pageSize, + path, userName, inactiveSinceDate, connection, ref cmd); + + PersonalizationStateInfoCollection stateInfoCollection = new PersonalizationStateInfoCollection(); + + using (var reader = cmd.ExecuteReader()) + { + while (reader.Read()) + { + string pathQuery = reader.GetString("Path"); + DateTime lastUpdatedDate = DateTime.SpecifyKind(reader.GetDateTime("LastUpdatedDate"), DateTimeKind.Utc); + int size = reader.GetInt32("Size"); + string usernameQuery = reader.GetString("name"); + DateTime lastActivityDate = DateTime.SpecifyKind(reader.GetDateTime("LastActivityDate"), DateTimeKind.Utc); + stateInfoCollection.Add(new UserPersonalizationStateInfo(pathQuery, lastActivityDate, size, usernameQuery, lastActivityDate)); + } + } + connection.CloseConnection(); + + return stateInfoCollection; + } + catch (Exception ex) + { + if (writeExceptionsToEventLog) + WriteToEventLog(ex, "MySQLPersonalizationProvider - FindUserState"); + throw; + } + finally + { + connection.CloseConnection(); + } + } + + private int GetCountOfSharedState(string path) + { + MySQLPersonalizationConnectionHelper connection = new MySQLPersonalizationConnectionHelper(connectionString); + try + { + MySqlCommand cmd = new MySqlCommand(); + connection.OpenConnection(true); + return PersonalizationProviderProcedures.myaspnet_PersonalizationAdministration_GetCountOfState( + true, ApplicationName, ApplicationId, path, + null, DateTime.MinValue, connection); + } + catch (Exception ex) + { + if (writeExceptionsToEventLog) + WriteToEventLog(ex, "MySQLPersonalizationProvider - GetCountOfSharedState"); + throw; + } + finally + { + connection.CloseConnection(); + } + } + + private int GetCountUserState(string path, DateTime userInactiveSinceDate, string userName) + { + MySQLPersonalizationConnectionHelper connection = new MySQLPersonalizationConnectionHelper(connectionString); + try + { + MySqlCommand cmd = new MySqlCommand(); + connection.OpenConnection(true); + return PersonalizationProviderProcedures.myaspnet_PersonalizationAdministration_GetCountOfState( + false, ApplicationName, ApplicationId, path, + userName, userInactiveSinceDate, connection); + } + catch (Exception ex) + { + if (writeExceptionsToEventLog) + WriteToEventLog(ex, "MySQLPersonalizationProvider - GetCountUserState"); + throw; + } + finally + { + connection.CloseConnection(); + } + } + + private int ResetUserState(ResetUserStateMode mode, DateTime userInactiveSinceDate, string[] paths, string[] usernames) + { + var connection = new MySQLPersonalizationConnectionHelper(connectionString); + connection.OpenConnection(true); + + try + { + if (ResetUserStateMode.PerInactiveDate == mode) + { + return PersonalizationProviderProcedures.my_aspnet_PersonalizationAdministration_ResetUserState(ApplicationId, userInactiveSinceDate.ToUniversalTime(), null, null, connection); + } + if (ResetUserStateMode.PerPaths == mode) + { + return PersonalizationProviderProcedures.my_aspnet_PersonalizationAdministration_ResetUserState(ApplicationId, userInactiveSinceDate, null, paths, connection); + } + else + { + return PersonalizationProviderProcedures.my_aspnet_PersonalizationAdministration_ResetUserState(ApplicationId, userInactiveSinceDate, usernames, paths, connection); + } + } + catch (Exception ex) + { + if (writeExceptionsToEventLog) + WriteToEventLog(ex, "MySQLPersonalizationProvider - ResetUserState"); + throw; + } + finally + { + connection.CloseConnection(); + } + } + + private void WriteToEventLog(Exception e, string action) + { + using (EventLog log = new EventLog()) + { + log.Source = eventSource; + log.Log = eventLog; + string message = exceptionMessage + Environment.NewLine + Environment.NewLine; + message += "Action: " + action + Environment.NewLine + Environment.NewLine; + message += "Exception: " + e; + log.WriteEntry(message); + } + } + + } +} diff --git a/MySql.Web/src/PersonalizationProviderProcedures.cs b/MySql.Web/src/PersonalizationProviderProcedures.cs index ca43fd268..7a150871a 100644 --- a/MySql.Web/src/PersonalizationProviderProcedures.cs +++ b/MySql.Web/src/PersonalizationProviderProcedures.cs @@ -1,698 +1,698 @@ -// Copyright (c) 2014, 2020, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data.MySqlClient; -using System; -using System.Globalization; - -namespace MySql.Web.Personalization -{ - internal class PersonalizationProviderProcedures - { - - /// - /// Retrieves profile data from my_aspnet_PersonalizationAllUsers or my_aspnet_PersonalizationPerUser meeting several input criteria. - /// - internal static int myaspnet_PersonalizationAdministration_FindState(bool allUsersScope, long applicationId, string applicationName, int pageIndex, int pageSize, string path, string userName, - DateTime inactiveSinceDate, MySQLPersonalizationConnectionHelper connection, ref MySqlCommand findStateCommand) - { - // create memory table to store results - - var sql = "CREATE TEMPORARY TABLE IF NOT EXISTS pageIndexResults(" + - "IndexId int AUTO_INCREMENT NOT NULL PRIMARY KEY, " + - "ItemId int not null)"; - - if (!connection.Opened) - throw new Exception("Error: Connection should be open"); - - var cmd = new MySqlCommand(sql, connection.Connection); - cmd.ExecuteNonQuery(); - - //make sure table is empty - cmd.CommandText = "TRUNCATE TABLE pageIndexResults"; - cmd.Connection = connection.Connection; - cmd.ExecuteNonQuery(); - - int pageLowerBound = pageSize * pageIndex; - int pageUpperBound = pageSize - 1 + pageLowerBound; - - - if (allUsersScope) - { - - var query = "INSERT INTO pageIndexResults (ItemId) (" + - "SELECT myaspnet_Paths.PathId " + - "FROM myaspnet_Paths, " + - "((SELECT aspnet_Paths.PathId " + - "FROM myaspnet_PersonalizationAllUsers, aspnet_Paths " + - "WHERE myaspnet_Paths.ApplicationId = @ApplicationId " + - "AND aspnet_PersonalizationAllUsers.PathId = aspnet_Paths.PathId " + - "AND (@Path IS NULL OR aspnet_Paths.LoweredPath LIKE @Path) " + - ") AS SharedDataPerPath " + - "FULL OUTER JOIN " + - "(SELECT DISTINCT aspnet_Paths.PathId " + - "FROM my_aspnet_personalizationperuser, my_aspnet_paths " + - "WHERE my_aspnet_paths.ApplicationId = @ApplicationId " + - "AND my_aspnet_personalizationperuser.PathId = aspnet_Paths.PathId " + - "AND (@Path IS NULL OR my_aspnet_paths.LoweredPath LIKE @Path) " + - ") AS UserDataPerPath " + - "ON SharedDataPerPath.PathId = UserDataPerPath.PathId " + - ") " + - "WHERE my_aspnet_Paths.PathId = SharedDataPerPath.PathId OR my_aspnet_Paths.PathId = UserDataPerPath.PathId " + - "ORDER BY my_aspnet_Paths.Path ASC)"; - - cmd.CommandText = query; - cmd.Parameters.AddWithValue("@ApplicationId", applicationId); - cmd.Parameters.AddWithValue("@Path", path); - cmd.Connection = connection.Connection; - cmd.ExecuteNonQuery(); - - cmd.CommandText = "SELECT Count(PathId) FROM pageIndexResults"; - cmd.Connection = connection.Connection; - int totalRecords = (int)cmd.ExecuteScalar(); - - query = "SELECT my_aspnet_Paths.Path, " + - "SharedDataPerPath.LastUpdatedDate, " + - "SharedDataPerPath.SharedDataLength, " + - "UserDataPerPath.UserDataLength, " + - "UserDataPerPath.UserCount " + - "FROM aspnet_Paths, " + - "((SELECT pageIndexResults.ItemId AS PathId, " + - "aspnet_PersonalizationAllUsers.LastUpdatedDate AS LastUpdatedDate, " + - "LENGTH(aspnet_PersonalizationAllUsers.PageSettings) AS SharedDataLength " + - "FROM my_aspnet_personalizationallusers, PageIndex " + - "WHERE my_aspnet_personalizationallusers.PathId = pageIndexResults.IndexId " + - "AND pageIndexResults.IndexId >= @PageLowerBound AND pageIndexResults.IndexId <= @PageUpperBound " + - ") AS SharedDataPerPath " + - "FULL OUTER JOIN " + - "(SELECT pageIndexResults.ItemId AS PathId, " + - "SUM(LENGTH(my_aspnet_personalizationperuser.PageSettings)) AS UserDataLength, " + - "COUNT(*) AS UserCount " + - "FROM my_aspnet_personalizationperuser, pageIndexResults " + - "WHERE my_aspnet_personalizationperuser.PathId = pageIndexResults.IndexId " + - "AND pageIndexResults.IndexId >= @PageLowerBound AND pageIndexResults.IndexId <= @PageUpperBound " + - "GROUP BY pageIndexResults.IndexId " + - ") AS UserDataPerPath " + - "ON SharedDataPerPath.PathId = UserDataPerPath.PathId " + - ") " + - "WHERE aspnet_Paths.PathId = SharedDataPerPath.PathId OR aspnet_Paths.PathId = UserDataPerPath.PathId " + - "ORDER BY my_aspnet_Paths.Path ASC "; - - findStateCommand.CommandText = query; - findStateCommand.Connection = connection.Connection; - findStateCommand.Parameters.AddWithValue("@PageLowerBound", pageLowerBound); - findStateCommand.Parameters.AddWithValue("@PageUpperBound", pageUpperBound); - - return totalRecords; - } - else - { - var query = "INSERT INTO pageIndexResults (ItemId) (" + - "SELECT my_aspnet_personalizationperuser.Id " + - "FROM my_aspnet_personalizationperuser, my_aspnet_users, my_aspnet_paths " + - "WHERE my_aspnet_paths.ApplicationId = @ApplicationId " + - "AND my_aspnet_personalizationperuser.UserId = my_aspnet_Users.Id " + - "AND my_aspnet_personalizationperuser.PathId = my_aspnet_Paths.PathId " + - "AND (@Path IS NULL OR my_aspnet_paths.LoweredPath LIKE @Path) " + - "AND (@UserName IS NULL OR my_aspnet_users.name LIKE @UserName) " + - "AND (@InactiveSinceDate IS NULL OR my_aspnet_users.LastActivityDate <= @InactiveSinceDate) " + - "ORDER BY my_aspnet_paths.Path ASC, my_aspnet_users.name ASC )"; - - cmd.CommandText = query; - cmd.Parameters.AddWithValue("@ApplicationId", applicationId); - cmd.Parameters.AddWithValue("@Path", path); - cmd.Parameters.AddWithValue("@UserName", userName); - cmd.Parameters.AddWithValue("@InactiveSinceDate", inactiveSinceDate); - cmd.Connection = connection.Connection; - cmd.ExecuteNonQuery(); - - cmd.CommandText = "SELECT Count(IndexId) FROM pageIndexResults"; - cmd.Connection = connection.Connection; - var totalRecords = cmd.ExecuteScalar().ToString(); - - query = "SELECT my_aspnet_Paths.Path, my_aspnet_personalizationperuser.LastUpdatedDate, LENGTH(my_aspnet_personalizationperuser.PageSettings) as Size, my_aspnet_Users.Name, my_aspnet_Users.LastActivityDate " + - "FROM my_aspnet_personalizationperuser, my_aspnet_users, my_aspnet_paths, pageIndexResults " + - "WHERE my_aspnet_personalizationperuser.Id = PageIndexResults.IndexId " + - "AND my_aspnet_personalizationperuser.UserId = my_aspnet_users.Id " + - "AND my_aspnet_personalizationperuser.PathId = my_aspnet_paths.PathId " + - "AND pageIndexResults.ItemId >= @PageLowerBound AND PageIndexResults.ItemId <= @PageUpperBound " + - "ORDER BY my_aspnet_paths.Path ASC, my_aspnet_users.name ASC "; - - findStateCommand.CommandText = query; - findStateCommand.Parameters.AddWithValue("@PageUpperBound", pageUpperBound); - findStateCommand.Parameters.AddWithValue("@PageLowerBound", pageLowerBound); - findStateCommand.Connection = connection.Connection; - - return int.Parse(totalRecords, CultureInfo.InvariantCulture); - } - } - - - internal static int myaspnet_PersonalizationAdministration_GetCountOfState(bool allUsersScope, string applicationName, long applicationId, string path, string userName, DateTime inactiveSinceDate, MySQLPersonalizationConnectionHelper connection) - { - if (applicationId <= 0) - return 0; - - if (!connection.Opened) - throw new Exception("Error: Connection should be open"); - - if (allUsersScope) - { - - MySqlCommand cmd = new MySqlCommand("Select count(*) from my_aspnet_personalizationallusers, my_aspnet_paths " + - "where my_aspnet_paths.applicationId = @ApplicationId and " + - "my_aspnet_personalizationallusers.pathid = my_aspnet_paths.pathid and " + - "(@Path is null or my_aspnet_paths.loweredpath like lower(@Path))", connection.Connection); - - cmd.Parameters.AddWithValue("@ApplicationId", applicationId); - cmd.Parameters.AddWithValue("@Path", path); - cmd.Connection = connection.Connection; - var count = cmd.ExecuteScalar().ToString(); - return int.Parse(count, CultureInfo.InvariantCulture); - } - else - { - MySqlCommand cmd = new MySqlCommand("Select count(*) from my_aspnet_personalizationperuser as peruser, my_aspnet_users as users, " + - "my_aspnet_paths as paths " + - "where paths.applicationId = @ApplicationId and " + - "peruser.userid = users.id and " + - "peruser.pathId = paths.pathId and " + - "(@Path is null or paths.loweredpath like lower(@Path) and " + - "(@UserName is null or users.name like lower(@UserName))) and " + - "(@InactiveSinceDate is null or users.lastactivitydate <= @InactiveSinceDate) ", connection.Connection); - - cmd.Parameters.AddWithValue("@ApplicationId", applicationId); - cmd.Parameters.AddWithValue("@Path", path); - cmd.Parameters.AddWithValue("@UserName", userName); - cmd.Parameters.AddWithValue("@InactiveSinceDate", inactiveSinceDate); - cmd.Connection = connection.Connection; - var count = cmd.ExecuteScalar().ToString(); - return int.Parse(count, CultureInfo.InvariantCulture); - } - } - - - internal static Byte[] my_aspnet_PersonalizationPerUser_GetPageSettings(long applicationId, string path, string userName, DateTime currentTimeUtc, MySQLPersonalizationConnectionHelper connection) - { - if (applicationId <= 0) - return null; - - if (!connection.Opened) - throw new Exception("Error: Connection should be open"); - - //get pathid - var cmd = new MySqlCommand("select pathId from my_aspnet_paths where applicationid = @ApplicationId and loweredpath = lower(@Path)", connection.Connection); - cmd.Connection = connection.Connection; - - cmd.Parameters.AddWithValue("@ApplicationId", applicationId); - cmd.Parameters.AddWithValue("@Path", path); - - var pathId = (cmd.ExecuteScalar() ?? "").ToString(); - - if (string.IsNullOrEmpty(pathId)) - return null; - - cmd = new MySqlCommand("select Id from my_aspnet_users where applicationid = @ApplicationId and name = @UserName", connection.Connection); - cmd.Connection = connection.Connection; - cmd.Parameters.AddWithValue("@ApplicationId", applicationId); - cmd.Parameters.AddWithValue("@UserName", userName); - - - var userId = (cmd.ExecuteScalar() ?? "").ToString(); - userId = string.IsNullOrEmpty(userId) ? "0" : userId; - - if (int.Parse(userId, CultureInfo.InvariantCulture) == 0) - return null; - - UpdateUserLastActiveDate(connection.Connection, int.Parse(userId, CultureInfo.InvariantCulture), currentTimeUtc); - - cmd = new MySqlCommand("select pagesettings from my_aspnet_personalizationperuser as peruser where peruser.pathid = @PathId and peruser.userid = @UserId"); - cmd.Connection = connection.Connection; - cmd.Parameters.AddWithValue("@PathId", pathId); - cmd.Parameters.AddWithValue("@UserId", userId); - - var reader = cmd.ExecuteReader(); - - byte[] settings = null; - while (reader.Read()) - { - int size = (int)reader.GetBytes(0, 0, null, 0, 0); - settings = new byte[size]; - reader.GetBytes(0, 0, settings, 0, size); - } - reader.Close(); - return settings; - } - - - internal static byte[] my_aspnet_PersonalizationAllUsers_GetPageSettings(long applicationId, string path, MySQLPersonalizationConnectionHelper connection) - { - if (applicationId <= 0) - return null; - - if (!connection.Opened) - throw new Exception("Error: Connection should be open"); - - var cmd = new MySqlCommand("Select pathid from my_aspnet_paths as paths where paths.applicationid = @ApplicationId and paths.loweredPath = lower(@Path)", connection.Connection); - cmd.Parameters.AddWithValue("@ApplicationId", applicationId); - cmd.Parameters.AddWithValue("@Path", path); - var pathId = (string)cmd.ExecuteScalar(); - - if (!string.IsNullOrEmpty(pathId)) - { - cmd.CommandText = "Select PageSettings from my_aspnet_personalizationallusers where pathId = @PathId"; - cmd.Parameters.AddWithValue("@PathId", pathId); - cmd.Connection = connection.Connection; - var reader = cmd.ExecuteReader(); - - byte[] settings = null; - while (reader.Read()) - { - int size = (int)reader.GetBytes(0, 0, null, 0, 0); - settings = new byte[size]; - reader.GetBytes(0, 0, settings, 0, size); - } - reader.Close(); - return settings; - } - - return null; - } - - - internal static void my_aspnet_PersonalizationPerUser_ResetPageSettings(long applicationId, string userName, string path, DateTime currentTimeUtc, MySQLPersonalizationConnectionHelper connection) - { - - if (applicationId <= 0) - return; - - if (!connection.Opened) - throw new Exception("Error: Connection should be open"); - - var cmd = new MySqlCommand("Select pathid from my_aspnet_paths as paths where paths.applicationid = @ApplicationId and paths.loweredPath = lower(@Path)", connection.Connection); - cmd.Parameters.AddWithValue("@ApplicationId", applicationId); - cmd.Parameters.AddWithValue("@Path", path); - var pathId = (string)cmd.ExecuteScalar(); - - if (!string.IsNullOrEmpty(pathId)) - { - cmd = new MySqlCommand("select Id from my_aspnet_users where applicationid = @ApplicationId and name = @UserName", connection.Connection); - cmd.Connection = connection.Connection; - cmd.Parameters.AddWithValue("@ApplicationId", applicationId); - cmd.Parameters.AddWithValue("@UserName", userName); - - var userId = (int)cmd.ExecuteScalar(); - if (userId != 0) - { - var rows = UpdateUserLastActiveDate(connection.Connection, userId, currentTimeUtc); - if (rows != 0) - { - cmd = new MySqlCommand("delete from my_aspnet_personalizationperuser WHERE pathId = @PathId AND userId = @UserId"); - cmd.Connection = connection.Connection; - cmd.Parameters.AddWithValue("@PathId", pathId); - cmd.Parameters.AddWithValue("@UserId", userId); - cmd.ExecuteNonQuery(); - } - } - } - } - - internal static void my_aspnet_PersonalizationAllUsers_ResetPageSettings(long applicationId, string path, MySQLPersonalizationConnectionHelper connection) - { - - if (applicationId <= 0) - return; - - if (!connection.Opened) - throw new Exception("Error: Connection should be open"); - - var cmd = new MySqlCommand("Select pathid from my_aspnet_paths as paths where paths.applicationid = @ApplicationId and paths.loweredPath = lower(@Path)", connection.Connection); - cmd.Parameters.AddWithValue("@ApplicationId", applicationId); - cmd.Parameters.AddWithValue("@Path", path); - var pathId = (cmd.ExecuteScalar() ?? "").ToString(); - - if (!string.IsNullOrEmpty(pathId)) - { - cmd = new MySqlCommand("delete my_aspnet_personalizationallusers.* from my_aspnet_personalizationallusers WHERE pathId = @PathId"); - cmd.Connection = connection.Connection; - cmd.Parameters.AddWithValue("@PathId", pathId); - cmd.ExecuteNonQuery(); - } - - } - - - private static int UpdateUserLastActiveDate(MySqlConnection cnn, int userId, DateTime currentTimeUtc) - { - MySqlTransaction trans; - trans = cnn.BeginTransaction(); - try - { - var cmd = new MySqlCommand("update my_aspnet_users set lastactivitydate = @CurrentTimeUtc where id = @UserId"); - cmd.Connection = cnn; - cmd.Transaction = trans; - cmd.Parameters.AddWithValue("@CurrentTimeUtc", currentTimeUtc); - cmd.Parameters.AddWithValue("@UserId", userId); - var rows = cmd.ExecuteNonQuery(); - trans.Commit(); - return rows; - } - catch - { - trans.Rollback(); - throw; - } - } - - - internal static int my_aspnet_PersonalizationAdministration_ResetUserState(long applicationId, DateTime inactiveSinceDate, string[] usernames, string[] paths, MySQLPersonalizationConnectionHelper connection) - { - if (applicationId <= 0) - return 0; - - if (!connection.Opened) - throw new Exception("Error: Connection should be open"); - - var rows = 0; - var cmd = new MySqlCommand(); - if (usernames == null) usernames = new string[1] { "" }; - if (paths == null) paths = new string[1] { "" }; - - foreach (var username in usernames) - { - foreach (var path in paths) - { - var query = "DELETE peruser.* FROM (my_aspnet_personalizationperuser as peruser " + - "INNER JOIN my_aspnet_users as users ON " + - "peruser.userid = users.id) " + - "INNER JOIN my_aspnet_paths as paths ON " + - "paths.applicationId = @ApplicationId AND " + - "paths.pathid = peruser.pathid AND " + - "(@InactiveSinceDate is null OR users.lastactivitydate <= @InactiveSinceDate) "; - query = string.IsNullOrEmpty(username) ? query : query += " AND (@UserName is null OR users.name = @UserName) "; - query = string.IsNullOrEmpty(path) ? query : query += " AND (@Path is null OR paths.loweredpath = LOWER(@Path))"; - cmd.CommandText = query; - cmd.Parameters.AddWithValue("@ApplicationId", applicationId); - cmd.Parameters.AddWithValue("@InactiveSinceDate", inactiveSinceDate); - cmd.Parameters.AddWithValue("@Path", path); - cmd.Parameters.AddWithValue("@UserName", username); - cmd.Connection = connection.Connection; - rows += cmd.ExecuteNonQuery(); - } - } - - return rows; - } - - - internal static int my_aspnet_PersonalizationAdministration_DeleteAllState(long applicationId, bool allUsersScope, MySQLPersonalizationConnectionHelper connection) - { - if (applicationId <= 0) - return 0; - - if (!connection.Opened) - throw new Exception("Error: Connection should be open"); - - var cmd = new MySqlCommand(); - cmd.Connection = connection.Connection; - - if (allUsersScope) - { - cmd.CommandText = "DELETE FROM my_aspnet_personalizationallusers " + - "WHERE PathId IN (SELECT Paths.PathId FROM my_aspnet_paths as paths " + - "WHERE paths.ApplicationId = @ApplicationId)"; - cmd.Parameters.AddWithValue("@ApplicationId", applicationId); - } - else - { - cmd.CommandText = "DELETE FROM my_aspnet_personalizationperuser " + - "WHERE PathId IN (SELECT Paths.PathId FROM my_aspnet_paths as paths " + - "WHERE paths.ApplicationId = @ApplicationId)"; - cmd.Parameters.AddWithValue("@ApplicationId", applicationId); - } - - var rows = cmd.ExecuteNonQuery(); - return rows; - } - - internal static int my_aspnet_PersonalizationAdministration_ResetSharedState(long applicationId, string[] paths, MySQLPersonalizationConnectionHelper connection) - { - if (applicationId <= 0) - return 0; - - if (!connection.Opened) - throw new Exception("Error: Connection should be open"); - - if (paths == null) - return 0; - - var cmd = new MySqlCommand(); - cmd.Connection = connection.Connection; - - var rows = 0; - - foreach (var path in paths) - { - cmd.CommandText = "DELETE my_aspnet_personalizationallusers.* FROM my_aspnet_personalizationallusers " + - "INNER JOIN my_aspnet_paths as paths ON " + - "((paths.ApplicationId = @ApplicationId AND " + - "my_aspnet_personalizationallusers.PathId = paths.PathId) AND " + - "paths.loweredpath = LOWER(@Path))"; - - cmd.Parameters.AddWithValue("@ApplicationId", applicationId); - cmd.Parameters.AddWithValue("@Path", path); - rows += cmd.ExecuteNonQuery(); - } - - return rows; - } - - - internal static int my_aspnet_PersonalizationAdministration_DeleteAllState(bool allUsersScope, long applicationId, MySQLPersonalizationConnectionHelper connection) - { - if (applicationId <= 0) - return 0; - - if (!connection.Opened) - throw new Exception("Error: Connection should be open"); - - var cmd = new MySqlCommand(); - cmd.Connection = connection.Connection; - - if (allUsersScope) - { - - cmd.CommandText = "DELETE FROM my_aspnet_personalizationallusers " + - "WHERE PathId IN " + - "(SELECT paths.PathId FROM my_aspnet_paths as paths " + - "WHERE paths.ApplicationId = @ApplicationId)"; - } - else - { - cmd.CommandText = "DELETE FROM my_aspnet_personalizationperuser " + - "WHERE PathId IN " + - "(SELECT Paths.PathId FROM my_aspnet_paths Paths " + - "WHERE Paths.ApplicationId = @ApplicationId)"; - } - cmd.Parameters.AddWithValue("@ApplicationId", applicationId); - var rows = cmd.ExecuteNonQuery(); - return rows; - } - - /// - /// Saves per-user state for the specified page and the specified user in the my_aspnet_PersonalizationPerUser table. - /// - /// - internal static int my_aspnet_PersonalizationPerUser_SetPageSettings(long applicationId, string userName, string path, byte[] settings, DateTime currentTimeUtc, MySQLPersonalizationConnectionHelper connection) - { - if (applicationId <= 0) - return 0; - - if (!connection.Opened) - throw new Exception("Error: Connection should be open"); - - var cmd = new MySqlCommand(); - cmd.Connection = connection.Connection; - - cmd.CommandText = "SELECT PathId FROM my_aspnet_paths WHERE ApplicationId = @ApplicationId AND LoweredPath = LOWER(@Path)"; - cmd.Parameters.AddWithValue("@ApplicationId", applicationId); - cmd.Parameters.AddWithValue("@Path", path); - var pathId = (string)cmd.ExecuteScalar(); - - cmd.Parameters.Clear(); - - if (pathId == null) - { - // create path - MySqlTransaction trans; - trans = connection.Connection.BeginTransaction(); - - try - { - cmd.Transaction = trans; - cmd.CommandText = "INSERT INTO my_aspnet_paths (applicationId, pathId, path, loweredpath) values (@ApplicationId, @PathId, @Path, LOWER(@Path))"; - cmd.Parameters.AddWithValue("@ApplicationId", applicationId); - cmd.Parameters.AddWithValue("@PathId", pathId = Guid.NewGuid().ToString()); - cmd.Parameters.AddWithValue("@Path", path); - cmd.ExecuteNonQuery(); - trans.Commit(); - } - catch - { - trans.Rollback(); - throw; - } - } - - cmd.Parameters.Clear(); - cmd.CommandText = "SELECT id FROM my_aspnet_users WHERE ApplicationId = @ApplicationId AND name = LOWER(@UserName)"; - cmd.Parameters.AddWithValue("@ApplicationId", applicationId); - cmd.Parameters.AddWithValue("@UserName", userName); - var userId = (cmd.ExecuteScalar() ?? "").ToString(); - - userId = string.IsNullOrEmpty(userId) ? "0" : userId; - - // create user - if (int.Parse(userId, CultureInfo.InvariantCulture) == 0) - { - // create path - MySqlTransaction trans; - trans = connection.Connection.BeginTransaction(); - - try - { - cmd.Parameters.Clear(); - cmd.Transaction = trans; - cmd.CommandText = "INSERT INTO my_aspnet_users (applicationId, name, isAnonymous, lastActivityDate) values (@ApplicationId, @UserName, false, @CurrentTimeUtc)"; - cmd.Parameters.AddWithValue("@ApplicationId", applicationId); - cmd.Parameters.AddWithValue("@UserName", userName); - cmd.Parameters.AddWithValue("@CurrentTimeUtc", DateTime.UtcNow); - cmd.ExecuteNonQuery(); - trans.Commit(); - } - catch - { - trans.Rollback(); - throw; - } - - cmd.Parameters.Clear(); - cmd.CommandText = "SELECT Id from my_aspnet_users where applicationId = @ApplicationId and name = @UserName)"; - cmd.Parameters.AddWithValue("@ApplicationId", applicationId); - cmd.Parameters.AddWithValue("@UserName", userName); - userId = (string)cmd.ExecuteScalar(); - - } - var rows = UpdateUserLastActiveDate(connection.Connection, int.Parse(userId, CultureInfo.InvariantCulture), DateTime.UtcNow); - if (rows == 0) - throw new Exception("User not found"); - - cmd.Parameters.Clear(); - cmd.CommandText = "Select COUNT(*) from my_aspnet_personalizationperuser where userid = @UserId and pathId = @PathId"; - cmd.Parameters.AddWithValue("@UserId", userId); - cmd.Parameters.AddWithValue("@PathId", pathId); - if ((long)cmd.ExecuteScalar() > 0) - { - cmd.Parameters.Clear(); - cmd.CommandText = "UPDATE my_aspnet_personalizationperuser SET PageSettings = @PageSettings, LastUpdatedDate = @CurrentTimeUtc " + - "where userid = @UserId and pathId = @PathId"; - cmd.Parameters.AddWithValue("@UserId", userId); - cmd.Parameters.AddWithValue("@PathId", pathId); - cmd.Parameters.AddWithValue("@PageSettings", settings); - cmd.Parameters.AddWithValue("@CurrentTimeUtc", DateTime.UtcNow); - cmd.ExecuteNonQuery(); - } - else - { - cmd.Parameters.Clear(); - cmd.CommandText = "INSERT INTO my_aspnet_personalizationperuser(applicationId, pathId, userId, pageSettings, lastUpdatedDate) VALUES(@applicationId, @PathId, @userId, @PageSettings, @LastUpdatedDate)"; - cmd.Parameters.AddWithValue("@applicationId", applicationId); - cmd.Parameters.AddWithValue("@UserId", userId); - cmd.Parameters.AddWithValue("@PathId", pathId); - cmd.Parameters.AddWithValue("@PageSettings", settings); - cmd.Parameters.AddWithValue("@LastUpdatedDate", DateTime.UtcNow); - rows = cmd.ExecuteNonQuery(); - } - return rows; - } - - /// - /// Saves shared state for the specified page in the aspnet_PersonalizationAllUsers table - /// - /// - internal static int my_aspnet_PersonalizationAllUsers_SetPageSettings(long applicationId, string path, byte[] settings, DateTime currentTimeUtc, MySQLPersonalizationConnectionHelper connection) - { - if (applicationId <= 0) - return 0; - - if (!connection.Opened) - throw new Exception("Error: Connection should be open"); - - var cmd = new MySqlCommand(); - cmd.Connection = connection.Connection; - - cmd.CommandText = "SELECT PathId FROM my_aspnet_paths WHERE ApplicationId = @ApplicationId AND LoweredPath = LOWER(@Path)"; - cmd.Parameters.AddWithValue("@ApplicationId", applicationId); - cmd.Parameters.AddWithValue("@Path", path); - var pathId = (string)cmd.ExecuteScalar(); - cmd.Parameters.Clear(); - - if (pathId == null) - { - // create path - MySqlTransaction trans; - trans = connection.Connection.BeginTransaction(); - - try - { - cmd.Transaction = trans; - cmd.CommandText = "INSERT INTO my_aspnet_paths (applicationId, pathId, path, loweredpath) values (@ApplicationId, @PathId, @Path, LOWER(@Path))"; - cmd.Parameters.AddWithValue("@ApplicationId", applicationId); - cmd.Parameters.AddWithValue("@PathId", pathId = Guid.NewGuid().ToString()); - cmd.Parameters.AddWithValue("@Path", path); - cmd.ExecuteNonQuery(); - trans.Commit(); - } - catch - { - trans.Rollback(); - throw; - } - } - - cmd.CommandText = "INSERT INTO my_aspnet_personalizationallusers(PathId, PageSettings, LastUpdatedDate) VALUES (@PathId, @PageSettings, @CurrentTimeUtc)"; - cmd.CommandText += " ON DUPLICATE KEY UPDATE PageSettings=Values(PageSettings), LastUpdatedDate=Values(LastUpdatedDate)"; - cmd.Parameters.Clear(); - cmd.Parameters.AddWithValue("@PageSettings", settings); - cmd.Parameters.AddWithValue("@PathId", pathId); - cmd.Parameters.AddWithValue("@CurrentTimeUtc", currentTimeUtc); - var rows = cmd.ExecuteNonQuery(); - return rows; - } - } -} +// Copyright © 2014, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data.MySqlClient; +using System; +using System.Globalization; + +namespace MySql.Web.Personalization +{ + internal class PersonalizationProviderProcedures + { + + /// + /// Retrieves profile data from my_aspnet_PersonalizationAllUsers or my_aspnet_PersonalizationPerUser meeting several input criteria. + /// + internal static int myaspnet_PersonalizationAdministration_FindState(bool allUsersScope, long applicationId, string applicationName, int pageIndex, int pageSize, string path, string userName, + DateTime inactiveSinceDate, MySQLPersonalizationConnectionHelper connection, ref MySqlCommand findStateCommand) + { + // create memory table to store results + + var sql = "CREATE TEMPORARY TABLE IF NOT EXISTS pageIndexResults(" + + "IndexId int AUTO_INCREMENT NOT NULL PRIMARY KEY, " + + "ItemId int not null)"; + + if (!connection.Opened) + throw new Exception("Error: Connection should be open"); + + var cmd = new MySqlCommand(sql, connection.Connection); + cmd.ExecuteNonQuery(); + + //make sure table is empty + cmd.CommandText = "TRUNCATE TABLE pageIndexResults"; + cmd.Connection = connection.Connection; + cmd.ExecuteNonQuery(); + + int pageLowerBound = pageSize * pageIndex; + int pageUpperBound = pageSize - 1 + pageLowerBound; + + + if (allUsersScope) + { + + var query = "INSERT INTO pageIndexResults (ItemId) (" + + "SELECT myaspnet_Paths.PathId " + + "FROM myaspnet_Paths, " + + "((SELECT aspnet_Paths.PathId " + + "FROM myaspnet_PersonalizationAllUsers, aspnet_Paths " + + "WHERE myaspnet_Paths.ApplicationId = @ApplicationId " + + "AND aspnet_PersonalizationAllUsers.PathId = aspnet_Paths.PathId " + + "AND (@Path IS NULL OR aspnet_Paths.LoweredPath LIKE @Path) " + + ") AS SharedDataPerPath " + + "FULL OUTER JOIN " + + "(SELECT DISTINCT aspnet_Paths.PathId " + + "FROM my_aspnet_personalizationperuser, my_aspnet_paths " + + "WHERE my_aspnet_paths.ApplicationId = @ApplicationId " + + "AND my_aspnet_personalizationperuser.PathId = aspnet_Paths.PathId " + + "AND (@Path IS NULL OR my_aspnet_paths.LoweredPath LIKE @Path) " + + ") AS UserDataPerPath " + + "ON SharedDataPerPath.PathId = UserDataPerPath.PathId " + + ") " + + "WHERE my_aspnet_Paths.PathId = SharedDataPerPath.PathId OR my_aspnet_Paths.PathId = UserDataPerPath.PathId " + + "ORDER BY my_aspnet_Paths.Path ASC)"; + + cmd.CommandText = query; + cmd.Parameters.AddWithValue("@ApplicationId", applicationId); + cmd.Parameters.AddWithValue("@Path", path); + cmd.Connection = connection.Connection; + cmd.ExecuteNonQuery(); + + cmd.CommandText = "SELECT Count(PathId) FROM pageIndexResults"; + cmd.Connection = connection.Connection; + int totalRecords = (int)cmd.ExecuteScalar(); + + query = "SELECT my_aspnet_Paths.Path, " + + "SharedDataPerPath.LastUpdatedDate, " + + "SharedDataPerPath.SharedDataLength, " + + "UserDataPerPath.UserDataLength, " + + "UserDataPerPath.UserCount " + + "FROM aspnet_Paths, " + + "((SELECT pageIndexResults.ItemId AS PathId, " + + "aspnet_PersonalizationAllUsers.LastUpdatedDate AS LastUpdatedDate, " + + "LENGTH(aspnet_PersonalizationAllUsers.PageSettings) AS SharedDataLength " + + "FROM my_aspnet_personalizationallusers, PageIndex " + + "WHERE my_aspnet_personalizationallusers.PathId = pageIndexResults.IndexId " + + "AND pageIndexResults.IndexId >= @PageLowerBound AND pageIndexResults.IndexId <= @PageUpperBound " + + ") AS SharedDataPerPath " + + "FULL OUTER JOIN " + + "(SELECT pageIndexResults.ItemId AS PathId, " + + "SUM(LENGTH(my_aspnet_personalizationperuser.PageSettings)) AS UserDataLength, " + + "COUNT(*) AS UserCount " + + "FROM my_aspnet_personalizationperuser, pageIndexResults " + + "WHERE my_aspnet_personalizationperuser.PathId = pageIndexResults.IndexId " + + "AND pageIndexResults.IndexId >= @PageLowerBound AND pageIndexResults.IndexId <= @PageUpperBound " + + "GROUP BY pageIndexResults.IndexId " + + ") AS UserDataPerPath " + + "ON SharedDataPerPath.PathId = UserDataPerPath.PathId " + + ") " + + "WHERE aspnet_Paths.PathId = SharedDataPerPath.PathId OR aspnet_Paths.PathId = UserDataPerPath.PathId " + + "ORDER BY my_aspnet_Paths.Path ASC "; + + findStateCommand.CommandText = query; + findStateCommand.Connection = connection.Connection; + findStateCommand.Parameters.AddWithValue("@PageLowerBound", pageLowerBound); + findStateCommand.Parameters.AddWithValue("@PageUpperBound", pageUpperBound); + + return totalRecords; + } + else + { + var query = "INSERT INTO pageIndexResults (ItemId) (" + + "SELECT my_aspnet_personalizationperuser.Id " + + "FROM my_aspnet_personalizationperuser, my_aspnet_users, my_aspnet_paths " + + "WHERE my_aspnet_paths.ApplicationId = @ApplicationId " + + "AND my_aspnet_personalizationperuser.UserId = my_aspnet_Users.Id " + + "AND my_aspnet_personalizationperuser.PathId = my_aspnet_Paths.PathId " + + "AND (@Path IS NULL OR my_aspnet_paths.LoweredPath LIKE @Path) " + + "AND (@UserName IS NULL OR my_aspnet_users.name LIKE @UserName) " + + "AND (@InactiveSinceDate IS NULL OR my_aspnet_users.LastActivityDate <= @InactiveSinceDate) " + + "ORDER BY my_aspnet_paths.Path ASC, my_aspnet_users.name ASC )"; + + cmd.CommandText = query; + cmd.Parameters.AddWithValue("@ApplicationId", applicationId); + cmd.Parameters.AddWithValue("@Path", path); + cmd.Parameters.AddWithValue("@UserName", userName); + cmd.Parameters.AddWithValue("@InactiveSinceDate", inactiveSinceDate); + cmd.Connection = connection.Connection; + cmd.ExecuteNonQuery(); + + cmd.CommandText = "SELECT Count(IndexId) FROM pageIndexResults"; + cmd.Connection = connection.Connection; + var totalRecords = cmd.ExecuteScalar().ToString(); + + query = "SELECT my_aspnet_Paths.Path, my_aspnet_personalizationperuser.LastUpdatedDate, LENGTH(my_aspnet_personalizationperuser.PageSettings) as Size, my_aspnet_Users.Name, my_aspnet_Users.LastActivityDate " + + "FROM my_aspnet_personalizationperuser, my_aspnet_users, my_aspnet_paths, pageIndexResults " + + "WHERE my_aspnet_personalizationperuser.Id = PageIndexResults.IndexId " + + "AND my_aspnet_personalizationperuser.UserId = my_aspnet_users.Id " + + "AND my_aspnet_personalizationperuser.PathId = my_aspnet_paths.PathId " + + "AND pageIndexResults.ItemId >= @PageLowerBound AND PageIndexResults.ItemId <= @PageUpperBound " + + "ORDER BY my_aspnet_paths.Path ASC, my_aspnet_users.name ASC "; + + findStateCommand.CommandText = query; + findStateCommand.Parameters.AddWithValue("@PageUpperBound", pageUpperBound); + findStateCommand.Parameters.AddWithValue("@PageLowerBound", pageLowerBound); + findStateCommand.Connection = connection.Connection; + + return int.Parse(totalRecords, CultureInfo.InvariantCulture); + } + } + + + internal static int myaspnet_PersonalizationAdministration_GetCountOfState(bool allUsersScope, string applicationName, long applicationId, string path, string userName, DateTime inactiveSinceDate, MySQLPersonalizationConnectionHelper connection) + { + if (applicationId <= 0) + return 0; + + if (!connection.Opened) + throw new Exception("Error: Connection should be open"); + + if (allUsersScope) + { + + MySqlCommand cmd = new MySqlCommand("Select count(*) from my_aspnet_personalizationallusers, my_aspnet_paths " + + "where my_aspnet_paths.applicationId = @ApplicationId and " + + "my_aspnet_personalizationallusers.pathid = my_aspnet_paths.pathid and " + + "(@Path is null or my_aspnet_paths.loweredpath like lower(@Path))", connection.Connection); + + cmd.Parameters.AddWithValue("@ApplicationId", applicationId); + cmd.Parameters.AddWithValue("@Path", path); + cmd.Connection = connection.Connection; + var count = cmd.ExecuteScalar().ToString(); + return int.Parse(count, CultureInfo.InvariantCulture); + } + else + { + MySqlCommand cmd = new MySqlCommand("Select count(*) from my_aspnet_personalizationperuser as peruser, my_aspnet_users as users, " + + "my_aspnet_paths as paths " + + "where paths.applicationId = @ApplicationId and " + + "peruser.userid = users.id and " + + "peruser.pathId = paths.pathId and " + + "(@Path is null or paths.loweredpath like lower(@Path) and " + + "(@UserName is null or users.name like lower(@UserName))) and " + + "(@InactiveSinceDate is null or users.lastactivitydate <= @InactiveSinceDate) ", connection.Connection); + + cmd.Parameters.AddWithValue("@ApplicationId", applicationId); + cmd.Parameters.AddWithValue("@Path", path); + cmd.Parameters.AddWithValue("@UserName", userName); + cmd.Parameters.AddWithValue("@InactiveSinceDate", inactiveSinceDate); + cmd.Connection = connection.Connection; + var count = cmd.ExecuteScalar().ToString(); + return int.Parse(count, CultureInfo.InvariantCulture); + } + } + + + internal static Byte[] my_aspnet_PersonalizationPerUser_GetPageSettings(long applicationId, string path, string userName, DateTime currentTimeUtc, MySQLPersonalizationConnectionHelper connection) + { + if (applicationId <= 0) + return null; + + if (!connection.Opened) + throw new Exception("Error: Connection should be open"); + + //get pathid + var cmd = new MySqlCommand("select pathId from my_aspnet_paths where applicationid = @ApplicationId and loweredpath = lower(@Path)", connection.Connection); + cmd.Connection = connection.Connection; + + cmd.Parameters.AddWithValue("@ApplicationId", applicationId); + cmd.Parameters.AddWithValue("@Path", path); + + var pathId = (cmd.ExecuteScalar() ?? "").ToString(); + + if (string.IsNullOrEmpty(pathId)) + return null; + + cmd = new MySqlCommand("select Id from my_aspnet_users where applicationid = @ApplicationId and name = @UserName", connection.Connection); + cmd.Connection = connection.Connection; + cmd.Parameters.AddWithValue("@ApplicationId", applicationId); + cmd.Parameters.AddWithValue("@UserName", userName); + + + var userId = (cmd.ExecuteScalar() ?? "").ToString(); + userId = string.IsNullOrEmpty(userId) ? "0" : userId; + + if (int.Parse(userId, CultureInfo.InvariantCulture) == 0) + return null; + + UpdateUserLastActiveDate(connection.Connection, int.Parse(userId, CultureInfo.InvariantCulture), currentTimeUtc); + + cmd = new MySqlCommand("select pagesettings from my_aspnet_personalizationperuser as peruser where peruser.pathid = @PathId and peruser.userid = @UserId"); + cmd.Connection = connection.Connection; + cmd.Parameters.AddWithValue("@PathId", pathId); + cmd.Parameters.AddWithValue("@UserId", userId); + + var reader = cmd.ExecuteReader(); + + byte[] settings = null; + while (reader.Read()) + { + int size = (int)reader.GetBytes(0, 0, null, 0, 0); + settings = new byte[size]; + reader.GetBytes(0, 0, settings, 0, size); + } + reader.Close(); + return settings; + } + + + internal static byte[] my_aspnet_PersonalizationAllUsers_GetPageSettings(long applicationId, string path, MySQLPersonalizationConnectionHelper connection) + { + if (applicationId <= 0) + return null; + + if (!connection.Opened) + throw new Exception("Error: Connection should be open"); + + var cmd = new MySqlCommand("Select pathid from my_aspnet_paths as paths where paths.applicationid = @ApplicationId and paths.loweredPath = lower(@Path)", connection.Connection); + cmd.Parameters.AddWithValue("@ApplicationId", applicationId); + cmd.Parameters.AddWithValue("@Path", path); + var pathId = (string)cmd.ExecuteScalar(); + + if (!string.IsNullOrEmpty(pathId)) + { + cmd.CommandText = "Select PageSettings from my_aspnet_personalizationallusers where pathId = @PathId"; + cmd.Parameters.AddWithValue("@PathId", pathId); + cmd.Connection = connection.Connection; + var reader = cmd.ExecuteReader(); + + byte[] settings = null; + while (reader.Read()) + { + int size = (int)reader.GetBytes(0, 0, null, 0, 0); + settings = new byte[size]; + reader.GetBytes(0, 0, settings, 0, size); + } + reader.Close(); + return settings; + } + + return null; + } + + + internal static void my_aspnet_PersonalizationPerUser_ResetPageSettings(long applicationId, string userName, string path, DateTime currentTimeUtc, MySQLPersonalizationConnectionHelper connection) + { + + if (applicationId <= 0) + return; + + if (!connection.Opened) + throw new Exception("Error: Connection should be open"); + + var cmd = new MySqlCommand("Select pathid from my_aspnet_paths as paths where paths.applicationid = @ApplicationId and paths.loweredPath = lower(@Path)", connection.Connection); + cmd.Parameters.AddWithValue("@ApplicationId", applicationId); + cmd.Parameters.AddWithValue("@Path", path); + var pathId = (string)cmd.ExecuteScalar(); + + if (!string.IsNullOrEmpty(pathId)) + { + cmd = new MySqlCommand("select Id from my_aspnet_users where applicationid = @ApplicationId and name = @UserName", connection.Connection); + cmd.Connection = connection.Connection; + cmd.Parameters.AddWithValue("@ApplicationId", applicationId); + cmd.Parameters.AddWithValue("@UserName", userName); + + var userId = (int)cmd.ExecuteScalar(); + if (userId != 0) + { + var rows = UpdateUserLastActiveDate(connection.Connection, userId, currentTimeUtc); + if (rows != 0) + { + cmd = new MySqlCommand("delete from my_aspnet_personalizationperuser WHERE pathId = @PathId AND userId = @UserId"); + cmd.Connection = connection.Connection; + cmd.Parameters.AddWithValue("@PathId", pathId); + cmd.Parameters.AddWithValue("@UserId", userId); + cmd.ExecuteNonQuery(); + } + } + } + } + + internal static void my_aspnet_PersonalizationAllUsers_ResetPageSettings(long applicationId, string path, MySQLPersonalizationConnectionHelper connection) + { + + if (applicationId <= 0) + return; + + if (!connection.Opened) + throw new Exception("Error: Connection should be open"); + + var cmd = new MySqlCommand("Select pathid from my_aspnet_paths as paths where paths.applicationid = @ApplicationId and paths.loweredPath = lower(@Path)", connection.Connection); + cmd.Parameters.AddWithValue("@ApplicationId", applicationId); + cmd.Parameters.AddWithValue("@Path", path); + var pathId = (cmd.ExecuteScalar() ?? "").ToString(); + + if (!string.IsNullOrEmpty(pathId)) + { + cmd = new MySqlCommand("delete my_aspnet_personalizationallusers.* from my_aspnet_personalizationallusers WHERE pathId = @PathId"); + cmd.Connection = connection.Connection; + cmd.Parameters.AddWithValue("@PathId", pathId); + cmd.ExecuteNonQuery(); + } + + } + + + private static int UpdateUserLastActiveDate(MySqlConnection cnn, int userId, DateTime currentTimeUtc) + { + MySqlTransaction trans; + trans = cnn.BeginTransaction(); + try + { + var cmd = new MySqlCommand("update my_aspnet_users set lastactivitydate = @CurrentTimeUtc where id = @UserId"); + cmd.Connection = cnn; + cmd.Transaction = trans; + cmd.Parameters.AddWithValue("@CurrentTimeUtc", currentTimeUtc); + cmd.Parameters.AddWithValue("@UserId", userId); + var rows = cmd.ExecuteNonQuery(); + trans.Commit(); + return rows; + } + catch + { + trans.Rollback(); + throw; + } + } + + + internal static int my_aspnet_PersonalizationAdministration_ResetUserState(long applicationId, DateTime inactiveSinceDate, string[] usernames, string[] paths, MySQLPersonalizationConnectionHelper connection) + { + if (applicationId <= 0) + return 0; + + if (!connection.Opened) + throw new Exception("Error: Connection should be open"); + + var rows = 0; + var cmd = new MySqlCommand(); + if (usernames == null) usernames = new string[1] { "" }; + if (paths == null) paths = new string[1] { "" }; + + foreach (var username in usernames) + { + foreach (var path in paths) + { + var query = "DELETE peruser.* FROM (my_aspnet_personalizationperuser as peruser " + + "INNER JOIN my_aspnet_users as users ON " + + "peruser.userid = users.id) " + + "INNER JOIN my_aspnet_paths as paths ON " + + "paths.applicationId = @ApplicationId AND " + + "paths.pathid = peruser.pathid AND " + + "(@InactiveSinceDate is null OR users.lastactivitydate <= @InactiveSinceDate) "; + query = string.IsNullOrEmpty(username) ? query : query += " AND (@UserName is null OR users.name = @UserName) "; + query = string.IsNullOrEmpty(path) ? query : query += " AND (@Path is null OR paths.loweredpath = LOWER(@Path))"; + cmd.CommandText = query; + cmd.Parameters.AddWithValue("@ApplicationId", applicationId); + cmd.Parameters.AddWithValue("@InactiveSinceDate", inactiveSinceDate); + cmd.Parameters.AddWithValue("@Path", path); + cmd.Parameters.AddWithValue("@UserName", username); + cmd.Connection = connection.Connection; + rows += cmd.ExecuteNonQuery(); + } + } + + return rows; + } + + + internal static int my_aspnet_PersonalizationAdministration_DeleteAllState(long applicationId, bool allUsersScope, MySQLPersonalizationConnectionHelper connection) + { + if (applicationId <= 0) + return 0; + + if (!connection.Opened) + throw new Exception("Error: Connection should be open"); + + var cmd = new MySqlCommand(); + cmd.Connection = connection.Connection; + + if (allUsersScope) + { + cmd.CommandText = "DELETE FROM my_aspnet_personalizationallusers " + + "WHERE PathId IN (SELECT Paths.PathId FROM my_aspnet_paths as paths " + + "WHERE paths.ApplicationId = @ApplicationId)"; + cmd.Parameters.AddWithValue("@ApplicationId", applicationId); + } + else + { + cmd.CommandText = "DELETE FROM my_aspnet_personalizationperuser " + + "WHERE PathId IN (SELECT Paths.PathId FROM my_aspnet_paths as paths " + + "WHERE paths.ApplicationId = @ApplicationId)"; + cmd.Parameters.AddWithValue("@ApplicationId", applicationId); + } + + var rows = cmd.ExecuteNonQuery(); + return rows; + } + + internal static int my_aspnet_PersonalizationAdministration_ResetSharedState(long applicationId, string[] paths, MySQLPersonalizationConnectionHelper connection) + { + if (applicationId <= 0) + return 0; + + if (!connection.Opened) + throw new Exception("Error: Connection should be open"); + + if (paths == null) + return 0; + + var cmd = new MySqlCommand(); + cmd.Connection = connection.Connection; + + var rows = 0; + + foreach (var path in paths) + { + cmd.CommandText = "DELETE my_aspnet_personalizationallusers.* FROM my_aspnet_personalizationallusers " + + "INNER JOIN my_aspnet_paths as paths ON " + + "((paths.ApplicationId = @ApplicationId AND " + + "my_aspnet_personalizationallusers.PathId = paths.PathId) AND " + + "paths.loweredpath = LOWER(@Path))"; + + cmd.Parameters.AddWithValue("@ApplicationId", applicationId); + cmd.Parameters.AddWithValue("@Path", path); + rows += cmd.ExecuteNonQuery(); + } + + return rows; + } + + + internal static int my_aspnet_PersonalizationAdministration_DeleteAllState(bool allUsersScope, long applicationId, MySQLPersonalizationConnectionHelper connection) + { + if (applicationId <= 0) + return 0; + + if (!connection.Opened) + throw new Exception("Error: Connection should be open"); + + var cmd = new MySqlCommand(); + cmd.Connection = connection.Connection; + + if (allUsersScope) + { + + cmd.CommandText = "DELETE FROM my_aspnet_personalizationallusers " + + "WHERE PathId IN " + + "(SELECT paths.PathId FROM my_aspnet_paths as paths " + + "WHERE paths.ApplicationId = @ApplicationId)"; + } + else + { + cmd.CommandText = "DELETE FROM my_aspnet_personalizationperuser " + + "WHERE PathId IN " + + "(SELECT Paths.PathId FROM my_aspnet_paths Paths " + + "WHERE Paths.ApplicationId = @ApplicationId)"; + } + cmd.Parameters.AddWithValue("@ApplicationId", applicationId); + var rows = cmd.ExecuteNonQuery(); + return rows; + } + + /// + /// Saves per-user state for the specified page and the specified user in the my_aspnet_PersonalizationPerUser table. + /// + /// + internal static int my_aspnet_PersonalizationPerUser_SetPageSettings(long applicationId, string userName, string path, byte[] settings, DateTime currentTimeUtc, MySQLPersonalizationConnectionHelper connection) + { + if (applicationId <= 0) + return 0; + + if (!connection.Opened) + throw new Exception("Error: Connection should be open"); + + var cmd = new MySqlCommand(); + cmd.Connection = connection.Connection; + + cmd.CommandText = "SELECT PathId FROM my_aspnet_paths WHERE ApplicationId = @ApplicationId AND LoweredPath = LOWER(@Path)"; + cmd.Parameters.AddWithValue("@ApplicationId", applicationId); + cmd.Parameters.AddWithValue("@Path", path); + var pathId = (string)cmd.ExecuteScalar(); + + cmd.Parameters.Clear(); + + if (pathId == null) + { + // create path + MySqlTransaction trans; + trans = connection.Connection.BeginTransaction(); + + try + { + cmd.Transaction = trans; + cmd.CommandText = "INSERT INTO my_aspnet_paths (applicationId, pathId, path, loweredpath) values (@ApplicationId, @PathId, @Path, LOWER(@Path))"; + cmd.Parameters.AddWithValue("@ApplicationId", applicationId); + cmd.Parameters.AddWithValue("@PathId", pathId = Guid.NewGuid().ToString()); + cmd.Parameters.AddWithValue("@Path", path); + cmd.ExecuteNonQuery(); + trans.Commit(); + } + catch + { + trans.Rollback(); + throw; + } + } + + cmd.Parameters.Clear(); + cmd.CommandText = "SELECT id FROM my_aspnet_users WHERE ApplicationId = @ApplicationId AND name = LOWER(@UserName)"; + cmd.Parameters.AddWithValue("@ApplicationId", applicationId); + cmd.Parameters.AddWithValue("@UserName", userName); + var userId = (cmd.ExecuteScalar() ?? "").ToString(); + + userId = string.IsNullOrEmpty(userId) ? "0" : userId; + + // create user + if (int.Parse(userId, CultureInfo.InvariantCulture) == 0) + { + // create path + MySqlTransaction trans; + trans = connection.Connection.BeginTransaction(); + + try + { + cmd.Parameters.Clear(); + cmd.Transaction = trans; + cmd.CommandText = "INSERT INTO my_aspnet_users (applicationId, name, isAnonymous, lastActivityDate) values (@ApplicationId, @UserName, false, @CurrentTimeUtc)"; + cmd.Parameters.AddWithValue("@ApplicationId", applicationId); + cmd.Parameters.AddWithValue("@UserName", userName); + cmd.Parameters.AddWithValue("@CurrentTimeUtc", DateTime.UtcNow); + cmd.ExecuteNonQuery(); + trans.Commit(); + } + catch + { + trans.Rollback(); + throw; + } + + cmd.Parameters.Clear(); + cmd.CommandText = "SELECT Id from my_aspnet_users where applicationId = @ApplicationId and name = @UserName)"; + cmd.Parameters.AddWithValue("@ApplicationId", applicationId); + cmd.Parameters.AddWithValue("@UserName", userName); + userId = (string)cmd.ExecuteScalar(); + + } + var rows = UpdateUserLastActiveDate(connection.Connection, int.Parse(userId, CultureInfo.InvariantCulture), DateTime.UtcNow); + if (rows == 0) + throw new Exception("User not found"); + + cmd.Parameters.Clear(); + cmd.CommandText = "Select COUNT(*) from my_aspnet_personalizationperuser where userid = @UserId and pathId = @PathId"; + cmd.Parameters.AddWithValue("@UserId", userId); + cmd.Parameters.AddWithValue("@PathId", pathId); + if ((long)cmd.ExecuteScalar() > 0) + { + cmd.Parameters.Clear(); + cmd.CommandText = "UPDATE my_aspnet_personalizationperuser SET PageSettings = @PageSettings, LastUpdatedDate = @CurrentTimeUtc " + + "where userid = @UserId and pathId = @PathId"; + cmd.Parameters.AddWithValue("@UserId", userId); + cmd.Parameters.AddWithValue("@PathId", pathId); + cmd.Parameters.AddWithValue("@PageSettings", settings); + cmd.Parameters.AddWithValue("@CurrentTimeUtc", DateTime.UtcNow); + cmd.ExecuteNonQuery(); + } + else + { + cmd.Parameters.Clear(); + cmd.CommandText = "INSERT INTO my_aspnet_personalizationperuser(applicationId, pathId, userId, pageSettings, lastUpdatedDate) VALUES(@applicationId, @PathId, @userId, @PageSettings, @LastUpdatedDate)"; + cmd.Parameters.AddWithValue("@applicationId", applicationId); + cmd.Parameters.AddWithValue("@UserId", userId); + cmd.Parameters.AddWithValue("@PathId", pathId); + cmd.Parameters.AddWithValue("@PageSettings", settings); + cmd.Parameters.AddWithValue("@LastUpdatedDate", DateTime.UtcNow); + rows = cmd.ExecuteNonQuery(); + } + return rows; + } + + /// + /// Saves shared state for the specified page in the aspnet_PersonalizationAllUsers table + /// + /// + internal static int my_aspnet_PersonalizationAllUsers_SetPageSettings(long applicationId, string path, byte[] settings, DateTime currentTimeUtc, MySQLPersonalizationConnectionHelper connection) + { + if (applicationId <= 0) + return 0; + + if (!connection.Opened) + throw new Exception("Error: Connection should be open"); + + var cmd = new MySqlCommand(); + cmd.Connection = connection.Connection; + + cmd.CommandText = "SELECT PathId FROM my_aspnet_paths WHERE ApplicationId = @ApplicationId AND LoweredPath = LOWER(@Path)"; + cmd.Parameters.AddWithValue("@ApplicationId", applicationId); + cmd.Parameters.AddWithValue("@Path", path); + var pathId = (string)cmd.ExecuteScalar(); + cmd.Parameters.Clear(); + + if (pathId == null) + { + // create path + MySqlTransaction trans; + trans = connection.Connection.BeginTransaction(); + + try + { + cmd.Transaction = trans; + cmd.CommandText = "INSERT INTO my_aspnet_paths (applicationId, pathId, path, loweredpath) values (@ApplicationId, @PathId, @Path, LOWER(@Path))"; + cmd.Parameters.AddWithValue("@ApplicationId", applicationId); + cmd.Parameters.AddWithValue("@PathId", pathId = Guid.NewGuid().ToString()); + cmd.Parameters.AddWithValue("@Path", path); + cmd.ExecuteNonQuery(); + trans.Commit(); + } + catch + { + trans.Rollback(); + throw; + } + } + + cmd.CommandText = "INSERT INTO my_aspnet_personalizationallusers(PathId, PageSettings, LastUpdatedDate) VALUES (@PathId, @PageSettings, @CurrentTimeUtc)"; + cmd.CommandText += " ON DUPLICATE KEY UPDATE PageSettings=Values(PageSettings), LastUpdatedDate=Values(LastUpdatedDate)"; + cmd.Parameters.Clear(); + cmd.Parameters.AddWithValue("@PageSettings", settings); + cmd.Parameters.AddWithValue("@PathId", pathId); + cmd.Parameters.AddWithValue("@CurrentTimeUtc", currentTimeUtc); + var rows = cmd.ExecuteNonQuery(); + return rows; + } + } +} diff --git a/MySql.Web/src/ProfileProvider.cs b/MySql.Web/src/ProfileProvider.cs index ef472b5fb..778ae9a5c 100644 --- a/MySql.Web/src/ProfileProvider.cs +++ b/MySql.Web/src/ProfileProvider.cs @@ -1,673 +1,673 @@ -// Copyright (c) 2004, 2020, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -// This code was contributed by Sean Wright (srwright@alcor.concordia.ca) on 2007-01-12 -// The copyright was assigned and transferred under the terms of -// the MySQL Contributor License Agreement (CLA) - -using MySql.Data.MySqlClient; -using MySql.Web.Common; -using MySql.Web.General; -using System; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.Configuration; -using System.Configuration.Provider; -using System.Data; -using System.Globalization; -using System.IO; -using System.Text; -using System.Web.Hosting; -using System.Web.Profile; - -namespace MySql.Web.Profile -{ - /// - /// Manages storage of profile information for an ASP.NET application in a MySQL database. - /// - public class MySQLProfileProvider : ProfileProvider - { - private string connectionString; - private Application app; - - #region Abstract Members - - /// - /// Initializes the provider. - /// - /// The friendly name of the provider. - /// A collection of the name/value pairs representing the provider-specific attributes specified in the configuration for this provider. - /// The name of the provider is null. - /// The name of the provider has a length of zero. - /// An attempt is made to call on a provider after the provider has already been initialized. - public override void Initialize(string name, NameValueCollection config) - { - if (config == null) - throw new ArgumentNullException("config"); - - if (name == null || name.Length == 0) - name = "MySQLProfileProvider"; - - if (string.IsNullOrEmpty(config["description"])) - { - config.Remove("description"); - config.Add("description", "MySQL Profile provider"); - } - base.Initialize(name, config); - - try - { - string applicationName = GetConfigValue(config["applicationName"], HostingEnvironment.ApplicationVirtualPath); - - connectionString = ConfigUtility.GetConnectionString(config); - if (String.IsNullOrEmpty(connectionString)) return; - - // make sure our schema is up to date - SchemaManager.CheckSchema(connectionString, config); - - app = new Application(applicationName, base.Description); - } - catch (Exception ex) - { - throw new ProviderException(Properties.Resources.ErrorInitProfileProvider, ex); - } - } - - /// - /// When overridden in a derived class, deletes all user-profile data - /// for profiles in which the last activity date occurred before the - /// specified date. - /// - /// One of the - /// - /// values, specifying whether anonymous, authenticated, or both - /// types of profiles are deleted. - /// A - /// that identifies which user profiles are considered inactive. If the - /// - /// value of a user profile occurs on or before this date and time, the - /// profile is considered inactive. - /// - /// The number of profiles deleted from the data source. - /// - public override int DeleteInactiveProfiles( - ProfileAuthenticationOption authenticationOption, - DateTime userInactiveSinceDate) - { - using (MySqlConnection c = new MySqlConnection(connectionString)) - { - c.Open(); - - MySqlCommand queryCmd = new MySqlCommand( - @"SELECT * FROM my_aspnet_users - WHERE applicationId=@appId AND - lastActivityDate < @lastActivityDate", - c); - queryCmd.Parameters.AddWithValue("@appId", app.FetchId(c)); - queryCmd.Parameters.AddWithValue("@lastActivityDate", userInactiveSinceDate); - if (authenticationOption == ProfileAuthenticationOption.Anonymous) - queryCmd.CommandText += " AND isAnonymous = 1"; - else if (authenticationOption == ProfileAuthenticationOption.Authenticated) - queryCmd.CommandText += " AND isAnonymous = 0"; - - MySqlCommand deleteCmd = new MySqlCommand( - "DELETE FROM my_aspnet_profiles WHERE userId = @userId", c); - deleteCmd.Parameters.Add("@userId", MySqlDbType.UInt64); - - List uidList = new List(); - using (MySqlDataReader reader = queryCmd.ExecuteReader()) - { - while (reader.Read()) - uidList.Add(reader.GetUInt64("userId")); - } - - int count = 0; - foreach (ulong uid in uidList) - { - deleteCmd.Parameters[0].Value = uid; - count += deleteCmd.ExecuteNonQuery(); - } - return count; - } - } - - /// - /// When overridden in a derived class, deletes profile properties - /// and information for profiles that match the supplied list of user names. - /// - /// A string array of user names for - /// profiles to be deleted. - /// - /// The number of profiles deleted from the data source. - /// - public override int DeleteProfiles(string[] usernames) - { - using (MySqlConnection c = new MySqlConnection(connectionString)) - { - c.Open(); - - MySqlCommand queryCmd = new MySqlCommand( - @"SELECT * FROM my_aspnet_users - WHERE applicationId=@appId AND name = @name", c); - queryCmd.Parameters.AddWithValue("@appId", app.FetchId(c)); - queryCmd.Parameters.Add("@name", MySqlDbType.VarChar); - - MySqlCommand deleteCmd = new MySqlCommand( - "DELETE FROM my_aspnet_profiles WHERE userId = @userId", c); - deleteCmd.Parameters.Add("@userId", MySqlDbType.Int32); - - int count = 0; - foreach (string name in usernames) - { - queryCmd.Parameters[1].Value = name; - int uid = (int)queryCmd.ExecuteScalar(); - - deleteCmd.Parameters[0].Value = uid; - count += deleteCmd.ExecuteNonQuery(); - } - return count; - } - } - - /// - /// When overridden in a derived class, deletes profile properties - /// and information for the supplied list of profiles. - /// - /// A - /// of - /// information about profiles that are to be deleted. - /// - /// The number of profiles deleted from the data source. - /// - public override int DeleteProfiles(ProfileInfoCollection profiles) - { - string[] s = new string[profiles.Count]; - - int i = 0; - foreach (ProfileInfo p in profiles) - s[i++] = p.UserName; - return DeleteProfiles(s); - } - - /// - /// When overridden in a derived class, retrieves profile information - /// for profiles in which the last activity date occurred on or before - /// the specified date and the user name matches the specified user name. - /// - /// One of the - /// values, - /// specifying whether anonymous, authenticated, or both types of profiles - /// are returned. - /// The user name to search for. - /// A - /// that identifies which user profiles are considered inactive. If the - /// value - /// of a user profile occurs on or before this date and time, the profile - /// is considered inactive. - /// The index of the page of results to return. - /// The size of the page of results to return. - /// When this method returns, contains the total - /// number of profiles. - /// - /// A containing - /// user profile information for inactive profiles where the user name - /// matches the supplied parameter. - /// - public override ProfileInfoCollection FindInactiveProfilesByUserName( - ProfileAuthenticationOption authenticationOption, - string usernameToMatch, DateTime userInactiveSinceDate, - int pageIndex, int pageSize, out int totalRecords) - { - return GetProfiles(authenticationOption, usernameToMatch, - userInactiveSinceDate, pageIndex, pageSize, out totalRecords); - } - - /// - /// When overridden in a derived class, retrieves profile information - /// for profiles in which the user name matches the specified user names. - /// - /// One of the - /// values, - /// specifying whether anonymous, authenticated, or both types of profiles - /// are returned. - /// The user name to search for. - /// The index of the page of results to return. - /// The size of the page of results to return. - /// When this method returns, contains the total - /// number of profiles. - /// - /// A containing - /// user-profile information for profiles where the user name matches the - /// supplied parameter. - /// - public override ProfileInfoCollection FindProfilesByUserName( - ProfileAuthenticationOption authenticationOption, - string usernameToMatch, int pageIndex, int pageSize, - out int totalRecords) - { - return GetProfiles(authenticationOption, usernameToMatch, - DateTime.MinValue, pageIndex, pageSize, out totalRecords); - } - - /// - /// When overridden in a derived class, retrieves user-profile data - /// from the data source for profiles in which the last activity date - /// occurred on or before the specified date. - /// - /// One of the - /// values, - /// specifying whether anonymous, authenticated, or both types of profiles - /// are returned. - /// A - /// that identifies which user profiles are considered inactive. If the - /// of - /// a user profile occurs on or before this date and time, the profile is - /// considered inactive. - /// The index of the page of results to return. - /// The size of the page of results to return. - /// When this method returns, contains the - /// total number of profiles. - /// - /// A containing user-profile information about the inactive profiles. - /// - public override ProfileInfoCollection GetAllInactiveProfiles( - ProfileAuthenticationOption authenticationOption, - DateTime userInactiveSinceDate, int pageIndex, int pageSize, - out int totalRecords) - { - return GetProfiles(authenticationOption, null, - userInactiveSinceDate, pageIndex, pageSize, out totalRecords); - } - - /// - /// When overridden in a derived class, retrieves user profile data for - /// all profiles in the data source. - /// - /// One of the - /// values, - /// specifying whether anonymous, authenticated, or both types of profiles - /// are returned. - /// The index of the page of results to return. - /// The size of the page of results to return. - /// When this method returns, contains the - /// total number of profiles. - /// - /// A containing - /// user-profile information for all profiles in the data source. - /// - public override ProfileInfoCollection GetAllProfiles( - ProfileAuthenticationOption authenticationOption, int pageIndex, - int pageSize, out int totalRecords) - { - return GetProfiles(authenticationOption, null, - DateTime.MinValue, pageIndex, pageSize, out totalRecords); - } - - /// - /// When overridden in a derived class, returns the number of profiles - /// in which the last activity date occurred on or before the specified - /// date. - /// - /// One of the - /// values, - /// specifying whether anonymous, authenticated, or both types of profiles - /// are returned. - /// A - /// that identifies which user profiles are considered inactive. If the - /// of - /// a user profile occurs on or before this date and time, the profile - /// is considered inactive. - /// - /// The number of profiles in which the last activity date occurred on - /// or before the specified date. - /// - public override int GetNumberOfInactiveProfiles( - ProfileAuthenticationOption authenticationOption, - DateTime userInactiveSinceDate) - { - using (MySqlConnection c = new MySqlConnection(connectionString)) - { - c.Open(); - - MySqlCommand queryCmd = new MySqlCommand( - @"SELECT COUNT(*) FROM my_aspnet_users - WHERE applicationId = @appId AND - lastActivityDate < @lastActivityDate", - c); - queryCmd.Parameters.AddWithValue("@appId", app.FetchId(c)); - queryCmd.Parameters.AddWithValue("@lastActivityDate", userInactiveSinceDate); - if (authenticationOption == ProfileAuthenticationOption.Anonymous) - queryCmd.CommandText += " AND isAnonymous = 1"; - else if (authenticationOption == ProfileAuthenticationOption.Authenticated) - queryCmd.CommandText += " AND isAnonymous = 0"; - return (int)queryCmd.ExecuteScalar(); - } - } - - /// - /// Gets or sets the name of the currently running application. - /// - /// - /// A that contains the application's shortened name, which does not contain a full path or extension, for example, SimpleAppSettings. - public override string ApplicationName - { - get { return app.Name; } - set { app.Name = value; } - } - - /// - /// Returns the collection of settings property values for the specified application instance and settings property group. - /// - /// A describing the current application use. - /// A containing the settings property group whose values are to be retrieved. - /// - /// A containing the values for the specified settings property group. - /// - public override SettingsPropertyValueCollection GetPropertyValues( - SettingsContext context, SettingsPropertyCollection collection) - { - SettingsPropertyValueCollection values = new SettingsPropertyValueCollection(); - - if (collection.Count < 1) return values; - - string username = (string)context["UserName"]; - - foreach (SettingsProperty property in collection) - { - if (property.PropertyType.IsPrimitive || property.PropertyType == typeof(string)) - property.SerializeAs = SettingsSerializeAs.String; - else - property.SerializeAs = SettingsSerializeAs.Xml; - - values.Add(new SettingsPropertyValue(property)); - } - - if (String.IsNullOrEmpty(username)) - return values; - - // retrieve encoded profile data from the database - try - { - - using (MySqlConnection c = new MySqlConnection(connectionString)) - { - c.Open(); - MySqlCommand cmd = new MySqlCommand( - @"SELECT * FROM my_aspnet_profiles p - JOIN my_aspnet_users u ON u.id = p.userId - WHERE u.applicationId = @appId AND u.name = @name", c); - cmd.Parameters.AddWithValue("@appId", app.FetchId(c)); - cmd.Parameters.AddWithValue("@name", username); - MySqlDataAdapter da = new MySqlDataAdapter(cmd); - DataTable dt = new DataTable(); - da.Fill(dt); - - if (dt.Rows.Count > 0) - DecodeProfileData(dt.Rows[0], values); - return values; - } - } - catch (Exception ex) - { - throw new ProviderException(Properties.Resources.UnableToRetrieveProfileData, ex); - } - } - - /// - /// Sets the values of the specified group of property settings. - /// - /// A describing the current application usage. - /// A representing the group of property settings to set. - public override void SetPropertyValues( - SettingsContext context, SettingsPropertyValueCollection collection) - { - bool isAuthenticated = (bool)context["IsAuthenticated"]; - string username = (string)context["UserName"]; - - if (String.IsNullOrEmpty(username)) return; - if (collection.Count < 1) return; - - string index = String.Empty; - string stringData = String.Empty; - byte[] binaryData = null; - int count = EncodeProfileData(collection, isAuthenticated, ref index, ref stringData, ref binaryData); - if (count < 1) return; - - MySqlTransaction txn = null; - // save the encoded profile data to the database - using (MySqlConnection connection = new MySqlConnection(connectionString)) - { - try - { - connection.Open(); - txn = connection.BeginTransaction(); - - // either create a new user or fetch the existing user id - long userId = SchemaManager.CreateOrFetchUserId(connection, username, - app.EnsureId(connection), isAuthenticated); - - MySqlCommand cmd = new MySqlCommand( - @"INSERT INTO my_aspnet_profiles - VALUES (@userId, @index, @stringData, @binaryData, NULL) ON DUPLICATE KEY UPDATE - valueindex=VALUES(valueindex), stringdata=VALUES(stringdata), - binarydata=VALUES(binarydata)", connection); - cmd.Parameters.Clear(); - cmd.Parameters.AddWithValue("@userId", userId); - cmd.Parameters.AddWithValue("@index", index); - cmd.Parameters.AddWithValue("@stringData", stringData); - cmd.Parameters.AddWithValue("@binaryData", binaryData); - count = cmd.ExecuteNonQuery(); - if (count == 0) - throw new Exception(Properties.Resources.ProfileUpdateFailed); - txn.Commit(); - } - catch (Exception ex) - { - if (txn != null) - txn.Rollback(); - throw new ProviderException(Properties.Resources.ProfileUpdateFailed, ex); - } - } - } - - #endregion - - internal static void DeleteUserData(MySqlConnection connection, int userId) - { - MySqlCommand cmd = new MySqlCommand( - "DELETE FROM my_aspnet_profiles WHERE userId=@userId", connection); - cmd.Parameters.AddWithValue("@userId", userId); - cmd.ExecuteNonQuery(); - } - - #region Private Methods - - private void DecodeProfileData(DataRow profileRow, SettingsPropertyValueCollection values) - { - string indexData = (string)profileRow["valueindex"]; - string stringData = (string)profileRow["stringData"]; - byte[] binaryData = (byte[])profileRow["binaryData"]; - - if (indexData == null) return; - - string[] indexes = indexData.Split(':'); - - foreach (string index in indexes) - { - string[] parts = index.Split('/'); - SettingsPropertyValue value = values[parts[0]]; - if (value == null) continue; - - int pos = Int32.Parse(parts[2], CultureInfo.InvariantCulture); - int len = Int32.Parse(parts[3], CultureInfo.InvariantCulture); - if (len == -1) - { - value.PropertyValue = null; - value.IsDirty = false; - value.Deserialized = true; - } - else if (parts[1].Equals("0")) - value.SerializedValue = stringData.Substring(pos, len); - else - { - byte[] buf = new byte[len]; - Buffer.BlockCopy(binaryData, pos, buf, 0, len); - value.SerializedValue = buf; - } - } - } - - private int EncodeProfileData(SettingsPropertyValueCollection collection, bool isAuthenticated, - ref string index, ref string stringData, ref byte[] binaryData) - { - bool itemsToSave = false; - - // first we need to determine if there are any items that need saving - // this is an optimization - foreach (SettingsPropertyValue value in collection) - { - if (!value.IsDirty) continue; - if (value.Property.Attributes["AllowAnonymous"].Equals(false) && - !isAuthenticated) continue; - itemsToSave = true; - break; - } - if (!itemsToSave) return 0; - - StringBuilder indexBuilder = new StringBuilder(); - StringBuilder stringDataBuilder = new StringBuilder(); - MemoryStream binaryBuilder = new MemoryStream(); - int count = 0; - - // ok, we have some values that need to be saved so we go back through - foreach (SettingsPropertyValue value in collection) - { - // if the value has not been written to and is still using the default value - // no need to save it - if (value.UsingDefaultValue && !value.IsDirty) continue; - - // we don't save properties that require the user to be authenticated when the - // current user is not authenticated. - if (value.Property.Attributes["AllowAnonymous"].Equals(false) && - !isAuthenticated) continue; - - count++; - object propValue = value.SerializedValue; - if ((value.Deserialized && value.PropertyValue == null) || - value.SerializedValue == null) - indexBuilder.AppendFormat("{0}//0/-1:", value.Name); - else if (propValue is string) - { - indexBuilder.AppendFormat("{0}/0/{1}/{2}:", value.Name, - stringDataBuilder.Length, (propValue as string).Length); - stringDataBuilder.Append(propValue); - } - else - { - byte[] binaryValue = (byte[])propValue; - indexBuilder.AppendFormat("{0}/1/{1}/{2}:", value.Name, - binaryBuilder.Position, binaryValue.Length); - binaryBuilder.Write(binaryValue, 0, binaryValue.Length); - } - } - index = indexBuilder.ToString(); - stringData = stringDataBuilder.ToString(); - binaryData = binaryBuilder.ToArray(); - return count; - } - - - private ProfileInfoCollection GetProfiles( - ProfileAuthenticationOption authenticationOption, - string usernameToMatch, DateTime userInactiveSinceDate, - int pageIndex, int pageSize, out int totalRecords) - { - List whereClauses = new List(); - - using (MySqlConnection c = new MySqlConnection(connectionString)) - { - c.Open(); - - MySqlCommand cmd = new MySqlCommand( - @"SELECT p.*, u.name, u.isAnonymous, u.lastActivityDate, - LENGTH(p.stringdata) + LENGTH(p.binarydata) AS profilesize - FROM my_aspnet_profiles p - JOIN my_aspnet_users u ON u.id = p.userId - WHERE u.applicationId = @appId", c); - cmd.Parameters.AddWithValue("@appId", app.FetchId(c)); - - if (usernameToMatch != null) - { - cmd.CommandText += " AND u.name LIKE @userName"; - cmd.Parameters.AddWithValue("@userName", usernameToMatch); - } - if (userInactiveSinceDate != DateTime.MinValue) - { - cmd.CommandText += " AND u.lastActivityDate < @lastActivityDate"; - cmd.Parameters.AddWithValue("@lastActivityDate", userInactiveSinceDate); - } - if (authenticationOption == ProfileAuthenticationOption.Anonymous) - cmd.CommandText += " AND u.isAnonymous = 1"; - else if (authenticationOption == ProfileAuthenticationOption.Authenticated) - cmd.CommandText += " AND u.isAnonymous = 0"; - - cmd.CommandText += String.Format(" LIMIT {0},{1}", pageIndex * pageSize, pageSize); - - ProfileInfoCollection pic = new ProfileInfoCollection(); - using (MySqlDataReader reader = cmd.ExecuteReader()) - { - while (reader.Read()) - { - ProfileInfo pi = new ProfileInfo( - reader.GetString("name"), - reader.GetBoolean("isAnonymous"), - reader.GetDateTime("lastActivityDate"), - reader.GetDateTime("lastUpdatedDate"), - reader.GetInt32("profilesize")); - pic.Add(pi); - } - } - cmd.CommandText = "SELECT FOUND_ROWS()"; - totalRecords = Convert.ToInt32(cmd.ExecuteScalar()); - return pic; - } - } - - private static string GetConfigValue(string configValue, string defaultValue) - { - if (string.IsNullOrEmpty(configValue)) - { - return defaultValue; - } - return configValue; - } - - #endregion - - } -} +// Copyright © 2004, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +// This code was contributed by Sean Wright (srwright@alcor.concordia.ca) on 2007-01-12 +// The copyright was assigned and transferred under the terms of +// the MySQL Contributor License Agreement (CLA) + +using MySql.Data.MySqlClient; +using MySql.Web.Common; +using MySql.Web.General; +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Configuration; +using System.Configuration.Provider; +using System.Data; +using System.Globalization; +using System.IO; +using System.Text; +using System.Web.Hosting; +using System.Web.Profile; + +namespace MySql.Web.Profile +{ + /// + /// Manages storage of profile information for an ASP.NET application in a MySQL database. + /// + public class MySQLProfileProvider : ProfileProvider + { + private string connectionString; + private Application app; + + #region Abstract Members + + /// + /// Initializes the provider. + /// + /// The friendly name of the provider. + /// A collection of the name/value pairs representing the provider-specific attributes specified in the configuration for this provider. + /// The name of the provider is null. + /// The name of the provider has a length of zero. + /// An attempt is made to call on a provider after the provider has already been initialized. + public override void Initialize(string name, NameValueCollection config) + { + if (config == null) + throw new ArgumentNullException("config"); + + if (name == null || name.Length == 0) + name = "MySQLProfileProvider"; + + if (string.IsNullOrEmpty(config["description"])) + { + config.Remove("description"); + config.Add("description", "MySQL Profile provider"); + } + base.Initialize(name, config); + + try + { + string applicationName = GetConfigValue(config["applicationName"], HostingEnvironment.ApplicationVirtualPath); + + connectionString = ConfigUtility.GetConnectionString(config); + if (String.IsNullOrEmpty(connectionString)) return; + + // make sure our schema is up to date + SchemaManager.CheckSchema(connectionString, config); + + app = new Application(applicationName, base.Description); + } + catch (Exception ex) + { + throw new ProviderException(Properties.Resources.ErrorInitProfileProvider, ex); + } + } + + /// + /// When overridden in a derived class, deletes all user-profile data + /// for profiles in which the last activity date occurred before the + /// specified date. + /// + /// One of the + /// + /// values, specifying whether anonymous, authenticated, or both + /// types of profiles are deleted. + /// A + /// that identifies which user profiles are considered inactive. If the + /// + /// value of a user profile occurs on or before this date and time, the + /// profile is considered inactive. + /// + /// The number of profiles deleted from the data source. + /// + public override int DeleteInactiveProfiles( + ProfileAuthenticationOption authenticationOption, + DateTime userInactiveSinceDate) + { + using (MySqlConnection c = new MySqlConnection(connectionString)) + { + c.Open(); + + MySqlCommand queryCmd = new MySqlCommand( + @"SELECT * FROM my_aspnet_users + WHERE applicationId=@appId AND + lastActivityDate < @lastActivityDate", + c); + queryCmd.Parameters.AddWithValue("@appId", app.FetchId(c)); + queryCmd.Parameters.AddWithValue("@lastActivityDate", userInactiveSinceDate); + if (authenticationOption == ProfileAuthenticationOption.Anonymous) + queryCmd.CommandText += " AND isAnonymous = 1"; + else if (authenticationOption == ProfileAuthenticationOption.Authenticated) + queryCmd.CommandText += " AND isAnonymous = 0"; + + MySqlCommand deleteCmd = new MySqlCommand( + "DELETE FROM my_aspnet_profiles WHERE userId = @userId", c); + deleteCmd.Parameters.Add("@userId", MySqlDbType.UInt64); + + List uidList = new List(); + using (MySqlDataReader reader = queryCmd.ExecuteReader()) + { + while (reader.Read()) + uidList.Add(reader.GetUInt64("userId")); + } + + int count = 0; + foreach (ulong uid in uidList) + { + deleteCmd.Parameters[0].Value = uid; + count += deleteCmd.ExecuteNonQuery(); + } + return count; + } + } + + /// + /// When overridden in a derived class, deletes profile properties + /// and information for profiles that match the supplied list of user names. + /// + /// A string array of user names for + /// profiles to be deleted. + /// + /// The number of profiles deleted from the data source. + /// + public override int DeleteProfiles(string[] usernames) + { + using (MySqlConnection c = new MySqlConnection(connectionString)) + { + c.Open(); + + MySqlCommand queryCmd = new MySqlCommand( + @"SELECT * FROM my_aspnet_users + WHERE applicationId=@appId AND name = @name", c); + queryCmd.Parameters.AddWithValue("@appId", app.FetchId(c)); + queryCmd.Parameters.Add("@name", MySqlDbType.VarChar); + + MySqlCommand deleteCmd = new MySqlCommand( + "DELETE FROM my_aspnet_profiles WHERE userId = @userId", c); + deleteCmd.Parameters.Add("@userId", MySqlDbType.Int32); + + int count = 0; + foreach (string name in usernames) + { + queryCmd.Parameters[1].Value = name; + int uid = (int)queryCmd.ExecuteScalar(); + + deleteCmd.Parameters[0].Value = uid; + count += deleteCmd.ExecuteNonQuery(); + } + return count; + } + } + + /// + /// When overridden in a derived class, deletes profile properties + /// and information for the supplied list of profiles. + /// + /// A + /// of + /// information about profiles that are to be deleted. + /// + /// The number of profiles deleted from the data source. + /// + public override int DeleteProfiles(ProfileInfoCollection profiles) + { + string[] s = new string[profiles.Count]; + + int i = 0; + foreach (ProfileInfo p in profiles) + s[i++] = p.UserName; + return DeleteProfiles(s); + } + + /// + /// When overridden in a derived class, retrieves profile information + /// for profiles in which the last activity date occurred on or before + /// the specified date and the user name matches the specified user name. + /// + /// One of the + /// values, + /// specifying whether anonymous, authenticated, or both types of profiles + /// are returned. + /// The user name to search for. + /// A + /// that identifies which user profiles are considered inactive. If the + /// value + /// of a user profile occurs on or before this date and time, the profile + /// is considered inactive. + /// The index of the page of results to return. + /// The size of the page of results to return. + /// When this method returns, contains the total + /// number of profiles. + /// + /// A containing + /// user profile information for inactive profiles where the user name + /// matches the supplied parameter. + /// + public override ProfileInfoCollection FindInactiveProfilesByUserName( + ProfileAuthenticationOption authenticationOption, + string usernameToMatch, DateTime userInactiveSinceDate, + int pageIndex, int pageSize, out int totalRecords) + { + return GetProfiles(authenticationOption, usernameToMatch, + userInactiveSinceDate, pageIndex, pageSize, out totalRecords); + } + + /// + /// When overridden in a derived class, retrieves profile information + /// for profiles in which the user name matches the specified user names. + /// + /// One of the + /// values, + /// specifying whether anonymous, authenticated, or both types of profiles + /// are returned. + /// The user name to search for. + /// The index of the page of results to return. + /// The size of the page of results to return. + /// When this method returns, contains the total + /// number of profiles. + /// + /// A containing + /// user-profile information for profiles where the user name matches the + /// supplied parameter. + /// + public override ProfileInfoCollection FindProfilesByUserName( + ProfileAuthenticationOption authenticationOption, + string usernameToMatch, int pageIndex, int pageSize, + out int totalRecords) + { + return GetProfiles(authenticationOption, usernameToMatch, + DateTime.MinValue, pageIndex, pageSize, out totalRecords); + } + + /// + /// When overridden in a derived class, retrieves user-profile data + /// from the data source for profiles in which the last activity date + /// occurred on or before the specified date. + /// + /// One of the + /// values, + /// specifying whether anonymous, authenticated, or both types of profiles + /// are returned. + /// A + /// that identifies which user profiles are considered inactive. If the + /// of + /// a user profile occurs on or before this date and time, the profile is + /// considered inactive. + /// The index of the page of results to return. + /// The size of the page of results to return. + /// When this method returns, contains the + /// total number of profiles. + /// + /// A containing user-profile information about the inactive profiles. + /// + public override ProfileInfoCollection GetAllInactiveProfiles( + ProfileAuthenticationOption authenticationOption, + DateTime userInactiveSinceDate, int pageIndex, int pageSize, + out int totalRecords) + { + return GetProfiles(authenticationOption, null, + userInactiveSinceDate, pageIndex, pageSize, out totalRecords); + } + + /// + /// When overridden in a derived class, retrieves user profile data for + /// all profiles in the data source. + /// + /// One of the + /// values, + /// specifying whether anonymous, authenticated, or both types of profiles + /// are returned. + /// The index of the page of results to return. + /// The size of the page of results to return. + /// When this method returns, contains the + /// total number of profiles. + /// + /// A containing + /// user-profile information for all profiles in the data source. + /// + public override ProfileInfoCollection GetAllProfiles( + ProfileAuthenticationOption authenticationOption, int pageIndex, + int pageSize, out int totalRecords) + { + return GetProfiles(authenticationOption, null, + DateTime.MinValue, pageIndex, pageSize, out totalRecords); + } + + /// + /// When overridden in a derived class, returns the number of profiles + /// in which the last activity date occurred on or before the specified + /// date. + /// + /// One of the + /// values, + /// specifying whether anonymous, authenticated, or both types of profiles + /// are returned. + /// A + /// that identifies which user profiles are considered inactive. If the + /// of + /// a user profile occurs on or before this date and time, the profile + /// is considered inactive. + /// + /// The number of profiles in which the last activity date occurred on + /// or before the specified date. + /// + public override int GetNumberOfInactiveProfiles( + ProfileAuthenticationOption authenticationOption, + DateTime userInactiveSinceDate) + { + using (MySqlConnection c = new MySqlConnection(connectionString)) + { + c.Open(); + + MySqlCommand queryCmd = new MySqlCommand( + @"SELECT COUNT(*) FROM my_aspnet_users + WHERE applicationId = @appId AND + lastActivityDate < @lastActivityDate", + c); + queryCmd.Parameters.AddWithValue("@appId", app.FetchId(c)); + queryCmd.Parameters.AddWithValue("@lastActivityDate", userInactiveSinceDate); + if (authenticationOption == ProfileAuthenticationOption.Anonymous) + queryCmd.CommandText += " AND isAnonymous = 1"; + else if (authenticationOption == ProfileAuthenticationOption.Authenticated) + queryCmd.CommandText += " AND isAnonymous = 0"; + return (int)queryCmd.ExecuteScalar(); + } + } + + /// + /// Gets or sets the name of the currently running application. + /// + /// + /// A that contains the application's shortened name, which does not contain a full path or extension, for example, SimpleAppSettings. + public override string ApplicationName + { + get { return app.Name; } + set { app.Name = value; } + } + + /// + /// Returns the collection of settings property values for the specified application instance and settings property group. + /// + /// A describing the current application use. + /// A containing the settings property group whose values are to be retrieved. + /// + /// A containing the values for the specified settings property group. + /// + public override SettingsPropertyValueCollection GetPropertyValues( + SettingsContext context, SettingsPropertyCollection collection) + { + SettingsPropertyValueCollection values = new SettingsPropertyValueCollection(); + + if (collection.Count < 1) return values; + + string username = (string)context["UserName"]; + + foreach (SettingsProperty property in collection) + { + if (property.PropertyType.IsPrimitive || property.PropertyType == typeof(string)) + property.SerializeAs = SettingsSerializeAs.String; + else + property.SerializeAs = SettingsSerializeAs.Xml; + + values.Add(new SettingsPropertyValue(property)); + } + + if (String.IsNullOrEmpty(username)) + return values; + + // retrieve encoded profile data from the database + try + { + + using (MySqlConnection c = new MySqlConnection(connectionString)) + { + c.Open(); + MySqlCommand cmd = new MySqlCommand( + @"SELECT * FROM my_aspnet_profiles p + JOIN my_aspnet_users u ON u.id = p.userId + WHERE u.applicationId = @appId AND u.name = @name", c); + cmd.Parameters.AddWithValue("@appId", app.FetchId(c)); + cmd.Parameters.AddWithValue("@name", username); + MySqlDataAdapter da = new MySqlDataAdapter(cmd); + DataTable dt = new DataTable(); + da.Fill(dt); + + if (dt.Rows.Count > 0) + DecodeProfileData(dt.Rows[0], values); + return values; + } + } + catch (Exception ex) + { + throw new ProviderException(Properties.Resources.UnableToRetrieveProfileData, ex); + } + } + + /// + /// Sets the values of the specified group of property settings. + /// + /// A describing the current application usage. + /// A representing the group of property settings to set. + public override void SetPropertyValues( + SettingsContext context, SettingsPropertyValueCollection collection) + { + bool isAuthenticated = (bool)context["IsAuthenticated"]; + string username = (string)context["UserName"]; + + if (String.IsNullOrEmpty(username)) return; + if (collection.Count < 1) return; + + string index = String.Empty; + string stringData = String.Empty; + byte[] binaryData = null; + int count = EncodeProfileData(collection, isAuthenticated, ref index, ref stringData, ref binaryData); + if (count < 1) return; + + MySqlTransaction txn = null; + // save the encoded profile data to the database + using (MySqlConnection connection = new MySqlConnection(connectionString)) + { + try + { + connection.Open(); + txn = connection.BeginTransaction(); + + // either create a new user or fetch the existing user id + long userId = SchemaManager.CreateOrFetchUserId(connection, username, + app.EnsureId(connection), isAuthenticated); + + MySqlCommand cmd = new MySqlCommand( + @"INSERT INTO my_aspnet_profiles + VALUES (@userId, @index, @stringData, @binaryData, NULL) ON DUPLICATE KEY UPDATE + valueindex=VALUES(valueindex), stringdata=VALUES(stringdata), + binarydata=VALUES(binarydata)", connection); + cmd.Parameters.Clear(); + cmd.Parameters.AddWithValue("@userId", userId); + cmd.Parameters.AddWithValue("@index", index); + cmd.Parameters.AddWithValue("@stringData", stringData); + cmd.Parameters.AddWithValue("@binaryData", binaryData); + count = cmd.ExecuteNonQuery(); + if (count == 0) + throw new Exception(Properties.Resources.ProfileUpdateFailed); + txn.Commit(); + } + catch (Exception ex) + { + if (txn != null) + txn.Rollback(); + throw new ProviderException(Properties.Resources.ProfileUpdateFailed, ex); + } + } + } + + #endregion + + internal static void DeleteUserData(MySqlConnection connection, int userId) + { + MySqlCommand cmd = new MySqlCommand( + "DELETE FROM my_aspnet_profiles WHERE userId=@userId", connection); + cmd.Parameters.AddWithValue("@userId", userId); + cmd.ExecuteNonQuery(); + } + + #region Private Methods + + private void DecodeProfileData(DataRow profileRow, SettingsPropertyValueCollection values) + { + string indexData = (string)profileRow["valueindex"]; + string stringData = (string)profileRow["stringData"]; + byte[] binaryData = (byte[])profileRow["binaryData"]; + + if (indexData == null) return; + + string[] indexes = indexData.Split(':'); + + foreach (string index in indexes) + { + string[] parts = index.Split('/'); + SettingsPropertyValue value = values[parts[0]]; + if (value == null) continue; + + int pos = Int32.Parse(parts[2], CultureInfo.InvariantCulture); + int len = Int32.Parse(parts[3], CultureInfo.InvariantCulture); + if (len == -1) + { + value.PropertyValue = null; + value.IsDirty = false; + value.Deserialized = true; + } + else if (parts[1].Equals("0")) + value.SerializedValue = stringData.Substring(pos, len); + else + { + byte[] buf = new byte[len]; + Buffer.BlockCopy(binaryData, pos, buf, 0, len); + value.SerializedValue = buf; + } + } + } + + private int EncodeProfileData(SettingsPropertyValueCollection collection, bool isAuthenticated, + ref string index, ref string stringData, ref byte[] binaryData) + { + bool itemsToSave = false; + + // first we need to determine if there are any items that need saving + // this is an optimization + foreach (SettingsPropertyValue value in collection) + { + if (!value.IsDirty) continue; + if (value.Property.Attributes["AllowAnonymous"].Equals(false) && + !isAuthenticated) continue; + itemsToSave = true; + break; + } + if (!itemsToSave) return 0; + + StringBuilder indexBuilder = new StringBuilder(); + StringBuilder stringDataBuilder = new StringBuilder(); + MemoryStream binaryBuilder = new MemoryStream(); + int count = 0; + + // ok, we have some values that need to be saved so we go back through + foreach (SettingsPropertyValue value in collection) + { + // if the value has not been written to and is still using the default value + // no need to save it + if (value.UsingDefaultValue && !value.IsDirty) continue; + + // we don't save properties that require the user to be authenticated when the + // current user is not authenticated. + if (value.Property.Attributes["AllowAnonymous"].Equals(false) && + !isAuthenticated) continue; + + count++; + object propValue = value.SerializedValue; + if ((value.Deserialized && value.PropertyValue == null) || + value.SerializedValue == null) + indexBuilder.AppendFormat("{0}//0/-1:", value.Name); + else if (propValue is string) + { + indexBuilder.AppendFormat("{0}/0/{1}/{2}:", value.Name, + stringDataBuilder.Length, (propValue as string).Length); + stringDataBuilder.Append(propValue); + } + else + { + byte[] binaryValue = (byte[])propValue; + indexBuilder.AppendFormat("{0}/1/{1}/{2}:", value.Name, + binaryBuilder.Position, binaryValue.Length); + binaryBuilder.Write(binaryValue, 0, binaryValue.Length); + } + } + index = indexBuilder.ToString(); + stringData = stringDataBuilder.ToString(); + binaryData = binaryBuilder.ToArray(); + return count; + } + + + private ProfileInfoCollection GetProfiles( + ProfileAuthenticationOption authenticationOption, + string usernameToMatch, DateTime userInactiveSinceDate, + int pageIndex, int pageSize, out int totalRecords) + { + List whereClauses = new List(); + + using (MySqlConnection c = new MySqlConnection(connectionString)) + { + c.Open(); + + MySqlCommand cmd = new MySqlCommand( + @"SELECT p.*, u.name, u.isAnonymous, u.lastActivityDate, + LENGTH(p.stringdata) + LENGTH(p.binarydata) AS profilesize + FROM my_aspnet_profiles p + JOIN my_aspnet_users u ON u.id = p.userId + WHERE u.applicationId = @appId", c); + cmd.Parameters.AddWithValue("@appId", app.FetchId(c)); + + if (usernameToMatch != null) + { + cmd.CommandText += " AND u.name LIKE @userName"; + cmd.Parameters.AddWithValue("@userName", usernameToMatch); + } + if (userInactiveSinceDate != DateTime.MinValue) + { + cmd.CommandText += " AND u.lastActivityDate < @lastActivityDate"; + cmd.Parameters.AddWithValue("@lastActivityDate", userInactiveSinceDate); + } + if (authenticationOption == ProfileAuthenticationOption.Anonymous) + cmd.CommandText += " AND u.isAnonymous = 1"; + else if (authenticationOption == ProfileAuthenticationOption.Authenticated) + cmd.CommandText += " AND u.isAnonymous = 0"; + + cmd.CommandText += String.Format(" LIMIT {0},{1}", pageIndex * pageSize, pageSize); + + ProfileInfoCollection pic = new ProfileInfoCollection(); + using (MySqlDataReader reader = cmd.ExecuteReader()) + { + while (reader.Read()) + { + ProfileInfo pi = new ProfileInfo( + reader.GetString("name"), + reader.GetBoolean("isAnonymous"), + reader.GetDateTime("lastActivityDate"), + reader.GetDateTime("lastUpdatedDate"), + reader.GetInt32("profilesize")); + pic.Add(pi); + } + } + cmd.CommandText = "SELECT FOUND_ROWS()"; + totalRecords = Convert.ToInt32(cmd.ExecuteScalar()); + return pic; + } + } + + private static string GetConfigValue(string configValue, string defaultValue) + { + if (string.IsNullOrEmpty(configValue)) + { + return defaultValue; + } + return configValue; + } + + #endregion + + } +} diff --git a/MySql.Web/src/Properties/AssemblyInfo.cs b/MySql.Web/src/Properties/AssemblyInfo.cs index 6751fac2a..fa38956fc 100644 --- a/MySql.Web/src/Properties/AssemblyInfo.cs +++ b/MySql.Web/src/Properties/AssemblyInfo.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2004, 2023, Oracle and/or its affiliates. +// Copyright © 2004, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -26,6 +26,7 @@ // along with this program; if not, write to the Free Software Foundation, Inc., // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +using System; using System.Reflection; using System.Runtime.InteropServices; using System.Security; @@ -34,20 +35,21 @@ // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("MySql.Web")] -[assembly: AssemblyDescription("ADO.Net driver for MySQL")] +[assembly: AssemblyDescription("MySql.Web includes a provider model for use with ASP.NET applications.")] [assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Oracle")] -[assembly: AssemblyProduct("MySql.Web")] -[assembly: AssemblyCopyright("Copyright © 2004, 2023, Oracle and/or its affiliates.")] -[assembly: AssemblyTrademark("")] +[assembly: AssemblyCompany("Oracle Corporation")] +[assembly: AssemblyProduct("MySQL Connector/NET")] +[assembly: AssemblyCopyright("Copyright © 2004, 2025, Oracle and/or its affiliates.")] +[assembly: AssemblyTrademark("Oracle®, Java, MySQL, and NetSuite are registered trademarks of Oracle and/or its affiliates.")] [assembly: AssemblyCulture("")] +[assembly: SecurityRules(SecurityRuleSet.Level1)] +[assembly: CLSCompliant(false)] [assembly: AllowPartiallyTrustedCallers()] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] -[assembly: SecurityRules(SecurityRuleSet.Level1)] diff --git a/MySql.Web/src/Properties/Resources.Designer.cs b/MySql.Web/src/Properties/Resources.Designer.cs index 2311964af..095ec407c 100644 --- a/MySql.Web/src/Properties/Resources.Designer.cs +++ b/MySql.Web/src/Properties/Resources.Designer.cs @@ -1,630 +1,630 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace MySql.Web.Properties { - using System; - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Resources { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Resources() { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("MySql.Web.Properties.Resources", typeof(Resources).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - /// - /// Looks up a localized string similar to Cannot delete a populated role.. - /// - internal static string CannotDeleteAPopulatedRole { - get { - return ResourceManager.GetString("CannotDeleteAPopulatedRole", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Setting EnablePasswordRetrieval to true when PasswordFormat is Hashed is not supported.. - /// - internal static string CannotRetrieveHashedPasswords { - get { - return ResourceManager.GetString("CannotRetrieveHashedPasswords", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to You cannot specify both a connection string name and a connection string.. - /// - internal static string CannotSpecifyNameAndConnectionString { - get { - return ResourceManager.GetString("CannotSpecifyNameAndConnectionString", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Cannot unencode a hashed password.. - /// - internal static string CannotUnencodeHashedPwd { - get { - return ResourceManager.GetString("CannotUnencodeHashedPwd", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Change password operation was canceled.. - /// - internal static string ChangePasswordCanceled { - get { - return ResourceManager.GetString("ChangePasswordCanceled", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Failed to clear the token for the userid {0} in the table {1} after password update.. - /// - internal static string ClearPassTokenFailed { - get { - return ResourceManager.GetString("ClearPassTokenFailed", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to An unexpected error occurred while creating the role '{0}'.. - /// - internal static string CreateRoleFailed { - get { - return ResourceManager.GetString("CreateRoleFailed", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Failed to delete OAuth Account, combination of provider '{0}' and provider user id '{1}' not found.. - /// - internal static string DeleteOAuthAccountFailed { - get { - return ResourceManager.GetString("DeleteOAuthAccountFailed", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to There was an error during membership provider initilization.. - /// - internal static string ErrorInitOfMembershipProvider { - get { - return ResourceManager.GetString("ErrorInitOfMembershipProvider", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to There was an error during role provider initilization.. - /// - internal static string ErrorInitOfRoleProvider { - get { - return ResourceManager.GetString("ErrorInitOfRoleProvider", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to There was an error during profile provider initilization.. - /// - internal static string ErrorInitProfileProvider { - get { - return ResourceManager.GetString("ErrorInitProfileProvider", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to There was an error resetting the password.. - /// - internal static string ErrorResettingPassword { - get { - return ResourceManager.GetString("ErrorResettingPassword", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Failed to generates the PasswordVerificationToken, update not performed to Database.. - /// - internal static string GeneratePassVerificationTokenFailed { - get { - return ResourceManager.GetString("GeneratePassVerificationTokenFailed", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Role names must not be null or empty.. - /// - internal static string IllegalRoleName { - get { - return ResourceManager.GetString("IllegalRoleName", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to User names must not be null or empty.. - /// - internal static string IllegalUserName { - get { - return ResourceManager.GetString("IllegalUserName", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Incorrect password answer.. - /// - internal static string IncorrectPasswordAnswer { - get { - return ResourceManager.GetString("IncorrectPasswordAnswer", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Please provide a valid value: value provided is null or empty.. - /// - internal static string InvalidArgument { - get { - return ResourceManager.GetString("InvalidArgument", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Some of the values in the arrays received are null or empty, please verify it.. - /// - internal static string InvalidArrayValue { - get { - return ResourceManager.GetString("InvalidArrayValue", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Invalid characters in user name.. - /// - internal static string InvalidCharactersInUserName { - get { - return ResourceManager.GetString("InvalidCharactersInUserName", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to User {0} not found in the table {1}.. - /// - internal static string InvalidUser { - get { - return ResourceManager.GetString("InvalidUser", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Unable to initialize provider. Missing or incorrect schema.. - /// - internal static string MissingOrWrongSchema { - get { - return ResourceManager.GetString("MissingOrWrongSchema", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The mono runtime did not support hashed passwords. Please use clear or encrypted passwords.. - /// - internal static string MonoDoesNotSupportHash { - get { - return ResourceManager.GetString("MonoDoesNotSupportHash", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Change password canceled due to New password validation failure.. - /// - internal static string NewPasswordValidationFailed { - get { - return ResourceManager.GetString("NewPasswordValidationFailed", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to There is no connection string configured.. - /// - internal static string NoConnString { - get { - return ResourceManager.GetString("NoConnString", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Non alpha numeric characters in '{0}' needs to be greater than or equal to '{1}'.. - /// - internal static string NotEnoughNonAlphaNumericInPwd { - get { - return ResourceManager.GetString("NotEnoughNonAlphaNumericInPwd", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Password answer supplied is invalid.. - /// - internal static string PasswordAnswerInvalid { - get { - return ResourceManager.GetString("PasswordAnswerInvalid", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Password exceeds maximum length allowed.. - /// - internal static string PasswordExceedsMaxLength { - get { - return ResourceManager.GetString("PasswordExceedsMaxLength", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Password format not supported.. - /// - internal static string PasswordFormatNotSupported { - get { - return ResourceManager.GetString("PasswordFormatNotSupported", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The length of parameter '{0}' needs to be greater or equal to '{1}'.. - /// - internal static string PasswordNotLongEnough { - get { - return ResourceManager.GetString("PasswordNotLongEnough", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Password question supplied is invalid.. - /// - internal static string PasswordQuestionInvalid { - get { - return ResourceManager.GetString("PasswordQuestionInvalid", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Password answer required for password reset.. - /// - internal static string PasswordRequiredForReset { - get { - return ResourceManager.GetString("PasswordRequiredForReset", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Reset password canceled due to password validation failure.. - /// - internal static string PasswordResetCanceledNotValid { - get { - return ResourceManager.GetString("PasswordResetCanceledNotValid", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Password Reset is not enabled.. - /// - internal static string PasswordResetNotEnabled { - get { - return ResourceManager.GetString("PasswordResetNotEnabled", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Password Retrieval Not Enabled.. - /// - internal static string PasswordRetrievalNotEnabled { - get { - return ResourceManager.GetString("PasswordRetrievalNotEnabled", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to MySqlSimpleMembershipProvider is already initialized and its schema does not match the MySqlMembershipProvider schema.. - /// - internal static string PreviousProviderException { - get { - return ResourceManager.GetString("PreviousProviderException", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Profile update failed.. - /// - internal static string ProfileUpdateFailed { - get { - return ResourceManager.GetString("ProfileUpdateFailed", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The role '{0}' already exists.. - /// - internal static string RoleAlreadyExists { - get { - return ResourceManager.GetString("RoleAlreadyExists", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The role '{0}' is in use.. - /// - internal static string RoleInUse { - get { - return ResourceManager.GetString("RoleInUse", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Role name already exists.. - /// - internal static string RoleNameAlreadyExists { - get { - return ResourceManager.GetString("RoleNameAlreadyExists", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Role name not found.. - /// - internal static string RoleNameNotFound { - get { - return ResourceManager.GetString("RoleNameNotFound", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Failed to save the request token secret value '{0}'.. - /// - internal static string SaveTokenFailed { - get { - return ResourceManager.GetString("SaveTokenFailed", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The MySqlSimpleMembershipProvider is already initialized.. - /// - internal static string SimpleMembershipAlreadyInitialized { - get { - return ResourceManager.GetString("SimpleMembershipAlreadyInitialized", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The membership provider was not initialized, it must be initialized before start using it.. - /// - internal static string SimpleMembershipNotInitialized { - get { - return ResourceManager.GetString("SimpleMembershipNotInitialized", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The MySqlSimpleRoleProvider is already initialized.. - /// - internal static string SimpleRoleAlreadyInitialized { - get { - return ResourceManager.GetString("SimpleRoleAlreadyInitialized", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The connection string name is missing for the MySqlSiteMapProvider. - /// - internal static string SiteMapConnectionStringMissing { - get { - return ResourceManager.GetString("SiteMapConnectionStringMissing", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Unable to create application.. - /// - internal static string UnableToCreateApplication { - get { - return ResourceManager.GetString("UnableToCreateApplication", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Unable to create user.. - /// - internal static string UnableToCreateUser { - get { - return ResourceManager.GetString("UnableToCreateUser", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Unable to lock out user.. - /// - internal static string UnableToLockOutUser { - get { - return ResourceManager.GetString("UnableToLockOutUser", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Unable to retrieve profile data from database.. - /// - internal static string UnableToRetrieveProfileData { - get { - return ResourceManager.GetString("UnableToRetrieveProfileData", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Unable to update failure count. Membership database may be corrupt.. - /// - internal static string UnableToUpdateFailureCount { - get { - return ResourceManager.GetString("UnableToUpdateFailureCount", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Unsupported password format.. - /// - internal static string UnsupportedPasswordFormat { - get { - return ResourceManager.GetString("UnsupportedPasswordFormat", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Failed to update the request token secret value '{0}'.. - /// - internal static string UpdateTokenFailed { - get { - return ResourceManager.GetString("UpdateTokenFailed", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to User {0} already exists.. - /// - internal static string UserAlreadyExists { - get { - return ResourceManager.GetString("UserAlreadyExists", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to UserIdColumn configuration was not initialized.. - /// - internal static string UserIdColumnNotInitialized { - get { - return ResourceManager.GetString("UserIdColumnNotInitialized", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to User is already in role.. - /// - internal static string UserIsAlreadyInRole { - get { - return ResourceManager.GetString("UserIsAlreadyInRole", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The supplied user is locked out.. - /// - internal static string UserIsLockedOut { - get { - return ResourceManager.GetString("UserIsLockedOut", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to UserNameColumn configuration was not initialized.. - /// - internal static string UserNameColumnNotInitialized { - get { - return ResourceManager.GetString("UserNameColumnNotInitialized", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Username not found.. - /// - internal static string UsernameNotFound { - get { - return ResourceManager.GetString("UsernameNotFound", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to User not found int the table {0}.. - /// - internal static string UserNotFound { - get { - return ResourceManager.GetString("UserNotFound", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to User not in role.. - /// - internal static string UserNotInRole { - get { - return ResourceManager.GetString("UserNotInRole", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to UserTableName configuration was not initialized.. - /// - internal static string UserTableNameNotInitilized { - get { - return ResourceManager.GetString("UserTableNameNotInitilized", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Unable to find the table users {0}. Please create it or initialize the MySqlSimpleMembershipProvider with 'createTables=true'.. - /// - internal static string UserTableNotFound { - get { - return ResourceManager.GetString("UserTableNotFound", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The validate password operation was canceled.. - /// - internal static string ValidatePasswordCanceled { - get { - return ResourceManager.GetString("ValidatePasswordCanceled", resourceCulture); - } - } - } -} +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace MySql.Web.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("MySql.Web.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to Cannot delete a populated role.. + /// + internal static string CannotDeleteAPopulatedRole { + get { + return ResourceManager.GetString("CannotDeleteAPopulatedRole", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Setting EnablePasswordRetrieval to true when PasswordFormat is Hashed is not supported.. + /// + internal static string CannotRetrieveHashedPasswords { + get { + return ResourceManager.GetString("CannotRetrieveHashedPasswords", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to You cannot specify both a connection string name and a connection string.. + /// + internal static string CannotSpecifyNameAndConnectionString { + get { + return ResourceManager.GetString("CannotSpecifyNameAndConnectionString", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cannot unencode a hashed password.. + /// + internal static string CannotUnencodeHashedPwd { + get { + return ResourceManager.GetString("CannotUnencodeHashedPwd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Change password operation was canceled.. + /// + internal static string ChangePasswordCanceled { + get { + return ResourceManager.GetString("ChangePasswordCanceled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Failed to clear the token for the userid {0} in the table {1} after password update.. + /// + internal static string ClearPassTokenFailed { + get { + return ResourceManager.GetString("ClearPassTokenFailed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to An unexpected error occurred while creating the role '{0}'.. + /// + internal static string CreateRoleFailed { + get { + return ResourceManager.GetString("CreateRoleFailed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Failed to delete OAuth Account, combination of provider '{0}' and provider user id '{1}' not found.. + /// + internal static string DeleteOAuthAccountFailed { + get { + return ResourceManager.GetString("DeleteOAuthAccountFailed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to There was an error during membership provider initilization.. + /// + internal static string ErrorInitOfMembershipProvider { + get { + return ResourceManager.GetString("ErrorInitOfMembershipProvider", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to There was an error during role provider initilization.. + /// + internal static string ErrorInitOfRoleProvider { + get { + return ResourceManager.GetString("ErrorInitOfRoleProvider", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to There was an error during profile provider initilization.. + /// + internal static string ErrorInitProfileProvider { + get { + return ResourceManager.GetString("ErrorInitProfileProvider", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to There was an error resetting the password.. + /// + internal static string ErrorResettingPassword { + get { + return ResourceManager.GetString("ErrorResettingPassword", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Failed to generates the PasswordVerificationToken, update not performed to Database.. + /// + internal static string GeneratePassVerificationTokenFailed { + get { + return ResourceManager.GetString("GeneratePassVerificationTokenFailed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Role names must not be null or empty.. + /// + internal static string IllegalRoleName { + get { + return ResourceManager.GetString("IllegalRoleName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to User names must not be null or empty.. + /// + internal static string IllegalUserName { + get { + return ResourceManager.GetString("IllegalUserName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Incorrect password answer.. + /// + internal static string IncorrectPasswordAnswer { + get { + return ResourceManager.GetString("IncorrectPasswordAnswer", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Please provide a valid value: value provided is null or empty.. + /// + internal static string InvalidArgument { + get { + return ResourceManager.GetString("InvalidArgument", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Some of the values in the arrays received are null or empty, please verify it.. + /// + internal static string InvalidArrayValue { + get { + return ResourceManager.GetString("InvalidArrayValue", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid characters in user name.. + /// + internal static string InvalidCharactersInUserName { + get { + return ResourceManager.GetString("InvalidCharactersInUserName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to User {0} not found in the table {1}.. + /// + internal static string InvalidUser { + get { + return ResourceManager.GetString("InvalidUser", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to initialize provider. Missing or incorrect schema.. + /// + internal static string MissingOrWrongSchema { + get { + return ResourceManager.GetString("MissingOrWrongSchema", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The mono runtime did not support hashed passwords. Please use clear or encrypted passwords.. + /// + internal static string MonoDoesNotSupportHash { + get { + return ResourceManager.GetString("MonoDoesNotSupportHash", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Change password canceled due to New password validation failure.. + /// + internal static string NewPasswordValidationFailed { + get { + return ResourceManager.GetString("NewPasswordValidationFailed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to There is no connection string configured.. + /// + internal static string NoConnString { + get { + return ResourceManager.GetString("NoConnString", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Non alpha numeric characters in '{0}' needs to be greater than or equal to '{1}'.. + /// + internal static string NotEnoughNonAlphaNumericInPwd { + get { + return ResourceManager.GetString("NotEnoughNonAlphaNumericInPwd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Password answer supplied is invalid.. + /// + internal static string PasswordAnswerInvalid { + get { + return ResourceManager.GetString("PasswordAnswerInvalid", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Password exceeds maximum length allowed.. + /// + internal static string PasswordExceedsMaxLength { + get { + return ResourceManager.GetString("PasswordExceedsMaxLength", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Password format not supported.. + /// + internal static string PasswordFormatNotSupported { + get { + return ResourceManager.GetString("PasswordFormatNotSupported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The length of parameter '{0}' needs to be greater or equal to '{1}'.. + /// + internal static string PasswordNotLongEnough { + get { + return ResourceManager.GetString("PasswordNotLongEnough", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Password question supplied is invalid.. + /// + internal static string PasswordQuestionInvalid { + get { + return ResourceManager.GetString("PasswordQuestionInvalid", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Password answer required for password reset.. + /// + internal static string PasswordRequiredForReset { + get { + return ResourceManager.GetString("PasswordRequiredForReset", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reset password canceled due to password validation failure.. + /// + internal static string PasswordResetCanceledNotValid { + get { + return ResourceManager.GetString("PasswordResetCanceledNotValid", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Password Reset is not enabled.. + /// + internal static string PasswordResetNotEnabled { + get { + return ResourceManager.GetString("PasswordResetNotEnabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Password Retrieval Not Enabled.. + /// + internal static string PasswordRetrievalNotEnabled { + get { + return ResourceManager.GetString("PasswordRetrievalNotEnabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MySqlSimpleMembershipProvider is already initialized and its schema does not match the MySqlMembershipProvider schema.. + /// + internal static string PreviousProviderException { + get { + return ResourceManager.GetString("PreviousProviderException", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Profile update failed.. + /// + internal static string ProfileUpdateFailed { + get { + return ResourceManager.GetString("ProfileUpdateFailed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The role '{0}' already exists.. + /// + internal static string RoleAlreadyExists { + get { + return ResourceManager.GetString("RoleAlreadyExists", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The role '{0}' is in use.. + /// + internal static string RoleInUse { + get { + return ResourceManager.GetString("RoleInUse", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Role name already exists.. + /// + internal static string RoleNameAlreadyExists { + get { + return ResourceManager.GetString("RoleNameAlreadyExists", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Role name not found.. + /// + internal static string RoleNameNotFound { + get { + return ResourceManager.GetString("RoleNameNotFound", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Failed to save the request token secret value '{0}'.. + /// + internal static string SaveTokenFailed { + get { + return ResourceManager.GetString("SaveTokenFailed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The MySqlSimpleMembershipProvider is already initialized.. + /// + internal static string SimpleMembershipAlreadyInitialized { + get { + return ResourceManager.GetString("SimpleMembershipAlreadyInitialized", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The membership provider was not initialized, it must be initialized before start using it.. + /// + internal static string SimpleMembershipNotInitialized { + get { + return ResourceManager.GetString("SimpleMembershipNotInitialized", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The MySqlSimpleRoleProvider is already initialized.. + /// + internal static string SimpleRoleAlreadyInitialized { + get { + return ResourceManager.GetString("SimpleRoleAlreadyInitialized", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The connection string name is missing for the MySqlSiteMapProvider. + /// + internal static string SiteMapConnectionStringMissing { + get { + return ResourceManager.GetString("SiteMapConnectionStringMissing", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to create application.. + /// + internal static string UnableToCreateApplication { + get { + return ResourceManager.GetString("UnableToCreateApplication", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to create user.. + /// + internal static string UnableToCreateUser { + get { + return ResourceManager.GetString("UnableToCreateUser", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to lock out user.. + /// + internal static string UnableToLockOutUser { + get { + return ResourceManager.GetString("UnableToLockOutUser", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to retrieve profile data from database.. + /// + internal static string UnableToRetrieveProfileData { + get { + return ResourceManager.GetString("UnableToRetrieveProfileData", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to update failure count. Membership database may be corrupt.. + /// + internal static string UnableToUpdateFailureCount { + get { + return ResourceManager.GetString("UnableToUpdateFailureCount", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unsupported password format.. + /// + internal static string UnsupportedPasswordFormat { + get { + return ResourceManager.GetString("UnsupportedPasswordFormat", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Failed to update the request token secret value '{0}'.. + /// + internal static string UpdateTokenFailed { + get { + return ResourceManager.GetString("UpdateTokenFailed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to User {0} already exists.. + /// + internal static string UserAlreadyExists { + get { + return ResourceManager.GetString("UserAlreadyExists", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to UserIdColumn configuration was not initialized.. + /// + internal static string UserIdColumnNotInitialized { + get { + return ResourceManager.GetString("UserIdColumnNotInitialized", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to User is already in role.. + /// + internal static string UserIsAlreadyInRole { + get { + return ResourceManager.GetString("UserIsAlreadyInRole", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The supplied user is locked out.. + /// + internal static string UserIsLockedOut { + get { + return ResourceManager.GetString("UserIsLockedOut", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to UserNameColumn configuration was not initialized.. + /// + internal static string UserNameColumnNotInitialized { + get { + return ResourceManager.GetString("UserNameColumnNotInitialized", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Username not found.. + /// + internal static string UsernameNotFound { + get { + return ResourceManager.GetString("UsernameNotFound", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to User not found int the table {0}.. + /// + internal static string UserNotFound { + get { + return ResourceManager.GetString("UserNotFound", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to User not in role.. + /// + internal static string UserNotInRole { + get { + return ResourceManager.GetString("UserNotInRole", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to UserTableName configuration was not initialized.. + /// + internal static string UserTableNameNotInitilized { + get { + return ResourceManager.GetString("UserTableNameNotInitilized", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to find the table users {0}. Please create it or initialize the MySqlSimpleMembershipProvider with 'createTables=true'.. + /// + internal static string UserTableNotFound { + get { + return ResourceManager.GetString("UserTableNotFound", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The validate password operation was canceled.. + /// + internal static string ValidatePasswordCanceled { + get { + return ResourceManager.GetString("ValidatePasswordCanceled", resourceCulture); + } + } + } +} diff --git a/MySql.Web/src/Properties/VersionInfo.cs b/MySql.Web/src/Properties/VersionInfo.cs new file mode 100644 index 000000000..e577111b1 --- /dev/null +++ b/MySql.Web/src/Properties/VersionInfo.cs @@ -0,0 +1,46 @@ +// Copyright © 2024, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using System.Reflection; +using System.Resources; + +// +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: + +[assembly: AssemblyVersion("9.4.0")] +[assembly: AssemblyInformationalVersion("9.4.0.0")] +[assembly: AssemblyFileVersion("9.4.0.0")] +[assembly: NeutralResourcesLanguage("en-US")] diff --git a/MySql.Web/src/Properties/schema1.sql b/MySql.Web/src/Properties/schema1.sql index 0b253cb86..ec80889ac 100644 --- a/MySql.Web/src/Properties/schema1.sql +++ b/MySql.Web/src/Properties/schema1.sql @@ -1,33 +1,33 @@ -CREATE TABLE mysql_Membership(`PKID` varchar(36) NOT NULL, - Username varchar(255) NOT NULL, - ApplicationName varchar(255) NOT NULL, - Email varchar(128) NOT NULL, - Comment varchar(255) default NULL, - Password varchar(128) NOT NULL, - PasswordQuestion varchar(255) default NULL, - PasswordAnswer varchar(255) default NULL, - IsApproved tinyint(1) default NULL, - LastActivityDate datetime default NULL, - LastLoginDate datetime default NULL, - LastPasswordChangedDate datetime default NULL, - CreationDate datetime default NULL, - IsOnline tinyint(1) default NULL, - IsLockedOut tinyint(1) default NULL, - LastLockedOutDate datetime default NULL, - FailedPasswordAttemptCount int(10) unsigned default NULL, - FailedPasswordAttemptWindowStart datetime default NULL, - FailedPasswordAnswerAttemptCount int(10) unsigned default NULL, - FailedPasswordAnswerAttemptWindowStart datetime default NULL, - PRIMARY KEY (`PKID`)) DEFAULT CHARSET=latin1 COMMENT='1'; - -CREATE TABLE mysql_UsersInRoles(`Username` varchar(255) NOT NULL, - `Rolename` varchar(255) NOT NULL, `ApplicationName` varchar(255) NOT NULL, - KEY `Username` (`Username`,`Rolename`,`ApplicationName`) - ) DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC; - -CREATE TABLE mysql_Roles(`Rolename` varchar(255) NOT NULL, - `ApplicationName` varchar(255) NOT NULL, - KEY `Rolename` (`Rolename`,`ApplicationName`) - ) DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC; - +CREATE TABLE mysql_Membership(`PKID` varchar(36) NOT NULL, + Username varchar(255) NOT NULL, + ApplicationName varchar(255) NOT NULL, + Email varchar(128) NOT NULL, + Comment varchar(255) default NULL, + Password varchar(128) NOT NULL, + PasswordQuestion varchar(255) default NULL, + PasswordAnswer varchar(255) default NULL, + IsApproved tinyint(1) default NULL, + LastActivityDate datetime default NULL, + LastLoginDate datetime default NULL, + LastPasswordChangedDate datetime default NULL, + CreationDate datetime default NULL, + IsOnline tinyint(1) default NULL, + IsLockedOut tinyint(1) default NULL, + LastLockedOutDate datetime default NULL, + FailedPasswordAttemptCount int(10) unsigned default NULL, + FailedPasswordAttemptWindowStart datetime default NULL, + FailedPasswordAnswerAttemptCount int(10) unsigned default NULL, + FailedPasswordAnswerAttemptWindowStart datetime default NULL, + PRIMARY KEY (`PKID`)) DEFAULT CHARSET=latin1 COMMENT='1'; + +CREATE TABLE mysql_UsersInRoles(`Username` varchar(255) NOT NULL, + `Rolename` varchar(255) NOT NULL, `ApplicationName` varchar(255) NOT NULL, + KEY `Username` (`Username`,`Rolename`,`ApplicationName`) + ) DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC; + +CREATE TABLE mysql_Roles(`Rolename` varchar(255) NOT NULL, + `ApplicationName` varchar(255) NOT NULL, + KEY `Rolename` (`Rolename`,`ApplicationName`) + ) DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC; + \ No newline at end of file diff --git a/MySql.Web/src/Properties/schema10.sql b/MySql.Web/src/Properties/schema10.sql index 08f758ccc..3bbc8dcde 100644 --- a/MySql.Web/src/Properties/schema10.sql +++ b/MySql.Web/src/Properties/schema10.sql @@ -1,23 +1,23 @@ -CREATE TABLE my_aspnet_personalizationperuser( -id INT PRIMARY KEY AUTO_INCREMENT, -applicationId INT NOT NULL, -pathId VARCHAR(36) DEFAULT NULL, -userId INT, -pageSettings BLOB NOT NULL, -lastUpdatedDate DATETIME NOT NULL)DEFAULT CHARSET=latin1 ; - - -CREATE TABLE my_aspnet_personalizationallusers( -pathId VARCHAR(36) PRIMARY KEY, -pageSettings BLOB NOT NULL, -lastUpdatedDate DATETIME NOT NULL)DEFAULT CHARSET=latin1 ; - -CREATE TABLE my_aspnet_paths -( -applicationId INT NOT NULL, -pathId VARCHAR(36) PRIMARY KEY, -path VARCHAR(256) NOT NULL, -loweredPath VARCHAR(256) NOT NULL -)DEFAULT CHARSET=latin1 ; - +CREATE TABLE my_aspnet_personalizationperuser( +id INT PRIMARY KEY AUTO_INCREMENT, +applicationId INT NOT NULL, +pathId VARCHAR(36) DEFAULT NULL, +userId INT, +pageSettings BLOB NOT NULL, +lastUpdatedDate DATETIME NOT NULL)DEFAULT CHARSET=latin1 ; + + +CREATE TABLE my_aspnet_personalizationallusers( +pathId VARCHAR(36) PRIMARY KEY, +pageSettings BLOB NOT NULL, +lastUpdatedDate DATETIME NOT NULL)DEFAULT CHARSET=latin1 ; + +CREATE TABLE my_aspnet_paths +( +applicationId INT NOT NULL, +pathId VARCHAR(36) PRIMARY KEY, +path VARCHAR(256) NOT NULL, +loweredPath VARCHAR(256) NOT NULL +)DEFAULT CHARSET=latin1 ; + UPDATE my_aspnet_schemaversion SET version=10; \ No newline at end of file diff --git a/MySql.Web/src/Properties/schema2.sql b/MySql.Web/src/Properties/schema2.sql index a34b8d152..69f091f8a 100644 --- a/MySql.Web/src/Properties/schema2.sql +++ b/MySql.Web/src/Properties/schema2.sql @@ -1,7 +1,7 @@ - ALTER TABLE mysql_Membership - ADD PasswordKey char(32) AFTER Password, - ADD PasswordFormat tinyint AFTER PasswordKey, - CHANGE Email Email VARCHAR(128), COMMENT='2'; - - + ALTER TABLE mysql_Membership + ADD PasswordKey char(32) AFTER Password, + ADD PasswordFormat tinyint AFTER PasswordKey, + CHANGE Email Email VARCHAR(128), COMMENT='2'; + + \ No newline at end of file diff --git a/MySql.Web/src/Properties/schema3.sql b/MySql.Web/src/Properties/schema3.sql index 8016b4b07..ee38a1017 100644 --- a/MySql.Web/src/Properties/schema3.sql +++ b/MySql.Web/src/Properties/schema3.sql @@ -1,85 +1,85 @@ -/* Provider schema block -- version 3 */ - -/* create our application and user tables */ -create table my_aspnet_applications(id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(256), description VARCHAR(256)); -create table my_aspnet_users(id INT PRIMARY KEY AUTO_INCREMENT, - applicationId INT NOT NULL, name VARCHAR(256) NOT NULL, - isAnonymous TINYINT(1) NOT NULL DEFAULT 1, lastActivityDate DATETIME); -create table my_aspnet_profiles(userId INT PRIMARY KEY, valueindex longtext, stringdata longtext, binarydata longblob, lastUpdatedDate timestamp); -create table my_aspnet_schemaversion(version INT); - -insert into my_aspnet_schemaversion VALUES (3); - -/* now we need to migrate all applications into our apps table */ -insert into my_aspnet_applications (name) select ApplicationName from mysql_Membership UNION select ApplicationName from mysql_UsersInRoles; - -/* now we make our changes to the existing tables */ -alter table mysql_Membership - rename to my_aspnet_membership, - drop primary key, - drop column pkid, - drop column IsOnline, - add column userId INT FIRST, - add column applicationId INT AFTER userId; - -alter table mysql_Roles - rename to my_aspnet_roles, - drop key Rolename, - add column id INT PRIMARY KEY AUTO_INCREMENT FIRST, - add column applicationId INT NOT NULL AFTER id; - -alter table mysql_UsersInRoles - drop key Username, - rename to my_aspnet_usersinroles, - add column userId INT FIRST, - add column roleId INT AFTER userId, - add column applicationId INT AFTER roleId; - -ALTER TABLE my_aspnet_membership CONVERT TO CHARACTER SET DEFAULT; -ALTER TABLE my_aspnet_roles CONVERT TO CHARACTER SET DEFAULT; -ALTER TABLE my_aspnet_usersinroles CONVERT TO CHARACTER SET DEFAULT; - -/* these next lines set the application Id on our tables appropriately */ -update my_aspnet_membership m, my_aspnet_applications a set m.applicationId = a.id where a.name=m.ApplicationName; -update my_aspnet_roles r, my_aspnet_applications a set r.applicationId = a.id where a.name=r.ApplicationName; -update my_aspnet_usersinroles u, my_aspnet_applications a set u.applicationId = a.id where a.name=u.ApplicationName; - -/* now merge our usernames into our users table */ -insert into my_aspnet_users (applicationId, name) - select applicationId, Username from my_aspnet_membership - UNION select applicationId, Username from my_aspnet_usersinroles; - -/* now set the user ids in our tables accordingly */ -update my_aspnet_membership m, my_aspnet_users u set m.userId = u.id where u.name=m.Username AND u.applicationId=m.applicationId; -update my_aspnet_usersinroles r, my_aspnet_users u set r.userId = u.id where u.name=r.Username AND u.applicationId=r.applicationId; - -/* now update the isanonymous and last activity date fields for the users */ -update my_aspnet_users u, my_aspnet_membership m - set u.isAnonymous=0, u.lastActivityDate=m.LastActivityDate - where u.name = m.Username; - -/* make final changes to our tables */ -alter table my_aspnet_membership - drop column Username, - drop column ApplicationName, - drop column applicationId, - add primary key (userId); - -/* next we set our role id values appropriately */ -update my_aspnet_usersinroles u, my_aspnet_roles r set u.roleId = r.id where u.Rolename = r.Rolename and r.applicationId=u.applicationId; - -/* now we make the final changes to our roles tables */ -alter table my_aspnet_roles - drop column ApplicationName, - change column Rolename name VARCHAR(255) NOT NULL; - -alter table my_aspnet_usersinroles - drop column ApplicationName, - drop column applicationId, - drop column Username, - drop column Rolename, - add primary key (userId, roleId); - - - +/* Provider schema block -- version 3 */ + +/* create our application and user tables */ +create table my_aspnet_applications(id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(256), description VARCHAR(256)); +create table my_aspnet_users(id INT PRIMARY KEY AUTO_INCREMENT, + applicationId INT NOT NULL, name VARCHAR(256) NOT NULL, + isAnonymous TINYINT(1) NOT NULL DEFAULT 1, lastActivityDate DATETIME); +create table my_aspnet_profiles(userId INT PRIMARY KEY, valueindex longtext, stringdata longtext, binarydata longblob, lastUpdatedDate timestamp); +create table my_aspnet_schemaversion(version INT); + +insert into my_aspnet_schemaversion VALUES (3); + +/* now we need to migrate all applications into our apps table */ +insert into my_aspnet_applications (name) select ApplicationName from mysql_Membership UNION select ApplicationName from mysql_UsersInRoles; + +/* now we make our changes to the existing tables */ +alter table mysql_Membership + rename to my_aspnet_membership, + drop primary key, + drop column pkid, + drop column IsOnline, + add column userId INT FIRST, + add column applicationId INT AFTER userId; + +alter table mysql_Roles + rename to my_aspnet_roles, + drop key Rolename, + add column id INT PRIMARY KEY AUTO_INCREMENT FIRST, + add column applicationId INT NOT NULL AFTER id; + +alter table mysql_UsersInRoles + drop key Username, + rename to my_aspnet_usersinroles, + add column userId INT FIRST, + add column roleId INT AFTER userId, + add column applicationId INT AFTER roleId; + +ALTER TABLE my_aspnet_membership CONVERT TO CHARACTER SET DEFAULT; +ALTER TABLE my_aspnet_roles CONVERT TO CHARACTER SET DEFAULT; +ALTER TABLE my_aspnet_usersinroles CONVERT TO CHARACTER SET DEFAULT; + +/* these next lines set the application Id on our tables appropriately */ +update my_aspnet_membership m, my_aspnet_applications a set m.applicationId = a.id where a.name=m.ApplicationName; +update my_aspnet_roles r, my_aspnet_applications a set r.applicationId = a.id where a.name=r.ApplicationName; +update my_aspnet_usersinroles u, my_aspnet_applications a set u.applicationId = a.id where a.name=u.ApplicationName; + +/* now merge our usernames into our users table */ +insert into my_aspnet_users (applicationId, name) + select applicationId, Username from my_aspnet_membership + UNION select applicationId, Username from my_aspnet_usersinroles; + +/* now set the user ids in our tables accordingly */ +update my_aspnet_membership m, my_aspnet_users u set m.userId = u.id where u.name=m.Username AND u.applicationId=m.applicationId; +update my_aspnet_usersinroles r, my_aspnet_users u set r.userId = u.id where u.name=r.Username AND u.applicationId=r.applicationId; + +/* now update the isanonymous and last activity date fields for the users */ +update my_aspnet_users u, my_aspnet_membership m + set u.isAnonymous=0, u.lastActivityDate=m.LastActivityDate + where u.name = m.Username; + +/* make final changes to our tables */ +alter table my_aspnet_membership + drop column Username, + drop column ApplicationName, + drop column applicationId, + add primary key (userId); + +/* next we set our role id values appropriately */ +update my_aspnet_usersinroles u, my_aspnet_roles r set u.roleId = r.id where u.Rolename = r.Rolename and r.applicationId=u.applicationId; + +/* now we make the final changes to our roles tables */ +alter table my_aspnet_roles + drop column ApplicationName, + change column Rolename name VARCHAR(255) NOT NULL; + +alter table my_aspnet_usersinroles + drop column ApplicationName, + drop column applicationId, + drop column Username, + drop column Rolename, + add primary key (userId, roleId); + + + \ No newline at end of file diff --git a/MySql.Web/src/Properties/schema4.sql b/MySql.Web/src/Properties/schema4.sql index 4f91e3145..1470878dd 100644 --- a/MySql.Web/src/Properties/schema4.sql +++ b/MySql.Web/src/Properties/schema4.sql @@ -1,5 +1,5 @@ -ALTER TABLE my_aspnet_membership CONVERT TO CHARACTER SET DEFAULT; -ALTER TABLE my_aspnet_roles CONVERT TO CHARACTER SET DEFAULT; -ALTER TABLE my_aspnet_usersinroles CONVERT TO CHARACTER SET DEFAULT; - -UPDATE my_aspnet_schemaversion SET version=4 WHERE version=3; +ALTER TABLE my_aspnet_membership CONVERT TO CHARACTER SET DEFAULT; +ALTER TABLE my_aspnet_roles CONVERT TO CHARACTER SET DEFAULT; +ALTER TABLE my_aspnet_usersinroles CONVERT TO CHARACTER SET DEFAULT; + +UPDATE my_aspnet_schemaversion SET version=4 WHERE version=3; diff --git a/MySql.Web/src/Properties/schema5.sql b/MySql.Web/src/Properties/schema5.sql index 39e1f6ca1..d1708c5a6 100644 --- a/MySql.Web/src/Properties/schema5.sql +++ b/MySql.Web/src/Properties/schema5.sql @@ -1,30 +1,30 @@ -CREATE TABLE my_aspnet_sessions -( - SessionId varchar(191) NOT NULL, - ApplicationId int NOT NULL, - Created datetime NOT NULL, - Expires datetime NOT NULL, - LockDate datetime NOT NULL, - LockId int NOT NULL, - Timeout int NOT NULL, - Locked tinyint(1) NOT NULL, - SessionItems BLOB, - Flags int NOT NULL, - primary key (SessionId,ApplicationId) -) DEFAULT CHARSET=latin1; - -/* - Cleaning up timed out sessions. - In 5.1 events provide a support for periodic jobs. - In older version we need a do-it-yourself event. -*/ -CREATE TABLE my_aspnet_sessioncleanup -( - LastRun datetime NOT NULL, - IntervalMinutes int NOT NULL -); - -INSERT INTO my_aspnet_sessioncleanup(LastRun,IntervalMinutes) values(NOW(), 10); - -UPDATE my_aspnet_schemaversion SET version=5; - +CREATE TABLE my_aspnet_sessions +( + SessionId varchar(191) NOT NULL, + ApplicationId int NOT NULL, + Created datetime NOT NULL, + Expires datetime NOT NULL, + LockDate datetime NOT NULL, + LockId int NOT NULL, + Timeout int NOT NULL, + Locked tinyint(1) NOT NULL, + SessionItems BLOB, + Flags int NOT NULL, + primary key (SessionId,ApplicationId) +) DEFAULT CHARSET=latin1; + +/* + Cleaning up timed out sessions. + In 5.1 events provide a support for periodic jobs. + In older version we need a do-it-yourself event. +*/ +CREATE TABLE my_aspnet_sessioncleanup +( + LastRun datetime NOT NULL, + IntervalMinutes int NOT NULL +); + +INSERT INTO my_aspnet_sessioncleanup(LastRun,IntervalMinutes) values(NOW(), 10); + +UPDATE my_aspnet_schemaversion SET version=5; + diff --git a/MySql.Web/src/Properties/schema6.sql b/MySql.Web/src/Properties/schema6.sql index 6147d16f3..58aad3cd1 100644 --- a/MySql.Web/src/Properties/schema6.sql +++ b/MySql.Web/src/Properties/schema6.sql @@ -1,4 +1,4 @@ -ALTER TABLE my_aspnet_sessions CONVERT TO CHARACTER SET DEFAULT; -ALTER TABLE my_aspnet_sessions MODIFY SessionItems LONGBLOB; - -UPDATE my_aspnet_schemaversion SET version=6; +ALTER TABLE my_aspnet_sessions CONVERT TO CHARACTER SET DEFAULT; +ALTER TABLE my_aspnet_sessions MODIFY SessionItems LONGBLOB; + +UPDATE my_aspnet_schemaversion SET version=6; diff --git a/MySql.Web/src/Properties/schema7.sql b/MySql.Web/src/Properties/schema7.sql index 0708c129e..be4a9691b 100644 --- a/MySql.Web/src/Properties/schema7.sql +++ b/MySql.Web/src/Properties/schema7.sql @@ -1,11 +1,11 @@ -RENAME TABLE my_aspnet_Applications TO my_aspnet_applications; -RENAME TABLE my_aspnet_Membership TO my_aspnet_membership; -RENAME TABLE my_aspnet_Profiles TO my_aspnet_profiles; -RENAME TABLE my_aspnet_Roles TO my_aspnet_roles; -RENAME TABLE my_aspnet_SchemaVersion TO my_aspnet_schemaversion; -RENAME TABLE my_aspnet_SessionCleanup TO my_aspnet_sessioncleanup; -RENAME TABLE my_aspnet_Sessions TO my_aspnet_sessions; -RENAME TABLE my_aspnet_Users TO my_aspnet_users; -RENAME TABLE my_aspnet_UsersInRoles TO my_aspnet_usersinroles; - +RENAME TABLE my_aspnet_Applications TO my_aspnet_applications; +RENAME TABLE my_aspnet_Membership TO my_aspnet_membership; +RENAME TABLE my_aspnet_Profiles TO my_aspnet_profiles; +RENAME TABLE my_aspnet_Roles TO my_aspnet_roles; +RENAME TABLE my_aspnet_SchemaVersion TO my_aspnet_schemaversion; +RENAME TABLE my_aspnet_SessionCleanup TO my_aspnet_sessioncleanup; +RENAME TABLE my_aspnet_Sessions TO my_aspnet_sessions; +RENAME TABLE my_aspnet_Users TO my_aspnet_users; +RENAME TABLE my_aspnet_UsersInRoles TO my_aspnet_usersinroles; + UPDATE my_aspnet_schemaversion SET version=7; \ No newline at end of file diff --git a/MySql.Web/src/Properties/schema8.sql b/MySql.Web/src/Properties/schema8.sql index 108026f76..8fcc73642 100644 --- a/MySql.Web/src/Properties/schema8.sql +++ b/MySql.Web/src/Properties/schema8.sql @@ -1,6 +1,6 @@ -DELETE FROM my_aspnet_sessioncleanup; - -ALTER TABLE my_aspnet_sessioncleanup ADD ApplicationId INT NOT NULL; -ALTER TABLE my_aspnet_sessioncleanup ADD Primary Key (ApplicationId); - +DELETE FROM my_aspnet_sessioncleanup; + +ALTER TABLE my_aspnet_sessioncleanup ADD ApplicationId INT NOT NULL; +ALTER TABLE my_aspnet_sessioncleanup ADD Primary Key (ApplicationId); + UPDATE my_aspnet_schemaversion SET version=8; \ No newline at end of file diff --git a/MySql.Web/src/RoleProvider.cs b/MySql.Web/src/RoleProvider.cs index ac441448c..ef8177e1d 100644 --- a/MySql.Web/src/RoleProvider.cs +++ b/MySql.Web/src/RoleProvider.cs @@ -1,643 +1,643 @@ -// Copyright (c) 2004, 2021, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -// This code was contributed by Sean Wright (srwright@alcor.concordia.ca) on 2007-01-12 -// The copyright was assigned and transferred under the terms of -// the MySQL Contributor License Agreement (CLA) - -using MySql.Data.MySqlClient; -using MySql.Web.Common; -using MySql.Web.General; -using System; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.Configuration.Provider; -using System.Diagnostics; -using System.Web.Hosting; -using System.Web.Security; - -namespace MySql.Web.Security -{ - /// - /// Manages storage of role membership information for an ASP.NET application in a MySQL database. - /// - public sealed class MySQLRoleProvider : RoleProvider - { - private string eventSource = "MySQLRoleProvider"; - private string eventLog = "Application"; - private string exceptionMessage = "An exception occurred. Please check the Event Log."; - private string connectionString; - private bool pWriteExceptionsToEventLog = false; - private Application app; - - /// - /// Initializes the provider. - /// - /// The friendly name of the provider. - /// A collection of the name/value pairs representing the provider-specific attributes specified in the configuration for this provider. - /// The name of the provider is null. - /// The name of the provider has a length of zero. - /// An attempt is made to call on a provider after the provider has already been initialized. - public override void Initialize(string name, NameValueCollection config) - { - if (config == null) - { - throw new ArgumentNullException("config"); - } - if (name == null || name.Length == 0) - { - name = "MySQLRoleProvider"; - } - if (string.IsNullOrEmpty(config["description"])) - { - config.Remove("description"); - config.Add("description", "MySQL Role provider"); - } - base.Initialize(name, config); - - string applicationName = HostingEnvironment.ApplicationVirtualPath; - if (!String.IsNullOrEmpty(config["applicationName"])) - applicationName = config["applicationName"]; - - if (!(config["writeExceptionsToEventLog"] == null)) - { - if (config["writeExceptionsToEventLog"].ToUpper() == "TRUE") - { - pWriteExceptionsToEventLog = true; - } - } - - connectionString = ConfigUtility.GetConnectionString(config); - if (String.IsNullOrEmpty(connectionString)) return; - - // make sure our schema is up to date - SchemaManager.CheckSchema(connectionString, config); - - app = new Application(applicationName, Description); - } - - #region Properties - - /// - /// Gets or sets the name of the application to store and retrieve role information for. - /// - /// The name of the application to store and retrieve role information for. - /// - /// - /// roleManager defaultProvider = "MySqlProvider" - /// enabled="true"> - /// providers> - /// add - /// name = "MySqlProvider" - /// type="MySql.Web.Security.MySQLRoleProvider" - /// connectionStringName="LocalMySqlServices" - /// writeExceptionsToEventLog="false" - /// applicationName="MyApplication" /> - /// /providers> - /// roleManager> - /// - /// - public override string ApplicationName - { - get { return app.Name; } - set { app.Name = value; } - } - - /// - /// Gets or sets a value indicating whether exceptions should be written to the event log. - /// - /// - /// true if exceptions should be written to the event log; otherwise, false. - /// - /// - /// - /// roleManager defaultProvider = "MySqlProvider" - /// enabled="true"> - /// providers> - /// add - /// name = "MySqlProvider" - /// type="MySql.Web.Security.MySQLRoleProvider" - /// connectionStringName="LocalMySqlServices" - /// writeExceptionsToEventLog="false" - /// applicationName="MyApplication" /> - /// /providers> - /// roleManager> - /// - /// - public bool WriteExceptionsToEventLog - { - get { return pWriteExceptionsToEventLog; } - set { pWriteExceptionsToEventLog = value; } - } - - #endregion - - #region Public Methods - - /// - /// Adds the users to the specified roles. - /// - /// The user names. - /// The role names. - public override void AddUsersToRoles(string[] usernames, string[] rolenames) - { - if (rolenames == null || rolenames.Length == 0) return; - if (usernames == null || usernames.Length == 0) return; - - foreach (string rolename in rolenames) - { - if (String.IsNullOrEmpty(rolename)) - throw new ArgumentException(Properties.Resources.IllegalRoleName, "rolenames"); - if (!RoleExists(rolename)) - throw new ProviderException(Properties.Resources.RoleNameNotFound); - } - - foreach (string username in usernames) - { - if (String.IsNullOrEmpty(username)) - throw new ArgumentException(Properties.Resources.IllegalUserName, "usernames"); - if (username.IndexOf(',') != -1) - throw new ArgumentException(Properties.Resources.InvalidCharactersInUserName); - - foreach (string rolename in rolenames) - { - if (IsUserInRole(username, rolename)) - throw new ProviderException(Properties.Resources.UserIsAlreadyInRole); - } - } - - using (MySqlConnection connection = new MySqlConnection(connectionString)) - { - MySqlTransaction txn = null; - try - { - connection.Open(); - txn = connection.BeginTransaction(); - MySqlCommand cmd = new MySqlCommand( - "INSERT INTO my_aspnet_usersinroles VALUES(@userId, @roleId)", connection); - cmd.Parameters.Add("@userId", MySqlDbType.Int32); - cmd.Parameters.Add("@roleId", MySqlDbType.Int32); - foreach (string username in usernames) - { - // either create a new user or fetch the existing user id - long userId = SchemaManager.CreateOrFetchUserId(connection, - username, app.FetchId(connection), true); - foreach (string rolename in rolenames) - { - int roleId = GetRoleId(connection, rolename); - cmd.Parameters[0].Value = userId; - cmd.Parameters[1].Value = roleId; - cmd.ExecuteNonQuery(); - } - } - txn.Commit(); - } - catch (Exception ex) - { - if (txn != null) - txn.Rollback(); - if (WriteExceptionsToEventLog) - WriteToEventLog(ex, "AddUsersToRoles"); - throw; - } - } - } - - /// - /// Creates the specified role. - /// - /// The role name. - public override void CreateRole(string rolename) - { - if (rolename.IndexOf(',') != -1) - throw new ArgumentException(Properties.Resources.InvalidCharactersInUserName); - if (RoleExists(rolename)) - throw new ProviderException(Properties.Resources.RoleNameAlreadyExists); - - using (MySqlConnection connection = new MySqlConnection(connectionString)) - { - try - { - connection.Open(); - - MySqlCommand cmd = new MySqlCommand( - @"INSERT INTO my_aspnet_roles Values(NULL, @appId, @name)", connection); - cmd.Parameters.AddWithValue("@appId", app.EnsureId(connection)); - cmd.Parameters.AddWithValue("@name", rolename); - cmd.ExecuteNonQuery(); - } - catch (MySqlException e) - { - if (WriteExceptionsToEventLog) - WriteToEventLog(e, "CreateRole"); - throw; - } - } - } - - /// - /// Deletes the specified role. - /// - /// The role name. - /// If set to true a will be raised if - /// there are users with the specified role. - /// true if the role was successfully deleted; otherwise, false. - /// The specified role doesn't exist or - /// is set to true and there are users with the specified role. - public override bool DeleteRole(string rolename, bool throwOnPopulatedRole) - { - using (MySqlConnection connection = new MySqlConnection(connectionString)) - { - MySqlTransaction txn = null; - try - { - if (!(RoleExists(rolename))) - throw new ProviderException(Properties.Resources.RoleNameNotFound); - if (throwOnPopulatedRole && GetUsersInRole(rolename).Length > 0) - throw new ProviderException(Properties.Resources.CannotDeleteAPopulatedRole); - - connection.Open(); - txn = connection.BeginTransaction(); - - // first delete all the user/role mappings with that roleid - MySqlCommand cmd = new MySqlCommand( - @"DELETE uir FROM my_aspnet_usersinroles uir JOIN - my_aspnet_roles r ON uir.roleId=r.id - WHERE r.name LIKE @rolename AND r.applicationId=@appId", connection); - cmd.Parameters.AddWithValue("@rolename", rolename); - cmd.Parameters.AddWithValue("@appId", app.FetchId(connection)); - cmd.ExecuteNonQuery(); - - // now delete the role itself - cmd.CommandText = @"DELETE FROM my_aspnet_roles WHERE name=@rolename - AND applicationId=@appId"; - cmd.ExecuteNonQuery(); - txn.Commit(); - } - catch (Exception ex) - { - if (txn != null) - txn.Rollback(); - if (WriteExceptionsToEventLog) - WriteToEventLog(ex, "DeleteRole"); - throw; - } - } - return true; - } - - /// - /// Gets a list of all the roles for the configured applicationName. - /// - /// - /// A string array containing the names of all the roles stored in the data source for the configured applicationName. - /// - public override string[] GetAllRoles() - { - using (MySqlConnection connection = new MySqlConnection(connectionString)) - { - connection.Open(); - return GetRolesByUserName(connection, null); - } - } - - /// - /// Gets a list of the roles that a specified user is in for the configured applicationName. - /// - /// The user to return a list of roles for. - /// - /// A string array containing the names of all the roles that the specified user is in for the configured applicationName. - /// - public override string[] GetRolesForUser(string username) - { - using (MySqlConnection connection = new MySqlConnection(connectionString)) - { - connection.Open(); - return GetRolesByUserName(connection, username); - } - } - - /// - /// Gets the users with the specified role. - /// - /// The role name. - /// A string array containing the names of all the users - /// who are members of the specified role. - public override string[] GetUsersInRole(string rolename) - { - List users = new List(); - - try - { - using (MySqlConnection connection = new MySqlConnection(connectionString)) - { - connection.Open(); - int roleId = GetRoleId(connection, rolename); - - string sql = @"SELECT u.name FROM my_aspnet_users u JOIN - my_aspnet_usersinroles uir ON uir.userId=u.id AND uir.roleId=@roleId - WHERE u.applicationId=@appId"; - MySqlCommand cmd = new MySqlCommand(sql, connection); - cmd.Parameters.AddWithValue("@roleId", roleId); - cmd.Parameters.AddWithValue("@appId", app.FetchId(connection)); - using (MySqlDataReader reader = cmd.ExecuteReader()) - { - while (reader.Read()) - users.Add(reader.GetString(0)); - } - } - return users.ToArray(); - } - catch (Exception ex) - { - if (WriteExceptionsToEventLog) - WriteToEventLog(ex, "GetUsersInRole"); - throw; - } - } - - /// - /// Determines whether [is user in role] [the specified username]. - /// - /// The username. - /// The rolename. - /// - /// true if [is user in role] [the specified username]; otherwise, false. - /// - public override bool IsUserInRole(string username, string rolename) - { - try - { - // this will refresh the app id if necessary - if (!RoleExists(rolename)) return false; - - using (MySqlConnection connection = new MySqlConnection(connectionString)) - { - connection.Open(); - - string sql = @"SELECT COUNT(*) FROM my_aspnet_usersinroles uir - JOIN my_aspnet_users u ON uir.userId=u.id - JOIN my_aspnet_roles r ON uir.roleId=r.id - WHERE u.applicationId=@appId AND - u.name = @userName AND r.name = @roleName"; - MySqlCommand cmd = new MySqlCommand(sql, connection); - cmd.Parameters.AddWithValue("@appId", app.FetchId(connection)); - cmd.Parameters.AddWithValue("@userName", username); - cmd.Parameters.AddWithValue("@roleName", rolename); - int count = Convert.ToInt32(cmd.ExecuteScalar()); - return count > 0; - } - } - catch (Exception ex) - { - if (WriteExceptionsToEventLog) - WriteToEventLog(ex, "IsUserInRole"); - throw; - } - } - - /// - /// Removes the users from the specified roles. - /// - /// The user names. - /// The role names. - public override void RemoveUsersFromRoles(string[] usernames, string[] rolenames) - { - if (rolenames == null || rolenames.Length == 0) return; - if (usernames == null || usernames.Length == 0) return; - - foreach (string rolename in rolenames) - { - if (!(RoleExists(rolename))) - throw new ProviderException(Properties.Resources.RoleNameNotFound); - } - - foreach (string username in usernames) - { - foreach (string rolename in rolenames) - { - if (!(IsUserInRole(username, rolename))) - throw new ProviderException(Properties.Resources.UserNotInRole); - } - } - - using (MySqlConnection connection = new MySqlConnection(connectionString)) - { - MySqlTransaction txn = null; - try - { - connection.Open(); - txn = connection.BeginTransaction(); - - string sql = @"DELETE uir FROM my_aspnet_usersinroles uir - JOIN my_aspnet_users u ON uir.userId=u.id - JOIN my_aspnet_roles r ON uir.roleId=r.id - WHERE u.name LIKE @username AND r.name LIKE @rolename - AND u.applicationId=@appId AND r.applicationId=@appId"; - - MySqlCommand cmd = new MySqlCommand(sql, connection); - cmd.Parameters.Add("@username", MySqlDbType.VarChar, 255); - cmd.Parameters.Add("@rolename", MySqlDbType.VarChar, 255); - cmd.Parameters.AddWithValue("@appId", app.FetchId(connection)); - - foreach (string username in usernames) - { - foreach (string rolename in rolenames) - { - cmd.Parameters[0].Value = username; - cmd.Parameters[1].Value = rolename; - cmd.ExecuteNonQuery(); - } - } - txn.Commit(); - } - catch (MySqlException e) - { - if (txn != null) - txn.Rollback(); - if (WriteExceptionsToEventLog) - WriteToEventLog(e, "RemoveUsersFromRoles"); - throw; - } - } - } - - /// - /// Determines whether the role exists. - /// - /// The rolename. - /// true if the role name already exists in the database; otherwise, false. - public override bool RoleExists(string rolename) - { - try - { - using (MySqlConnection connection = new MySqlConnection(connectionString)) - { - connection.Open(); - MySqlCommand cmd = new MySqlCommand( - @"SELECT COUNT(*) FROM my_aspnet_roles WHERE applicationId=@appId - AND name LIKE @name", connection); - cmd.Parameters.AddWithValue("@appId", app.FetchId(connection)); - cmd.Parameters.AddWithValue("@name", rolename); - int count = Convert.ToInt32(cmd.ExecuteScalar()); - return count != 0; - } - } - catch (Exception ex) - { - if (WriteExceptionsToEventLog) - WriteToEventLog(ex, "RoleExists"); - throw; - } - } - - /// - /// Finds the users with the specified role. - /// - /// The role name. - /// The user name to match. - /// A string array containing the names of all the users where the - /// user name matches usernameToMatch and the user is a member of the specified role. - public override string[] FindUsersInRole(string rolename, string usernameToMatch) - { - if (!RoleExists(rolename)) - throw new ProviderException(Properties.Resources.RoleNameNotFound); - - List users = new List(); - - try - { - using (MySqlConnection connection = new MySqlConnection(connectionString)) - { - connection.Open(); - - string sql = @"SELECT u.name FROM my_aspnet_usersinroles uir - JOIN my_aspnet_users u ON uir.userId=u.id - JOIN my_aspnet_roles r ON uir.roleId=r.id - WHERE r.name LIKE @rolename AND - u.name LIKE @username AND - u.applicationId=@appId"; - - MySqlCommand cmd = new MySqlCommand(sql, connection); - cmd.Parameters.AddWithValue("@username", usernameToMatch); - cmd.Parameters.AddWithValue("@rolename", rolename); - cmd.Parameters.AddWithValue("@appId", app.FetchId(connection)); - using (MySqlDataReader reader = cmd.ExecuteReader()) - { - while (reader.Read()) - users.Add(reader.GetString(0)); - } - } - return users.ToArray(); - } - catch (MySqlException e) - { - if (WriteExceptionsToEventLog) - WriteToEventLog(e, "FindUsersInRole"); - throw; - } - } - - #endregion - - internal static void DeleteUserData(MySqlConnection connection, int userId) - { - MySqlCommand cmd = new MySqlCommand( - "DELETE FROM my_aspnet_usersinroles WHERE userId=@userId", connection); - cmd.Parameters.AddWithValue("@userId", userId); - cmd.ExecuteNonQuery(); - } - - #region Private Methods - - private string[] GetRolesByUserName(MySqlConnection connection, string username) - { - List roleList = new List(); - - try - { - string sql = "SELECT r.name FROM my_aspnet_roles r "; - if (username != null) - sql += "JOIN my_aspnet_usersinroles uir ON uir.roleId=r.id AND uir.userId=" + - GetUserId(connection, username); - sql += " WHERE r.applicationId=@appId"; - MySqlCommand cmd = new MySqlCommand(sql, connection); - cmd.Parameters.AddWithValue("@appId", app.FetchId(connection)); - using (MySqlDataReader reader = cmd.ExecuteReader()) - { - while (reader.Read()) - roleList.Add(reader.GetString(0)); - } - return (string[])roleList.ToArray(); - } - catch (Exception ex) - { - if (WriteExceptionsToEventLog) - WriteToEventLog(ex, "GetRolesByUserName"); - throw; - } - } - - private int GetUserId(MySqlConnection connection, string username) - { - MySqlCommand cmd = new MySqlCommand( - "SELECT id FROM my_aspnet_users WHERE name=@name AND applicationId=@appId", - connection); - cmd.Parameters.AddWithValue("@name", username); - cmd.Parameters.AddWithValue("@appId", app.FetchId(connection)); - object id = cmd.ExecuteScalar(); - return Convert.ToInt32(id); - } - - private int GetRoleId(MySqlConnection connection, string rolename) - { - MySqlCommand cmd = new MySqlCommand( - "SELECT id FROM my_aspnet_roles WHERE name=@name AND applicationId=@appId", - connection); - cmd.Parameters.AddWithValue("@name", rolename); - cmd.Parameters.AddWithValue("@appId", app.FetchId(connection)); - return (int)cmd.ExecuteScalar(); - } - - private void WriteToEventLog(Exception e, string action) - { - using (EventLog log = new EventLog()) - { - log.Source = eventSource; - log.Log = eventLog; - string message = exceptionMessage + Environment.NewLine + Environment.NewLine; - message += "Action: " + action + Environment.NewLine + Environment.NewLine; - message += "Exception: " + e; - log.WriteEntry(message); - } - } - - #endregion - - } -} \ No newline at end of file +// Copyright © 2004, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +// This code was contributed by Sean Wright (srwright@alcor.concordia.ca) on 2007-01-12 +// The copyright was assigned and transferred under the terms of +// the MySQL Contributor License Agreement (CLA) + +using MySql.Data.MySqlClient; +using MySql.Web.Common; +using MySql.Web.General; +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Configuration.Provider; +using System.Diagnostics; +using System.Web.Hosting; +using System.Web.Security; + +namespace MySql.Web.Security +{ + /// + /// Manages storage of role membership information for an ASP.NET application in a MySQL database. + /// + public sealed class MySQLRoleProvider : RoleProvider + { + private string eventSource = "MySQLRoleProvider"; + private string eventLog = "Application"; + private string exceptionMessage = "An exception occurred. Please check the Event Log."; + private string connectionString; + private bool pWriteExceptionsToEventLog = false; + private Application app; + + /// + /// Initializes the provider. + /// + /// The friendly name of the provider. + /// A collection of the name/value pairs representing the provider-specific attributes specified in the configuration for this provider. + /// The name of the provider is null. + /// The name of the provider has a length of zero. + /// An attempt is made to call on a provider after the provider has already been initialized. + public override void Initialize(string name, NameValueCollection config) + { + if (config == null) + { + throw new ArgumentNullException("config"); + } + if (name == null || name.Length == 0) + { + name = "MySQLRoleProvider"; + } + if (string.IsNullOrEmpty(config["description"])) + { + config.Remove("description"); + config.Add("description", "MySQL Role provider"); + } + base.Initialize(name, config); + + string applicationName = HostingEnvironment.ApplicationVirtualPath; + if (!String.IsNullOrEmpty(config["applicationName"])) + applicationName = config["applicationName"]; + + if (!(config["writeExceptionsToEventLog"] == null)) + { + if (config["writeExceptionsToEventLog"].ToUpper() == "TRUE") + { + pWriteExceptionsToEventLog = true; + } + } + + connectionString = ConfigUtility.GetConnectionString(config); + if (String.IsNullOrEmpty(connectionString)) return; + + // make sure our schema is up to date + SchemaManager.CheckSchema(connectionString, config); + + app = new Application(applicationName, Description); + } + + #region Properties + + /// + /// Gets or sets the name of the application to store and retrieve role information for. + /// + /// The name of the application to store and retrieve role information for. + /// + /// + /// roleManager defaultProvider = "MySqlProvider" + /// enabled="true"> + /// providers> + /// add + /// name = "MySqlProvider" + /// type="MySql.Web.Security.MySQLRoleProvider" + /// connectionStringName="LocalMySqlServices" + /// writeExceptionsToEventLog="false" + /// applicationName="MyApplication" /> + /// /providers> + /// roleManager> + /// + /// + public override string ApplicationName + { + get { return app.Name; } + set { app.Name = value; } + } + + /// + /// Gets or sets a value indicating whether exceptions should be written to the event log. + /// + /// + /// true if exceptions should be written to the event log; otherwise, false. + /// + /// + /// + /// roleManager defaultProvider = "MySqlProvider" + /// enabled="true"> + /// providers> + /// add + /// name = "MySqlProvider" + /// type="MySql.Web.Security.MySQLRoleProvider" + /// connectionStringName="LocalMySqlServices" + /// writeExceptionsToEventLog="false" + /// applicationName="MyApplication" /> + /// /providers> + /// roleManager> + /// + /// + public bool WriteExceptionsToEventLog + { + get { return pWriteExceptionsToEventLog; } + set { pWriteExceptionsToEventLog = value; } + } + + #endregion + + #region Public Methods + + /// + /// Adds the users to the specified roles. + /// + /// The user names. + /// The role names. + public override void AddUsersToRoles(string[] usernames, string[] rolenames) + { + if (rolenames == null || rolenames.Length == 0) return; + if (usernames == null || usernames.Length == 0) return; + + foreach (string rolename in rolenames) + { + if (String.IsNullOrEmpty(rolename)) + throw new ArgumentException(Properties.Resources.IllegalRoleName, "rolenames"); + if (!RoleExists(rolename)) + throw new ProviderException(Properties.Resources.RoleNameNotFound); + } + + foreach (string username in usernames) + { + if (String.IsNullOrEmpty(username)) + throw new ArgumentException(Properties.Resources.IllegalUserName, "usernames"); + if (username.IndexOf(',') != -1) + throw new ArgumentException(Properties.Resources.InvalidCharactersInUserName); + + foreach (string rolename in rolenames) + { + if (IsUserInRole(username, rolename)) + throw new ProviderException(Properties.Resources.UserIsAlreadyInRole); + } + } + + using (MySqlConnection connection = new MySqlConnection(connectionString)) + { + MySqlTransaction txn = null; + try + { + connection.Open(); + txn = connection.BeginTransaction(); + MySqlCommand cmd = new MySqlCommand( + "INSERT INTO my_aspnet_usersinroles VALUES(@userId, @roleId)", connection); + cmd.Parameters.Add("@userId", MySqlDbType.Int32); + cmd.Parameters.Add("@roleId", MySqlDbType.Int32); + foreach (string username in usernames) + { + // either create a new user or fetch the existing user id + long userId = SchemaManager.CreateOrFetchUserId(connection, + username, app.FetchId(connection), true); + foreach (string rolename in rolenames) + { + int roleId = GetRoleId(connection, rolename); + cmd.Parameters[0].Value = userId; + cmd.Parameters[1].Value = roleId; + cmd.ExecuteNonQuery(); + } + } + txn.Commit(); + } + catch (Exception ex) + { + if (txn != null) + txn.Rollback(); + if (WriteExceptionsToEventLog) + WriteToEventLog(ex, "AddUsersToRoles"); + throw; + } + } + } + + /// + /// Creates the specified role. + /// + /// The role name. + public override void CreateRole(string rolename) + { + if (rolename.IndexOf(',') != -1) + throw new ArgumentException(Properties.Resources.InvalidCharactersInUserName); + if (RoleExists(rolename)) + throw new ProviderException(Properties.Resources.RoleNameAlreadyExists); + + using (MySqlConnection connection = new MySqlConnection(connectionString)) + { + try + { + connection.Open(); + + MySqlCommand cmd = new MySqlCommand( + @"INSERT INTO my_aspnet_roles Values(NULL, @appId, @name)", connection); + cmd.Parameters.AddWithValue("@appId", app.EnsureId(connection)); + cmd.Parameters.AddWithValue("@name", rolename); + cmd.ExecuteNonQuery(); + } + catch (MySqlException e) + { + if (WriteExceptionsToEventLog) + WriteToEventLog(e, "CreateRole"); + throw; + } + } + } + + /// + /// Deletes the specified role. + /// + /// The role name. + /// If set to true a will be raised if + /// there are users with the specified role. + /// true if the role was successfully deleted; otherwise, false. + /// The specified role doesn't exist or + /// is set to true and there are users with the specified role. + public override bool DeleteRole(string rolename, bool throwOnPopulatedRole) + { + using (MySqlConnection connection = new MySqlConnection(connectionString)) + { + MySqlTransaction txn = null; + try + { + if (!(RoleExists(rolename))) + throw new ProviderException(Properties.Resources.RoleNameNotFound); + if (throwOnPopulatedRole && GetUsersInRole(rolename).Length > 0) + throw new ProviderException(Properties.Resources.CannotDeleteAPopulatedRole); + + connection.Open(); + txn = connection.BeginTransaction(); + + // first delete all the user/role mappings with that roleid + MySqlCommand cmd = new MySqlCommand( + @"DELETE uir FROM my_aspnet_usersinroles uir JOIN + my_aspnet_roles r ON uir.roleId=r.id + WHERE r.name LIKE @rolename AND r.applicationId=@appId", connection); + cmd.Parameters.AddWithValue("@rolename", rolename); + cmd.Parameters.AddWithValue("@appId", app.FetchId(connection)); + cmd.ExecuteNonQuery(); + + // now delete the role itself + cmd.CommandText = @"DELETE FROM my_aspnet_roles WHERE name=@rolename + AND applicationId=@appId"; + cmd.ExecuteNonQuery(); + txn.Commit(); + } + catch (Exception ex) + { + if (txn != null) + txn.Rollback(); + if (WriteExceptionsToEventLog) + WriteToEventLog(ex, "DeleteRole"); + throw; + } + } + return true; + } + + /// + /// Gets a list of all the roles for the configured applicationName. + /// + /// + /// A string array containing the names of all the roles stored in the data source for the configured applicationName. + /// + public override string[] GetAllRoles() + { + using (MySqlConnection connection = new MySqlConnection(connectionString)) + { + connection.Open(); + return GetRolesByUserName(connection, null); + } + } + + /// + /// Gets a list of the roles that a specified user is in for the configured applicationName. + /// + /// The user to return a list of roles for. + /// + /// A string array containing the names of all the roles that the specified user is in for the configured applicationName. + /// + public override string[] GetRolesForUser(string username) + { + using (MySqlConnection connection = new MySqlConnection(connectionString)) + { + connection.Open(); + return GetRolesByUserName(connection, username); + } + } + + /// + /// Gets the users with the specified role. + /// + /// The role name. + /// A string array containing the names of all the users + /// who are members of the specified role. + public override string[] GetUsersInRole(string rolename) + { + List users = new List(); + + try + { + using (MySqlConnection connection = new MySqlConnection(connectionString)) + { + connection.Open(); + int roleId = GetRoleId(connection, rolename); + + string sql = @"SELECT u.name FROM my_aspnet_users u JOIN + my_aspnet_usersinroles uir ON uir.userId=u.id AND uir.roleId=@roleId + WHERE u.applicationId=@appId"; + MySqlCommand cmd = new MySqlCommand(sql, connection); + cmd.Parameters.AddWithValue("@roleId", roleId); + cmd.Parameters.AddWithValue("@appId", app.FetchId(connection)); + using (MySqlDataReader reader = cmd.ExecuteReader()) + { + while (reader.Read()) + users.Add(reader.GetString(0)); + } + } + return users.ToArray(); + } + catch (Exception ex) + { + if (WriteExceptionsToEventLog) + WriteToEventLog(ex, "GetUsersInRole"); + throw; + } + } + + /// + /// Determines whether [is user in role] [the specified username]. + /// + /// The username. + /// The rolename. + /// + /// true if [is user in role] [the specified username]; otherwise, false. + /// + public override bool IsUserInRole(string username, string rolename) + { + try + { + // this will refresh the app id if necessary + if (!RoleExists(rolename)) return false; + + using (MySqlConnection connection = new MySqlConnection(connectionString)) + { + connection.Open(); + + string sql = @"SELECT COUNT(*) FROM my_aspnet_usersinroles uir + JOIN my_aspnet_users u ON uir.userId=u.id + JOIN my_aspnet_roles r ON uir.roleId=r.id + WHERE u.applicationId=@appId AND + u.name = @userName AND r.name = @roleName"; + MySqlCommand cmd = new MySqlCommand(sql, connection); + cmd.Parameters.AddWithValue("@appId", app.FetchId(connection)); + cmd.Parameters.AddWithValue("@userName", username); + cmd.Parameters.AddWithValue("@roleName", rolename); + int count = Convert.ToInt32(cmd.ExecuteScalar()); + return count > 0; + } + } + catch (Exception ex) + { + if (WriteExceptionsToEventLog) + WriteToEventLog(ex, "IsUserInRole"); + throw; + } + } + + /// + /// Removes the users from the specified roles. + /// + /// The user names. + /// The role names. + public override void RemoveUsersFromRoles(string[] usernames, string[] rolenames) + { + if (rolenames == null || rolenames.Length == 0) return; + if (usernames == null || usernames.Length == 0) return; + + foreach (string rolename in rolenames) + { + if (!(RoleExists(rolename))) + throw new ProviderException(Properties.Resources.RoleNameNotFound); + } + + foreach (string username in usernames) + { + foreach (string rolename in rolenames) + { + if (!(IsUserInRole(username, rolename))) + throw new ProviderException(Properties.Resources.UserNotInRole); + } + } + + using (MySqlConnection connection = new MySqlConnection(connectionString)) + { + MySqlTransaction txn = null; + try + { + connection.Open(); + txn = connection.BeginTransaction(); + + string sql = @"DELETE uir FROM my_aspnet_usersinroles uir + JOIN my_aspnet_users u ON uir.userId=u.id + JOIN my_aspnet_roles r ON uir.roleId=r.id + WHERE u.name LIKE @username AND r.name LIKE @rolename + AND u.applicationId=@appId AND r.applicationId=@appId"; + + MySqlCommand cmd = new MySqlCommand(sql, connection); + cmd.Parameters.Add("@username", MySqlDbType.VarChar, 255); + cmd.Parameters.Add("@rolename", MySqlDbType.VarChar, 255); + cmd.Parameters.AddWithValue("@appId", app.FetchId(connection)); + + foreach (string username in usernames) + { + foreach (string rolename in rolenames) + { + cmd.Parameters[0].Value = username; + cmd.Parameters[1].Value = rolename; + cmd.ExecuteNonQuery(); + } + } + txn.Commit(); + } + catch (MySqlException e) + { + if (txn != null) + txn.Rollback(); + if (WriteExceptionsToEventLog) + WriteToEventLog(e, "RemoveUsersFromRoles"); + throw; + } + } + } + + /// + /// Determines whether the role exists. + /// + /// The rolename. + /// true if the role name already exists in the database; otherwise, false. + public override bool RoleExists(string rolename) + { + try + { + using (MySqlConnection connection = new MySqlConnection(connectionString)) + { + connection.Open(); + MySqlCommand cmd = new MySqlCommand( + @"SELECT COUNT(*) FROM my_aspnet_roles WHERE applicationId=@appId + AND name LIKE @name", connection); + cmd.Parameters.AddWithValue("@appId", app.FetchId(connection)); + cmd.Parameters.AddWithValue("@name", rolename); + int count = Convert.ToInt32(cmd.ExecuteScalar()); + return count != 0; + } + } + catch (Exception ex) + { + if (WriteExceptionsToEventLog) + WriteToEventLog(ex, "RoleExists"); + throw; + } + } + + /// + /// Finds the users with the specified role. + /// + /// The role name. + /// The user name to match. + /// A string array containing the names of all the users where the + /// user name matches usernameToMatch and the user is a member of the specified role. + public override string[] FindUsersInRole(string rolename, string usernameToMatch) + { + if (!RoleExists(rolename)) + throw new ProviderException(Properties.Resources.RoleNameNotFound); + + List users = new List(); + + try + { + using (MySqlConnection connection = new MySqlConnection(connectionString)) + { + connection.Open(); + + string sql = @"SELECT u.name FROM my_aspnet_usersinroles uir + JOIN my_aspnet_users u ON uir.userId=u.id + JOIN my_aspnet_roles r ON uir.roleId=r.id + WHERE r.name LIKE @rolename AND + u.name LIKE @username AND + u.applicationId=@appId"; + + MySqlCommand cmd = new MySqlCommand(sql, connection); + cmd.Parameters.AddWithValue("@username", usernameToMatch); + cmd.Parameters.AddWithValue("@rolename", rolename); + cmd.Parameters.AddWithValue("@appId", app.FetchId(connection)); + using (MySqlDataReader reader = cmd.ExecuteReader()) + { + while (reader.Read()) + users.Add(reader.GetString(0)); + } + } + return users.ToArray(); + } + catch (MySqlException e) + { + if (WriteExceptionsToEventLog) + WriteToEventLog(e, "FindUsersInRole"); + throw; + } + } + + #endregion + + internal static void DeleteUserData(MySqlConnection connection, int userId) + { + MySqlCommand cmd = new MySqlCommand( + "DELETE FROM my_aspnet_usersinroles WHERE userId=@userId", connection); + cmd.Parameters.AddWithValue("@userId", userId); + cmd.ExecuteNonQuery(); + } + + #region Private Methods + + private string[] GetRolesByUserName(MySqlConnection connection, string username) + { + List roleList = new List(); + + try + { + string sql = "SELECT r.name FROM my_aspnet_roles r "; + if (username != null) + sql += "JOIN my_aspnet_usersinroles uir ON uir.roleId=r.id AND uir.userId=" + + GetUserId(connection, username); + sql += " WHERE r.applicationId=@appId"; + MySqlCommand cmd = new MySqlCommand(sql, connection); + cmd.Parameters.AddWithValue("@appId", app.FetchId(connection)); + using (MySqlDataReader reader = cmd.ExecuteReader()) + { + while (reader.Read()) + roleList.Add(reader.GetString(0)); + } + return (string[])roleList.ToArray(); + } + catch (Exception ex) + { + if (WriteExceptionsToEventLog) + WriteToEventLog(ex, "GetRolesByUserName"); + throw; + } + } + + private int GetUserId(MySqlConnection connection, string username) + { + MySqlCommand cmd = new MySqlCommand( + "SELECT id FROM my_aspnet_users WHERE name=@name AND applicationId=@appId", + connection); + cmd.Parameters.AddWithValue("@name", username); + cmd.Parameters.AddWithValue("@appId", app.FetchId(connection)); + object id = cmd.ExecuteScalar(); + return Convert.ToInt32(id); + } + + private int GetRoleId(MySqlConnection connection, string rolename) + { + MySqlCommand cmd = new MySqlCommand( + "SELECT id FROM my_aspnet_roles WHERE name=@name AND applicationId=@appId", + connection); + cmd.Parameters.AddWithValue("@name", rolename); + cmd.Parameters.AddWithValue("@appId", app.FetchId(connection)); + return (int)cmd.ExecuteScalar(); + } + + private void WriteToEventLog(Exception e, string action) + { + using (EventLog log = new EventLog()) + { + log.Source = eventSource; + log.Log = eventLog; + string message = exceptionMessage + Environment.NewLine + Environment.NewLine; + message += "Action: " + action + Environment.NewLine + Environment.NewLine; + message += "Exception: " + e; + log.WriteEntry(message); + } + } + + #endregion + + } +} diff --git a/MySql.Web/src/Runtime.cs b/MySql.Web/src/Runtime.cs index 8d2a2d337..78214fe94 100644 --- a/MySql.Web/src/Runtime.cs +++ b/MySql.Web/src/Runtime.cs @@ -1,59 +1,59 @@ -// Copyright (c) 2004, 2020, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -// This code was contributed by Sean Wright (srwright@alcor.concordia.ca) on 2007-01-12 -// The copyright was assigned and transferred under the terms of -// the MySQL Contributor License Agreement (CLA) - -using System; - -namespace MySql.Web.Security -{ - internal static class Runtime - { - private static bool inited; - private static bool isMono; - - public static bool IsMono - { - get - { - if (!inited) - Init(); - return isMono; - } - } - - private static void Init() - { - inited = true; - Type t = Type.GetType("Mono.Runtime"); - isMono = t != null; - } - } -} +// Copyright © 2004, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +// This code was contributed by Sean Wright (srwright@alcor.concordia.ca) on 2007-01-12 +// The copyright was assigned and transferred under the terms of +// the MySQL Contributor License Agreement (CLA) + +using System; + +namespace MySql.Web.Security +{ + internal static class Runtime + { + private static bool inited; + private static bool isMono; + + public static bool IsMono + { + get + { + if (!inited) + Init(); + return isMono; + } + } + + private static void Init() + { + inited = true; + Type t = Type.GetType("Mono.Runtime"); + isMono = t != null; + } + } +} diff --git a/MySql.Web/src/SchemaManager.cs b/MySql.Web/src/SchemaManager.cs index ece9c2f1a..ed0632e3c 100644 --- a/MySql.Web/src/SchemaManager.cs +++ b/MySql.Web/src/SchemaManager.cs @@ -1,191 +1,191 @@ -// Copyright (c) 2004, 2020, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -// This code was contributed by Sean Wright (srwright@alcor.concordia.ca) on 2007-01-12 -// The copyright was assigned and transferred under the terms of -// the MySQL Contributor License Agreement (CLA) - -using MySql.Data.MySqlClient; -using System; -using System.Collections.Specialized; -using System.Configuration.Provider; -using System.Data; -using System.Diagnostics; -using System.IO; -using System.Reflection; -using System.Text; - -namespace MySql.Web.Common -{ - /// - /// Provided methods that allow managing a database. - /// - public static class SchemaManager - { - private const int schemaVersion = 10; - - /// - /// Gets the most recent version of the schema. - /// - /// The most recent version number of the schema. - public static int Version - { - get { return schemaVersion; } - } - - internal static void CheckSchema(string connectionString, NameValueCollection config) - { - int ver = GetSchemaVersion(connectionString); - if (ver == Version) return; - - try - { - if (String.Compare(config["autogenerateschema"], "true", true) == 0) - UpgradeToCurrent(connectionString, ver); - else - throw new ProviderException(Properties.Resources.MissingOrWrongSchema); - - } - catch (Exception ex) - { - throw new ProviderException(Properties.Resources.MissingOrWrongSchema, ex); - } - } - - internal static string GetSchema(int version) - { - var assembly = Assembly.GetExecutingAssembly(); - using (Stream stream = assembly.GetManifestResourceStream($"MySql.Web.Properties.schema{version}.sql")) - using (StreamReader reader = new StreamReader(stream)) - return reader.ReadToEnd(); - } - - private static void UpgradeToCurrent(string connectionString, int version) - { - if (version == Version) return; - - using (MySqlConnection connection = new MySqlConnection(connectionString)) - { - connection.Open(); - - for (int ver = version + 1; ver <= Version; ver++) - { - string schema = GetSchema(ver); - MySqlScript script = new MySqlScript(connection); - script.Query = schema; - - try - { - script.Execute(); - } - catch (MySqlException ex) - { - if (ex.Number == 1050 && ver == 7) - { - // Schema7 performs several renames of tables to their lowercase representation. - // If the current server OS does not support renaming to lowercase, then let's just continue. - script.Query = "UPDATE my_aspnet_schemaversion SET version=7"; - script.Execute(); - continue; - } - throw ex; - } - } - } - } - - private static int GetSchemaVersion(string connectionString) - { - // retrieve the current schema version - using (MySqlConnection conn = new MySqlConnection(connectionString)) - { - conn.Open(); - - MySqlCommand cmd = new MySqlCommand("SELECT * FROM my_aspnet_schemaversion", conn); - try - { - object ver = cmd.ExecuteScalar(); - if (ver != null) - return (int)ver; - } - catch (MySqlException ex) - { - if (ex.Number != (int)MySqlErrorCode.NoSuchTable) - throw; - string[] restrictions = new string[4]; - restrictions[2] = "mysql_membership"; - DataTable dt = conn.GetSchema("Tables", restrictions); - if (dt.Rows.Count == 1) - { - var value = dt.Rows[0]["TABLE_COMMENT"]; - if (value is Byte[]) - { - Byte[] byteArray = value as Byte[]; - return Convert.ToInt32(Encoding.UTF8.GetString(byteArray, 0, byteArray.Length)); - } - else - return Convert.ToInt32(value); - } - } - return 0; - } - } - - /// - /// Creates the or fetch user id. - /// - /// The connection. - /// The username. - /// The application id. - /// if set to true [authenticated]. - /// - internal static long CreateOrFetchUserId(MySqlConnection connection, string username, - long applicationId, bool authenticated) - { - Debug.Assert(applicationId > 0); - - // first attempt to fetch an existing user id - MySqlCommand cmd = new MySqlCommand(@"SELECT id FROM my_aspnet_users - WHERE applicationId = @appId AND name = @name", connection); - cmd.Parameters.AddWithValue("@appId", applicationId); - cmd.Parameters.AddWithValue("@name", username); - object userId = cmd.ExecuteScalar(); - if (userId != null) return (int)userId; - - cmd.CommandText = @"INSERT INTO my_aspnet_users VALUES - (NULL, @appId, @name, @isAnon, Now())"; - cmd.Parameters.AddWithValue("@isAnon", !authenticated); - int recordsAffected = cmd.ExecuteNonQuery(); - if (recordsAffected != 1) - throw new ProviderException(Properties.Resources.UnableToCreateUser); - - cmd.CommandText = "SELECT LAST_INSERT_ID()"; - return Convert.ToInt64(cmd.ExecuteScalar()); - } - } -} \ No newline at end of file +// Copyright © 2004, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +// This code was contributed by Sean Wright (srwright@alcor.concordia.ca) on 2007-01-12 +// The copyright was assigned and transferred under the terms of +// the MySQL Contributor License Agreement (CLA) + +using MySql.Data.MySqlClient; +using System; +using System.Collections.Specialized; +using System.Configuration.Provider; +using System.Data; +using System.Diagnostics; +using System.IO; +using System.Reflection; +using System.Text; + +namespace MySql.Web.Common +{ + /// + /// Provided methods that allow managing a database. + /// + public static class SchemaManager + { + private const int schemaVersion = 10; + + /// + /// Gets the most recent version of the schema. + /// + /// The most recent version number of the schema. + public static int Version + { + get { return schemaVersion; } + } + + internal static void CheckSchema(string connectionString, NameValueCollection config) + { + int ver = GetSchemaVersion(connectionString); + if (ver == Version) return; + + try + { + if (String.Compare(config["autogenerateschema"], "true", true) == 0) + UpgradeToCurrent(connectionString, ver); + else + throw new ProviderException(Properties.Resources.MissingOrWrongSchema); + + } + catch (Exception ex) + { + throw new ProviderException(Properties.Resources.MissingOrWrongSchema, ex); + } + } + + internal static string GetSchema(int version) + { + var assembly = Assembly.GetExecutingAssembly(); + using (Stream stream = assembly.GetManifestResourceStream($"MySql.Web.Properties.schema{version}.sql")) + using (StreamReader reader = new StreamReader(stream)) + return reader.ReadToEnd(); + } + + private static void UpgradeToCurrent(string connectionString, int version) + { + if (version == Version) return; + + using (MySqlConnection connection = new MySqlConnection(connectionString)) + { + connection.Open(); + + for (int ver = version + 1; ver <= Version; ver++) + { + string schema = GetSchema(ver); + MySqlScript script = new MySqlScript(connection); + script.Query = schema; + + try + { + script.Execute(); + } + catch (MySqlException ex) + { + if (ex.Number == 1050 && ver == 7) + { + // Schema7 performs several renames of tables to their lowercase representation. + // If the current server OS does not support renaming to lowercase, then let's just continue. + script.Query = "UPDATE my_aspnet_schemaversion SET version=7"; + script.Execute(); + continue; + } + throw ex; + } + } + } + } + + private static int GetSchemaVersion(string connectionString) + { + // retrieve the current schema version + using (MySqlConnection conn = new MySqlConnection(connectionString)) + { + conn.Open(); + + MySqlCommand cmd = new MySqlCommand("SELECT * FROM my_aspnet_schemaversion", conn); + try + { + object ver = cmd.ExecuteScalar(); + if (ver != null) + return (int)ver; + } + catch (MySqlException ex) + { + if (ex.Number != (int)MySqlErrorCode.NoSuchTable) + throw; + string[] restrictions = new string[4]; + restrictions[2] = "mysql_membership"; + DataTable dt = conn.GetSchema("Tables", restrictions); + if (dt.Rows.Count == 1) + { + var value = dt.Rows[0]["TABLE_COMMENT"]; + if (value is Byte[]) + { + Byte[] byteArray = value as Byte[]; + return Convert.ToInt32(Encoding.UTF8.GetString(byteArray, 0, byteArray.Length)); + } + else + return Convert.ToInt32(value); + } + } + return 0; + } + } + + /// + /// Creates the or fetch user id. + /// + /// The connection. + /// The username. + /// The application id. + /// if set to true [authenticated]. + /// + internal static long CreateOrFetchUserId(MySqlConnection connection, string username, + long applicationId, bool authenticated) + { + Debug.Assert(applicationId > 0); + + // first attempt to fetch an existing user id + MySqlCommand cmd = new MySqlCommand(@"SELECT id FROM my_aspnet_users + WHERE applicationId = @appId AND name = @name", connection); + cmd.Parameters.AddWithValue("@appId", applicationId); + cmd.Parameters.AddWithValue("@name", username); + object userId = cmd.ExecuteScalar(); + if (userId != null) return (int)userId; + + cmd.CommandText = @"INSERT INTO my_aspnet_users VALUES + (NULL, @appId, @name, @isAnon, Now())"; + cmd.Parameters.AddWithValue("@isAnon", !authenticated); + int recordsAffected = cmd.ExecuteNonQuery(); + if (recordsAffected != 1) + throw new ProviderException(Properties.Resources.UnableToCreateUser); + + cmd.CommandText = "SELECT LAST_INSERT_ID()"; + return Convert.ToInt64(cmd.ExecuteScalar()); + } + } +} diff --git a/MySql.Web/src/SessionProvider.cs b/MySql.Web/src/SessionProvider.cs index ca4499da7..c24f741f1 100644 --- a/MySql.Web/src/SessionProvider.cs +++ b/MySql.Web/src/SessionProvider.cs @@ -1,909 +1,909 @@ -// Copyright (c) 2004, 2020, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data.MySqlClient; -using MySql.Web.Common; -using MySql.Web.General; -using System; -using System.Collections.Specialized; -using System.Configuration; -using System.Configuration.Provider; -using System.Diagnostics; -using System.IO; -using System.Security; -using System.Threading; -using System.Web; -using System.Web.Configuration; -using System.Web.Hosting; -using System.Web.SessionState; - -namespace MySql.Web.SessionState -{ - /// - /// This class allows ASP.NET applications to store and manage session state information in a - /// MySQL database. - /// Expired session data is periodically deleted from the database. - /// - public class MySqlSessionStateStore : SessionStateStoreProviderBase - { - string connectionString; - // ConnectionStringSettings connectionStringSettings; - string eventSource = "MySQLSessionStateStore"; - string eventLog = "Application"; - string exceptionMessage = "An exception occurred. Please check the event log."; - Application app; - - SessionStateSection sessionStateConfig; - - // cleanup old session - Timer cleanupTimer; - int cleanupInterval; - bool cleanupRunning; - - - bool writeExceptionsToEventLog = false; - - SessionStateItemExpireCallback expireCallback = null; - bool enableExpireCallback = false; - - - /// - /// Indicates whether if expire callback is on or off. - /// - public bool EnableExpireCallback - { - get { return enableExpireCallback; } - set { enableExpireCallback = value; } - } - - /// - /// Indicates whether to write exceptions to event log. - /// - public bool WriteExceptionsToEventLog - { - get { return writeExceptionsToEventLog; } - set { writeExceptionsToEventLog = value; } - } - - /// - /// The name of the ASP .NET application. - /// - public string ApplicationName - { - get { return app.Name; } - set { app.Name = value; } - } - - private long ApplicationId - { - get { return app.Id; } - } - - - /// - /// Handles a MySql type exception. - /// - /// exception - /// name of the function that throwed the exception - /// If is set it will write exception info to event log. - /// - /// is false. - private void HandleMySqlException(MySqlException e, string action) - { - if (WriteExceptionsToEventLog) - { - using (EventLog log = new EventLog()) - { - log.Source = eventSource; - log.Log = eventLog; - - string message = "An exception occurred communicating with the data source.\n\n"; - message += "Action: " + action; - message += "Exception: " + e.ToString(); - log.WriteEntry(message); - } - } - throw new ProviderException(exceptionMessage, e); - } - - - - /// - /// Initializes the provider with the property values specified in the ASP .NET application configuration file. - /// - /// The name of the provider instance to initialize. - /// Object that contains the names and values of configuration options for the provider. - /// - public override void Initialize(string name, NameValueCollection config) - { - //Initialize values from web.config. - if (config == null) - throw new ArgumentException("config"); - if (name == null || name.Length == 0) - throw new ArgumentException("name"); - if (String.IsNullOrEmpty(config["description"])) - { - config.Remove("description"); - config["description"] = "MySQL Session State Store Provider"; - } - base.Initialize(name, config); - string applicationName = HostingEnvironment.ApplicationVirtualPath; - if (!String.IsNullOrEmpty(config["applicationName"])) - applicationName = config["applicationName"]; - - // Get configuration element. - Configuration webConfig = WebConfigurationManager.OpenWebConfiguration(HostingEnvironment.ApplicationVirtualPath); - sessionStateConfig = (SessionStateSection)webConfig.SectionGroups["system.web"].Sections["sessionState"]; - - // Initialize connection. - connectionString = ConfigUtility.GetConnectionString(config); - if (string.IsNullOrEmpty(connectionString)) return; - - writeExceptionsToEventLog = false; - if (config["writeExceptionsToEventLog"] != null) - { - writeExceptionsToEventLog = (config["writeExceptionsToEventLog"].ToUpper() == "TRUE"); - } - - enableExpireCallback = false; - - if (config["enableExpireCallback"] != null) - { - enableExpireCallback = (config["enableExpireCallback"].ToUpper() == "TRUE"); - } - - // Make sure we have the correct schema. - SchemaManager.CheckSchema(connectionString, config); - app = new Application(applicationName, base.Description); - - // Get the application id. - try - { - using (MySqlConnection conn = new MySqlConnection(connectionString)) - { - conn.Open(); - app.EnsureId(conn); - CheckStorageEngine(conn); - } - } - catch (MySqlException e) - { - HandleMySqlException(e, "Initialize"); - } - - try - { - using (MySqlConnection conn = new MySqlConnection(connectionString)) - { - MySqlCommand cmd = new MySqlCommand( - "INSERT IGNORE INTO my_aspnet_sessioncleanup SET" + - " ApplicationId = @ApplicationId, " + - " LastRun = NOW(), " + - " IntervalMinutes = 10", - conn); - cmd.Parameters.AddWithValue("@ApplicationId", ApplicationId); - conn.Open(); - cmd.ExecuteNonQuery(); - cleanupInterval = GetCleanupInterval(conn, ApplicationId); - } - } - catch (MySqlException e) - { - HandleMySqlException(e, "Initialize"); - } - - // Setup the cleanup timer - if (cleanupInterval <= 0) - cleanupInterval = 1; - cleanupTimer = new Timer(new TimerCallback(CleanupOldSessions), null, 0, - cleanupInterval * 1000 * 60); - } - - /// - /// Creates a new object for the current request. - /// - /// - /// The HttpContext object for the current request. - /// - /// - /// The timeout value (in minutes) for the SessionStateStoreData object that is created. - /// - public override SessionStateStoreData CreateNewStoreData(System.Web.HttpContext context, int timeout) - { - - return new SessionStateStoreData(new SessionStateItemCollection(), - SessionStateUtility.GetSessionStaticObjects(context), timeout); - } - - /// - /// Adds a new session state item to the database. - /// - /// - /// The HttpContext object for the current request. - /// - /// - /// The session ID for the current request. - /// - /// - /// The timeout value for the current request. - /// - public override void CreateUninitializedItem(System.Web.HttpContext context, string id, int timeout) - { - try - { - using (MySqlConnection conn = new MySqlConnection(connectionString)) - { - MySqlCommand cmd = new MySqlCommand( - @"INSERT INTO my_aspnet_sessions - (SessionId, ApplicationId, Created, Expires, LockDate, - LockId, Timeout, Locked, SessionItems, Flags) - Values (@SessionId, @ApplicationId, NOW(), NOW() + INTERVAL @Timeout MINUTE, NOW(), - @LockId , @Timeout, @Locked, @SessionItems, @Flags) - on duplicate key update Created = values( Created ), Expires = values( Expires ), - LockDate = values( LockDate ), LockId = values( LockId ), Timeout = values( Timeout) , - Locked = values( Locked ), SessionItems = values( SessionItems ), Flags = values( Flags )", - conn); - - cmd.Parameters.AddWithValue("@SessionId", id); - cmd.Parameters.AddWithValue("@ApplicationId", ApplicationId); - cmd.Parameters.AddWithValue("@LockId", 0); - cmd.Parameters.AddWithValue("@Timeout", timeout); - cmd.Parameters.AddWithValue("@Locked", 0); - cmd.Parameters.AddWithValue("@SessionItems", null); - cmd.Parameters.AddWithValue("@Flags", 1); - conn.Open(); - cmd.ExecuteNonQuery(); - } - } - catch (MySqlException e) - { - HandleMySqlException(e, "CreateUninitializedItem"); - } - } - - - /// - /// Releases all the resources for this instance. - /// - public override void Dispose() - { - if (cleanupTimer != null) - cleanupTimer.Dispose(); - } - - /// - /// Allows the object to perform any cleanup that may be - /// required for the current request. - /// - /// The HttpContext object for the current request. - public override void EndRequest(System.Web.HttpContext context) - { - } - - /// - /// Returns a read-only session item from the database. - /// - public override SessionStateStoreData GetItem(System.Web.HttpContext context, string id, out bool locked, out TimeSpan lockAge, out object lockId, out SessionStateActions actions) - { - return GetSessionStoreItem(false, context, id, out locked, out lockAge, out lockId, out actions); - } - - /// - /// Locks a session item and returns it from the database. - /// - /// The HttpContext object for the current request. - /// The session ID for the current request. - /// - /// true if the session item is locked in the database; otherwise, false. - /// - /// - /// TimeSpan object that indicates the amount of time the session item has been locked in the database. - /// - /// - /// A lock identifier object. - /// - /// - /// A enumeration value that indicates whether or - /// not the session is uninitialized and cookieless. - /// - /// - public override SessionStateStoreData GetItemExclusive(System.Web.HttpContext context, string id, - out bool locked, out TimeSpan lockAge, out object lockId, out SessionStateActions actions) - { - return GetSessionStoreItem(true, context, id, out locked, out lockAge, out lockId, out actions); - } - - /// - /// Performs any per-request initializations that the MySqlSessionStateStore provider requires. - /// - public override void InitializeRequest(System.Web.HttpContext context) - { - } - - /// - /// Forcibly releases the lock on a session item in the database if multiple attempts to - /// retrieve the session item fail. - /// - /// The HttpContext object for the current request. - /// The session ID for the current request. - /// The lock identifier for the current request. - public override void ReleaseItemExclusive(System.Web.HttpContext context, string id, object lockId) - { - try - { - using (MySqlConnection conn = new MySqlConnection(connectionString)) - { - MySqlCommand cmd = new MySqlCommand( - "UPDATE my_aspnet_sessions SET Locked = 0, Expires = NOW() + INTERVAL @Timeout MINUTE " + - "WHERE SessionId = @SessionId AND ApplicationId = @ApplicationId AND LockId = @LockId", - conn); - - cmd.Parameters.AddWithValue("@Timeout", sessionStateConfig.Timeout.TotalMinutes); - cmd.Parameters.AddWithValue("@SessionId", id); - cmd.Parameters.AddWithValue("@ApplicationId", ApplicationId); - cmd.Parameters.AddWithValue("@LockId", lockId); - conn.Open(); - cmd.ExecuteNonQuery(); - } - } - catch (MySqlException e) - { - HandleMySqlException(e, "ReleaseItemExclusive"); - } - } - - /// - /// Removes the specified session item from the database - /// - /// The HttpContext object for the current request. - /// The session ID for the current request. - /// The lock identifier for the current request. - /// The session item to remove from the database. - public override void RemoveItem(System.Web.HttpContext context, string id, object lockId, SessionStateStoreData item) - { - bool sessionDeleted; - - try - { - using (MySqlConnection conn = new MySqlConnection(connectionString)) - { - MySqlCommand cmd = new MySqlCommand("DELETE FROM my_aspnet_sessions " + - " WHERE SessionId = @SessionId AND ApplicationId = @ApplicationId AND LockId = @LockId", - conn); - - cmd.Parameters.AddWithValue("@SessionId", id); - cmd.Parameters.AddWithValue("@ApplicationId", ApplicationId); - cmd.Parameters.AddWithValue("@LockId", lockId); - conn.Open(); - sessionDeleted = cmd.ExecuteNonQuery() > 0; - } - if (sessionDeleted && this.enableExpireCallback) - { - this.expireCallback.Invoke(id, item); - } - } - catch (MySqlException ex) - { - HandleMySqlException(ex, "RemoveItem Error: " + ex.Message); - } - } - - - /// - /// Resets the expiration date and timeout for a session item in the database. - /// - /// The HttpContext object for the current request. - /// The session ID for the current request. - public override void ResetItemTimeout(System.Web.HttpContext context, string id) - { - try - { - using (MySqlConnection conn = new MySqlConnection(connectionString)) - { - MySqlCommand cmd = new MySqlCommand( - "UPDATE my_aspnet_sessions SET Expires = NOW() + INTERVAL @Timeout MINUTE" + - " WHERE SessionId = @SessionId AND ApplicationId = @ApplicationId", conn); - - cmd.Parameters.AddWithValue("@Timeout", sessionStateConfig.Timeout.TotalMinutes); - cmd.Parameters.AddWithValue("@SessionId", id); - cmd.Parameters.AddWithValue("@ApplicationId", ApplicationId); - conn.Open(); - cmd.ExecuteNonQuery(); - } - } - catch (MySqlException e) - { - HandleMySqlException(e, "ResetItemTimeout"); - } - } - - /// - /// Updates the session time information in the database with the specified session item, - /// and releases the lock. - /// - /// The HttpContext object for the current request. - /// The session ID for the current request. - /// The session item containing new values to update the session item in the database with. - /// - /// The lock identifier for the current request. - /// A Boolean value that indicates whether or not the session item is new in the database. - /// A false value indicates an existing item. - /// - public override void SetAndReleaseItemExclusive(System.Web.HttpContext context, string id, SessionStateStoreData item, object lockId, bool newItem) - { - try - { - using (MySqlConnection conn = new MySqlConnection(connectionString)) - { - // Serialize the SessionStateItemCollection as a byte array - byte[] sessItems = Serialize((SessionStateItemCollection)item.Items); - MySqlCommand cmd; - if (newItem) - { - //Insert the new session item . If there was expired session - //with the same SessionId and Application id, it will be removed - - cmd = new MySqlCommand( - @"INSERT INTO my_aspnet_sessions - (SessionId, ApplicationId, Created, Expires, LockDate, - LockId, Timeout, Locked, SessionItems, Flags) - Values (@SessionId, @ApplicationId, NOW(), NOW() + INTERVAL @Timeout MINUTE, NOW(), - @LockId , @Timeout, @Locked, @SessionItems, @Flags) - on duplicate key update Created = values( Created ), Expires = values( Expires ), - LockDate = values( LockDate ), LockId = values( LockId ), Timeout = values( Timeout) , - Locked = values( Locked ), SessionItems = values( SessionItems ), Flags = values( Flags )", conn); - cmd.Parameters.AddWithValue("@SessionId", id); - cmd.Parameters.AddWithValue("@ApplicationId", ApplicationId); - cmd.Parameters.AddWithValue("@Timeout", item.Timeout); - cmd.Parameters.AddWithValue("@LockId", 0); - cmd.Parameters.AddWithValue("@Locked", 0); - cmd.Parameters.AddWithValue("@SessionItems", sessItems); - cmd.Parameters.AddWithValue("@Flags", 0); - } - else - { - //Update the existing session item. - cmd = new MySqlCommand( - "UPDATE my_aspnet_sessions SET Expires = NOW() + INTERVAL @Timeout MINUTE," + - " SessionItems = @SessionItems, Locked = @Locked " + - " WHERE SessionId = @SessionId AND ApplicationId = @ApplicationId AND LockId = @LockId", - conn); - - cmd.Parameters.AddWithValue("@Timeout", item.Timeout); - cmd.Parameters.AddWithValue("@SessionItems", sessItems); - cmd.Parameters.AddWithValue("@Locked", 0); - cmd.Parameters.AddWithValue("@SessionId", id); - cmd.Parameters.AddWithValue("@ApplicationId", ApplicationId); - cmd.Parameters.AddWithValue("@LockId", lockId); - } - conn.Open(); - cmd.ExecuteNonQuery(); - } - } - catch (MySqlException e) - { - HandleMySqlException(e, "SetAndReleaseItemExclusive"); - } - } - - - /// - /// GetSessionStoreItem is called by both the GetItem and GetItemExclusive methods. GetSessionStoreItem - /// retrieves the session data from the data source. If the lockRecord parameter is true (in the case of - /// GetItemExclusive), then GetSessionStoreItem locks the record and sets a New LockId and LockDate. - /// - private SessionStateStoreData GetSessionStoreItem(bool lockRecord, - HttpContext context, - string id, - out bool locked, - out TimeSpan lockAge, - out object lockId, - out SessionStateActions actionFlags) - { - - // Initial values for return value and out parameters. - SessionStateStoreData item = null; - lockAge = TimeSpan.Zero; - lockId = null; - locked = false; - actionFlags = SessionStateActions.None; - - // MySqlCommand for database commands. - MySqlCommand cmd = null; - // serialized SessionStateItemCollection. - byte[] serializedItems = null; - // True if a record is found in the database. - bool foundRecord = false; - // True if the returned session item is expired and needs to be deleted. - bool deleteData = false; - // Timeout value from the data store. - int timeout = 0; - - try - { - using (MySqlConnection conn = new MySqlConnection(connectionString)) - { - conn.Open(); - // lockRecord is True when called from GetItemExclusive and - // False when called from GetItem. - // Obtain a lock if possible. Ignore the record if it is expired. - if (lockRecord) - { - cmd = new MySqlCommand( - "UPDATE my_aspnet_sessions SET " + - " Locked = 1, LockDate = NOW()" + - " WHERE SessionId = @SessionId AND ApplicationId = @ApplicationId AND" + - " Locked = 0 AND Expires > NOW()", conn); - - cmd.Parameters.AddWithValue("@SessionId", id); - cmd.Parameters.AddWithValue("@ApplicationId", ApplicationId); - - if (cmd.ExecuteNonQuery() == 0) - { - // No record was updated because the record was locked or not found. - locked = true; - } - else - { - // The record was updated. - locked = false; - } - } - - // Retrieve the current session item information. - cmd = new MySqlCommand( - "SELECT NOW(), Expires , SessionItems, LockId, Flags, Timeout, " + - " LockDate, Locked " + - " FROM my_aspnet_sessions" + - " WHERE SessionId = @SessionId AND ApplicationId = @ApplicationId", conn); - - cmd.Parameters.AddWithValue("@SessionId", id); - cmd.Parameters.AddWithValue("@ApplicationId", ApplicationId); - - // Retrieve session item data from the data source. - using (MySqlDataReader reader = cmd.ExecuteReader()) - { - if (reader.Read()) - { - DateTime now = reader.GetDateTime(0); - DateTime expires = reader.GetDateTime(1); - if (now.CompareTo(expires) > 0) - { - //The record was expired. Mark it as not locked. - locked = false; - // The session was expired. Mark the data for deletion. - deleteData = true; - } - else - { - foundRecord = true; - } - - object items = reader.GetValue(2); - serializedItems = (items is DBNull) ? null : (byte[])items; - lockId = reader.GetValue(3); - if (lockId is DBNull) - lockId = (int)0; - - actionFlags = (SessionStateActions)(reader.GetInt32(4)); - timeout = reader.GetInt32(5); - DateTime lockDate = reader.GetDateTime(6); - lockAge = now.Subtract(lockDate); - // If it's a read-only session set locked to the current lock - // status (writable sessions have already done this) - if (!lockRecord) - locked = reader.GetBoolean(7); - } - } - - // The record was not found. Ensure that locked is false. - if (!foundRecord) - locked = false; - - // If the record was found and you obtained a lock, then set - // the lockId, clear the actionFlags, - // and create the SessionStateStoreItem to return. - if (foundRecord && !locked) - { - lockId = (int)(lockId) + 1; - - cmd = new MySqlCommand("UPDATE my_aspnet_sessions SET" + - " LockId = @LockId, Flags = 0 " + - " WHERE SessionId = @SessionId AND ApplicationId = @ApplicationId", conn); - - cmd.Parameters.AddWithValue("@LockId", lockId); - cmd.Parameters.AddWithValue("@SessionId", id); - cmd.Parameters.AddWithValue("@ApplicationId", ApplicationId); - cmd.ExecuteNonQuery(); - - - // If the actionFlags parameter is not InitializeItem, - // deserialize the stored SessionStateItemCollection. - if (actionFlags == SessionStateActions.InitializeItem) - { - item = CreateNewStoreData(context, (int)sessionStateConfig.Timeout.TotalMinutes); - } - else - { - item = Deserialize(context, serializedItems, timeout); - } - } - } - } - catch (MySqlException e) - { - HandleMySqlException(e, "GetSessionStoreItem"); - } - return item; - } - - /// - /// Sets the reference for the ExpireCallback delegate if setting is enabled. - /// - /// - /// true if is true; otherwise, false. - public override bool SetItemExpireCallback(SessionStateItemExpireCallback expireCallback) - { - if (this.enableExpireCallback) - { - this.expireCallback = expireCallback; - return true; - } - return false; - } - - /// - /// Serialize is called by the SetAndReleaseItemExclusive method to - /// convert the SessionStateItemCollection into a byte array to - /// be stored in the blob field. - /// - private byte[] Serialize(SessionStateItemCollection items) - { - MemoryStream ms = new MemoryStream(); - BinaryWriter writer = new BinaryWriter(ms); - if (items != null) - { - items.Serialize(writer); - } - writer.Close(); - return ms.ToArray(); - } - - /// - /// Deserialize is called by the GetSessionStoreItem method to - /// convert the byte array stored in the blob field to a - /// SessionStateItemCollection. - /// - private SessionStateStoreData Deserialize(HttpContext context, - byte[] serializedItems, int timeout) - { - - SessionStateItemCollection sessionItems = new SessionStateItemCollection(); - - if (serializedItems != null) - { - MemoryStream ms = new MemoryStream(serializedItems); - if (ms.Length > 0) - { - BinaryReader reader = new BinaryReader(ms); - sessionItems = SessionStateItemCollection.Deserialize(reader); - } - } - - return new SessionStateStoreData(sessionItems, SessionStateUtility.GetSessionStaticObjects(context), - timeout); - } - - - private SessionStateItemCollection DeserializeSessionItems(byte[] serializedItems) - { - SessionStateItemCollection sessionItems = new SessionStateItemCollection(); - if (serializedItems != null) - { - MemoryStream ms = new MemoryStream(serializedItems); - if (ms.Length > 0) - { - BinaryReader reader = new BinaryReader(ms); - sessionItems = SessionStateItemCollection.Deserialize(reader); - } - } - return sessionItems; - } - - - private void CleanupOldSessions(object o) - { - - lock (this) - { - if (cleanupRunning) - return; - - cleanupRunning = true; - } - try - { - using (MySqlConnection con = new MySqlConnection(connectionString)) - { - con.Open(); - MySqlCommand cmd = new MySqlCommand( - "UPDATE my_aspnet_sessioncleanup SET LastRun=NOW() WHERE" + - " LastRun + INTERVAL IntervalMinutes MINUTE < NOW() AND ApplicationId = @ApplicationId", con); - cmd.Parameters.AddWithValue("@ApplicationId", ApplicationId); - int updatedSessions = cmd.ExecuteNonQuery(); - if (updatedSessions > 0) - DeleteTimedOutSessions(); - } - } - catch (MySqlException e) - { - HandleMySqlException(e, "CleanupOldSessions"); - } - finally - { - lock (this) - { - cleanupRunning = false; - } - } - } - - int GetCleanupInterval(MySqlConnection con, long ApplicationId) - { - MySqlCommand cmd = new MySqlCommand("SELECT IntervalMinutes from my_aspnet_sessioncleanup where ApplicationId = @ApplicationId", con); - cmd.Parameters.AddWithValue("@ApplicationId", ApplicationId); - return (int)cmd.ExecuteScalar(); - } - - /// - /// Checks storage engine used by my_aspnet_sessions. - /// - /// The connection object used to check the storage engine. - /// Warn if MyISAM is used - it does not handle concurrent updates well - /// which is important for session provider, as each access to session - /// does an update to "expires" field. - private void CheckStorageEngine(MySqlConnection con) - { - - try - { - MySqlCommand cmd = new MySqlCommand( - "SELECT ENGINE FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='my_aspnet_sessions'", - con); - using (MySqlDataReader reader = cmd.ExecuteReader()) - { - if (reader.Read()) - { - string engine = reader.GetString(0); - if (engine == "MyISAM") - { - string message = - "Storage engine for table my_aspnet_sessions is MyISAM." + - "If possible, please change it to a transactional storage engine " + - "to improve performance,e.g with 'alter table my_aspnet_sessions engine innodb'\n"; - try - { - using (EventLog log = new EventLog()) - { - log.Source = eventSource; - log.Log = eventLog; - log.WriteEntry(message); - } - } - catch (SecurityException) - { - // Can't write to event log due to security restrictions - Trace.WriteLine(message); - } - } - } - } - } - catch (MySqlException e) - { - Trace.Write("got exception while checking for engine" + e); - } - } - - private void DeleteTimedOutSessions() - { - if (this.enableExpireCallback) - { - DeleteTimedOutSessionsWithCallback(); - } - else - { - DeleteTimedOutSessionsWithoutCallback(); - } - } - - private void DeleteTimedOutSessionsWithoutCallback() - { - try - { - using (MySqlConnection con = new MySqlConnection(connectionString)) - { - con.Open(); - MySqlCommand cmd = new MySqlCommand("DELETE FROM my_aspnet_sessions WHERE Expires < NOW() AND ApplicationId = @ApplicationId", con); - cmd.Parameters.AddWithValue("@ApplicationId", ApplicationId); - cmd.ExecuteNonQuery(); - } - } - catch (Exception e) - { - Trace.Write("Got exception in Delete Timed Out Sessions With Out Callback " + e); - throw; - } - } - - private void DeleteTimedOutSessionsWithCallback() - { - using (MySqlConnection con = new MySqlConnection(connectionString)) - { - con.Open(); - MySqlCommand cmd = new MySqlCommand("SELECT SessionID, SessionItems FROM my_aspnet_sessions WHERE Expires < NOW() AND ApplicationId = @ApplicationId", con); - cmd.Parameters.AddWithValue("@ApplicationId", ApplicationId); - - using (MySqlDataReader reader = cmd.ExecuteReader()) - { - while (reader.Read()) - { - string sid = reader.GetString(0); - object items = reader.GetValue(1); - byte[] rawSessionItems = (items is DBNull) ? null : (byte[])items; - - SessionStateItemCollection sessionItems = this.DeserializeSessionItems(rawSessionItems); - SessionStateStoreData ssd = new SessionStateStoreData(sessionItems, new HttpStaticObjectsCollection(), 0); - - try - { - if (this.expireCallback != null) this.expireCallback.Invoke(sid, ssd); - - using (MySqlConnection con2 = new MySqlConnection(connectionString)) - { - MySqlCommand cmd2 = new MySqlCommand("DELETE FROM my_aspnet_sessions" + - " WHERE SessionId = @SessionId" + - " AND ApplicationId = @ApplicationId", con2); - cmd2.Parameters.AddWithValue("@SessionId", sid); - cmd2.Parameters.AddWithValue("@ApplicationId", ApplicationId); - con2.Open(); - cmd2.ExecuteNonQuery(); - } - - } - catch (Exception e) - { - Trace.Write("Got exception in Delete Timed Out Sessions With Callback " + e); - throw; - } - } - } - } - } - } -} \ No newline at end of file +// Copyright © 2004, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data.MySqlClient; +using MySql.Web.Common; +using MySql.Web.General; +using System; +using System.Collections.Specialized; +using System.Configuration; +using System.Configuration.Provider; +using System.Diagnostics; +using System.IO; +using System.Security; +using System.Threading; +using System.Web; +using System.Web.Configuration; +using System.Web.Hosting; +using System.Web.SessionState; + +namespace MySql.Web.SessionState +{ + /// + /// This class allows ASP.NET applications to store and manage session state information in a + /// MySQL database. + /// Expired session data is periodically deleted from the database. + /// + public class MySqlSessionStateStore : SessionStateStoreProviderBase + { + string connectionString; + // ConnectionStringSettings connectionStringSettings; + string eventSource = "MySQLSessionStateStore"; + string eventLog = "Application"; + string exceptionMessage = "An exception occurred. Please check the event log."; + Application app; + + SessionStateSection sessionStateConfig; + + // cleanup old session + Timer cleanupTimer; + int cleanupInterval; + bool cleanupRunning; + + + bool writeExceptionsToEventLog = false; + + SessionStateItemExpireCallback expireCallback = null; + bool enableExpireCallback = false; + + + /// + /// Indicates whether if expire callback is on or off. + /// + public bool EnableExpireCallback + { + get { return enableExpireCallback; } + set { enableExpireCallback = value; } + } + + /// + /// Indicates whether to write exceptions to event log. + /// + public bool WriteExceptionsToEventLog + { + get { return writeExceptionsToEventLog; } + set { writeExceptionsToEventLog = value; } + } + + /// + /// The name of the ASP .NET application. + /// + public string ApplicationName + { + get { return app.Name; } + set { app.Name = value; } + } + + private long ApplicationId + { + get { return app.Id; } + } + + + /// + /// Handles a MySql type exception. + /// + /// exception + /// name of the function that throwed the exception + /// If is set it will write exception info to event log. + /// + /// is false. + private void HandleMySqlException(MySqlException e, string action) + { + if (WriteExceptionsToEventLog) + { + using (EventLog log = new EventLog()) + { + log.Source = eventSource; + log.Log = eventLog; + + string message = "An exception occurred communicating with the data source.\n\n"; + message += "Action: " + action; + message += "Exception: " + e.ToString(); + log.WriteEntry(message); + } + } + throw new ProviderException(exceptionMessage, e); + } + + + + /// + /// Initializes the provider with the property values specified in the ASP .NET application configuration file. + /// + /// The name of the provider instance to initialize. + /// Object that contains the names and values of configuration options for the provider. + /// + public override void Initialize(string name, NameValueCollection config) + { + //Initialize values from web.config. + if (config == null) + throw new ArgumentException("config"); + if (name == null || name.Length == 0) + throw new ArgumentException("name"); + if (String.IsNullOrEmpty(config["description"])) + { + config.Remove("description"); + config["description"] = "MySQL Session State Store Provider"; + } + base.Initialize(name, config); + string applicationName = HostingEnvironment.ApplicationVirtualPath; + if (!String.IsNullOrEmpty(config["applicationName"])) + applicationName = config["applicationName"]; + + // Get configuration element. + Configuration webConfig = WebConfigurationManager.OpenWebConfiguration(HostingEnvironment.ApplicationVirtualPath); + sessionStateConfig = (SessionStateSection)webConfig.SectionGroups["system.web"].Sections["sessionState"]; + + // Initialize connection. + connectionString = ConfigUtility.GetConnectionString(config); + if (string.IsNullOrEmpty(connectionString)) return; + + writeExceptionsToEventLog = false; + if (config["writeExceptionsToEventLog"] != null) + { + writeExceptionsToEventLog = (config["writeExceptionsToEventLog"].ToUpper() == "TRUE"); + } + + enableExpireCallback = false; + + if (config["enableExpireCallback"] != null) + { + enableExpireCallback = (config["enableExpireCallback"].ToUpper() == "TRUE"); + } + + // Make sure we have the correct schema. + SchemaManager.CheckSchema(connectionString, config); + app = new Application(applicationName, base.Description); + + // Get the application id. + try + { + using (MySqlConnection conn = new MySqlConnection(connectionString)) + { + conn.Open(); + app.EnsureId(conn); + CheckStorageEngine(conn); + } + } + catch (MySqlException e) + { + HandleMySqlException(e, "Initialize"); + } + + try + { + using (MySqlConnection conn = new MySqlConnection(connectionString)) + { + MySqlCommand cmd = new MySqlCommand( + "INSERT IGNORE INTO my_aspnet_sessioncleanup SET" + + " ApplicationId = @ApplicationId, " + + " LastRun = NOW(), " + + " IntervalMinutes = 10", + conn); + cmd.Parameters.AddWithValue("@ApplicationId", ApplicationId); + conn.Open(); + cmd.ExecuteNonQuery(); + cleanupInterval = GetCleanupInterval(conn, ApplicationId); + } + } + catch (MySqlException e) + { + HandleMySqlException(e, "Initialize"); + } + + // Setup the cleanup timer + if (cleanupInterval <= 0) + cleanupInterval = 1; + cleanupTimer = new Timer(new TimerCallback(CleanupOldSessions), null, 0, + cleanupInterval * 1000 * 60); + } + + /// + /// Creates a new object for the current request. + /// + /// + /// The HttpContext object for the current request. + /// + /// + /// The timeout value (in minutes) for the SessionStateStoreData object that is created. + /// + public override SessionStateStoreData CreateNewStoreData(System.Web.HttpContext context, int timeout) + { + + return new SessionStateStoreData(new SessionStateItemCollection(), + SessionStateUtility.GetSessionStaticObjects(context), timeout); + } + + /// + /// Adds a new session state item to the database. + /// + /// + /// The HttpContext object for the current request. + /// + /// + /// The session ID for the current request. + /// + /// + /// The timeout value for the current request. + /// + public override void CreateUninitializedItem(System.Web.HttpContext context, string id, int timeout) + { + try + { + using (MySqlConnection conn = new MySqlConnection(connectionString)) + { + MySqlCommand cmd = new MySqlCommand( + @"INSERT INTO my_aspnet_sessions + (SessionId, ApplicationId, Created, Expires, LockDate, + LockId, Timeout, Locked, SessionItems, Flags) + Values (@SessionId, @ApplicationId, NOW(), NOW() + INTERVAL @Timeout MINUTE, NOW(), + @LockId , @Timeout, @Locked, @SessionItems, @Flags) + on duplicate key update Created = values( Created ), Expires = values( Expires ), + LockDate = values( LockDate ), LockId = values( LockId ), Timeout = values( Timeout) , + Locked = values( Locked ), SessionItems = values( SessionItems ), Flags = values( Flags )", + conn); + + cmd.Parameters.AddWithValue("@SessionId", id); + cmd.Parameters.AddWithValue("@ApplicationId", ApplicationId); + cmd.Parameters.AddWithValue("@LockId", 0); + cmd.Parameters.AddWithValue("@Timeout", timeout); + cmd.Parameters.AddWithValue("@Locked", 0); + cmd.Parameters.AddWithValue("@SessionItems", null); + cmd.Parameters.AddWithValue("@Flags", 1); + conn.Open(); + cmd.ExecuteNonQuery(); + } + } + catch (MySqlException e) + { + HandleMySqlException(e, "CreateUninitializedItem"); + } + } + + + /// + /// Releases all the resources for this instance. + /// + public override void Dispose() + { + if (cleanupTimer != null) + cleanupTimer.Dispose(); + } + + /// + /// Allows the object to perform any cleanup that may be + /// required for the current request. + /// + /// The HttpContext object for the current request. + public override void EndRequest(System.Web.HttpContext context) + { + } + + /// + /// Returns a read-only session item from the database. + /// + public override SessionStateStoreData GetItem(System.Web.HttpContext context, string id, out bool locked, out TimeSpan lockAge, out object lockId, out SessionStateActions actions) + { + return GetSessionStoreItem(false, context, id, out locked, out lockAge, out lockId, out actions); + } + + /// + /// Locks a session item and returns it from the database. + /// + /// The HttpContext object for the current request. + /// The session ID for the current request. + /// + /// true if the session item is locked in the database; otherwise, false. + /// + /// + /// TimeSpan object that indicates the amount of time the session item has been locked in the database. + /// + /// + /// A lock identifier object. + /// + /// + /// A enumeration value that indicates whether or + /// not the session is uninitialized and cookieless. + /// + /// + public override SessionStateStoreData GetItemExclusive(System.Web.HttpContext context, string id, + out bool locked, out TimeSpan lockAge, out object lockId, out SessionStateActions actions) + { + return GetSessionStoreItem(true, context, id, out locked, out lockAge, out lockId, out actions); + } + + /// + /// Performs any per-request initializations that the MySqlSessionStateStore provider requires. + /// + public override void InitializeRequest(System.Web.HttpContext context) + { + } + + /// + /// Forcibly releases the lock on a session item in the database if multiple attempts to + /// retrieve the session item fail. + /// + /// The HttpContext object for the current request. + /// The session ID for the current request. + /// The lock identifier for the current request. + public override void ReleaseItemExclusive(System.Web.HttpContext context, string id, object lockId) + { + try + { + using (MySqlConnection conn = new MySqlConnection(connectionString)) + { + MySqlCommand cmd = new MySqlCommand( + "UPDATE my_aspnet_sessions SET Locked = 0, Expires = NOW() + INTERVAL @Timeout MINUTE " + + "WHERE SessionId = @SessionId AND ApplicationId = @ApplicationId AND LockId = @LockId", + conn); + + cmd.Parameters.AddWithValue("@Timeout", sessionStateConfig.Timeout.TotalMinutes); + cmd.Parameters.AddWithValue("@SessionId", id); + cmd.Parameters.AddWithValue("@ApplicationId", ApplicationId); + cmd.Parameters.AddWithValue("@LockId", lockId); + conn.Open(); + cmd.ExecuteNonQuery(); + } + } + catch (MySqlException e) + { + HandleMySqlException(e, "ReleaseItemExclusive"); + } + } + + /// + /// Removes the specified session item from the database + /// + /// The HttpContext object for the current request. + /// The session ID for the current request. + /// The lock identifier for the current request. + /// The session item to remove from the database. + public override void RemoveItem(System.Web.HttpContext context, string id, object lockId, SessionStateStoreData item) + { + bool sessionDeleted; + + try + { + using (MySqlConnection conn = new MySqlConnection(connectionString)) + { + MySqlCommand cmd = new MySqlCommand("DELETE FROM my_aspnet_sessions " + + " WHERE SessionId = @SessionId AND ApplicationId = @ApplicationId AND LockId = @LockId", + conn); + + cmd.Parameters.AddWithValue("@SessionId", id); + cmd.Parameters.AddWithValue("@ApplicationId", ApplicationId); + cmd.Parameters.AddWithValue("@LockId", lockId); + conn.Open(); + sessionDeleted = cmd.ExecuteNonQuery() > 0; + } + if (sessionDeleted && this.enableExpireCallback) + { + this.expireCallback.Invoke(id, item); + } + } + catch (MySqlException ex) + { + HandleMySqlException(ex, "RemoveItem Error: " + ex.Message); + } + } + + + /// + /// Resets the expiration date and timeout for a session item in the database. + /// + /// The HttpContext object for the current request. + /// The session ID for the current request. + public override void ResetItemTimeout(System.Web.HttpContext context, string id) + { + try + { + using (MySqlConnection conn = new MySqlConnection(connectionString)) + { + MySqlCommand cmd = new MySqlCommand( + "UPDATE my_aspnet_sessions SET Expires = NOW() + INTERVAL @Timeout MINUTE" + + " WHERE SessionId = @SessionId AND ApplicationId = @ApplicationId", conn); + + cmd.Parameters.AddWithValue("@Timeout", sessionStateConfig.Timeout.TotalMinutes); + cmd.Parameters.AddWithValue("@SessionId", id); + cmd.Parameters.AddWithValue("@ApplicationId", ApplicationId); + conn.Open(); + cmd.ExecuteNonQuery(); + } + } + catch (MySqlException e) + { + HandleMySqlException(e, "ResetItemTimeout"); + } + } + + /// + /// Updates the session time information in the database with the specified session item, + /// and releases the lock. + /// + /// The HttpContext object for the current request. + /// The session ID for the current request. + /// The session item containing new values to update the session item in the database with. + /// + /// The lock identifier for the current request. + /// A Boolean value that indicates whether or not the session item is new in the database. + /// A false value indicates an existing item. + /// + public override void SetAndReleaseItemExclusive(System.Web.HttpContext context, string id, SessionStateStoreData item, object lockId, bool newItem) + { + try + { + using (MySqlConnection conn = new MySqlConnection(connectionString)) + { + // Serialize the SessionStateItemCollection as a byte array + byte[] sessItems = Serialize((SessionStateItemCollection)item.Items); + MySqlCommand cmd; + if (newItem) + { + //Insert the new session item . If there was expired session + //with the same SessionId and Application id, it will be removed + + cmd = new MySqlCommand( + @"INSERT INTO my_aspnet_sessions + (SessionId, ApplicationId, Created, Expires, LockDate, + LockId, Timeout, Locked, SessionItems, Flags) + Values (@SessionId, @ApplicationId, NOW(), NOW() + INTERVAL @Timeout MINUTE, NOW(), + @LockId , @Timeout, @Locked, @SessionItems, @Flags) + on duplicate key update Created = values( Created ), Expires = values( Expires ), + LockDate = values( LockDate ), LockId = values( LockId ), Timeout = values( Timeout) , + Locked = values( Locked ), SessionItems = values( SessionItems ), Flags = values( Flags )", conn); + cmd.Parameters.AddWithValue("@SessionId", id); + cmd.Parameters.AddWithValue("@ApplicationId", ApplicationId); + cmd.Parameters.AddWithValue("@Timeout", item.Timeout); + cmd.Parameters.AddWithValue("@LockId", 0); + cmd.Parameters.AddWithValue("@Locked", 0); + cmd.Parameters.AddWithValue("@SessionItems", sessItems); + cmd.Parameters.AddWithValue("@Flags", 0); + } + else + { + //Update the existing session item. + cmd = new MySqlCommand( + "UPDATE my_aspnet_sessions SET Expires = NOW() + INTERVAL @Timeout MINUTE," + + " SessionItems = @SessionItems, Locked = @Locked " + + " WHERE SessionId = @SessionId AND ApplicationId = @ApplicationId AND LockId = @LockId", + conn); + + cmd.Parameters.AddWithValue("@Timeout", item.Timeout); + cmd.Parameters.AddWithValue("@SessionItems", sessItems); + cmd.Parameters.AddWithValue("@Locked", 0); + cmd.Parameters.AddWithValue("@SessionId", id); + cmd.Parameters.AddWithValue("@ApplicationId", ApplicationId); + cmd.Parameters.AddWithValue("@LockId", lockId); + } + conn.Open(); + cmd.ExecuteNonQuery(); + } + } + catch (MySqlException e) + { + HandleMySqlException(e, "SetAndReleaseItemExclusive"); + } + } + + + /// + /// GetSessionStoreItem is called by both the GetItem and GetItemExclusive methods. GetSessionStoreItem + /// retrieves the session data from the data source. If the lockRecord parameter is true (in the case of + /// GetItemExclusive), then GetSessionStoreItem locks the record and sets a New LockId and LockDate. + /// + private SessionStateStoreData GetSessionStoreItem(bool lockRecord, + HttpContext context, + string id, + out bool locked, + out TimeSpan lockAge, + out object lockId, + out SessionStateActions actionFlags) + { + + // Initial values for return value and out parameters. + SessionStateStoreData item = null; + lockAge = TimeSpan.Zero; + lockId = null; + locked = false; + actionFlags = SessionStateActions.None; + + // MySqlCommand for database commands. + MySqlCommand cmd = null; + // serialized SessionStateItemCollection. + byte[] serializedItems = null; + // True if a record is found in the database. + bool foundRecord = false; + // True if the returned session item is expired and needs to be deleted. + bool deleteData = false; + // Timeout value from the data store. + int timeout = 0; + + try + { + using (MySqlConnection conn = new MySqlConnection(connectionString)) + { + conn.Open(); + // lockRecord is True when called from GetItemExclusive and + // False when called from GetItem. + // Obtain a lock if possible. Ignore the record if it is expired. + if (lockRecord) + { + cmd = new MySqlCommand( + "UPDATE my_aspnet_sessions SET " + + " Locked = 1, LockDate = NOW()" + + " WHERE SessionId = @SessionId AND ApplicationId = @ApplicationId AND" + + " Locked = 0 AND Expires > NOW()", conn); + + cmd.Parameters.AddWithValue("@SessionId", id); + cmd.Parameters.AddWithValue("@ApplicationId", ApplicationId); + + if (cmd.ExecuteNonQuery() == 0) + { + // No record was updated because the record was locked or not found. + locked = true; + } + else + { + // The record was updated. + locked = false; + } + } + + // Retrieve the current session item information. + cmd = new MySqlCommand( + "SELECT NOW(), Expires , SessionItems, LockId, Flags, Timeout, " + + " LockDate, Locked " + + " FROM my_aspnet_sessions" + + " WHERE SessionId = @SessionId AND ApplicationId = @ApplicationId", conn); + + cmd.Parameters.AddWithValue("@SessionId", id); + cmd.Parameters.AddWithValue("@ApplicationId", ApplicationId); + + // Retrieve session item data from the data source. + using (MySqlDataReader reader = cmd.ExecuteReader()) + { + if (reader.Read()) + { + DateTime now = reader.GetDateTime(0); + DateTime expires = reader.GetDateTime(1); + if (now.CompareTo(expires) > 0) + { + //The record was expired. Mark it as not locked. + locked = false; + // The session was expired. Mark the data for deletion. + deleteData = true; + } + else + { + foundRecord = true; + } + + object items = reader.GetValue(2); + serializedItems = (items is DBNull) ? null : (byte[])items; + lockId = reader.GetValue(3); + if (lockId is DBNull) + lockId = (int)0; + + actionFlags = (SessionStateActions)(reader.GetInt32(4)); + timeout = reader.GetInt32(5); + DateTime lockDate = reader.GetDateTime(6); + lockAge = now.Subtract(lockDate); + // If it's a read-only session set locked to the current lock + // status (writable sessions have already done this) + if (!lockRecord) + locked = reader.GetBoolean(7); + } + } + + // The record was not found. Ensure that locked is false. + if (!foundRecord) + locked = false; + + // If the record was found and you obtained a lock, then set + // the lockId, clear the actionFlags, + // and create the SessionStateStoreItem to return. + if (foundRecord && !locked) + { + lockId = (int)(lockId) + 1; + + cmd = new MySqlCommand("UPDATE my_aspnet_sessions SET" + + " LockId = @LockId, Flags = 0 " + + " WHERE SessionId = @SessionId AND ApplicationId = @ApplicationId", conn); + + cmd.Parameters.AddWithValue("@LockId", lockId); + cmd.Parameters.AddWithValue("@SessionId", id); + cmd.Parameters.AddWithValue("@ApplicationId", ApplicationId); + cmd.ExecuteNonQuery(); + + + // If the actionFlags parameter is not InitializeItem, + // deserialize the stored SessionStateItemCollection. + if (actionFlags == SessionStateActions.InitializeItem) + { + item = CreateNewStoreData(context, (int)sessionStateConfig.Timeout.TotalMinutes); + } + else + { + item = Deserialize(context, serializedItems, timeout); + } + } + } + } + catch (MySqlException e) + { + HandleMySqlException(e, "GetSessionStoreItem"); + } + return item; + } + + /// + /// Sets the reference for the ExpireCallback delegate if setting is enabled. + /// + /// + /// true if is true; otherwise, false. + public override bool SetItemExpireCallback(SessionStateItemExpireCallback expireCallback) + { + if (this.enableExpireCallback) + { + this.expireCallback = expireCallback; + return true; + } + return false; + } + + /// + /// Serialize is called by the SetAndReleaseItemExclusive method to + /// convert the SessionStateItemCollection into a byte array to + /// be stored in the blob field. + /// + private byte[] Serialize(SessionStateItemCollection items) + { + MemoryStream ms = new MemoryStream(); + BinaryWriter writer = new BinaryWriter(ms); + if (items != null) + { + items.Serialize(writer); + } + writer.Close(); + return ms.ToArray(); + } + + /// + /// Deserialize is called by the GetSessionStoreItem method to + /// convert the byte array stored in the blob field to a + /// SessionStateItemCollection. + /// + private SessionStateStoreData Deserialize(HttpContext context, + byte[] serializedItems, int timeout) + { + + SessionStateItemCollection sessionItems = new SessionStateItemCollection(); + + if (serializedItems != null) + { + MemoryStream ms = new MemoryStream(serializedItems); + if (ms.Length > 0) + { + BinaryReader reader = new BinaryReader(ms); + sessionItems = SessionStateItemCollection.Deserialize(reader); + } + } + + return new SessionStateStoreData(sessionItems, SessionStateUtility.GetSessionStaticObjects(context), + timeout); + } + + + private SessionStateItemCollection DeserializeSessionItems(byte[] serializedItems) + { + SessionStateItemCollection sessionItems = new SessionStateItemCollection(); + if (serializedItems != null) + { + MemoryStream ms = new MemoryStream(serializedItems); + if (ms.Length > 0) + { + BinaryReader reader = new BinaryReader(ms); + sessionItems = SessionStateItemCollection.Deserialize(reader); + } + } + return sessionItems; + } + + + private void CleanupOldSessions(object o) + { + + lock (this) + { + if (cleanupRunning) + return; + + cleanupRunning = true; + } + try + { + using (MySqlConnection con = new MySqlConnection(connectionString)) + { + con.Open(); + MySqlCommand cmd = new MySqlCommand( + "UPDATE my_aspnet_sessioncleanup SET LastRun=NOW() WHERE" + + " LastRun + INTERVAL IntervalMinutes MINUTE < NOW() AND ApplicationId = @ApplicationId", con); + cmd.Parameters.AddWithValue("@ApplicationId", ApplicationId); + int updatedSessions = cmd.ExecuteNonQuery(); + if (updatedSessions > 0) + DeleteTimedOutSessions(); + } + } + catch (MySqlException e) + { + HandleMySqlException(e, "CleanupOldSessions"); + } + finally + { + lock (this) + { + cleanupRunning = false; + } + } + } + + int GetCleanupInterval(MySqlConnection con, long ApplicationId) + { + MySqlCommand cmd = new MySqlCommand("SELECT IntervalMinutes from my_aspnet_sessioncleanup where ApplicationId = @ApplicationId", con); + cmd.Parameters.AddWithValue("@ApplicationId", ApplicationId); + return (int)cmd.ExecuteScalar(); + } + + /// + /// Checks storage engine used by my_aspnet_sessions. + /// + /// The connection object used to check the storage engine. + /// Warn if MyISAM is used - it does not handle concurrent updates well + /// which is important for session provider, as each access to session + /// does an update to "expires" field. + private void CheckStorageEngine(MySqlConnection con) + { + + try + { + MySqlCommand cmd = new MySqlCommand( + "SELECT ENGINE FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='my_aspnet_sessions'", + con); + using (MySqlDataReader reader = cmd.ExecuteReader()) + { + if (reader.Read()) + { + string engine = reader.GetString(0); + if (engine == "MyISAM") + { + string message = + "Storage engine for table my_aspnet_sessions is MyISAM." + + "If possible, please change it to a transactional storage engine " + + "to improve performance,e.g with 'alter table my_aspnet_sessions engine innodb'\n"; + try + { + using (EventLog log = new EventLog()) + { + log.Source = eventSource; + log.Log = eventLog; + log.WriteEntry(message); + } + } + catch (SecurityException) + { + // Can't write to event log due to security restrictions + Trace.WriteLine(message); + } + } + } + } + } + catch (MySqlException e) + { + Trace.Write("got exception while checking for engine" + e); + } + } + + private void DeleteTimedOutSessions() + { + if (this.enableExpireCallback) + { + DeleteTimedOutSessionsWithCallback(); + } + else + { + DeleteTimedOutSessionsWithoutCallback(); + } + } + + private void DeleteTimedOutSessionsWithoutCallback() + { + try + { + using (MySqlConnection con = new MySqlConnection(connectionString)) + { + con.Open(); + MySqlCommand cmd = new MySqlCommand("DELETE FROM my_aspnet_sessions WHERE Expires < NOW() AND ApplicationId = @ApplicationId", con); + cmd.Parameters.AddWithValue("@ApplicationId", ApplicationId); + cmd.ExecuteNonQuery(); + } + } + catch (Exception e) + { + Trace.Write("Got exception in Delete Timed Out Sessions With Out Callback " + e); + throw; + } + } + + private void DeleteTimedOutSessionsWithCallback() + { + using (MySqlConnection con = new MySqlConnection(connectionString)) + { + con.Open(); + MySqlCommand cmd = new MySqlCommand("SELECT SessionID, SessionItems FROM my_aspnet_sessions WHERE Expires < NOW() AND ApplicationId = @ApplicationId", con); + cmd.Parameters.AddWithValue("@ApplicationId", ApplicationId); + + using (MySqlDataReader reader = cmd.ExecuteReader()) + { + while (reader.Read()) + { + string sid = reader.GetString(0); + object items = reader.GetValue(1); + byte[] rawSessionItems = (items is DBNull) ? null : (byte[])items; + + SessionStateItemCollection sessionItems = this.DeserializeSessionItems(rawSessionItems); + SessionStateStoreData ssd = new SessionStateStoreData(sessionItems, new HttpStaticObjectsCollection(), 0); + + try + { + if (this.expireCallback != null) this.expireCallback.Invoke(sid, ssd); + + using (MySqlConnection con2 = new MySqlConnection(connectionString)) + { + MySqlCommand cmd2 = new MySqlCommand("DELETE FROM my_aspnet_sessions" + + " WHERE SessionId = @SessionId" + + " AND ApplicationId = @ApplicationId", con2); + cmd2.Parameters.AddWithValue("@SessionId", sid); + cmd2.Parameters.AddWithValue("@ApplicationId", ApplicationId); + con2.Open(); + cmd2.ExecuteNonQuery(); + } + + } + catch (Exception e) + { + Trace.Write("Got exception in Delete Timed Out Sessions With Callback " + e); + throw; + } + } + } + } + } + } +} diff --git a/MySql.Web/src/SimpleMembershipProvider.cs b/MySql.Web/src/SimpleMembershipProvider.cs index 4f8cede19..a2d1d6735 100644 --- a/MySql.Web/src/SimpleMembershipProvider.cs +++ b/MySql.Web/src/SimpleMembershipProvider.cs @@ -1,1138 +1,1138 @@ -// Copyright (c) 2014, 2020, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Web.Common; -using MySql.Web.General; -using MySql.Web.Properties; -using System; -using System.Collections.Generic; -using System.Configuration; -using System.Configuration.Provider; -using System.Globalization; -using System.Linq; -using System.Security.Cryptography; -using System.Text; -using System.Web; -using System.Web.Hosting; -using System.Web.Security; -using WebMatrix.WebData; - -namespace MySql.Web.Security -{ - /// - /// Manages storage of simple membership information for an ASP.NET application in a MySQL database. - /// - public class MySqlSimpleMembershipProvider : ExtendedMembershipProvider - { - #region Private - private readonly MembershipProvider _prevProvider; - - Application _app; - bool _enablePwdReset; - bool _enablePwdRetrival; - int _maxPwdAttempts; - int _minReqNonAlphanumericalChars; - int _minReqPwdLength; - int _pwdAttemptWindow; - MembershipPasswordFormat _pwdFormat; - string _pwdStrenghtRegex; - bool _reqQuestionAnswer; - bool _reqUniqueEmail; - string _connString; - string _userTableName; - string _userIdColumn; - string _userNameColumn; - bool _autoGenerateTables; - private readonly string _membershipTable = "webpages_membership"; - private readonly string _oauthMembershipTable = "webpages_oauthmembership"; - private readonly string _userInRolesTable = "webpages_usersinroles"; - private readonly string _oauthTokenTable = "webpages_oauthtoken"; - - private static string GetConfigValue(string configVal, string defaultVal) - { - return !string.IsNullOrEmpty(configVal) ? configVal : defaultVal; - } - #endregion - public MySqlSimpleMembershipProvider() - : this(null) - { } - - public MySqlSimpleMembershipProvider(MembershipProvider previousProvider) - { - _prevProvider = previousProvider; - if (_prevProvider != null) - { - _prevProvider.ValidatingPassword += delegate (object sender, ValidatePasswordEventArgs args) { this.OnValidatingPassword(args); }; - } - } - - public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config) - { - if (config == null) - { - NullArgumentException("config"); - } - if (string.IsNullOrEmpty(name)) - { - name = "MySqlExtendedMembershipProvider"; - } - if (string.IsNullOrEmpty(config["description"])) - { - config.Remove("description"); - config.Add("description", string.Format("MySql Default {0} Description", name)); - } - - base.Initialize(name, config); - - var appName = GetConfigValue(config["applicationName"], HostingEnvironment.SiteName); - _maxPwdAttempts = Int32.Parse(GetConfigValue(config["maxInvalidPasswordAttempts"], "5"), CultureInfo.InvariantCulture); - _pwdAttemptWindow = Int32.Parse(GetConfigValue(config["passwordAttemptWindow"], "10"), CultureInfo.InvariantCulture); - _minReqNonAlphanumericalChars = Int32.Parse(GetConfigValue(config["minRequiredNonalphanumericCharacters"], "1"), CultureInfo.InvariantCulture); - _minReqPwdLength = Int32.Parse(GetConfigValue(config["minRequiredPasswordLength"], "7"), CultureInfo.InvariantCulture); - _pwdStrenghtRegex = GetConfigValue(config["passwordStrengthRegularExpression"], ""); - _enablePwdReset = bool.Parse(GetConfigValue(config["enablePasswordReset"], "True")); - _enablePwdRetrival = bool.Parse(GetConfigValue(config["enablePasswordRetrieval"], "False")); - _reqQuestionAnswer = bool.Parse(GetConfigValue(config["requiresQuestionAndAnswer"], "False")); - _reqUniqueEmail = bool.Parse(GetConfigValue(config["requiresUniqueEmail"], "True")); - - var pwdFormat = !string.IsNullOrEmpty(config["passwordFormat"]) ? config["passwordFormat"].ToString().ToLowerInvariant() : "hashed"; - - switch (pwdFormat) - { - case "hashed": - _pwdFormat = MembershipPasswordFormat.Hashed; - break; - case "encrypted": - _pwdFormat = MembershipPasswordFormat.Encrypted; - break; - case "clear": - _pwdFormat = MembershipPasswordFormat.Clear; - break; - default: - throw new ProviderException(Resources.PasswordFormatNotSupported); - } - - if (_pwdFormat == MembershipPasswordFormat.Hashed) - { - if (_enablePwdRetrival) - throw new ProviderException(Resources.CannotRetrieveHashedPasswords); - } - - _app = new Application(appName, base.Description); - _connString = ConfigUtility.GetConnectionString(config); - if (string.IsNullOrEmpty(_connString)) return; - - UserTableName = GetConfigValue(config["userTableName"], ""); - UserIdColumn = GetConfigValue(config["userIdColumn"], ""); - UserNameColumn = GetConfigValue(config["userNameColumn"], ""); - _autoGenerateTables = bool.Parse(GetConfigValue(config["autoGenerateTables"], "True")); - if (_autoGenerateTables) - CreateTables(); - else - ValidateUserTable(); - - Initialized = true; - } - - public override bool ChangePassword(string username, string oldPassword, string newPassword) - { - if (!Initialized) - { - _prevProvider.ChangePassword(username, oldPassword, newPassword); - } - - if (string.IsNullOrEmpty(username)) - NullArgumentException("username"); - if (string.IsNullOrEmpty(oldPassword)) - NullArgumentException("oldPassword"); - if (string.IsNullOrEmpty(newPassword)) - NullArgumentException("newPassword"); - - int userid = GetUserId(username); - if (userid <= 0) - { - return false; - } - if (VerifyPassword(userid, oldPassword, GetHashedUserPassword(userid))) - { - return UpdatePassword(userid, newPassword) > 0; - } - - return false; - } - - public override bool ChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion, string newPasswordAnswer) - { - IsValidOperation(false); - return _prevProvider.ChangePasswordQuestionAndAnswer(username, password, newPasswordQuestion, newPasswordAnswer); - } - - public override bool ConfirmAccount(string accountConfirmationToken) - { - IsValidOperation(true); - using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(GetConnectionString())) - { - var token = dbConn.ExecuteQuerySingleRecord(string.Format("select userid, confirmationtoken from {0} where confirmationtoken=?", _membershipTable), accountConfirmationToken); - if (token == null || (token != null && string.IsNullOrEmpty(token[1].ToString()))) - { - return false; - } - return dbConn.ExecuteNonQuery(string.Format("update {0} set isconfirmed=1 where userid=?;", _membershipTable), (int)token[0]) > 0; - } - } - - public override bool ConfirmAccount(string userName, string accountConfirmationToken) - { - var userid = GetUserId(userName); - if (userid <= 0) - return false; - - using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(GetConnectionString())) - { - var token = dbConn.ExecuteQuerySingleRecord(string.Format("select userid, confirmationtoken from {0} where confirmationtoken=? and userid=?", _membershipTable), accountConfirmationToken, userid); - if (token == null || (token != null && string.IsNullOrEmpty(token[1].ToString()))) - { - return false; - } - return dbConn.ExecuteNonQuery(string.Format("update {0} set isconfirmed=1 where userid=?;", _membershipTable), userid) > 0; - } - } - - public override string CreateAccount(string userName, string password, bool requireConfirmationToken) - { - IsValidOperation(true); - if (string.IsNullOrEmpty(userName)) - NullArgumentException(userName); - if (string.IsNullOrEmpty(password)) - NullArgumentException(password); - var hashedPass = HashPassword(password); - if (hashedPass.Length > 128) - throw new ArgumentException(Resources.PasswordExceedsMaxLength, password); - - using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(GetConnectionString())) - { - var userid = GetUserId(userName); - if (userid <= 0) - { - throw new InvalidOperationException(string.Format(Resources.UserNotFound, UserTableName)); - } - if (dbConn.ExecuteQuerySingleRecord(string.Format("select userid from {0} where userid=?;", _membershipTable), userid) != null) - { - throw new InvalidOperationException(string.Format(Resources.UserAlreadyExists, userName)); - } - object token = DBNull.Value; - if (requireConfirmationToken) - token = GenerateToken(); - - string insertQuery = string.Format("insert into {0} (userid, createdate, confirmationtoken, isconfirmed, password, passwordchangeddate, passwordsalt) values(?,now(),?,?,?,now(),?)", _membershipTable); - if (dbConn.ExecuteNonQuery(insertQuery, userid, token, !requireConfirmationToken, hashedPass, string.Empty) <= 0) - { - throw new MembershipCreateUserException(MembershipCreateStatus.ProviderError); - } - return token == DBNull.Value ? null : token.ToString(); - } - } - - public override void CreateOrUpdateOAuthAccount(string provider, string providerUserId, string userName) - { - IsValidOperation(true); - if (string.IsNullOrEmpty(userName)) - NullArgumentException(userName); - var userid = GetUserId(userName); - if (userid <= 0) - { - throw new InvalidOperationException(string.Format(Resources.UserNotFound, UserTableName)); - } - var oauthUserId = GetUserIdFromOAuth(provider, providerUserId); - using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(GetConnectionString())) - { - if (oauthUserId == 0) - { - if (dbConn.ExecuteNonQuery(string.Format("insert into {0} (provider, provideruserid, userid) values(?,?,?)", _oauthMembershipTable), provider, providerUserId, userid) <= 0) - { - throw new MembershipCreateUserException(MembershipCreateStatus.ProviderError); - } - } - else - { - if (dbConn.ExecuteNonQuery(string.Format("update {0} set userid=? where upper(provider) = ? and upper(provideruserid)=?;", _oauthMembershipTable), userid, provider.ToUpper(), providerUserId.ToUpper()) <= 0) - { - throw new MembershipCreateUserException(MembershipCreateStatus.ProviderError); - } - } - } - } - - public override MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status) - { - IsValidOperation(false); - return _prevProvider.CreateUser(username, password, email, passwordQuestion, passwordAnswer, isApproved, providerUserKey, out status); - } - - public override string CreateUserAndAccount(string userName, string password, bool requireConfirmation, IDictionary values) - { - IsValidOperation(true); - CreateUserInUserTable(userName, values); - return CreateAccount(userName, password, requireConfirmation); - } - - public override bool DeleteAccount(string userName) - { - IsValidOperation(true); - int userid = GetUserId(userName); - if (userid < 0) - { - return false; - } - using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(GetConnectionString())) - { - return (dbConn.ExecuteNonQuery(string.Format("delete from {0} where userid=?;", _membershipTable), userid) > 0); - } - } - - public override void DeleteOAuthAccount(string provider, string providerUserId) - { - IsValidOperation(true); - using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(GetConnectionString())) - { - if (dbConn.ExecuteNonQuery(string.Format("delete from {0} where upper(provider) = ? and upper(provideruserid)=?;", _oauthMembershipTable), provider.ToUpper(), providerUserId.ToUpper()) <= 0) - { - throw new Exception(string.Format(Resources.DeleteOAuthAccountFailed, provider, providerUserId)); - } - } - } - - public override void DeleteOAuthToken(string token) - { - IsValidOperation(true); - using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(GetConnectionString())) - { - dbConn.ExecuteNonQuery(string.Format("delete from {0} where token=?", _oauthTokenTable), token); - } - } - - public override bool DeleteUser(string username, bool deleteAllRelatedData) - { - if (!Initialized) - return _prevProvider.DeleteUser(username, deleteAllRelatedData); - - int userid = GetUserId(username); - if (userid < 0) - return false; - - using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(GetConnectionString())) - { - if (deleteAllRelatedData) - { - return dbConn.ExecuteInTransaction( - new List>() - { - new Tuple(string.Format("delete from {0} where {1}=?;", UserTableName, UserIdColumn), new object [] { userid }), - new Tuple(string.Format("delete from {0} where userid=?;", _oauthMembershipTable), new object [] { userid }), - new Tuple(string.Format("delete from {0} where userid=?;", _membershipTable), new object [] { userid }), - new Tuple(string.Format("delete from {0} where userid=?;", _userInRolesTable), new object [] { userid }) - }); - } - else - { - return (dbConn.ExecuteNonQuery(string.Format("delete from {0} where {1}=?;", UserTableName, UserIdColumn), userid) > 0); - } - } - } - - public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords) - { - IsValidOperation(false); - return _prevProvider.FindUsersByEmail(emailToMatch, pageIndex, pageSize, out totalRecords); - } - - public override MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalRecords) - { - IsValidOperation(false); - return _prevProvider.FindUsersByName(usernameToMatch, pageIndex, pageSize, out totalRecords); - } - - public override string GeneratePasswordResetToken(string userName, int tokenExpirationInMinutesFromNow) - { - IsValidOperation(true); - if (string.IsNullOrEmpty(userName)) - NullArgumentException("username"); - int userid = GetUserId(userName); - if (userid <= 0) - InvalidUserException(userName); - - if (UserConfirmed(userid)) - { - using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(GetConnectionString())) - { - string token = dbConn.ExecuteScalar(string.Format("select PasswordVerificationToken from {0} where userid=? and PasswordVerificationTokenExpirationDate > ?;", _membershipTable), userid, DateTime.Now) as string; - if (token != null) - { - token = GenerateToken(); - if (dbConn.ExecuteNonQuery(string.Format("update {0} set PasswordVerificationToken=?, PasswordVerificationTokenExpirationDate=? where userid=?;", _membershipTable), token, DateTime.Now.AddMinutes(tokenExpirationInMinutesFromNow), userid) <= 0) - { - throw new ProviderException(Resources.GeneratePassVerificationTokenFailed); - } - } - return token; - } - } - return null; - } - - public override ICollection GetAccountsForUser(string userName) - { - IsValidOperation(true); - int userid = GetUserId(userName); - if (userid > 0) - { - using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(GetConnectionString())) - { - var records = dbConn.ExecuteQuery(string.Format("select provider, provideruserid from {0} where userid=?", _oauthMembershipTable), userid); - if (records != null && records.Count() > 0) - { - var accounts = new List(); - records.ToList().ForEach(record => accounts.Add(new OAuthAccountData(record["provider"].ToString(), record["provideruserid"].ToString()))); - return accounts; - } - } - } - return new OAuthAccountData[0]; - } - - public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords) - { - IsValidOperation(false); - return _prevProvider.GetAllUsers(pageIndex, pageSize, out totalRecords); - } - - public override DateTime GetCreateDate(string userName) - { - int userid = GetUserId(userName); - if (userid < 0) - InvalidUserException(userName); - - using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(GetConnectionString())) - { - var createDate = dbConn.ExecuteScalar(string.Format("select CreateDate from {0} where userid=?;", _membershipTable), userid); - if (createDate != null && createDate != DBNull.Value) - return (DateTime)createDate; - - return DateTime.MinValue; - } - } - - public override DateTime GetLastPasswordFailureDate(string userName) - { - int userid = GetUserId(userName); - if (userid < 0) - InvalidUserException(userName); - - using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(GetConnectionString())) - { - var failureDate = dbConn.ExecuteScalar(string.Format("select LastPasswordFailureDate from {0} where userid=?;", _membershipTable), userid); - if (failureDate != null && failureDate != DBNull.Value) - return (DateTime)failureDate; - - return DateTime.MinValue; - } - } - - public override int GetNumberOfUsersOnline() - { - IsValidOperation(false); - return _prevProvider.GetNumberOfUsersOnline(); - } - - public override string GetPassword(string username, string answer) - { - IsValidOperation(false); - return _prevProvider.GetPassword(username, answer); - } - - public override DateTime GetPasswordChangedDate(string userName) - { - int userid = GetUserId(userName); - if (userid < 0) - InvalidUserException(userName); - - using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(GetConnectionString())) - { - var changedDate = dbConn.ExecuteScalar(string.Format("select PasswordChangedDate from {0} where userid=?;", _membershipTable), userid); - if (changedDate != null) - return (DateTime)changedDate; - - return DateTime.MinValue; - } - } - - public override int GetPasswordFailuresSinceLastSuccess(string userName) - { - int userid = GetUserId(userName); - if (userid < 0) - InvalidUserException(userName); - - return GetPasswordFailuresSinceLastSuccess(userid); - } - - private int GetPasswordFailuresSinceLastSuccess(int userId) - { - using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(GetConnectionString())) - { - var failures = dbConn.ExecuteScalar(string.Format("select PasswordFailuresSinceLastSuccess from {0} where userid=?;", _membershipTable), userId); - if (failures != null) - return (int)failures; - - return -1; - } - } - - public override MembershipUser GetUser(object providerUserKey, bool userIsOnline) - { - IsValidOperation(false); - return _prevProvider.GetUser(providerUserKey, userIsOnline); - } - - public override MembershipUser GetUser(string username, bool userIsOnline) - { - if (!Initialized) - return _prevProvider.GetUser(username, userIsOnline); - - int userid = GetUserId(username); - if (userid < 0) - { - return null; - } - return new MembershipUser(Membership.Provider.Name, username, userid, null, null, null, true, false, DateTime.MinValue, DateTime.MinValue, DateTime.MinValue, DateTime.MinValue, DateTime.MinValue); - } - - /// - /// Gets the id of the specified user. - /// - /// The name of the user. - /// An integer representing the id of the user. - public int GetUserId(string userName) - { - return GetUserId(userName, GetConnectionString(), UserTableName, UserIdColumn, UserNameColumn); - } - - internal static int GetUserId(string userName, string connectionString, string userTableName, string userIdColumn, string userNameColumn) - { - using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(connectionString)) - { - var user = dbConn.ExecuteQuerySingleRecord(string.Format("select {0} from {1} where {2} = ?;", userIdColumn, userTableName, userNameColumn), userName); - if (user != null) - return (int)user[userIdColumn]; - - return 0; - } - } - - public override int GetUserIdFromOAuth(string provider, string providerUserId) - { - IsValidOperation(true); - using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(GetConnectionString())) - { - var user = dbConn.ExecuteQuerySingleRecord(string.Format("select userid from {0} where upper(provider) = ? and upper(provideruserid)=?;", _oauthMembershipTable), provider.ToUpper(), providerUserId.ToUpper()); - if (user != null) - return (int)user["userid"]; - - return 0; - } - } - - public override int GetUserIdFromPasswordResetToken(string token) - { - IsValidOperation(true); - return GetUserIdFromPasswordResetToken(token, false); - } - - public override string GetOAuthTokenSecret(string token) - { - IsValidOperation(true); - using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(GetConnectionString())) - { - return dbConn.ExecuteScalar(string.Format("select secret from {0} where token=?;", _oauthTokenTable), token) as string; - } - } - - private int GetUserIdFromPasswordResetToken(string token, bool checkExpirationDate = false) - { - using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(GetConnectionString())) - { - var user = dbConn.ExecuteQuerySingleRecord(string.Format("select userid from {0} where PasswordVerificationToken = ? {1};", _membershipTable, (checkExpirationDate ? "and PasswordVerificationTokenExpirationDate > now()" : "")), token); - if (user != null) - return (int)user["userid"]; - - return 0; - } - } - - public override string GetUserNameByEmail(string email) - { - IsValidOperation(false); - return _prevProvider.GetUserNameByEmail(email); - } - - public override string GetUserNameFromId(int userId) - { - IsValidOperation(true); - using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(GetConnectionString())) - { - return dbConn.ExecuteScalar(string.Format("select {0} from {1} where {2}=?;", UserNameColumn, UserTableName, UserIdColumn), userId) as string; - } - } - - public override bool HasLocalAccount(int userId) - { - IsValidOperation(true); - using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(GetConnectionString())) - { - return (dbConn.ExecuteQuery(string.Format("select userid from {0} where userid=?;", _membershipTable), userId).Count() > 0); - } - } - - public override bool IsConfirmed(string userName) - { - IsValidOperation(true); - if (string.IsNullOrEmpty(userName)) - NullArgumentException("username"); - int userid = GetUserId(userName); - if (userid <= 0) - InvalidUserException(userName); - return UserConfirmed(userid); - } - - public override void ReplaceOAuthRequestTokenWithAccessToken(string requestToken, string accessToken, string accessTokenSecret) - { - IsValidOperation(true); - using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(GetConnectionString())) - { - dbConn.ExecuteNonQuery(string.Format("delete from {0} where token=?", _oauthTokenTable), requestToken); - } - StoreOAuthRequestToken(accessToken, accessTokenSecret); - } - - public override string ResetPassword(string username, string answer) - { - IsValidOperation(false); - return _prevProvider.ResetPassword(username, answer); - } - - public override bool ResetPasswordWithToken(string token, string newPassword) - { - IsValidOperation(true); - if (string.IsNullOrEmpty(token)) - { - NullArgumentException("token"); - } - if (string.IsNullOrEmpty(newPassword)) - { - NullArgumentException("newPasword"); - } - int userid = GetUserIdFromPasswordResetToken(token, true); - if (userid <= 0) - { - return false; - } - bool passUpdated = UpdatePassword(userid, newPassword) > 0; - if (passUpdated) - { - using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(GetConnectionString())) - { - if (dbConn.ExecuteNonQuery(string.Format("update {0} set PasswordVerificationToken=null, PasswordVerificationTokenExpirationDate=null where userid=?;", _membershipTable), userid) <= 0) - { - throw new ProviderException(string.Format(Resources.ClearPassTokenFailed, userid, _membershipTable)); - } - } - } - return passUpdated; - } - - public override void StoreOAuthRequestToken(string requestToken, string requestTokenSecret) - { - IsValidOperation(true); - string secret = GetOAuthTokenSecret(requestToken); - if (secret != null) - { - if (secret.Equals(requestTokenSecret, StringComparison.OrdinalIgnoreCase)) - return; - using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(GetConnectionString())) - { - if (dbConn.ExecuteNonQuery(string.Format("update {0} set secret=? where token=?;", _oauthTokenTable), requestTokenSecret, requestToken) <= 0) - throw new ProviderException(string.Format(Resources.UpdateTokenFailed, requestTokenSecret)); - } - } - else - { - using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(GetConnectionString())) - { - if (dbConn.ExecuteNonQuery(string.Format("insert into {0} (token, secret) values (?,?);", _oauthTokenTable), requestTokenSecret, requestToken) <= 0) - throw new ProviderException(string.Format(Resources.SaveTokenFailed, requestTokenSecret)); - } - } - } - - public override bool UnlockUser(string userName) - { - IsValidOperation(false); - return _prevProvider.UnlockUser(userName); - } - - public override void UpdateUser(MembershipUser user) - { - IsValidOperation(false); - _prevProvider.UpdateUser(user); - } - - public override bool ValidateUser(string username, string password) - { - if (!Initialized) - return _prevProvider.ValidateUser(username, password); - if (string.IsNullOrEmpty(username)) - NullArgumentException("userName"); - if (string.IsNullOrEmpty(password)) - NullArgumentException("password"); - int userid = GetUserId(username); - if (userid > 0) - { - if (!UserConfirmed(userid)) - return false; - else - return VerifyPassword(userid, password, GetHashedUserPassword(userid)); - } - return false; - } - - #region Properties - public override string ApplicationName - { - get - { - if (Initialized) - throw new NotSupportedException(); - else - return _prevProvider.ApplicationName; - } - set - { - if (Initialized) - throw new NotSupportedException(); - else - _prevProvider.ApplicationName = value; - } - } - - /// - /// Gets or sets the connection string. - /// - public string ConnectionString - { get; set; } - - /// - /// Gets or sets the name associated to the connection string when stored in the configuration manager. - /// - public string ConnectionStringName - { get; set; } - - public override bool EnablePasswordReset - { - get - { - return Initialized ? false : _prevProvider.EnablePasswordReset; - } - } - - public override bool EnablePasswordRetrieval - { - get - { - return Initialized ? false : _prevProvider.EnablePasswordRetrieval; - } - } - - public override int MaxInvalidPasswordAttempts - { - get - { - return Initialized ? Int32.MaxValue : _prevProvider.MaxInvalidPasswordAttempts; - } - } - - public override int MinRequiredPasswordLength - { - get - { - return Initialized ? 7 : _prevProvider.MinRequiredPasswordLength; - } - } - - public override int MinRequiredNonAlphanumericCharacters - { - get - { - return Initialized ? 1 : _prevProvider.MinRequiredNonAlphanumericCharacters; - } - } - - public override int PasswordAttemptWindow - { - get - { - return Initialized ? Int32.MaxValue : _prevProvider.PasswordAttemptWindow; - } - } - - public override MembershipPasswordFormat PasswordFormat - { - get - { - return Initialized ? MembershipPasswordFormat.Hashed : _prevProvider.PasswordFormat; - } - } - - public override string PasswordStrengthRegularExpression - { - get - { - return Initialized ? string.Empty : _prevProvider.PasswordStrengthRegularExpression; - } - } - - /// - /// Gets or sets the name of this provider. - /// - public string ProviderName - { get; set; } - - public override bool RequiresQuestionAndAnswer - { - get - { - return Initialized ? false : _prevProvider.RequiresQuestionAndAnswer; - } - } - - public override bool RequiresUniqueEmail - { - get - { - return Initialized ? false : _prevProvider.RequiresUniqueEmail; - } - } - - /// - /// Gets the name of the table storing user information. - /// - public string UserTableName - { - get - { - if (string.IsNullOrEmpty(_userTableName)) - throw new InvalidOperationException(Resources.UserTableNameNotInitilized); - - return _userTableName; - } - internal set - { - _userTableName = value; - } - } - - /// - /// Gets the name of the column storing the user ids. - /// - public string UserIdColumn - { - get - { - if (string.IsNullOrEmpty(_userIdColumn)) - throw new InvalidOperationException(Resources.UserIdColumnNotInitialized); - - return _userIdColumn; - } - internal set - { - _userIdColumn = value; - } - } - - /// - /// Gets the name of the column storing the user names. - /// - public string UserNameColumn - { - get - { - if (string.IsNullOrEmpty(_userNameColumn)) - throw new InvalidOperationException(Resources.UserNameColumnNotInitialized); - - return _userNameColumn; - } - internal set - { - _userNameColumn = value; - } - } - - #endregion - - #region Private_Internal - - internal void CreateTables() - { - string connString = GetConnectionString(); - using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(connString)) - { - if (!VerifyIfTableExists(connString, UserTableName)) - { - dbConn.ExecuteNonQuery(string.Format("create table {0} ({1} int not null primary key auto_increment, {2} varchar(250) not null unique);", UserTableName, UserIdColumn, UserNameColumn)); - } - - //create schema - string schema = SchemaManager.GetSchema(11); - dbConn.ExecuteNonQuery(schema); - } - } - - internal void ValidateUserTable() - { - if (!VerifyIfTableExists(GetConnectionString(), UserTableName)) - { - throw new InvalidOperationException(string.Format(Resources.UserTableNotFound, UserTableName)); - } - } - - internal bool Initialized - { - get; - set; - } - - private string GetConnectionString() - { - if (!string.IsNullOrEmpty(ConnectionString)) - return ConnectionString; - else - { - ConnectionStringSettings connString = ConfigurationManager.ConnectionStrings[ConnectionStringName]; - if (connString != null) - return connString.ConnectionString; - } - - if (!string.IsNullOrEmpty(_connString)) - return _connString; - throw new InvalidOperationException(Resources.NoConnString); - } - - internal static bool VerifyIfTableExists(string connectionString, string tableName) - { - using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(connectionString)) - { - var tables = dbConn.ExecuteQuery("show tables;"); - return tables.Where(record => record[0].ToString().Equals(tableName, StringComparison.OrdinalIgnoreCase)).Count() > 0; - } - } - - internal string GetHashedUserPassword(int userId) - { - using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(GetConnectionString())) - { - var userPassword = dbConn.ExecuteQuerySingleRecord(string.Format("select password from {0} where userid=?;", _membershipTable), userId); - if (userPassword != null) - return userPassword[0].ToString(); - return null; - } - } - - internal string HashPassword(string password) - { - if (string.IsNullOrEmpty(password)) - { - throw new ArgumentException(Resources.InvalidArgument, password); - } - - Rfc2898DeriveBytes rfc2898 = new Rfc2898DeriveBytes(password, 16, 1000); - byte[] salt = rfc2898.Salt; - byte[] passBytes = rfc2898.GetBytes(32); - byte[] result = new byte[48]; - Buffer.BlockCopy(salt, 0, result, 0, 16); - Buffer.BlockCopy(passBytes, 0, result, 16, 32); - return Convert.ToBase64String(result); - } - - internal bool VerifyPassword(int userid, string password, string hashedPassword) - { - if (string.IsNullOrEmpty(password)) - { - throw new ArgumentException(Resources.InvalidArgument, password); - } - if (string.IsNullOrEmpty(hashedPassword)) - { - throw new ArgumentException(Resources.InvalidArgument, hashedPassword); - } - byte[] hashed = Convert.FromBase64String(hashedPassword); - if (hashed.Length != 48) - { - return false; - } - byte[] salt = new byte[16]; - byte[] passBytes = new byte[32]; - Buffer.BlockCopy(hashed, 0, salt, 0, 16); - Buffer.BlockCopy(hashed, 16, passBytes, 0, 32); - - Rfc2898DeriveBytes rfc2898 = new Rfc2898DeriveBytes(password, salt, 1000); - bool validation = CompareBuffer(rfc2898.GetBytes(32), passBytes); - using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(GetConnectionString())) - { - if (validation) - { - dbConn.ExecuteNonQuery(string.Format("update {0} set PasswordFailuresSinceLastSuccess=0 where userid=?;", _membershipTable), userid); - } - else - { - int failures = GetPasswordFailuresSinceLastSuccess(userid); - dbConn.ExecuteNonQuery(string.Format("update {0} set PasswordFailuresSinceLastSuccess=?, LastPasswordFailureDate=now() where userid=?;", _membershipTable), (failures == -1 ? 1 : failures + 1), userid); - } - } - return validation; - } - - internal bool CompareBuffer(byte[] source, byte[] target) - { - if (source == null || target == null || (source.Length != target.Length)) - return false; - for (int ctr = 0; ctr < target.Length; ctr++) - { - if (target[ctr] != source[ctr]) - return false; - } - - return true; - } - - private int UpdatePassword(int userId, string newPassword) - { - string hashedPass = HashPassword(newPassword); - if (hashedPass.Length > 128) - throw new ArgumentException(Resources.PasswordExceedsMaxLength, newPassword); - using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(GetConnectionString())) - { - return dbConn.ExecuteNonQuery(string.Format("update {0} set password=?, PasswordChangedDate=now(), PasswordSalt='' where userid=?;", _membershipTable), hashedPass, userId); - } - } - - internal void IsValidOperation(bool currentProvider) - { - switch (currentProvider) - { - case true: - if (!Initialized) - ProviderException(); - break; - case false: - if (Initialized) - PreviousProviderException(); - break; - } - } - - private void ProviderException() - { - throw new Exception(Resources.SimpleMembershipNotInitialized); - } - - private void PreviousProviderException() - { - throw new NotSupportedException(Resources.PreviousProviderException); - } - - private void InvalidUserException(string userName) - { - throw new Exception(string.Format(Resources.InvalidUser, userName, UserTableName)); - } - - internal static void NullArgumentException(string parameterName) - { - throw new ArgumentException(Resources.InvalidArgument, parameterName); - } - - private string GenerateToken() - { - RNGCryptoServiceProvider provider = new RNGCryptoServiceProvider(); - byte[] data = new byte[16]; - provider.GetBytes(data); - return HttpServerUtility.UrlTokenEncode(data); - } - - private void CreateUserInUserTable(string userName, IDictionary values) - { - IsValidOperation(true); - var userid = GetUserId(userName); - if (userid > 0) - { - throw new MembershipCreateUserException(MembershipCreateStatus.DuplicateUserName); - } - StringBuilder columns = new StringBuilder(); - columns.Append(UserNameColumn); - StringBuilder args = new StringBuilder(); - args.Append("?"); - var argsValues = new List(); - argsValues.Add(userName); - - if (values != null) - { - foreach (var value in values) - { - if (string.Equals(UserNameColumn, value.Key, StringComparison.OrdinalIgnoreCase)) - continue; - columns.Append(string.Format(",{0}", value.Key)); - args.Append(",?"); - argsValues.Add(value.Value != null ? value.Value : DBNull.Value); - } - } - using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(GetConnectionString())) - { - string query = string.Format("insert into {0} ({1}) values({2})", UserTableName, columns.ToString(), args.ToString()); - if (dbConn.ExecuteNonQuery(query, argsValues.ToArray()) < 1) - { - throw new MembershipCreateUserException(MembershipCreateStatus.ProviderError); - } - } - } - - private bool UserConfirmed(int userId) - { - using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(GetConnectionString())) - { - return ((long)dbConn.ExecuteScalar(string.Format("select count(*) from {0} where userid=? and isconfirmed=1;", _membershipTable), userId)) > 0; - } - } - #endregion - } -} +// Copyright © 2014, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Web.Common; +using MySql.Web.General; +using MySql.Web.Properties; +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Configuration.Provider; +using System.Globalization; +using System.Linq; +using System.Security.Cryptography; +using System.Text; +using System.Web; +using System.Web.Hosting; +using System.Web.Security; +using WebMatrix.WebData; + +namespace MySql.Web.Security +{ + /// + /// Manages storage of simple membership information for an ASP.NET application in a MySQL database. + /// + public class MySqlSimpleMembershipProvider : ExtendedMembershipProvider + { + #region Private + private readonly MembershipProvider _prevProvider; + + Application _app; + bool _enablePwdReset; + bool _enablePwdRetrival; + int _maxPwdAttempts; + int _minReqNonAlphanumericalChars; + int _minReqPwdLength; + int _pwdAttemptWindow; + MembershipPasswordFormat _pwdFormat; + string _pwdStrenghtRegex; + bool _reqQuestionAnswer; + bool _reqUniqueEmail; + string _connString; + string _userTableName; + string _userIdColumn; + string _userNameColumn; + bool _autoGenerateTables; + private readonly string _membershipTable = "webpages_membership"; + private readonly string _oauthMembershipTable = "webpages_oauthmembership"; + private readonly string _userInRolesTable = "webpages_usersinroles"; + private readonly string _oauthTokenTable = "webpages_oauthtoken"; + + private static string GetConfigValue(string configVal, string defaultVal) + { + return !string.IsNullOrEmpty(configVal) ? configVal : defaultVal; + } + #endregion + public MySqlSimpleMembershipProvider() + : this(null) + { } + + public MySqlSimpleMembershipProvider(MembershipProvider previousProvider) + { + _prevProvider = previousProvider; + if (_prevProvider != null) + { + _prevProvider.ValidatingPassword += delegate (object sender, ValidatePasswordEventArgs args) { this.OnValidatingPassword(args); }; + } + } + + public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config) + { + if (config == null) + { + NullArgumentException("config"); + } + if (string.IsNullOrEmpty(name)) + { + name = "MySqlExtendedMembershipProvider"; + } + if (string.IsNullOrEmpty(config["description"])) + { + config.Remove("description"); + config.Add("description", string.Format("MySql Default {0} Description", name)); + } + + base.Initialize(name, config); + + var appName = GetConfigValue(config["applicationName"], HostingEnvironment.SiteName); + _maxPwdAttempts = Int32.Parse(GetConfigValue(config["maxInvalidPasswordAttempts"], "5"), CultureInfo.InvariantCulture); + _pwdAttemptWindow = Int32.Parse(GetConfigValue(config["passwordAttemptWindow"], "10"), CultureInfo.InvariantCulture); + _minReqNonAlphanumericalChars = Int32.Parse(GetConfigValue(config["minRequiredNonalphanumericCharacters"], "1"), CultureInfo.InvariantCulture); + _minReqPwdLength = Int32.Parse(GetConfigValue(config["minRequiredPasswordLength"], "7"), CultureInfo.InvariantCulture); + _pwdStrenghtRegex = GetConfigValue(config["passwordStrengthRegularExpression"], ""); + _enablePwdReset = bool.Parse(GetConfigValue(config["enablePasswordReset"], "True")); + _enablePwdRetrival = bool.Parse(GetConfigValue(config["enablePasswordRetrieval"], "False")); + _reqQuestionAnswer = bool.Parse(GetConfigValue(config["requiresQuestionAndAnswer"], "False")); + _reqUniqueEmail = bool.Parse(GetConfigValue(config["requiresUniqueEmail"], "True")); + + var pwdFormat = !string.IsNullOrEmpty(config["passwordFormat"]) ? config["passwordFormat"].ToString().ToLowerInvariant() : "hashed"; + + switch (pwdFormat) + { + case "hashed": + _pwdFormat = MembershipPasswordFormat.Hashed; + break; + case "encrypted": + _pwdFormat = MembershipPasswordFormat.Encrypted; + break; + case "clear": + _pwdFormat = MembershipPasswordFormat.Clear; + break; + default: + throw new ProviderException(Resources.PasswordFormatNotSupported); + } + + if (_pwdFormat == MembershipPasswordFormat.Hashed) + { + if (_enablePwdRetrival) + throw new ProviderException(Resources.CannotRetrieveHashedPasswords); + } + + _app = new Application(appName, base.Description); + _connString = ConfigUtility.GetConnectionString(config); + if (string.IsNullOrEmpty(_connString)) return; + + UserTableName = GetConfigValue(config["userTableName"], ""); + UserIdColumn = GetConfigValue(config["userIdColumn"], ""); + UserNameColumn = GetConfigValue(config["userNameColumn"], ""); + _autoGenerateTables = bool.Parse(GetConfigValue(config["autoGenerateTables"], "True")); + if (_autoGenerateTables) + CreateTables(); + else + ValidateUserTable(); + + Initialized = true; + } + + public override bool ChangePassword(string username, string oldPassword, string newPassword) + { + if (!Initialized) + { + _prevProvider.ChangePassword(username, oldPassword, newPassword); + } + + if (string.IsNullOrEmpty(username)) + NullArgumentException("username"); + if (string.IsNullOrEmpty(oldPassword)) + NullArgumentException("oldPassword"); + if (string.IsNullOrEmpty(newPassword)) + NullArgumentException("newPassword"); + + int userid = GetUserId(username); + if (userid <= 0) + { + return false; + } + if (VerifyPassword(userid, oldPassword, GetHashedUserPassword(userid))) + { + return UpdatePassword(userid, newPassword) > 0; + } + + return false; + } + + public override bool ChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion, string newPasswordAnswer) + { + IsValidOperation(false); + return _prevProvider.ChangePasswordQuestionAndAnswer(username, password, newPasswordQuestion, newPasswordAnswer); + } + + public override bool ConfirmAccount(string accountConfirmationToken) + { + IsValidOperation(true); + using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(GetConnectionString())) + { + var token = dbConn.ExecuteQuerySingleRecord(string.Format("select userid, confirmationtoken from {0} where confirmationtoken=?", _membershipTable), accountConfirmationToken); + if (token == null || (token != null && string.IsNullOrEmpty(token[1].ToString()))) + { + return false; + } + return dbConn.ExecuteNonQuery(string.Format("update {0} set isconfirmed=1 where userid=?;", _membershipTable), (int)token[0]) > 0; + } + } + + public override bool ConfirmAccount(string userName, string accountConfirmationToken) + { + var userid = GetUserId(userName); + if (userid <= 0) + return false; + + using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(GetConnectionString())) + { + var token = dbConn.ExecuteQuerySingleRecord(string.Format("select userid, confirmationtoken from {0} where confirmationtoken=? and userid=?", _membershipTable), accountConfirmationToken, userid); + if (token == null || (token != null && string.IsNullOrEmpty(token[1].ToString()))) + { + return false; + } + return dbConn.ExecuteNonQuery(string.Format("update {0} set isconfirmed=1 where userid=?;", _membershipTable), userid) > 0; + } + } + + public override string CreateAccount(string userName, string password, bool requireConfirmationToken) + { + IsValidOperation(true); + if (string.IsNullOrEmpty(userName)) + NullArgumentException(userName); + if (string.IsNullOrEmpty(password)) + NullArgumentException(password); + var hashedPass = HashPassword(password); + if (hashedPass.Length > 128) + throw new ArgumentException(Resources.PasswordExceedsMaxLength, password); + + using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(GetConnectionString())) + { + var userid = GetUserId(userName); + if (userid <= 0) + { + throw new InvalidOperationException(string.Format(Resources.UserNotFound, UserTableName)); + } + if (dbConn.ExecuteQuerySingleRecord(string.Format("select userid from {0} where userid=?;", _membershipTable), userid) != null) + { + throw new InvalidOperationException(string.Format(Resources.UserAlreadyExists, userName)); + } + object token = DBNull.Value; + if (requireConfirmationToken) + token = GenerateToken(); + + string insertQuery = string.Format("insert into {0} (userid, createdate, confirmationtoken, isconfirmed, password, passwordchangeddate, passwordsalt) values(?,now(),?,?,?,now(),?)", _membershipTable); + if (dbConn.ExecuteNonQuery(insertQuery, userid, token, !requireConfirmationToken, hashedPass, string.Empty) <= 0) + { + throw new MembershipCreateUserException(MembershipCreateStatus.ProviderError); + } + return token == DBNull.Value ? null : token.ToString(); + } + } + + public override void CreateOrUpdateOAuthAccount(string provider, string providerUserId, string userName) + { + IsValidOperation(true); + if (string.IsNullOrEmpty(userName)) + NullArgumentException(userName); + var userid = GetUserId(userName); + if (userid <= 0) + { + throw new InvalidOperationException(string.Format(Resources.UserNotFound, UserTableName)); + } + var oauthUserId = GetUserIdFromOAuth(provider, providerUserId); + using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(GetConnectionString())) + { + if (oauthUserId == 0) + { + if (dbConn.ExecuteNonQuery(string.Format("insert into {0} (provider, provideruserid, userid) values(?,?,?)", _oauthMembershipTable), provider, providerUserId, userid) <= 0) + { + throw new MembershipCreateUserException(MembershipCreateStatus.ProviderError); + } + } + else + { + if (dbConn.ExecuteNonQuery(string.Format("update {0} set userid=? where upper(provider) = ? and upper(provideruserid)=?;", _oauthMembershipTable), userid, provider.ToUpper(), providerUserId.ToUpper()) <= 0) + { + throw new MembershipCreateUserException(MembershipCreateStatus.ProviderError); + } + } + } + } + + public override MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status) + { + IsValidOperation(false); + return _prevProvider.CreateUser(username, password, email, passwordQuestion, passwordAnswer, isApproved, providerUserKey, out status); + } + + public override string CreateUserAndAccount(string userName, string password, bool requireConfirmation, IDictionary values) + { + IsValidOperation(true); + CreateUserInUserTable(userName, values); + return CreateAccount(userName, password, requireConfirmation); + } + + public override bool DeleteAccount(string userName) + { + IsValidOperation(true); + int userid = GetUserId(userName); + if (userid < 0) + { + return false; + } + using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(GetConnectionString())) + { + return (dbConn.ExecuteNonQuery(string.Format("delete from {0} where userid=?;", _membershipTable), userid) > 0); + } + } + + public override void DeleteOAuthAccount(string provider, string providerUserId) + { + IsValidOperation(true); + using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(GetConnectionString())) + { + if (dbConn.ExecuteNonQuery(string.Format("delete from {0} where upper(provider) = ? and upper(provideruserid)=?;", _oauthMembershipTable), provider.ToUpper(), providerUserId.ToUpper()) <= 0) + { + throw new Exception(string.Format(Resources.DeleteOAuthAccountFailed, provider, providerUserId)); + } + } + } + + public override void DeleteOAuthToken(string token) + { + IsValidOperation(true); + using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(GetConnectionString())) + { + dbConn.ExecuteNonQuery(string.Format("delete from {0} where token=?", _oauthTokenTable), token); + } + } + + public override bool DeleteUser(string username, bool deleteAllRelatedData) + { + if (!Initialized) + return _prevProvider.DeleteUser(username, deleteAllRelatedData); + + int userid = GetUserId(username); + if (userid < 0) + return false; + + using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(GetConnectionString())) + { + if (deleteAllRelatedData) + { + return dbConn.ExecuteInTransaction( + new List>() + { + new Tuple(string.Format("delete from {0} where {1}=?;", UserTableName, UserIdColumn), new object [] { userid }), + new Tuple(string.Format("delete from {0} where userid=?;", _oauthMembershipTable), new object [] { userid }), + new Tuple(string.Format("delete from {0} where userid=?;", _membershipTable), new object [] { userid }), + new Tuple(string.Format("delete from {0} where userid=?;", _userInRolesTable), new object [] { userid }) + }); + } + else + { + return (dbConn.ExecuteNonQuery(string.Format("delete from {0} where {1}=?;", UserTableName, UserIdColumn), userid) > 0); + } + } + } + + public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords) + { + IsValidOperation(false); + return _prevProvider.FindUsersByEmail(emailToMatch, pageIndex, pageSize, out totalRecords); + } + + public override MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalRecords) + { + IsValidOperation(false); + return _prevProvider.FindUsersByName(usernameToMatch, pageIndex, pageSize, out totalRecords); + } + + public override string GeneratePasswordResetToken(string userName, int tokenExpirationInMinutesFromNow) + { + IsValidOperation(true); + if (string.IsNullOrEmpty(userName)) + NullArgumentException("username"); + int userid = GetUserId(userName); + if (userid <= 0) + InvalidUserException(userName); + + if (UserConfirmed(userid)) + { + using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(GetConnectionString())) + { + string token = dbConn.ExecuteScalar(string.Format("select PasswordVerificationToken from {0} where userid=? and PasswordVerificationTokenExpirationDate > ?;", _membershipTable), userid, DateTime.Now) as string; + if (token != null) + { + token = GenerateToken(); + if (dbConn.ExecuteNonQuery(string.Format("update {0} set PasswordVerificationToken=?, PasswordVerificationTokenExpirationDate=? where userid=?;", _membershipTable), token, DateTime.Now.AddMinutes(tokenExpirationInMinutesFromNow), userid) <= 0) + { + throw new ProviderException(Resources.GeneratePassVerificationTokenFailed); + } + } + return token; + } + } + return null; + } + + public override ICollection GetAccountsForUser(string userName) + { + IsValidOperation(true); + int userid = GetUserId(userName); + if (userid > 0) + { + using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(GetConnectionString())) + { + var records = dbConn.ExecuteQuery(string.Format("select provider, provideruserid from {0} where userid=?", _oauthMembershipTable), userid); + if (records != null && records.Count() > 0) + { + var accounts = new List(); + records.ToList().ForEach(record => accounts.Add(new OAuthAccountData(record["provider"].ToString(), record["provideruserid"].ToString()))); + return accounts; + } + } + } + return new OAuthAccountData[0]; + } + + public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords) + { + IsValidOperation(false); + return _prevProvider.GetAllUsers(pageIndex, pageSize, out totalRecords); + } + + public override DateTime GetCreateDate(string userName) + { + int userid = GetUserId(userName); + if (userid < 0) + InvalidUserException(userName); + + using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(GetConnectionString())) + { + var createDate = dbConn.ExecuteScalar(string.Format("select CreateDate from {0} where userid=?;", _membershipTable), userid); + if (createDate != null && createDate != DBNull.Value) + return (DateTime)createDate; + + return DateTime.MinValue; + } + } + + public override DateTime GetLastPasswordFailureDate(string userName) + { + int userid = GetUserId(userName); + if (userid < 0) + InvalidUserException(userName); + + using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(GetConnectionString())) + { + var failureDate = dbConn.ExecuteScalar(string.Format("select LastPasswordFailureDate from {0} where userid=?;", _membershipTable), userid); + if (failureDate != null && failureDate != DBNull.Value) + return (DateTime)failureDate; + + return DateTime.MinValue; + } + } + + public override int GetNumberOfUsersOnline() + { + IsValidOperation(false); + return _prevProvider.GetNumberOfUsersOnline(); + } + + public override string GetPassword(string username, string answer) + { + IsValidOperation(false); + return _prevProvider.GetPassword(username, answer); + } + + public override DateTime GetPasswordChangedDate(string userName) + { + int userid = GetUserId(userName); + if (userid < 0) + InvalidUserException(userName); + + using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(GetConnectionString())) + { + var changedDate = dbConn.ExecuteScalar(string.Format("select PasswordChangedDate from {0} where userid=?;", _membershipTable), userid); + if (changedDate != null) + return (DateTime)changedDate; + + return DateTime.MinValue; + } + } + + public override int GetPasswordFailuresSinceLastSuccess(string userName) + { + int userid = GetUserId(userName); + if (userid < 0) + InvalidUserException(userName); + + return GetPasswordFailuresSinceLastSuccess(userid); + } + + private int GetPasswordFailuresSinceLastSuccess(int userId) + { + using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(GetConnectionString())) + { + var failures = dbConn.ExecuteScalar(string.Format("select PasswordFailuresSinceLastSuccess from {0} where userid=?;", _membershipTable), userId); + if (failures != null) + return (int)failures; + + return -1; + } + } + + public override MembershipUser GetUser(object providerUserKey, bool userIsOnline) + { + IsValidOperation(false); + return _prevProvider.GetUser(providerUserKey, userIsOnline); + } + + public override MembershipUser GetUser(string username, bool userIsOnline) + { + if (!Initialized) + return _prevProvider.GetUser(username, userIsOnline); + + int userid = GetUserId(username); + if (userid < 0) + { + return null; + } + return new MembershipUser(Membership.Provider.Name, username, userid, null, null, null, true, false, DateTime.MinValue, DateTime.MinValue, DateTime.MinValue, DateTime.MinValue, DateTime.MinValue); + } + + /// + /// Gets the id of the specified user. + /// + /// The name of the user. + /// An integer representing the id of the user. + public int GetUserId(string userName) + { + return GetUserId(userName, GetConnectionString(), UserTableName, UserIdColumn, UserNameColumn); + } + + internal static int GetUserId(string userName, string connectionString, string userTableName, string userIdColumn, string userNameColumn) + { + using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(connectionString)) + { + var user = dbConn.ExecuteQuerySingleRecord(string.Format("select {0} from {1} where {2} = ?;", userIdColumn, userTableName, userNameColumn), userName); + if (user != null) + return (int)user[userIdColumn]; + + return 0; + } + } + + public override int GetUserIdFromOAuth(string provider, string providerUserId) + { + IsValidOperation(true); + using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(GetConnectionString())) + { + var user = dbConn.ExecuteQuerySingleRecord(string.Format("select userid from {0} where upper(provider) = ? and upper(provideruserid)=?;", _oauthMembershipTable), provider.ToUpper(), providerUserId.ToUpper()); + if (user != null) + return (int)user["userid"]; + + return 0; + } + } + + public override int GetUserIdFromPasswordResetToken(string token) + { + IsValidOperation(true); + return GetUserIdFromPasswordResetToken(token, false); + } + + public override string GetOAuthTokenSecret(string token) + { + IsValidOperation(true); + using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(GetConnectionString())) + { + return dbConn.ExecuteScalar(string.Format("select secret from {0} where token=?;", _oauthTokenTable), token) as string; + } + } + + private int GetUserIdFromPasswordResetToken(string token, bool checkExpirationDate = false) + { + using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(GetConnectionString())) + { + var user = dbConn.ExecuteQuerySingleRecord(string.Format("select userid from {0} where PasswordVerificationToken = ? {1};", _membershipTable, (checkExpirationDate ? "and PasswordVerificationTokenExpirationDate > now()" : "")), token); + if (user != null) + return (int)user["userid"]; + + return 0; + } + } + + public override string GetUserNameByEmail(string email) + { + IsValidOperation(false); + return _prevProvider.GetUserNameByEmail(email); + } + + public override string GetUserNameFromId(int userId) + { + IsValidOperation(true); + using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(GetConnectionString())) + { + return dbConn.ExecuteScalar(string.Format("select {0} from {1} where {2}=?;", UserNameColumn, UserTableName, UserIdColumn), userId) as string; + } + } + + public override bool HasLocalAccount(int userId) + { + IsValidOperation(true); + using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(GetConnectionString())) + { + return (dbConn.ExecuteQuery(string.Format("select userid from {0} where userid=?;", _membershipTable), userId).Count() > 0); + } + } + + public override bool IsConfirmed(string userName) + { + IsValidOperation(true); + if (string.IsNullOrEmpty(userName)) + NullArgumentException("username"); + int userid = GetUserId(userName); + if (userid <= 0) + InvalidUserException(userName); + return UserConfirmed(userid); + } + + public override void ReplaceOAuthRequestTokenWithAccessToken(string requestToken, string accessToken, string accessTokenSecret) + { + IsValidOperation(true); + using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(GetConnectionString())) + { + dbConn.ExecuteNonQuery(string.Format("delete from {0} where token=?", _oauthTokenTable), requestToken); + } + StoreOAuthRequestToken(accessToken, accessTokenSecret); + } + + public override string ResetPassword(string username, string answer) + { + IsValidOperation(false); + return _prevProvider.ResetPassword(username, answer); + } + + public override bool ResetPasswordWithToken(string token, string newPassword) + { + IsValidOperation(true); + if (string.IsNullOrEmpty(token)) + { + NullArgumentException("token"); + } + if (string.IsNullOrEmpty(newPassword)) + { + NullArgumentException("newPasword"); + } + int userid = GetUserIdFromPasswordResetToken(token, true); + if (userid <= 0) + { + return false; + } + bool passUpdated = UpdatePassword(userid, newPassword) > 0; + if (passUpdated) + { + using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(GetConnectionString())) + { + if (dbConn.ExecuteNonQuery(string.Format("update {0} set PasswordVerificationToken=null, PasswordVerificationTokenExpirationDate=null where userid=?;", _membershipTable), userid) <= 0) + { + throw new ProviderException(string.Format(Resources.ClearPassTokenFailed, userid, _membershipTable)); + } + } + } + return passUpdated; + } + + public override void StoreOAuthRequestToken(string requestToken, string requestTokenSecret) + { + IsValidOperation(true); + string secret = GetOAuthTokenSecret(requestToken); + if (secret != null) + { + if (secret.Equals(requestTokenSecret, StringComparison.OrdinalIgnoreCase)) + return; + using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(GetConnectionString())) + { + if (dbConn.ExecuteNonQuery(string.Format("update {0} set secret=? where token=?;", _oauthTokenTable), requestTokenSecret, requestToken) <= 0) + throw new ProviderException(string.Format(Resources.UpdateTokenFailed, requestTokenSecret)); + } + } + else + { + using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(GetConnectionString())) + { + if (dbConn.ExecuteNonQuery(string.Format("insert into {0} (token, secret) values (?,?);", _oauthTokenTable), requestTokenSecret, requestToken) <= 0) + throw new ProviderException(string.Format(Resources.SaveTokenFailed, requestTokenSecret)); + } + } + } + + public override bool UnlockUser(string userName) + { + IsValidOperation(false); + return _prevProvider.UnlockUser(userName); + } + + public override void UpdateUser(MembershipUser user) + { + IsValidOperation(false); + _prevProvider.UpdateUser(user); + } + + public override bool ValidateUser(string username, string password) + { + if (!Initialized) + return _prevProvider.ValidateUser(username, password); + if (string.IsNullOrEmpty(username)) + NullArgumentException("userName"); + if (string.IsNullOrEmpty(password)) + NullArgumentException("password"); + int userid = GetUserId(username); + if (userid > 0) + { + if (!UserConfirmed(userid)) + return false; + else + return VerifyPassword(userid, password, GetHashedUserPassword(userid)); + } + return false; + } + + #region Properties + public override string ApplicationName + { + get + { + if (Initialized) + throw new NotSupportedException(); + else + return _prevProvider.ApplicationName; + } + set + { + if (Initialized) + throw new NotSupportedException(); + else + _prevProvider.ApplicationName = value; + } + } + + /// + /// Gets or sets the connection string. + /// + public string ConnectionString + { get; set; } + + /// + /// Gets or sets the name associated to the connection string when stored in the configuration manager. + /// + public string ConnectionStringName + { get; set; } + + public override bool EnablePasswordReset + { + get + { + return Initialized ? false : _prevProvider.EnablePasswordReset; + } + } + + public override bool EnablePasswordRetrieval + { + get + { + return Initialized ? false : _prevProvider.EnablePasswordRetrieval; + } + } + + public override int MaxInvalidPasswordAttempts + { + get + { + return Initialized ? Int32.MaxValue : _prevProvider.MaxInvalidPasswordAttempts; + } + } + + public override int MinRequiredPasswordLength + { + get + { + return Initialized ? 7 : _prevProvider.MinRequiredPasswordLength; + } + } + + public override int MinRequiredNonAlphanumericCharacters + { + get + { + return Initialized ? 1 : _prevProvider.MinRequiredNonAlphanumericCharacters; + } + } + + public override int PasswordAttemptWindow + { + get + { + return Initialized ? Int32.MaxValue : _prevProvider.PasswordAttemptWindow; + } + } + + public override MembershipPasswordFormat PasswordFormat + { + get + { + return Initialized ? MembershipPasswordFormat.Hashed : _prevProvider.PasswordFormat; + } + } + + public override string PasswordStrengthRegularExpression + { + get + { + return Initialized ? string.Empty : _prevProvider.PasswordStrengthRegularExpression; + } + } + + /// + /// Gets or sets the name of this provider. + /// + public string ProviderName + { get; set; } + + public override bool RequiresQuestionAndAnswer + { + get + { + return Initialized ? false : _prevProvider.RequiresQuestionAndAnswer; + } + } + + public override bool RequiresUniqueEmail + { + get + { + return Initialized ? false : _prevProvider.RequiresUniqueEmail; + } + } + + /// + /// Gets the name of the table storing user information. + /// + public string UserTableName + { + get + { + if (string.IsNullOrEmpty(_userTableName)) + throw new InvalidOperationException(Resources.UserTableNameNotInitilized); + + return _userTableName; + } + internal set + { + _userTableName = value; + } + } + + /// + /// Gets the name of the column storing the user ids. + /// + public string UserIdColumn + { + get + { + if (string.IsNullOrEmpty(_userIdColumn)) + throw new InvalidOperationException(Resources.UserIdColumnNotInitialized); + + return _userIdColumn; + } + internal set + { + _userIdColumn = value; + } + } + + /// + /// Gets the name of the column storing the user names. + /// + public string UserNameColumn + { + get + { + if (string.IsNullOrEmpty(_userNameColumn)) + throw new InvalidOperationException(Resources.UserNameColumnNotInitialized); + + return _userNameColumn; + } + internal set + { + _userNameColumn = value; + } + } + + #endregion + + #region Private_Internal + + internal void CreateTables() + { + string connString = GetConnectionString(); + using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(connString)) + { + if (!VerifyIfTableExists(connString, UserTableName)) + { + dbConn.ExecuteNonQuery(string.Format("create table {0} ({1} int not null primary key auto_increment, {2} varchar(250) not null unique);", UserTableName, UserIdColumn, UserNameColumn)); + } + + //create schema + string schema = SchemaManager.GetSchema(11); + dbConn.ExecuteNonQuery(schema); + } + } + + internal void ValidateUserTable() + { + if (!VerifyIfTableExists(GetConnectionString(), UserTableName)) + { + throw new InvalidOperationException(string.Format(Resources.UserTableNotFound, UserTableName)); + } + } + + internal bool Initialized + { + get; + set; + } + + private string GetConnectionString() + { + if (!string.IsNullOrEmpty(ConnectionString)) + return ConnectionString; + else + { + ConnectionStringSettings connString = ConfigurationManager.ConnectionStrings[ConnectionStringName]; + if (connString != null) + return connString.ConnectionString; + } + + if (!string.IsNullOrEmpty(_connString)) + return _connString; + throw new InvalidOperationException(Resources.NoConnString); + } + + internal static bool VerifyIfTableExists(string connectionString, string tableName) + { + using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(connectionString)) + { + var tables = dbConn.ExecuteQuery("show tables;"); + return tables.Where(record => record[0].ToString().Equals(tableName, StringComparison.OrdinalIgnoreCase)).Count() > 0; + } + } + + internal string GetHashedUserPassword(int userId) + { + using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(GetConnectionString())) + { + var userPassword = dbConn.ExecuteQuerySingleRecord(string.Format("select password from {0} where userid=?;", _membershipTable), userId); + if (userPassword != null) + return userPassword[0].ToString(); + return null; + } + } + + internal string HashPassword(string password) + { + if (string.IsNullOrEmpty(password)) + { + throw new ArgumentException(Resources.InvalidArgument, password); + } + + Rfc2898DeriveBytes rfc2898 = new Rfc2898DeriveBytes(password, 16, 1000); + byte[] salt = rfc2898.Salt; + byte[] passBytes = rfc2898.GetBytes(32); + byte[] result = new byte[48]; + Buffer.BlockCopy(salt, 0, result, 0, 16); + Buffer.BlockCopy(passBytes, 0, result, 16, 32); + return Convert.ToBase64String(result); + } + + internal bool VerifyPassword(int userid, string password, string hashedPassword) + { + if (string.IsNullOrEmpty(password)) + { + throw new ArgumentException(Resources.InvalidArgument, password); + } + if (string.IsNullOrEmpty(hashedPassword)) + { + throw new ArgumentException(Resources.InvalidArgument, hashedPassword); + } + byte[] hashed = Convert.FromBase64String(hashedPassword); + if (hashed.Length != 48) + { + return false; + } + byte[] salt = new byte[16]; + byte[] passBytes = new byte[32]; + Buffer.BlockCopy(hashed, 0, salt, 0, 16); + Buffer.BlockCopy(hashed, 16, passBytes, 0, 32); + + Rfc2898DeriveBytes rfc2898 = new Rfc2898DeriveBytes(password, salt, 1000); + bool validation = CompareBuffer(rfc2898.GetBytes(32), passBytes); + using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(GetConnectionString())) + { + if (validation) + { + dbConn.ExecuteNonQuery(string.Format("update {0} set PasswordFailuresSinceLastSuccess=0 where userid=?;", _membershipTable), userid); + } + else + { + int failures = GetPasswordFailuresSinceLastSuccess(userid); + dbConn.ExecuteNonQuery(string.Format("update {0} set PasswordFailuresSinceLastSuccess=?, LastPasswordFailureDate=now() where userid=?;", _membershipTable), (failures == -1 ? 1 : failures + 1), userid); + } + } + return validation; + } + + internal bool CompareBuffer(byte[] source, byte[] target) + { + if (source == null || target == null || (source.Length != target.Length)) + return false; + for (int ctr = 0; ctr < target.Length; ctr++) + { + if (target[ctr] != source[ctr]) + return false; + } + + return true; + } + + private int UpdatePassword(int userId, string newPassword) + { + string hashedPass = HashPassword(newPassword); + if (hashedPass.Length > 128) + throw new ArgumentException(Resources.PasswordExceedsMaxLength, newPassword); + using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(GetConnectionString())) + { + return dbConn.ExecuteNonQuery(string.Format("update {0} set password=?, PasswordChangedDate=now(), PasswordSalt='' where userid=?;", _membershipTable), hashedPass, userId); + } + } + + internal void IsValidOperation(bool currentProvider) + { + switch (currentProvider) + { + case true: + if (!Initialized) + ProviderException(); + break; + case false: + if (Initialized) + PreviousProviderException(); + break; + } + } + + private void ProviderException() + { + throw new Exception(Resources.SimpleMembershipNotInitialized); + } + + private void PreviousProviderException() + { + throw new NotSupportedException(Resources.PreviousProviderException); + } + + private void InvalidUserException(string userName) + { + throw new Exception(string.Format(Resources.InvalidUser, userName, UserTableName)); + } + + internal static void NullArgumentException(string parameterName) + { + throw new ArgumentException(Resources.InvalidArgument, parameterName); + } + + private string GenerateToken() + { + RNGCryptoServiceProvider provider = new RNGCryptoServiceProvider(); + byte[] data = new byte[16]; + provider.GetBytes(data); + return HttpServerUtility.UrlTokenEncode(data); + } + + private void CreateUserInUserTable(string userName, IDictionary values) + { + IsValidOperation(true); + var userid = GetUserId(userName); + if (userid > 0) + { + throw new MembershipCreateUserException(MembershipCreateStatus.DuplicateUserName); + } + StringBuilder columns = new StringBuilder(); + columns.Append(UserNameColumn); + StringBuilder args = new StringBuilder(); + args.Append("?"); + var argsValues = new List(); + argsValues.Add(userName); + + if (values != null) + { + foreach (var value in values) + { + if (string.Equals(UserNameColumn, value.Key, StringComparison.OrdinalIgnoreCase)) + continue; + columns.Append(string.Format(",{0}", value.Key)); + args.Append(",?"); + argsValues.Add(value.Value != null ? value.Value : DBNull.Value); + } + } + using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(GetConnectionString())) + { + string query = string.Format("insert into {0} ({1}) values({2})", UserTableName, columns.ToString(), args.ToString()); + if (dbConn.ExecuteNonQuery(query, argsValues.ToArray()) < 1) + { + throw new MembershipCreateUserException(MembershipCreateStatus.ProviderError); + } + } + } + + private bool UserConfirmed(int userId) + { + using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(GetConnectionString())) + { + return ((long)dbConn.ExecuteScalar(string.Format("select count(*) from {0} where userid=? and isconfirmed=1;", _membershipTable), userId)) > 0; + } + } + #endregion + } +} diff --git a/MySql.Web/src/SimpleRoleProvider.cs b/MySql.Web/src/SimpleRoleProvider.cs index 3cdde662a..f75e7f193 100644 --- a/MySql.Web/src/SimpleRoleProvider.cs +++ b/MySql.Web/src/SimpleRoleProvider.cs @@ -1,534 +1,534 @@ -// Copyright (c) 2014, 2020, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Web.Common; -using MySql.Web.General; -using MySql.Web.Properties; -using System; -using System.Collections.Generic; -using System.Configuration.Provider; -using System.Globalization; -using System.Linq; -using System.Web.Hosting; -using System.Web.Security; -using WebMatrix.WebData; - -namespace MySql.Web.Security -{ - /// - /// Manages storage of simple role membership information for an ASP.NET application in a MySQL database. - /// - public class MySqlSimpleRoleProvider : SimpleRoleProvider - { - #region Private - private readonly RoleProvider _prevProvider; - - Application _app; - bool _enablePwdReset; - bool _enablePwdRetrival; - int _maxPwdAttempts; - int _minReqNonAlphanumericalChars; - int _minReqPwdLength; - int _pwdAttemptWindow; - MembershipPasswordFormat _pwdFormat; - string _pwdStrenghtRegex; - bool _reqQuestionAnswer; - bool _reqUniqueEmail; - string _userTableName; - string _userIdColumn; - string _userNameColumn; - bool _autoGenerateTables; - private readonly string _rolesTable = "webpages_Roles"; - private readonly string _userInRolesTable = "webpages_UsersInRoles"; - private static string GetConfigValue(string configVal, string defaultVal) - { - return !string.IsNullOrEmpty(configVal) ? configVal : defaultVal; - } - - private void NotInitializedException() - { - throw new Exception(Resources.SimpleMembershipNotInitialized); - } - - #endregion - public MySqlSimpleRoleProvider() - : this(null) - { } - - public MySqlSimpleRoleProvider(RoleProvider previousProvider) - { - _prevProvider = previousProvider; - } - - public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config) - { - if (config == null) - { - throw new ArgumentNullException("config"); - } - if (string.IsNullOrEmpty(name)) - { - name = "MySqlExtendedMembershipProvider"; - } - if (string.IsNullOrEmpty(config["description"])) - { - config.Remove("description"); - config.Add("description", string.Format("MySql Default {0} Description", name)); - } - - base.Initialize(name, config); - - var appName = GetConfigValue(config["applicationName"], HostingEnvironment.SiteName); - _maxPwdAttempts = Int32.Parse(GetConfigValue(config["maxInvalidPasswordAttempts"], "5"), CultureInfo.InvariantCulture); - _pwdAttemptWindow = Int32.Parse(GetConfigValue(config["passwordAttemptWindow"], "10"), CultureInfo.InvariantCulture); - _minReqNonAlphanumericalChars = Int32.Parse(GetConfigValue(config["minRequiredNonalphanumericCharacters"], "1"), CultureInfo.InvariantCulture); - _minReqPwdLength = Int32.Parse(GetConfigValue(config["minRequiredPasswordLength"], "7"), CultureInfo.InvariantCulture); - _pwdStrenghtRegex = GetConfigValue(config["passwordStrengthRegularExpression"], ""); - _enablePwdReset = bool.Parse(GetConfigValue(config["enablePasswordReset"], "True")); - _enablePwdRetrival = bool.Parse(GetConfigValue(config["enablePasswordRetrieval"], "False")); - _reqQuestionAnswer = bool.Parse(GetConfigValue(config["requiresQuestionAndAnswer"], "False")); - _reqUniqueEmail = bool.Parse(GetConfigValue(config["requiresUniqueEmail"], "True")); - - var pwdFormat = !string.IsNullOrEmpty(config["passwordFormat"]) ? config["passwordFormat"].ToString().ToLowerInvariant() : "hashed"; - - switch (pwdFormat) - { - case "hashed": - _pwdFormat = MembershipPasswordFormat.Hashed; - break; - case "encrypted": - _pwdFormat = MembershipPasswordFormat.Encrypted; - break; - case "clear": - _pwdFormat = MembershipPasswordFormat.Clear; - break; - default: - throw new ProviderException(Resources.PasswordFormatNotSupported); - } - - if (_pwdFormat == MembershipPasswordFormat.Hashed) - { - if (_enablePwdRetrival) - throw new ProviderException(Resources.CannotRetrieveHashedPasswords); - } - - _app = new Application(appName, base.Description); - ConnectionString = ConfigUtility.GetConnectionString(config); - if (string.IsNullOrEmpty(ConnectionString)) return; - - UserTableName = GetConfigValue(config["userTableName"], ""); - UserIdColumn = GetConfigValue(config["userIdColumn"], ""); - UserNameColumn = GetConfigValue(config["userNameColumn"], ""); - _autoGenerateTables = bool.Parse(GetConfigValue(config["autoGenerateTables"], "True")); - if (_autoGenerateTables) - CreateTables(); - - Initialized = true; - } - - public override void AddUsersToRoles(string[] usernames, string[] roleNames) - { - if (!Initialized) - { - _prevProvider.AddUsersToRoles(usernames, roleNames); - } - else - { - if (usernames.Where(username => string.IsNullOrEmpty(username)).Count() > 0 || usernames.Where(username => string.IsNullOrEmpty(username)).Count() > 0) - throw new ArgumentException(Resources.InvalidArrayValue); - - using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(ConnectionString)) - { - foreach (var userid in GetUsersId(usernames)) - { - foreach (var roleid in GetRolesId(roleNames)) - { - if (userid > 0 && roleid > 0) - { - dbConn.ExecuteNonQuery(string.Format("insert into {0} (userid, roleid) values(?,?);", _userInRolesTable), userid, roleid); - } - } - } - } - } - } - - public override void CreateRole(string roleName) - { - if (!Initialized) - { - _prevProvider.CreateRole(roleName); - } - else - { - if (string.IsNullOrEmpty(roleName)) - MySqlSimpleMembershipProvider.NullArgumentException("roleName"); - - using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(ConnectionString)) - { - int roleid = GetRoleId(roleName); - if (roleid != 0) - { - throw new InvalidOperationException(string.Format(Resources.RoleAlreadyExists, roleName)); - } - if (dbConn.ExecuteNonQuery(string.Format("insert into {0} (rolename) values(?);", _rolesTable), roleName) <= 0) - { - throw new ProviderException(string.Format(Resources.CreateRoleFailed, roleName)); - } - } - } - } - - public override bool DeleteRole(string roleName, bool throwOnPopulatedRole) - { - if (!Initialized) - { - return _prevProvider.DeleteRole(roleName, throwOnPopulatedRole); - } - if (string.IsNullOrEmpty(roleName)) - MySqlSimpleMembershipProvider.NullArgumentException("roleName"); - - int roleid = GetRoleId(roleName); - if (roleid <= 0) - { - return false; - } - using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(ConnectionString)) - { - if (throwOnPopulatedRole) - { - if (IsRoleInUse(roleid)) - throw new InvalidOperationException(string.Format(Resources.RoleInUse, roleName)); - } - else - { - dbConn.ExecuteNonQuery(string.Format("delete from {0} where roleid=?;", _userInRolesTable), roleid); - } - return dbConn.ExecuteNonQuery(string.Format("delete from {0} where roleid=?;", _rolesTable), roleid) > 0; - } - } - - public override string[] FindUsersInRole(string roleName, string usernameToMatch) - { - if (!Initialized) - { - return _prevProvider.FindUsersInRole(roleName, usernameToMatch); - } - if (string.IsNullOrEmpty(roleName)) - MySqlSimpleMembershipProvider.NullArgumentException("roleName"); - if (string.IsNullOrEmpty(usernameToMatch)) - return GetUsersInRole(roleName); - - using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(ConnectionString)) - { - var usersName = dbConn.ExecuteQuery(string.Format("select ut.{0} from {1} as rt join {2} as urt on rt.roleid=urt.roleid join {3} as ut on rt.userid=ut.{4} where rt.rolename=? and ut.name like '%?%'", UserNameColumn, _rolesTable, _userInRolesTable, UserTableName, UserIdColumn), roleName, usernameToMatch); - if (usersName.Count() > 0) - return usersName.Select(username => username[0].ToString()).ToArray(); - } - return null; - } - - public override string[] GetAllRoles() - { - if (!Initialized) - return _prevProvider.GetAllRoles(); - - using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(ConnectionString)) - { - var roles = dbConn.ExecuteQuery(string.Format("select rolename from {0};", _rolesTable)); - if (roles.Count() > 0) - return roles.Select(role => role[0].ToString()).ToArray(); - } - return null; - } - - public override string[] GetRolesForUser(string username) - { - if (!Initialized) - return _prevProvider.GetRolesForUser(username); - if (string.IsNullOrEmpty(username)) - MySqlSimpleMembershipProvider.NullArgumentException("username"); - - string connString = ConnectionString; - int userid = MySqlSimpleMembershipProvider.GetUserId(username, connString, UserTableName, UserIdColumn, UserNameColumn); - if (userid > 0) - { - using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(connString)) - { - var roles = dbConn.ExecuteQuery(string.Format("select rt.rolename from {0} as urt join {1} as rt on urt.roleid = rt.roleid where urt.userid=?;", _userInRolesTable, _rolesTable), userid); - if (roles.Count() > 0) - return roles.Select(role => role[0].ToString()).ToArray(); - } - } - return null; - } - - public override string[] GetUsersInRole(string roleName) - { - if (!Initialized) - return _prevProvider.GetUsersInRole(roleName); - if (string.IsNullOrEmpty(roleName)) - MySqlSimpleMembershipProvider.NullArgumentException("roleName"); - - int roleid = GetRoleId(roleName); - if (roleid > 0) - { - using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(ConnectionString)) - { - var users = dbConn.ExecuteQuery(string.Format("select ut.{0} from {1} as urt join {2} as ut on urt.userid = ut.{3} where urt.roleid=?;", UserNameColumn, _userInRolesTable, UserTableName, UserIdColumn), roleid); - if (users.Count() > 0) - return users.Select(role => role[0].ToString()).ToArray(); - } - } - return null; - } - - public override bool IsUserInRole(string username, string roleName) - { - if (!Initialized) - return _prevProvider.IsUserInRole(username, roleName); - string connString = ConnectionString; - if (string.IsNullOrEmpty(username)) - MySqlSimpleMembershipProvider.NullArgumentException("username"); - if (string.IsNullOrEmpty(roleName)) - MySqlSimpleMembershipProvider.NullArgumentException("roleName"); - int userid = MySqlSimpleMembershipProvider.GetUserId(username, connString, UserTableName, UserIdColumn, UserNameColumn); - int roleid = GetRoleId(roleName); - if (userid <= 0 || roleid <= 0) - return false; - using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(connString)) - { - return (dbConn.ExecuteQuery(string.Format("select count(userid) from {0} where userid=? and roleid=?;", _userInRolesTable), userid, roleid)).Count() > 0; - } - } - - public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames) - { - if (!Initialized) - _prevProvider.RemoveUsersFromRoles(usernames, roleNames); - else - { - if (usernames.Where(username => string.IsNullOrEmpty(username)).Count() > 0 || usernames.Where(username => string.IsNullOrEmpty(username)).Count() > 0) - throw new ArgumentException(Resources.InvalidArrayValue); - using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(ConnectionString)) - { - foreach (var userid in GetUsersId(usernames)) - { - foreach (var roleid in GetRolesId(roleNames)) - { - if (userid > 0 && roleid > 0) - { - dbConn.ExecuteNonQuery(string.Format("delete from {0} where userid=? and roleid=?;", _userInRolesTable), userid, roleid); - } - } - } - } - } - } - - public override bool RoleExists(string roleName) - { - if (!Initialized) - return _prevProvider.RoleExists(roleName); - return (GetRoleId(roleName) > 0); - } - - #region Properties - - public override string ApplicationName - { - get - { - if (Initialized) - { - throw new NotSupportedException(); - } - else - { - return _prevProvider.ApplicationName; - } - } - set - { - if (Initialized) - { - throw new NotSupportedException(); - } - else - { - _prevProvider.ApplicationName = value; - } - } - } - - /// - /// Gets or sets the connection string. - /// - public string ConnectionString { get; set; } - - /// - /// Gets or sets the name associated to the connection string when stored in the configuration manager. - /// - public string ConnectionStringName { get; set; } - - /// - /// Gets the name of the table storing user information. - /// - public string UserTableName - { - get - { - if (string.IsNullOrEmpty(_userTableName)) - throw new InvalidOperationException(Resources.UserTableNameNotInitilized); - - return _userTableName; - } - internal set - { - _userTableName = value; - } - } - - /// - /// Gets the name of the column storing the user ids. - /// - public string UserIdColumn - { - get - { - if (string.IsNullOrEmpty(_userIdColumn)) - throw new InvalidOperationException(Resources.UserIdColumnNotInitialized); - - return _userIdColumn; - } - internal set - { - _userIdColumn = value; - } - } - - /// - /// Gets the name of the column storing the user names. - /// - public string UserNameColumn - { - get - { - if (string.IsNullOrEmpty(_userNameColumn)) - throw new InvalidOperationException(Resources.UserNameColumnNotInitialized); - - return _userNameColumn; - } - internal set - { - _userNameColumn = value; - } - } - - #endregion - - #region Private_Internal - internal bool Initialized - { - get; - set; - } - - internal void CreateTables() - { - var connString = ConnectionString; - using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(connString)) - { - //create schema - string schema = SchemaManager.GetSchema(11); - dbConn.ExecuteNonQuery(schema); - } - } - - //private string GetConnectionString() - //{ - // if (!string.IsNullOrEmpty(ConnectionString)) - // return ConnectionString; - // else - // { - // ConnectionStringSettings connString = ConfigurationManager.ConnectionStrings[ConnectionStringName]; - // if (connString != null) - // return connString.ConnectionString; - // } - - // if (!string.IsNullOrEmpty(_connString)) - // return _connString; - // throw new InvalidOperationException(Resources.NoConnString); - //} - - private IEnumerable GetUsersId(string[] usersName) - { - foreach (string userName in usersName) - { - yield return MySqlSimpleMembershipProvider.GetUserId(userName, ConnectionString, UserTableName, UserIdColumn, UserNameColumn); - } - } - - private IEnumerable GetRolesId(string[] roles) - { - foreach (string role in roles) - { - yield return GetRoleId(role); - } - } - - internal int GetRoleId(string role) - { - using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(ConnectionString)) - { - var roleid = dbConn.ExecuteQuerySingleRecord(string.Format("select roleid from {0} where rolename=?;", _rolesTable), role); - if (roleid != null) - return (int)roleid[0]; - - return 0; - } - } - - private bool UserHasRole(int userid, int roleid) - { - using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(ConnectionString)) - { - return (dbConn.ExecuteQuery(string.Format("select count(*) from {0} where userid=? and roleid=?;", _userInRolesTable), userid, roleid).Count() > 0); - } - } - - private bool IsRoleInUse(int roleid) - { - using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(ConnectionString)) - { - return (dbConn.ExecuteQuery(string.Format("select count(*) from {0} where roleid=?;", _userInRolesTable), roleid).Count() > 0); - } - } - #endregion - } -} +// Copyright © 2014, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Web.Common; +using MySql.Web.General; +using MySql.Web.Properties; +using System; +using System.Collections.Generic; +using System.Configuration.Provider; +using System.Globalization; +using System.Linq; +using System.Web.Hosting; +using System.Web.Security; +using WebMatrix.WebData; + +namespace MySql.Web.Security +{ + /// + /// Manages storage of simple role membership information for an ASP.NET application in a MySQL database. + /// + public class MySqlSimpleRoleProvider : SimpleRoleProvider + { + #region Private + private readonly RoleProvider _prevProvider; + + Application _app; + bool _enablePwdReset; + bool _enablePwdRetrival; + int _maxPwdAttempts; + int _minReqNonAlphanumericalChars; + int _minReqPwdLength; + int _pwdAttemptWindow; + MembershipPasswordFormat _pwdFormat; + string _pwdStrenghtRegex; + bool _reqQuestionAnswer; + bool _reqUniqueEmail; + string _userTableName; + string _userIdColumn; + string _userNameColumn; + bool _autoGenerateTables; + private readonly string _rolesTable = "webpages_Roles"; + private readonly string _userInRolesTable = "webpages_UsersInRoles"; + private static string GetConfigValue(string configVal, string defaultVal) + { + return !string.IsNullOrEmpty(configVal) ? configVal : defaultVal; + } + + private void NotInitializedException() + { + throw new Exception(Resources.SimpleMembershipNotInitialized); + } + + #endregion + public MySqlSimpleRoleProvider() + : this(null) + { } + + public MySqlSimpleRoleProvider(RoleProvider previousProvider) + { + _prevProvider = previousProvider; + } + + public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config) + { + if (config == null) + { + throw new ArgumentNullException("config"); + } + if (string.IsNullOrEmpty(name)) + { + name = "MySqlExtendedMembershipProvider"; + } + if (string.IsNullOrEmpty(config["description"])) + { + config.Remove("description"); + config.Add("description", string.Format("MySql Default {0} Description", name)); + } + + base.Initialize(name, config); + + var appName = GetConfigValue(config["applicationName"], HostingEnvironment.SiteName); + _maxPwdAttempts = Int32.Parse(GetConfigValue(config["maxInvalidPasswordAttempts"], "5"), CultureInfo.InvariantCulture); + _pwdAttemptWindow = Int32.Parse(GetConfigValue(config["passwordAttemptWindow"], "10"), CultureInfo.InvariantCulture); + _minReqNonAlphanumericalChars = Int32.Parse(GetConfigValue(config["minRequiredNonalphanumericCharacters"], "1"), CultureInfo.InvariantCulture); + _minReqPwdLength = Int32.Parse(GetConfigValue(config["minRequiredPasswordLength"], "7"), CultureInfo.InvariantCulture); + _pwdStrenghtRegex = GetConfigValue(config["passwordStrengthRegularExpression"], ""); + _enablePwdReset = bool.Parse(GetConfigValue(config["enablePasswordReset"], "True")); + _enablePwdRetrival = bool.Parse(GetConfigValue(config["enablePasswordRetrieval"], "False")); + _reqQuestionAnswer = bool.Parse(GetConfigValue(config["requiresQuestionAndAnswer"], "False")); + _reqUniqueEmail = bool.Parse(GetConfigValue(config["requiresUniqueEmail"], "True")); + + var pwdFormat = !string.IsNullOrEmpty(config["passwordFormat"]) ? config["passwordFormat"].ToString().ToLowerInvariant() : "hashed"; + + switch (pwdFormat) + { + case "hashed": + _pwdFormat = MembershipPasswordFormat.Hashed; + break; + case "encrypted": + _pwdFormat = MembershipPasswordFormat.Encrypted; + break; + case "clear": + _pwdFormat = MembershipPasswordFormat.Clear; + break; + default: + throw new ProviderException(Resources.PasswordFormatNotSupported); + } + + if (_pwdFormat == MembershipPasswordFormat.Hashed) + { + if (_enablePwdRetrival) + throw new ProviderException(Resources.CannotRetrieveHashedPasswords); + } + + _app = new Application(appName, base.Description); + ConnectionString = ConfigUtility.GetConnectionString(config); + if (string.IsNullOrEmpty(ConnectionString)) return; + + UserTableName = GetConfigValue(config["userTableName"], ""); + UserIdColumn = GetConfigValue(config["userIdColumn"], ""); + UserNameColumn = GetConfigValue(config["userNameColumn"], ""); + _autoGenerateTables = bool.Parse(GetConfigValue(config["autoGenerateTables"], "True")); + if (_autoGenerateTables) + CreateTables(); + + Initialized = true; + } + + public override void AddUsersToRoles(string[] usernames, string[] roleNames) + { + if (!Initialized) + { + _prevProvider.AddUsersToRoles(usernames, roleNames); + } + else + { + if (usernames.Where(username => string.IsNullOrEmpty(username)).Count() > 0 || usernames.Where(username => string.IsNullOrEmpty(username)).Count() > 0) + throw new ArgumentException(Resources.InvalidArrayValue); + + using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(ConnectionString)) + { + foreach (var userid in GetUsersId(usernames)) + { + foreach (var roleid in GetRolesId(roleNames)) + { + if (userid > 0 && roleid > 0) + { + dbConn.ExecuteNonQuery(string.Format("insert into {0} (userid, roleid) values(?,?);", _userInRolesTable), userid, roleid); + } + } + } + } + } + } + + public override void CreateRole(string roleName) + { + if (!Initialized) + { + _prevProvider.CreateRole(roleName); + } + else + { + if (string.IsNullOrEmpty(roleName)) + MySqlSimpleMembershipProvider.NullArgumentException("roleName"); + + using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(ConnectionString)) + { + int roleid = GetRoleId(roleName); + if (roleid != 0) + { + throw new InvalidOperationException(string.Format(Resources.RoleAlreadyExists, roleName)); + } + if (dbConn.ExecuteNonQuery(string.Format("insert into {0} (rolename) values(?);", _rolesTable), roleName) <= 0) + { + throw new ProviderException(string.Format(Resources.CreateRoleFailed, roleName)); + } + } + } + } + + public override bool DeleteRole(string roleName, bool throwOnPopulatedRole) + { + if (!Initialized) + { + return _prevProvider.DeleteRole(roleName, throwOnPopulatedRole); + } + if (string.IsNullOrEmpty(roleName)) + MySqlSimpleMembershipProvider.NullArgumentException("roleName"); + + int roleid = GetRoleId(roleName); + if (roleid <= 0) + { + return false; + } + using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(ConnectionString)) + { + if (throwOnPopulatedRole) + { + if (IsRoleInUse(roleid)) + throw new InvalidOperationException(string.Format(Resources.RoleInUse, roleName)); + } + else + { + dbConn.ExecuteNonQuery(string.Format("delete from {0} where roleid=?;", _userInRolesTable), roleid); + } + return dbConn.ExecuteNonQuery(string.Format("delete from {0} where roleid=?;", _rolesTable), roleid) > 0; + } + } + + public override string[] FindUsersInRole(string roleName, string usernameToMatch) + { + if (!Initialized) + { + return _prevProvider.FindUsersInRole(roleName, usernameToMatch); + } + if (string.IsNullOrEmpty(roleName)) + MySqlSimpleMembershipProvider.NullArgumentException("roleName"); + if (string.IsNullOrEmpty(usernameToMatch)) + return GetUsersInRole(roleName); + + using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(ConnectionString)) + { + var usersName = dbConn.ExecuteQuery(string.Format("select ut.{0} from {1} as rt join {2} as urt on rt.roleid=urt.roleid join {3} as ut on rt.userid=ut.{4} where rt.rolename=? and ut.name like '%?%'", UserNameColumn, _rolesTable, _userInRolesTable, UserTableName, UserIdColumn), roleName, usernameToMatch); + if (usersName.Count() > 0) + return usersName.Select(username => username[0].ToString()).ToArray(); + } + return null; + } + + public override string[] GetAllRoles() + { + if (!Initialized) + return _prevProvider.GetAllRoles(); + + using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(ConnectionString)) + { + var roles = dbConn.ExecuteQuery(string.Format("select rolename from {0};", _rolesTable)); + if (roles.Count() > 0) + return roles.Select(role => role[0].ToString()).ToArray(); + } + return null; + } + + public override string[] GetRolesForUser(string username) + { + if (!Initialized) + return _prevProvider.GetRolesForUser(username); + if (string.IsNullOrEmpty(username)) + MySqlSimpleMembershipProvider.NullArgumentException("username"); + + string connString = ConnectionString; + int userid = MySqlSimpleMembershipProvider.GetUserId(username, connString, UserTableName, UserIdColumn, UserNameColumn); + if (userid > 0) + { + using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(connString)) + { + var roles = dbConn.ExecuteQuery(string.Format("select rt.rolename from {0} as urt join {1} as rt on urt.roleid = rt.roleid where urt.userid=?;", _userInRolesTable, _rolesTable), userid); + if (roles.Count() > 0) + return roles.Select(role => role[0].ToString()).ToArray(); + } + } + return null; + } + + public override string[] GetUsersInRole(string roleName) + { + if (!Initialized) + return _prevProvider.GetUsersInRole(roleName); + if (string.IsNullOrEmpty(roleName)) + MySqlSimpleMembershipProvider.NullArgumentException("roleName"); + + int roleid = GetRoleId(roleName); + if (roleid > 0) + { + using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(ConnectionString)) + { + var users = dbConn.ExecuteQuery(string.Format("select ut.{0} from {1} as urt join {2} as ut on urt.userid = ut.{3} where urt.roleid=?;", UserNameColumn, _userInRolesTable, UserTableName, UserIdColumn), roleid); + if (users.Count() > 0) + return users.Select(role => role[0].ToString()).ToArray(); + } + } + return null; + } + + public override bool IsUserInRole(string username, string roleName) + { + if (!Initialized) + return _prevProvider.IsUserInRole(username, roleName); + string connString = ConnectionString; + if (string.IsNullOrEmpty(username)) + MySqlSimpleMembershipProvider.NullArgumentException("username"); + if (string.IsNullOrEmpty(roleName)) + MySqlSimpleMembershipProvider.NullArgumentException("roleName"); + int userid = MySqlSimpleMembershipProvider.GetUserId(username, connString, UserTableName, UserIdColumn, UserNameColumn); + int roleid = GetRoleId(roleName); + if (userid <= 0 || roleid <= 0) + return false; + using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(connString)) + { + return (dbConn.ExecuteQuery(string.Format("select count(userid) from {0} where userid=? and roleid=?;", _userInRolesTable), userid, roleid)).Count() > 0; + } + } + + public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames) + { + if (!Initialized) + _prevProvider.RemoveUsersFromRoles(usernames, roleNames); + else + { + if (usernames.Where(username => string.IsNullOrEmpty(username)).Count() > 0 || usernames.Where(username => string.IsNullOrEmpty(username)).Count() > 0) + throw new ArgumentException(Resources.InvalidArrayValue); + using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(ConnectionString)) + { + foreach (var userid in GetUsersId(usernames)) + { + foreach (var roleid in GetRolesId(roleNames)) + { + if (userid > 0 && roleid > 0) + { + dbConn.ExecuteNonQuery(string.Format("delete from {0} where userid=? and roleid=?;", _userInRolesTable), userid, roleid); + } + } + } + } + } + } + + public override bool RoleExists(string roleName) + { + if (!Initialized) + return _prevProvider.RoleExists(roleName); + return (GetRoleId(roleName) > 0); + } + + #region Properties + + public override string ApplicationName + { + get + { + if (Initialized) + { + throw new NotSupportedException(); + } + else + { + return _prevProvider.ApplicationName; + } + } + set + { + if (Initialized) + { + throw new NotSupportedException(); + } + else + { + _prevProvider.ApplicationName = value; + } + } + } + + /// + /// Gets or sets the connection string. + /// + public string ConnectionString { get; set; } + + /// + /// Gets or sets the name associated to the connection string when stored in the configuration manager. + /// + public string ConnectionStringName { get; set; } + + /// + /// Gets the name of the table storing user information. + /// + public string UserTableName + { + get + { + if (string.IsNullOrEmpty(_userTableName)) + throw new InvalidOperationException(Resources.UserTableNameNotInitilized); + + return _userTableName; + } + internal set + { + _userTableName = value; + } + } + + /// + /// Gets the name of the column storing the user ids. + /// + public string UserIdColumn + { + get + { + if (string.IsNullOrEmpty(_userIdColumn)) + throw new InvalidOperationException(Resources.UserIdColumnNotInitialized); + + return _userIdColumn; + } + internal set + { + _userIdColumn = value; + } + } + + /// + /// Gets the name of the column storing the user names. + /// + public string UserNameColumn + { + get + { + if (string.IsNullOrEmpty(_userNameColumn)) + throw new InvalidOperationException(Resources.UserNameColumnNotInitialized); + + return _userNameColumn; + } + internal set + { + _userNameColumn = value; + } + } + + #endregion + + #region Private_Internal + internal bool Initialized + { + get; + set; + } + + internal void CreateTables() + { + var connString = ConnectionString; + using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(connString)) + { + //create schema + string schema = SchemaManager.GetSchema(11); + dbConn.ExecuteNonQuery(schema); + } + } + + //private string GetConnectionString() + //{ + // if (!string.IsNullOrEmpty(ConnectionString)) + // return ConnectionString; + // else + // { + // ConnectionStringSettings connString = ConfigurationManager.ConnectionStrings[ConnectionStringName]; + // if (connString != null) + // return connString.ConnectionString; + // } + + // if (!string.IsNullOrEmpty(_connString)) + // return _connString; + // throw new InvalidOperationException(Resources.NoConnString); + //} + + private IEnumerable GetUsersId(string[] usersName) + { + foreach (string userName in usersName) + { + yield return MySqlSimpleMembershipProvider.GetUserId(userName, ConnectionString, UserTableName, UserIdColumn, UserNameColumn); + } + } + + private IEnumerable GetRolesId(string[] roles) + { + foreach (string role in roles) + { + yield return GetRoleId(role); + } + } + + internal int GetRoleId(string role) + { + using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(ConnectionString)) + { + var roleid = dbConn.ExecuteQuerySingleRecord(string.Format("select roleid from {0} where rolename=?;", _rolesTable), role); + if (roleid != null) + return (int)roleid[0]; + + return 0; + } + } + + private bool UserHasRole(int userid, int roleid) + { + using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(ConnectionString)) + { + return (dbConn.ExecuteQuery(string.Format("select count(*) from {0} where userid=? and roleid=?;", _userInRolesTable), userid, roleid).Count() > 0); + } + } + + private bool IsRoleInUse(int roleid) + { + using (MySqlDatabaseWrapper dbConn = new MySqlDatabaseWrapper(ConnectionString)) + { + return (dbConn.ExecuteQuery(string.Format("select count(*) from {0} where roleid=?;", _userInRolesTable), roleid).Count() > 0); + } + } + #endregion + } +} diff --git a/MySql.Web/src/SiteMapProvider.cs b/MySql.Web/src/SiteMapProvider.cs index 6ff4c1d1f..257ad7991 100644 --- a/MySql.Web/src/SiteMapProvider.cs +++ b/MySql.Web/src/SiteMapProvider.cs @@ -1,199 +1,199 @@ -// Copyright (c) 2004, 2020, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data.MySqlClient; -using MySql.Web.Common; -using MySql.Web.Properties; -using System; -using System.Collections.Generic; -using System.Configuration.Provider; -using System.Data; -using System.Diagnostics; -using System.Web; - -namespace MySql.Web.SiteMap -{ - /// - /// SiteMap provider backed by MySql database. - /// - public class MySqlSiteMapProvider : StaticSiteMapProvider - { - private readonly object _lockObject = new object(); - private string _connStr; - private SiteMapNode _rootNode; - private Dictionary _nodes = new Dictionary(); - private bool writeExceptionsToEventLog; - string eventSource = "MySQLSiteMap"; - string eventLog = "Application"; - string exceptionMessage = "An exception occurred. Please check the event log."; - - internal bool WriteExceptionsToEventLog { get { return writeExceptionsToEventLog; } } - - public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config) - { - base.Initialize(name, config); - - if (config == null) - throw new ArgumentException(Resources.SiteMapConnectionStringMissing); - - _connStr = ConfigUtility.GetConnectionString(config); - if (string.IsNullOrEmpty(_connStr)) - throw new ArgumentException(Resources.SiteMapConnectionStringMissing); - - writeExceptionsToEventLog = false; - if (config["writeExceptionsToEventLog"] != null) - { - writeExceptionsToEventLog = (config["writeExceptionsToEventLog"].ToUpper() == "TRUE"); - } - - SchemaManager.CheckSchema(_connStr, config); - } - - public override SiteMapNode BuildSiteMap() - { - lock (_lockObject) - { - if (_rootNode != null) return _rootNode; - string sql = "select Id, Title, Description, Url, Roles, ParentId from my_aspnet_sitemap"; - MySqlConnection conn = new MySqlConnection(_connStr); - try - { - conn.Open(); - MySqlCommand cmd = new MySqlCommand(sql, conn); - using (MySqlDataReader r = cmd.ExecuteReader()) - { - int IdFld = r.GetOrdinal("Id"); - int TitleFld = r.GetOrdinal("Title"); - int DescFld = r.GetOrdinal("Description"); - int UrlFld = r.GetOrdinal("Url"); - int RolesFld = r.GetOrdinal("Roles"); - int ParentIdFld = r.GetOrdinal("ParentId"); - - while (r.Read()) - { - int IdVal; - string TitleVal; - string DescVal; - string UrlVal; - string RolesVal; - int ParentIdVal; - - LoadValue(r, IdFld, out IdVal); - LoadValue(r, TitleFld, out TitleVal); - LoadValue(r, DescFld, out DescVal); - LoadValue(r, UrlFld, out UrlVal); - LoadValue(r, RolesFld, out RolesVal); - LoadValue(r, ParentIdFld, out ParentIdVal); - - SiteMapNode node = new SiteMapNode(this, IdVal.ToString(), UrlVal, TitleVal, DescVal); - _nodes.Add(IdVal, node); - if (ParentIdVal != 0) - { - SiteMapNode parentNode = _nodes[ParentIdVal]; - AddNode(node, parentNode); - } - else - { - AddNode(node); - } - if (ParentIdVal == 0) - { - _rootNode = node; - } - } - } - } - catch (MySqlException ex) - { - HandleMySqlException(ex, "BuildSiteMap"); - } - finally - { - if ((conn.State & ConnectionState.Open) != 0) conn.Close(); - } - return _rootNode; - } - } - - private void LoadValue(MySqlDataReader r, int fldNum, out T val) - { - if (r.IsDBNull(fldNum)) - val = default(T); - else - { - val = (T)r.GetValue(fldNum); - } - } - - public override SiteMapNode FindSiteMapNodeFromKey(string key) - { - if (string.IsNullOrEmpty(key)) return null; - else - { - int idKey = Convert.ToInt32(key); - SiteMapNode node; - _nodes.TryGetValue(idKey, out node); - return node; - } - } - - /// - /// Handles MySql exception. - /// If WriteExceptionsToEventLog is set, will write exception info - /// to event log. - /// It throws provider exception (original exception is stored as inner exception) - /// - /// exception - /// name of the function that throwed the exception - private void HandleMySqlException(MySqlException e, string action) - { - if (WriteExceptionsToEventLog) - { - using (EventLog log = new EventLog()) - { - log.Source = eventSource; - log.Log = eventLog; - - string message = "An exception occurred communicating with the data source.\n\n"; - message += "Action: " + action; - message += "Exception: " + e.ToString(); - log.WriteEntry(message); - } - } - throw new ProviderException(exceptionMessage, e); - } - - protected override SiteMapNode GetRootNodeCore() - { - if (_rootNode == null) - BuildSiteMap(); - - return _rootNode; - } - } -} +// Copyright © 2004, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data.MySqlClient; +using MySql.Web.Common; +using MySql.Web.Properties; +using System; +using System.Collections.Generic; +using System.Configuration.Provider; +using System.Data; +using System.Diagnostics; +using System.Web; + +namespace MySql.Web.SiteMap +{ + /// + /// SiteMap provider backed by MySql database. + /// + public class MySqlSiteMapProvider : StaticSiteMapProvider + { + private readonly object _lockObject = new object(); + private string _connStr; + private SiteMapNode _rootNode; + private Dictionary _nodes = new Dictionary(); + private bool writeExceptionsToEventLog; + string eventSource = "MySQLSiteMap"; + string eventLog = "Application"; + string exceptionMessage = "An exception occurred. Please check the event log."; + + internal bool WriteExceptionsToEventLog { get { return writeExceptionsToEventLog; } } + + public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config) + { + base.Initialize(name, config); + + if (config == null) + throw new ArgumentException(Resources.SiteMapConnectionStringMissing); + + _connStr = ConfigUtility.GetConnectionString(config); + if (string.IsNullOrEmpty(_connStr)) + throw new ArgumentException(Resources.SiteMapConnectionStringMissing); + + writeExceptionsToEventLog = false; + if (config["writeExceptionsToEventLog"] != null) + { + writeExceptionsToEventLog = (config["writeExceptionsToEventLog"].ToUpper() == "TRUE"); + } + + SchemaManager.CheckSchema(_connStr, config); + } + + public override SiteMapNode BuildSiteMap() + { + lock (_lockObject) + { + if (_rootNode != null) return _rootNode; + string sql = "select Id, Title, Description, Url, Roles, ParentId from my_aspnet_sitemap"; + MySqlConnection conn = new MySqlConnection(_connStr); + try + { + conn.Open(); + MySqlCommand cmd = new MySqlCommand(sql, conn); + using (MySqlDataReader r = cmd.ExecuteReader()) + { + int IdFld = r.GetOrdinal("Id"); + int TitleFld = r.GetOrdinal("Title"); + int DescFld = r.GetOrdinal("Description"); + int UrlFld = r.GetOrdinal("Url"); + int RolesFld = r.GetOrdinal("Roles"); + int ParentIdFld = r.GetOrdinal("ParentId"); + + while (r.Read()) + { + int IdVal; + string TitleVal; + string DescVal; + string UrlVal; + string RolesVal; + int ParentIdVal; + + LoadValue(r, IdFld, out IdVal); + LoadValue(r, TitleFld, out TitleVal); + LoadValue(r, DescFld, out DescVal); + LoadValue(r, UrlFld, out UrlVal); + LoadValue(r, RolesFld, out RolesVal); + LoadValue(r, ParentIdFld, out ParentIdVal); + + SiteMapNode node = new SiteMapNode(this, IdVal.ToString(), UrlVal, TitleVal, DescVal); + _nodes.Add(IdVal, node); + if (ParentIdVal != 0) + { + SiteMapNode parentNode = _nodes[ParentIdVal]; + AddNode(node, parentNode); + } + else + { + AddNode(node); + } + if (ParentIdVal == 0) + { + _rootNode = node; + } + } + } + } + catch (MySqlException ex) + { + HandleMySqlException(ex, "BuildSiteMap"); + } + finally + { + if ((conn.State & ConnectionState.Open) != 0) conn.Close(); + } + return _rootNode; + } + } + + private void LoadValue(MySqlDataReader r, int fldNum, out T val) + { + if (r.IsDBNull(fldNum)) + val = default(T); + else + { + val = (T)r.GetValue(fldNum); + } + } + + public override SiteMapNode FindSiteMapNodeFromKey(string key) + { + if (string.IsNullOrEmpty(key)) return null; + else + { + int idKey = Convert.ToInt32(key); + SiteMapNode node; + _nodes.TryGetValue(idKey, out node); + return node; + } + } + + /// + /// Handles MySql exception. + /// If WriteExceptionsToEventLog is set, will write exception info + /// to event log. + /// It throws provider exception (original exception is stored as inner exception) + /// + /// exception + /// name of the function that throwed the exception + private void HandleMySqlException(MySqlException e, string action) + { + if (WriteExceptionsToEventLog) + { + using (EventLog log = new EventLog()) + { + log.Source = eventSource; + log.Log = eventLog; + + string message = "An exception occurred communicating with the data source.\n\n"; + message += "Action: " + action; + message += "Exception: " + e.ToString(); + log.WriteEntry(message); + } + } + throw new ProviderException(exceptionMessage, e); + } + + protected override SiteMapNode GetRootNodeCore() + { + if (_rootNode == null) + BuildSiteMap(); + + return _rootNode; + } + } +} diff --git a/MySql.Web/tests/MySql.Web.Tests.csproj b/MySql.Web/tests/MySql.Web.Tests.csproj index 78995b8cb..600a45c0d 100644 --- a/MySql.Web/tests/MySql.Web.Tests.csproj +++ b/MySql.Web/tests/MySql.Web.Tests.csproj @@ -2,9 +2,9 @@ MySql.Web.Tests - Copyright (c) 2016, 2023, Oracle and/or its affiliates. + Copyright © 2016, 2025, Oracle and/or its affiliates. en-US - 8.2.0 + 9.4.0 Oracle net462;net48; MySql.Web.Tests @@ -12,7 +12,7 @@ MySql;.NET Connector;MySql Connector/NET http://www.mysql.com/common/logos/logo-mysql-170x115.png http://dev.mysql.com/downloads/ - GPL-2.0-only + GPL-2.0-only WITH Universal-FOSS-exception-1.0 true false false @@ -23,6 +23,7 @@ True True ..\..\ConnectorNetPublicKey.snk + latest @@ -30,9 +31,9 @@ - - - + + + diff --git a/MySql.Web/tests/PersonalizationTests.cs b/MySql.Web/tests/PersonalizationTests.cs index 480d55de1..1ed8622c8 100644 --- a/MySql.Web/tests/PersonalizationTests.cs +++ b/MySql.Web/tests/PersonalizationTests.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2014, 2020, Oracle and/or its affiliates. +// Copyright © 2014, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -29,6 +29,7 @@ using MySql.Data.MySqlClient; using MySql.Web.Personalization; using NUnit.Framework; +using NUnit.Framework.Legacy; using System; using System.Collections.Specialized; using System.Web.UI.WebControls.WebParts; @@ -143,7 +144,7 @@ public void CanFindState() psq.PathToMatch = "~/default.aspx"; psq.UserInactiveSinceDate = DateTime.UtcNow.AddMinutes(1); var collection = p.FindState(PersonalizationScope.User, psq, 1, 1, out totalRecords); - Assert.AreEqual(1, totalRecords); + Assert.That(totalRecords, Is.EqualTo(1)); } [Test] @@ -158,7 +159,7 @@ public void CanGetCountofStateForUser() psq.UserInactiveSinceDate = DateTime.UtcNow.AddMinutes(1); //System.Threading.Thread.Sleep(1000); totalRecords = p.GetCountOfState(PersonalizationScope.User, psq); - Assert.AreEqual(1, totalRecords); + Assert.That(totalRecords, Is.EqualTo(1)); } [Test] @@ -171,7 +172,7 @@ public void CanGetCountofStateForAllUsers() psq.PathToMatch = "~/default.aspx"; psq.UserInactiveSinceDate = DateTime.UtcNow; totalRecords = p.GetCountOfState(PersonalizationScope.Shared, psq); - Assert.AreEqual(1, totalRecords); + Assert.That(totalRecords, Is.EqualTo(1)); } [Test] @@ -187,7 +188,7 @@ public void CanResetStateForUser() users[0] = @"GabPC\Gab"; totalRecords = p.ResetState(PersonalizationScope.User, paths, users); - Assert.AreEqual(1, totalRecords); + Assert.That(totalRecords, Is.EqualTo(1)); } [Test] @@ -204,7 +205,7 @@ public void CanResetStateForAllUsers() int totalRecords; totalRecords = p.ResetState(PersonalizationScope.Shared, paths, users); - Assert.AreEqual(1, totalRecords); + Assert.That(totalRecords, Is.EqualTo(1)); } [Test] @@ -215,7 +216,7 @@ public void CanResetAllState() int totalRecords; totalRecords = p.ResetState(PersonalizationScope.Shared, null, null); - Assert.AreEqual(1, totalRecords); + Assert.That(totalRecords, Is.EqualTo(1)); } @@ -227,7 +228,7 @@ public void CanResetUsertState() int totalRecords; totalRecords = p.ResetUserState("~/default.aspx", Convert.ToDateTime("2038-01-19 03:14:07.999999")); // TimeStamp MaxValue - Assert.AreEqual(1, totalRecords); + Assert.That(totalRecords, Is.EqualTo(1)); } } diff --git a/MySql.Web/tests/ProfileTests.cs b/MySql.Web/tests/ProfileTests.cs index 986fe4ee1..dbceae9cb 100644 --- a/MySql.Web/tests/ProfileTests.cs +++ b/MySql.Web/tests/ProfileTests.cs @@ -1,287 +1,288 @@ -// Copyright (c) 2013, 2020, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Web.Profile; -using NUnit.Framework; -using System; -using System.Collections.Specialized; -using System.Configuration; -using System.Data; -using System.Reflection; -using System.Web.Profile; - -namespace MySql.Web.Tests -{ - public class ProfileTests : WebTestBase - { - private MySQLProfileProvider InitProfileProvider() - { - MySQLProfileProvider p = new MySQLProfileProvider(); - NameValueCollection config = new NameValueCollection(); - config.Add("connectionStringName", "LocalMySqlServer"); - config.Add("applicationName", "/"); - p.Initialize(null, config); - return p; - } - [TearDown] - public void Cleanup() - { - execSQL(@"delete from my_aspnet_applications; - delete from my_aspnet_paths; - delete from my_aspnet_users; - delete from my_aspnet_profiles; - delete from my_aspnet_personalizationallusers;"); - } - - [Test] - public void SettingValuesCreatesAnAppAndUserId() - { - - MySQLProfileProvider provider = InitProfileProvider(); - SettingsContext ctx = new SettingsContext(); - ctx.Add("IsAuthenticated", false); - ctx.Add("UserName", "user1"); - - SettingsPropertyValueCollection values = new SettingsPropertyValueCollection(); - SettingsProperty property1 = new SettingsProperty("color"); - property1.PropertyType = typeof(string); - property1.Attributes["AllowAnonymous"] = true; - SettingsPropertyValue value = new SettingsPropertyValue(property1); - value.PropertyValue = "blue"; - values.Add(value); - - provider.SetPropertyValues(ctx, values); - - DataTable dt = FillTable("SELECT * FROM my_aspnet_applications"); - Assert.True(1 == dt.Rows.Count, "Rows count on table my_aspnet_applications is not 1"); - - dt = FillTable("SELECT * FROM my_aspnet_users"); - Assert.True(1 == dt.Rows.Count, "Rows count on table my_aspnet_users is not 1"); - - - dt = FillTable("SELECT * FROM my_aspnet_profiles"); - Assert.True(1 == dt.Rows.Count, "Rows count on table my_aspnet_profiles is not 1"); - - values["color"].PropertyValue = "green"; - provider.SetPropertyValues(ctx, values); - - dt = FillTable("SELECT * FROM my_aspnet_applications"); - Assert.True(1 == dt.Rows.Count, "Rows count on table my_aspnet_applications is not 1 after setting property"); - - dt = FillTable("SELECT * FROM my_aspnet_users"); - Assert.True(1 == dt.Rows.Count, "Rows count on table my_aspnet_users is not 1 after setting property"); - - dt = FillTable("SELECT * FROM my_aspnet_profiles"); - Assert.True(1 == dt.Rows.Count, "Rows count on table my_aspnet_profiles is not 1 after setting property"); - } - - [Test] - public void AnonymousUserSettingNonAnonymousProperties() - { - MySQLProfileProvider provider = InitProfileProvider(); - SettingsContext ctx = new SettingsContext(); - ctx.Add("IsAuthenticated", false); - ctx.Add("UserName", "user1"); - - SettingsPropertyValueCollection values = new SettingsPropertyValueCollection(); - SettingsProperty property1 = new SettingsProperty("color"); - property1.PropertyType = typeof(string); - property1.Attributes["AllowAnonymous"] = false; - SettingsPropertyValue value = new SettingsPropertyValue(property1); - value.PropertyValue = "blue"; - values.Add(value); - - provider.SetPropertyValues(ctx, values); - - DataTable dt = FillTable("SELECT * FROM my_aspnet_applications"); - Assert.True(0 == dt.Rows.Count, "Table my_aspnet_applications Rows is not 0"); - - dt = FillTable("SELECT * FROM my_aspnet_users"); - Assert.True(0 == dt.Rows.Count, "Table my_aspnet_users Rows is not 0"); - - dt = FillTable("SELECT * FROM my_aspnet_profiles"); - Assert.True(0 == dt.Rows.Count, "Table my_aspnet_profiles Rows is not 0"); - - } - - [Test] - public void StringCollectionAsProperty() - { - ProfileBase profile = ProfileBase.Create("foo", true); - ResetAppId(profile.Providers["MySqlProfileProvider"] as MySQLProfileProvider); - StringCollection colors = new StringCollection(); - colors.Add("red"); - colors.Add("green"); - colors.Add("blue"); - profile["FavoriteColors"] = colors; - profile.Save(); - - DataTable dt = FillTable("SELECT * FROM my_aspnet_applications"); - Assert.AreEqual(1, dt.Rows.Count); - dt = FillTable("SELECT * FROM my_aspnet_users"); - Assert.AreEqual(1, dt.Rows.Count); - dt = FillTable("SELECT * FROM my_aspnet_profiles"); - Assert.AreEqual(1, dt.Rows.Count); - - // now retrieve them - SettingsPropertyCollection getProps = new SettingsPropertyCollection(); - SettingsProperty getProp1 = new SettingsProperty("FavoriteColors"); - getProp1.PropertyType = typeof(StringCollection); - getProp1.SerializeAs = SettingsSerializeAs.Xml; - getProps.Add(getProp1); - - MySQLProfileProvider provider = InitProfileProvider(); - SettingsContext ctx = new SettingsContext(); - ctx.Add("IsAuthenticated", true); - ctx.Add("UserName", "foo"); - SettingsPropertyValueCollection getValues = provider.GetPropertyValues(ctx, getProps); - Assert.AreEqual(1, getValues.Count); - SettingsPropertyValue getValue1 = getValues["FavoriteColors"]; - StringCollection outValue = (StringCollection)getValue1.PropertyValue; - Assert.AreEqual(3, outValue.Count); - Assert.AreEqual("red", outValue[0]); - Assert.AreEqual("green", outValue[1]); - Assert.AreEqual("blue", outValue[2]); - } - - [Test] - public void AuthenticatedDateTime() - { - ProfileBase profile = ProfileBase.Create("foo", true); - ResetAppId(profile.Providers["MySqlProfileProvider"] as MySQLProfileProvider); - DateTime date = DateTime.Now; - profile["BirthDate"] = date; - profile.Save(); - - SettingsPropertyCollection getProps = new SettingsPropertyCollection(); - SettingsProperty getProp1 = new SettingsProperty("BirthDate"); - getProp1.PropertyType = typeof(DateTime); - getProp1.SerializeAs = SettingsSerializeAs.Xml; - getProps.Add(getProp1); - - MySQLProfileProvider provider = InitProfileProvider(); - SettingsContext ctx = new SettingsContext(); - ctx.Add("IsAuthenticated", true); - ctx.Add("UserName", "foo"); - - SettingsPropertyValueCollection getValues = provider.GetPropertyValues(ctx, getProps); - Assert.AreEqual(1, getValues.Count); - SettingsPropertyValue getValue1 = getValues["BirthDate"]; - Assert.AreEqual(date, getValue1.PropertyValue); - } - - /// - /// We have to manually reset the app id because our profile provider is loaded from - /// previous tests but we are destroying our database between tests. This means that - /// our provider thinks we have an application in our database when we really don't. - /// Doing this will force the provider to generate a new app id. - /// Note that this is not really a problem in a normal app that is not destroying - /// the database behind the back of the provider. - /// - /// - private void ResetAppId(MySQLProfileProvider p) - { - Type t = p.GetType(); - FieldInfo fi = t.GetField("app", - BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.GetField); - object appObject = fi.GetValue(p); - Type appType = appObject.GetType(); - PropertyInfo pi = appType.GetProperty("Id"); - pi.SetValue(appObject, -1, null); - } - - [Test, Order(4)] - public void AuthenticatedStringProperty() - { - ProfileBase profile = ProfileBase.Create("foo", true); - ResetAppId(profile.Providers["MySqlProfileProvider"] as MySQLProfileProvider); - profile["Name"] = "Fred Flintstone"; - profile.Save(); - - SettingsPropertyCollection getProps = new SettingsPropertyCollection(); - SettingsProperty getProp1 = new SettingsProperty("Name"); - getProp1.PropertyType = typeof(String); - getProps.Add(getProp1); - - MySQLProfileProvider provider = InitProfileProvider(); - SettingsContext ctx = new SettingsContext(); - ctx.Add("IsAuthenticated", true); - ctx.Add("UserName", "foo"); - - SettingsPropertyValueCollection getValues = provider.GetPropertyValues(ctx, getProps); - Assert.AreEqual(1, getValues.Count); - SettingsPropertyValue getValue1 = getValues["Name"]; - Assert.AreEqual("Fred Flintstone", getValue1.PropertyValue); - } - - /// - /// Bug #41654 FindProfilesByUserName error into Connector .NET - /// - [Test] - public void GetAllProfiles() - { - ProfileBase profile = ProfileBase.Create("foo", true); - ResetAppId(profile.Providers["MySqlProfileProvider"] as MySQLProfileProvider); - profile["Name"] = "Fred Flintstone"; - profile.Save(); - - SettingsPropertyCollection getProps = new SettingsPropertyCollection(); - SettingsProperty getProp1 = new SettingsProperty("Name"); - getProp1.PropertyType = typeof(String); - getProps.Add(getProp1); - - MySQLProfileProvider provider = InitProfileProvider(); - SettingsContext ctx = new SettingsContext(); - ctx.Add("IsAuthenticated", true); - ctx.Add("UserName", "foo"); - - int total; - ProfileInfoCollection profiles = provider.GetAllProfiles( - ProfileAuthenticationOption.All, 0, 10, out total); - Assert.AreEqual(1, total); - } - - /// - /// Tests deleting a user profile - /// - [Test] - public void DeleteProfiles() - { - ProfileBase profile = ProfileBase.Create("foo", true); - profile.SetPropertyValue("Name", "this is my name"); - profile.Save(); - profile = ProfileBase.Create("foo", true); // refresh profile from database - Assert.AreEqual("this is my name", profile.GetPropertyValue("Name")); - - Assert.AreEqual(1, ProfileManager.DeleteProfiles(new string[] { "foo" })); - profile = ProfileBase.Create("foo", true); // refresh profile from database - Assert.AreEqual(string.Empty, profile.GetPropertyValue("Name")); - } - - } -} +// Copyright © 2013, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Web.Profile; +using NUnit.Framework; +using NUnit.Framework.Legacy; +using System; +using System.Collections.Specialized; +using System.Configuration; +using System.Data; +using System.Reflection; +using System.Web.Profile; + +namespace MySql.Web.Tests +{ + public class ProfileTests : WebTestBase + { + private MySQLProfileProvider InitProfileProvider() + { + MySQLProfileProvider p = new MySQLProfileProvider(); + NameValueCollection config = new NameValueCollection(); + config.Add("connectionStringName", "LocalMySqlServer"); + config.Add("applicationName", "/"); + p.Initialize(null, config); + return p; + } + [TearDown] + public void Cleanup() + { + execSQL(@"delete from my_aspnet_applications; + delete from my_aspnet_paths; + delete from my_aspnet_users; + delete from my_aspnet_profiles; + delete from my_aspnet_personalizationallusers;"); + } + + [Test] + public void SettingValuesCreatesAnAppAndUserId() + { + + MySQLProfileProvider provider = InitProfileProvider(); + SettingsContext ctx = new SettingsContext(); + ctx.Add("IsAuthenticated", false); + ctx.Add("UserName", "user1"); + + SettingsPropertyValueCollection values = new SettingsPropertyValueCollection(); + SettingsProperty property1 = new SettingsProperty("color"); + property1.PropertyType = typeof(string); + property1.Attributes["AllowAnonymous"] = true; + SettingsPropertyValue value = new SettingsPropertyValue(property1); + value.PropertyValue = "blue"; + values.Add(value); + + provider.SetPropertyValues(ctx, values); + + DataTable dt = FillTable("SELECT * FROM my_aspnet_applications"); + Assert.That(1 == dt.Rows.Count, "Rows count on table my_aspnet_applications is not 1"); + + dt = FillTable("SELECT * FROM my_aspnet_users"); + Assert.That(1 == dt.Rows.Count, "Rows count on table my_aspnet_users is not 1"); + + + dt = FillTable("SELECT * FROM my_aspnet_profiles"); + Assert.That(1 == dt.Rows.Count, "Rows count on table my_aspnet_profiles is not 1"); + + values["color"].PropertyValue = "green"; + provider.SetPropertyValues(ctx, values); + + dt = FillTable("SELECT * FROM my_aspnet_applications"); + Assert.That(1 == dt.Rows.Count, "Rows count on table my_aspnet_applications is not 1 after setting property"); + + dt = FillTable("SELECT * FROM my_aspnet_users"); + Assert.That(1 == dt.Rows.Count, "Rows count on table my_aspnet_users is not 1 after setting property"); + + dt = FillTable("SELECT * FROM my_aspnet_profiles"); + Assert.That(1 == dt.Rows.Count, "Rows count on table my_aspnet_profiles is not 1 after setting property"); + } + + [Test] + public void AnonymousUserSettingNonAnonymousProperties() + { + MySQLProfileProvider provider = InitProfileProvider(); + SettingsContext ctx = new SettingsContext(); + ctx.Add("IsAuthenticated", false); + ctx.Add("UserName", "user1"); + + SettingsPropertyValueCollection values = new SettingsPropertyValueCollection(); + SettingsProperty property1 = new SettingsProperty("color"); + property1.PropertyType = typeof(string); + property1.Attributes["AllowAnonymous"] = false; + SettingsPropertyValue value = new SettingsPropertyValue(property1); + value.PropertyValue = "blue"; + values.Add(value); + + provider.SetPropertyValues(ctx, values); + + DataTable dt = FillTable("SELECT * FROM my_aspnet_applications"); + Assert.That(0 == dt.Rows.Count, "Table my_aspnet_applications Rows is not 0"); + + dt = FillTable("SELECT * FROM my_aspnet_users"); + Assert.That(0 == dt.Rows.Count, "Table my_aspnet_users Rows is not 0"); + + dt = FillTable("SELECT * FROM my_aspnet_profiles"); + Assert.That(0 == dt.Rows.Count, "Table my_aspnet_profiles Rows is not 0"); + + } + + [Test] + public void StringCollectionAsProperty() + { + ProfileBase profile = ProfileBase.Create("foo", true); + ResetAppId(profile.Providers["MySqlProfileProvider"] as MySQLProfileProvider); + StringCollection colors = new StringCollection(); + colors.Add("red"); + colors.Add("green"); + colors.Add("blue"); + profile["FavoriteColors"] = colors; + profile.Save(); + + DataTable dt = FillTable("SELECT * FROM my_aspnet_applications"); + Assert.That(dt.Rows.Count, Is.EqualTo(1)); + dt = FillTable("SELECT * FROM my_aspnet_users"); + Assert.That(dt.Rows.Count, Is.EqualTo(1)); + dt = FillTable("SELECT * FROM my_aspnet_profiles"); + Assert.That(dt.Rows.Count, Is.EqualTo(1)); + + // now retrieve them + SettingsPropertyCollection getProps = new SettingsPropertyCollection(); + SettingsProperty getProp1 = new SettingsProperty("FavoriteColors"); + getProp1.PropertyType = typeof(StringCollection); + getProp1.SerializeAs = SettingsSerializeAs.Xml; + getProps.Add(getProp1); + + MySQLProfileProvider provider = InitProfileProvider(); + SettingsContext ctx = new SettingsContext(); + ctx.Add("IsAuthenticated", true); + ctx.Add("UserName", "foo"); + SettingsPropertyValueCollection getValues = provider.GetPropertyValues(ctx, getProps); + Assert.That(getValues.Count, Is.EqualTo(1)); + SettingsPropertyValue getValue1 = getValues["FavoriteColors"]; + StringCollection outValue = (StringCollection)getValue1.PropertyValue; + Assert.That(outValue.Count, Is.EqualTo(3)); + Assert.That(outValue[0], Is.EqualTo("red")); + Assert.That(outValue[1], Is.EqualTo("green")); + Assert.That(outValue[2], Is.EqualTo("blue")); + } + + [Test] + public void AuthenticatedDateTime() + { + ProfileBase profile = ProfileBase.Create("foo", true); + ResetAppId(profile.Providers["MySqlProfileProvider"] as MySQLProfileProvider); + DateTime date = DateTime.Now; + profile["BirthDate"] = date; + profile.Save(); + + SettingsPropertyCollection getProps = new SettingsPropertyCollection(); + SettingsProperty getProp1 = new SettingsProperty("BirthDate"); + getProp1.PropertyType = typeof(DateTime); + getProp1.SerializeAs = SettingsSerializeAs.Xml; + getProps.Add(getProp1); + + MySQLProfileProvider provider = InitProfileProvider(); + SettingsContext ctx = new SettingsContext(); + ctx.Add("IsAuthenticated", true); + ctx.Add("UserName", "foo"); + + SettingsPropertyValueCollection getValues = provider.GetPropertyValues(ctx, getProps); + Assert.That(getValues.Count, Is.EqualTo(1)); + SettingsPropertyValue getValue1 = getValues["BirthDate"]; + Assert.That(getValue1.PropertyValue, Is.EqualTo(date)); + } + + /// + /// We have to manually reset the app id because our profile provider is loaded from + /// previous tests but we are destroying our database between tests. This means that + /// our provider thinks we have an application in our database when we really don't. + /// Doing this will force the provider to generate a new app id. + /// Note that this is not really a problem in a normal app that is not destroying + /// the database behind the back of the provider. + /// + /// + private void ResetAppId(MySQLProfileProvider p) + { + Type t = p.GetType(); + FieldInfo fi = t.GetField("app", + BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.GetField); + object appObject = fi.GetValue(p); + Type appType = appObject.GetType(); + PropertyInfo pi = appType.GetProperty("Id"); + pi.SetValue(appObject, -1, null); + } + + [Test, Order(4)] + public void AuthenticatedStringProperty() + { + ProfileBase profile = ProfileBase.Create("foo", true); + ResetAppId(profile.Providers["MySqlProfileProvider"] as MySQLProfileProvider); + profile["Name"] = "Fred Flintstone"; + profile.Save(); + + SettingsPropertyCollection getProps = new SettingsPropertyCollection(); + SettingsProperty getProp1 = new SettingsProperty("Name"); + getProp1.PropertyType = typeof(String); + getProps.Add(getProp1); + + MySQLProfileProvider provider = InitProfileProvider(); + SettingsContext ctx = new SettingsContext(); + ctx.Add("IsAuthenticated", true); + ctx.Add("UserName", "foo"); + + SettingsPropertyValueCollection getValues = provider.GetPropertyValues(ctx, getProps); + Assert.That(getValues.Count, Is.EqualTo(1)); + SettingsPropertyValue getValue1 = getValues["Name"]; + Assert.That(getValue1.PropertyValue, Is.EqualTo("Fred Flintstone")); + } + + /// + /// Bug #41654 FindProfilesByUserName error into Connector .NET + /// + [Test] + public void GetAllProfiles() + { + ProfileBase profile = ProfileBase.Create("foo", true); + ResetAppId(profile.Providers["MySqlProfileProvider"] as MySQLProfileProvider); + profile["Name"] = "Fred Flintstone"; + profile.Save(); + + SettingsPropertyCollection getProps = new SettingsPropertyCollection(); + SettingsProperty getProp1 = new SettingsProperty("Name"); + getProp1.PropertyType = typeof(String); + getProps.Add(getProp1); + + MySQLProfileProvider provider = InitProfileProvider(); + SettingsContext ctx = new SettingsContext(); + ctx.Add("IsAuthenticated", true); + ctx.Add("UserName", "foo"); + + int total; + ProfileInfoCollection profiles = provider.GetAllProfiles( + ProfileAuthenticationOption.All, 0, 10, out total); + Assert.That(total, Is.EqualTo(1)); + } + + /// + /// Tests deleting a user profile + /// + [Test] + public void DeleteProfiles() + { + ProfileBase profile = ProfileBase.Create("foo", true); + profile.SetPropertyValue("Name", "this is my name"); + profile.Save(); + profile = ProfileBase.Create("foo", true); // refresh profile from database + Assert.That(profile.GetPropertyValue("Name"), Is.EqualTo("this is my name")); + + Assert.That(ProfileManager.DeleteProfiles(new string[] { "foo" }), Is.EqualTo(1)); + profile = ProfileBase.Create("foo", true); // refresh profile from database + Assert.That(profile.GetPropertyValue("Name"), Is.Empty); + } + + } +} diff --git a/MySql.Web/tests/Properties/AssemblyInfo.cs b/MySql.Web/tests/Properties/AssemblyInfo.cs index 9a023faaf..e4cc0a0e5 100644 --- a/MySql.Web/tests/Properties/AssemblyInfo.cs +++ b/MySql.Web/tests/Properties/AssemblyInfo.cs @@ -1,49 +1,49 @@ -// Copyright (c) 2004, 2020, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using NUnit.Framework; -using System.Reflection; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("MySql.Web.Tests")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Oracle")] -[assembly: AssemblyProduct("MySql.Web.Tests")] -[assembly: AssemblyCopyright("Copyright © 2004, 2019, Oracle and/or its affiliates. All rights reserved.")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] -[assembly: NonParallelizable] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] \ No newline at end of file +// Copyright © 2004, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using NUnit.Framework; +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("MySql.Web.Tests")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Oracle")] +[assembly: AssemblyProduct("MySql.Web.Tests")] +[assembly: AssemblyCopyright("Copyright © 2004, 2025, Oracle and/or its affiliates.")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +[assembly: NonParallelizable] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] diff --git a/MySql.Web/tests/RoleManagement.cs b/MySql.Web/tests/RoleManagement.cs index 17b39f2c9..7a1d56fcc 100644 --- a/MySql.Web/tests/RoleManagement.cs +++ b/MySql.Web/tests/RoleManagement.cs @@ -1,234 +1,235 @@ -// Copyright (c) 2013, 2020, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Web.Security; -using NUnit.Framework; -using System; -using System.Collections.Specialized; -using System.Web.Security; - -namespace MySql.Web.Tests -{ - public class RoleManagement : WebTestBase - { - private MySQLMembershipProvider membershipProvider; - private MySQLRoleProvider roleProvider; - - public RoleManagement() - { - membershipProvider = new MySQLMembershipProvider(); - NameValueCollection config = new NameValueCollection(); - config.Add("connectionStringName", "LocalMySqlServer"); - config.Add("applicationName", "/"); - membershipProvider.Initialize(null, config); - - roleProvider = new MySQLRoleProvider(); - roleProvider.Initialize(null, config); - } - - private void AddUser(string username, string password) - { - MembershipCreateStatus status; - membershipProvider.CreateUser(username, password, "foo@bar.com", null, - null, true, null, out status); - Assert.False(status != MembershipCreateStatus.Success, "User creation failed"); - } - - private void AttemptToAddUserToRole(string username, string role) - { - try - { - roleProvider.AddUsersToRoles(new string[] { username }, - new string[] { role }); - } - catch (ArgumentException) - { - } - } - - - [Test] - public void CreateAndDeleteRoles() - { - // Add the role - roleProvider.CreateRole("Administrator"); - string[] roles = roleProvider.GetAllRoles(); - Assert.AreEqual(1, roles.Length); - Assert.AreEqual("Administrator", roles[0]); - roleProvider.DeleteRole("Administrator", false); - } - - [Test] - public void AddUserToRole() - { - AddUser("eve", "eveeve!"); - roleProvider.CreateRole("Administrator"); - - roleProvider.AddUsersToRoles(new string[] { "eve" }, - new string[] { "Administrator" }); - Assert.True(roleProvider.IsUserInRole("eve", "Administrator")); - - roleProvider.RemoveUsersFromRoles(new string[] { "eve" }, new string[] { "Administrator" }); - Assert.False(roleProvider.IsUserInRole("eve", "Administrator")); - - roleProvider.DeleteRole("Administrator", false); - Assert.AreEqual(0, roleProvider.GetAllRoles().Length); - - //clean up - membershipProvider.DeleteUser("eve", true); - - } - - /// - /// Bug #38243 Not Handling non existing user when calling AddUsersToRoles method - /// - [Test] - public void AddNonExistingUserToRole() - { - roleProvider.CreateRole("Administrator"); - roleProvider.AddUsersToRoles(new string[] { "eve" }, - new string[] { "Administrator" }); - Assert.True(roleProvider.IsUserInRole("eve", "Administrator")); - - //Cleanup - roleProvider.RemoveUsersFromRoles(new string[] { "eve" }, new string[] { "Administrator" }); - roleProvider.DeleteRole("Administrator", false); - - } - - - [Test] - public void IllegalRoleAndUserNames() - { - AttemptToAddUserToRole("test", null); - AttemptToAddUserToRole("test", ""); - roleProvider.CreateRole("Administrator"); - AttemptToAddUserToRole(null, "Administrator"); - AttemptToAddUserToRole("", "Administrator"); - - //Cleanup - roleProvider.DeleteRole("Administrator", false); - } - - [Test] - public void AddUserToRoleWithRoleClass() - { - roleProvider.CreateRole("Administrator"); - - MembershipCreateStatus status; - membershipProvider.CreateUser("eve", "eve1@eve", "eve@boo.com", - "question", "answer", true, null, out status); - Assert.AreEqual(MembershipCreateStatus.Success, status); - - roleProvider.AddUsersToRoles(new string[] { "eve" }, new string[] { "Administrator" }); - Assert.True(roleProvider.IsUserInRole("eve", "Administrator")); - - //Cleanup - membershipProvider.DeleteUser("eve", true); - roleProvider.DeleteRole("Administrator", true); - - } - - [Test] - public void IsUserInRoleCrossDomain() - { - MySQLMembershipProvider provider = new MySQLMembershipProvider(); - NameValueCollection config1 = new NameValueCollection(); - config1.Add("connectionStringName", "LocalMySqlServer"); - config1.Add("applicationName", "/"); - config1.Add("passwordStrengthRegularExpression", "bar.*"); - config1.Add("passwordFormat", "Clear"); - provider.Initialize(null, config1); - MembershipCreateStatus status; - provider.CreateUser("foo", "bar!bar", null, null, null, true, null, out status); - - MySQLMembershipProvider provider2 = new MySQLMembershipProvider(); - NameValueCollection config2 = new NameValueCollection(); - config2.Add("connectionStringName", "LocalMySqlServer"); - config2.Add("applicationName", "/myapp"); - config2.Add("passwordStrengthRegularExpression", ".*"); - config2.Add("passwordFormat", "Clear"); - provider2.Initialize(null, config2); - - roleProvider = new MySQLRoleProvider(); - NameValueCollection config = new NameValueCollection(); - config.Add("connectionStringName", "LocalMySqlServer"); - config.Add("applicationName", "/"); - roleProvider.Initialize(null, config); - - MySQLRoleProvider r2 = new MySQLRoleProvider(); - NameValueCollection configr2 = new NameValueCollection(); - configr2.Add("connectionStringName", "LocalMySqlServer"); - configr2.Add("applicationName", "/myapp"); - r2.Initialize(null, configr2); - - roleProvider.CreateRole("Administrator"); - roleProvider.AddUsersToRoles(new string[] { "foo" }, - new string[] { "Administrator" }); - Assert.False(r2.IsUserInRole("foo", "Administrator")); - - roleProvider.DeleteRole("Administrator", false); - Assert.AreEqual(0, roleProvider.GetAllRoles().Length); - - //Cleanup - provider.DeleteUser("foo", true); - - } - - /// - /// Testing fix for Calling RoleProvider.RemoveUserFromRole() causes an exception due to a wrong table being used. - /// http://clustra.no.oracle.com/orabugs/bug.php?id=14405338 / http://bugs.mysql.com/bug.php?id=65805. - /// - [Test] - public void TestUserRemoveFindFromRole() - { - roleProvider = new MySQLRoleProvider(); - NameValueCollection config = new NameValueCollection(); - config.Add("connectionStringName", "LocalMySqlServer"); - config.Add("applicationName", "/"); - roleProvider.Initialize(null, config); - - AddUser("eve", "eveeve!"); - roleProvider.CreateRole("Administrator"); - roleProvider.AddUsersToRoles(new string[] { "eve" }, - new string[] { "Administrator" }); - Assert.True(roleProvider.IsUserInRole("eve", "Administrator")); - string[] users = roleProvider.FindUsersInRole("Administrator", "eve"); - Assert.AreEqual(1, users.Length); - Assert.AreEqual("eve", users[0]); - roleProvider.RemoveUsersFromRoles(new string[] { "eve" }, new string[] { "Administrator" }); - Assert.False(roleProvider.IsUserInRole("eve", "Administrator")); - - //Cleanup - membershipProvider.DeleteUser("eve", true); - roleProvider.DeleteRole("Administrator", false); - - } - - } -} +// Copyright © 2013, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Web.Security; +using NUnit.Framework; +using NUnit.Framework.Legacy; +using System; +using System.Collections.Specialized; +using System.Web.Security; + +namespace MySql.Web.Tests +{ + public class RoleManagement : WebTestBase + { + private MySQLMembershipProvider membershipProvider; + private MySQLRoleProvider roleProvider; + + public RoleManagement() + { + membershipProvider = new MySQLMembershipProvider(); + NameValueCollection config = new NameValueCollection(); + config.Add("connectionStringName", "LocalMySqlServer"); + config.Add("applicationName", "/"); + membershipProvider.Initialize(null, config); + + roleProvider = new MySQLRoleProvider(); + roleProvider.Initialize(null, config); + } + + private void AddUser(string username, string password) + { + MembershipCreateStatus status; + membershipProvider.CreateUser(username, password, "foo@bar.com", null, + null, true, null, out status); + Assert.That(status == MembershipCreateStatus.Success, "User creation failed"); + } + + private void AttemptToAddUserToRole(string username, string role) + { + try + { + roleProvider.AddUsersToRoles(new string[] { username }, + new string[] { role }); + } + catch (ArgumentException) + { + } + } + + + [Test] + public void CreateAndDeleteRoles() + { + // Add the role + roleProvider.CreateRole("Administrator"); + string[] roles = roleProvider.GetAllRoles(); + Assert.That(roles.Length, Is.EqualTo(1)); + Assert.That(roles[0], Is.EqualTo("Administrator")); + roleProvider.DeleteRole("Administrator", false); + } + + [Test] + public void AddUserToRole() + { + AddUser("eve", "eveeve!"); + roleProvider.CreateRole("Administrator"); + + roleProvider.AddUsersToRoles(new string[] { "eve" }, + new string[] { "Administrator" }); + Assert.That(roleProvider.IsUserInRole("eve", "Administrator")); + + roleProvider.RemoveUsersFromRoles(new string[] { "eve" }, new string[] { "Administrator" }); + Assert.That(!roleProvider.IsUserInRole("eve", "Administrator")); + + roleProvider.DeleteRole("Administrator", false); + Assert.That(roleProvider.GetAllRoles().Length, Is.EqualTo(0)); + + //clean up + membershipProvider.DeleteUser("eve", true); + + } + + /// + /// Bug #38243 Not Handling non existing user when calling AddUsersToRoles method + /// + [Test] + public void AddNonExistingUserToRole() + { + roleProvider.CreateRole("Administrator"); + roleProvider.AddUsersToRoles(new string[] { "eve" }, + new string[] { "Administrator" }); + Assert.That(roleProvider.IsUserInRole("eve", "Administrator")); + + //Cleanup + roleProvider.RemoveUsersFromRoles(new string[] { "eve" }, new string[] { "Administrator" }); + roleProvider.DeleteRole("Administrator", false); + + } + + + [Test] + public void IllegalRoleAndUserNames() + { + AttemptToAddUserToRole("test", null); + AttemptToAddUserToRole("test", ""); + roleProvider.CreateRole("Administrator"); + AttemptToAddUserToRole(null, "Administrator"); + AttemptToAddUserToRole("", "Administrator"); + + //Cleanup + roleProvider.DeleteRole("Administrator", false); + } + + [Test] + public void AddUserToRoleWithRoleClass() + { + roleProvider.CreateRole("Administrator"); + + MembershipCreateStatus status; + membershipProvider.CreateUser("eve", "eve1@eve", "eve@boo.com", + "question", "answer", true, null, out status); + Assert.That(status, Is.EqualTo(MembershipCreateStatus.Success)); + + roleProvider.AddUsersToRoles(new string[] { "eve" }, new string[] { "Administrator" }); + Assert.That(roleProvider.IsUserInRole("eve", "Administrator")); + + //Cleanup + membershipProvider.DeleteUser("eve", true); + roleProvider.DeleteRole("Administrator", true); + + } + + [Test] + public void IsUserInRoleCrossDomain() + { + MySQLMembershipProvider provider = new MySQLMembershipProvider(); + NameValueCollection config1 = new NameValueCollection(); + config1.Add("connectionStringName", "LocalMySqlServer"); + config1.Add("applicationName", "/"); + config1.Add("passwordStrengthRegularExpression", "bar.*"); + config1.Add("passwordFormat", "Clear"); + provider.Initialize(null, config1); + MembershipCreateStatus status; + provider.CreateUser("foo", "bar!bar", null, null, null, true, null, out status); + + MySQLMembershipProvider provider2 = new MySQLMembershipProvider(); + NameValueCollection config2 = new NameValueCollection(); + config2.Add("connectionStringName", "LocalMySqlServer"); + config2.Add("applicationName", "/myapp"); + config2.Add("passwordStrengthRegularExpression", ".*"); + config2.Add("passwordFormat", "Clear"); + provider2.Initialize(null, config2); + + roleProvider = new MySQLRoleProvider(); + NameValueCollection config = new NameValueCollection(); + config.Add("connectionStringName", "LocalMySqlServer"); + config.Add("applicationName", "/"); + roleProvider.Initialize(null, config); + + MySQLRoleProvider r2 = new MySQLRoleProvider(); + NameValueCollection configr2 = new NameValueCollection(); + configr2.Add("connectionStringName", "LocalMySqlServer"); + configr2.Add("applicationName", "/myapp"); + r2.Initialize(null, configr2); + + roleProvider.CreateRole("Administrator"); + roleProvider.AddUsersToRoles(new string[] { "foo" }, + new string[] { "Administrator" }); + Assert.That(!r2.IsUserInRole("foo", "Administrator")); + + roleProvider.DeleteRole("Administrator", false); + Assert.That(roleProvider.GetAllRoles().Length, Is.EqualTo(0)); + + //Cleanup + provider.DeleteUser("foo", true); + + } + + /// + /// Testing fix for Calling RoleProvider.RemoveUserFromRole() causes an exception due to a wrong table being used. + /// http://clustra.no.oracle.com/orabugs/bug.php?id=14405338 / http://bugs.mysql.com/bug.php?id=65805. + /// + [Test] + public void TestUserRemoveFindFromRole() + { + roleProvider = new MySQLRoleProvider(); + NameValueCollection config = new NameValueCollection(); + config.Add("connectionStringName", "LocalMySqlServer"); + config.Add("applicationName", "/"); + roleProvider.Initialize(null, config); + + AddUser("eve", "eveeve!"); + roleProvider.CreateRole("Administrator"); + roleProvider.AddUsersToRoles(new string[] { "eve" }, + new string[] { "Administrator" }); + Assert.That(roleProvider.IsUserInRole("eve", "Administrator")); + string[] users = roleProvider.FindUsersInRole("Administrator", "eve"); + Assert.That(users.Length, Is.EqualTo(1)); + Assert.That(users[0], Is.EqualTo("eve")); + roleProvider.RemoveUsersFromRoles(new string[] { "eve" }, new string[] { "Administrator" }); + Assert.That(!roleProvider.IsUserInRole("eve", "Administrator")); + + //Cleanup + membershipProvider.DeleteUser("eve", true); + roleProvider.DeleteRole("Administrator", false); + + } + + } +} diff --git a/MySql.Web/tests/SchemaManagerTests.cs b/MySql.Web/tests/SchemaManagerTests.cs index d2c38baf6..2b089c4c3 100644 --- a/MySql.Web/tests/SchemaManagerTests.cs +++ b/MySql.Web/tests/SchemaManagerTests.cs @@ -1,319 +1,320 @@ -// Copyright (c) 2013, 2020, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data.MySqlClient; -using MySql.Web.Common; -using MySql.Web.Security; -using NUnit.Framework; -using System; -using System.Collections.Specialized; -using System.Configuration.Provider; -using System.Data; -using System.Web.Security; - -namespace MySql.Web.Tests -{ - public class SchemaManagerTests : WebTestBase - { - protected override void InitSchema() - { - // we override this and leave it empty because we don't want - // to init the schema for this test. - } - - [OneTimeSetUp] - public void Setup() - { - LoadData(); - } - - - /// - /// Bug #37469 autogenerateschema optimizing - /// - [Test] - public void SchemaCheck() - { - for (int i = 0; i <= SchemaManager.Version; i++) - { - MySQLMembershipProvider provider = new MySQLMembershipProvider(); - NameValueCollection config = new NameValueCollection(); - config.Add("connectionStringName", "LocalMySqlServer"); - config.Add("applicationName", "/"); - config.Add("passwordFormat", "Clear"); - - if (i > 0) - for (int x = 1; x <= i; x++) - LoadSchema(x); - - try - { - provider.Initialize(null, config); - if (i < SchemaManager.Version) - Assert.False(false, "Should have failed"); - } - catch (ProviderException) - { - if (i == SchemaManager.Version) - Assert.False(false, "This should not have failed"); - } - } - } - - /// - /// Bug #36444 'autogenerateschema' produces tables with 'random' collations - /// - [Test] - public void CurrentSchema() - { - execSQL(@"set character_set_database=utf8; - ALTER TABLE my_aspnet_membership CONVERT TO CHARACTER SET DEFAULT; - UPDATE my_aspnet_schemaversion SET version=4;"); - - MySqlCommand cmd = new MySqlCommand("SELECT * FROM my_aspnet_schemaversion", Connection); - object ver = cmd.ExecuteScalar(); - Assert.AreEqual(4, ver); - - cmd.CommandText = "SHOW CREATE TABLE my_aspnet_membership"; - using (MySqlDataReader reader = cmd.ExecuteReader()) - { - reader.Read(); - string createSql = reader.GetString(1); - Assert.True(createSql.IndexOf("CHARSET=utf8") != -1); - } - } - - [Test] - public void UpgradeV1ToV2() - { - execSQL(@"CREATE TABLE if not exists mysql_Membership(`PKID` varchar(36) NOT NULL, - Username varchar(255) NOT NULL, - ApplicationName varchar(255) NOT NULL, - Email varchar(128) NOT NULL, - Comment varchar(255) default NULL, - Password varchar(128) NOT NULL, - PasswordQuestion varchar(255) default NULL, - PasswordAnswer varchar(255) default NULL, - IsApproved tinyint(1) default NULL, - LastActivityDate datetime default NULL, - LastLoginDate datetime default NULL, - LastPasswordChangedDate datetime default NULL, - CreationDate datetime default NULL, - IsOnline tinyint(1) default NULL, - IsLockedOut tinyint(1) default NULL, - LastLockedOutDate datetime default NULL, - FailedPasswordAttemptCount int(10) unsigned default NULL, - FailedPasswordAttemptWindowStart datetime default NULL, - FailedPasswordAnswerAttemptCount int(10) unsigned default NULL, - FailedPasswordAnswerAttemptWindowStart datetime default NULL, - PRIMARY KEY (`PKID`)) DEFAULT CHARSET=latin1 COMMENT='1'; - ALTER TABLE mysql_Membership CHANGE Email Email VARCHAR(128), COMMENT='1';"); - - - MySqlCommand cmd = new MySqlCommand("SHOW CREATE TABLE mysql_membership", Connection); - using (MySqlDataReader reader = cmd.ExecuteReader()) - { - reader.Read(); - string createTable = reader.GetString(1); - int index = createTable.IndexOf("COMMENT='1'"); - Assert.AreNotEqual(-1, index); - } - - execSQL(@" ALTER TABLE mysql_Membership - CHANGE Email Email VARCHAR(128), COMMENT='2';"); - cmd = new MySqlCommand("SHOW CREATE TABLE mysql_membership", Connection); - using (MySqlDataReader reader = cmd.ExecuteReader()) - { - reader.Read(); - string createTable = reader.GetString(1); - int index = createTable.IndexOf("COMMENT='2'"); - Assert.AreNotEqual(-1, index); - } - } - - private void LoadData() - { - LoadSchema(1); - LoadSchema(2); - execSQL(@"INSERT INTO mysql_membership (pkid, username, password, applicationname, lastactivitydate) - VALUES('1', 'user1', '', 'app1', '2007-01-01')"); - execSQL(@"INSERT INTO mysql_membership (pkid, username, password, applicationname, lastactivitydate) - VALUES('2', 'user2', '', 'app1', '2007-01-01')"); - execSQL(@"INSERT INTO mysql_membership (pkid, username, password, applicationname, lastactivitydate) - VALUES('3', 'user1', '', 'app2', '2007-01-01')"); - execSQL(@"INSERT INTO mysql_membership (pkid, username, password, applicationname, lastactivitydate) - VALUES('4', 'user2', '', 'app2', '2007-01-01')"); - execSQL(@"INSERT INTO mysql_roles VALUES ('role1', 'app1')"); - execSQL(@"INSERT INTO mysql_roles VALUES ('role2', 'app1')"); - execSQL(@"INSERT INTO mysql_roles VALUES ('role1', 'app2')"); - execSQL(@"INSERT INTO mysql_roles VALUES ('role2', 'app2')"); - execSQL(@"INSERT INTO mysql_UsersInRoles VALUES ('user1', 'role1', 'app1')"); - execSQL(@"INSERT INTO mysql_UsersInRoles VALUES ('user2', 'role2', 'app1')"); - execSQL(@"INSERT INTO mysql_UsersInRoles VALUES ('user1', 'role1', 'app2')"); - execSQL(@"INSERT INTO mysql_UsersInRoles VALUES ('user2', 'role2', 'app2')"); - LoadSchema(3); - Assert.False(TableExists("mysql_membership")); - Assert.False(TableExists("mysql_roles")); - Assert.False(TableExists("mysql_usersinroles")); - } - - [Test] - public void CheckAppsUpgrade() - { - DataTable apps = FillTable("SELECT * FROM my_aspnet_applications"); - Assert.AreEqual(2, apps.Rows.Count); - Assert.AreEqual(1, apps.Rows[0]["id"]); - Assert.AreEqual("app1", apps.Rows[0]["name"]); - Assert.AreEqual(2, apps.Rows[1]["id"]); - Assert.AreEqual("app2", apps.Rows[1]["name"]); - } - - [Test] - public void CheckUsersUpgrade() - { - DataTable dt = FillTable("SELECT * FROM my_aspnet_users"); - Assert.AreEqual(4, dt.Rows.Count); - Assert.AreEqual(1, dt.Rows[0]["id"]); - Assert.AreEqual(1, dt.Rows[0]["applicationId"]); - Assert.AreEqual("user1", dt.Rows[0]["name"]); - Assert.AreEqual(2, dt.Rows[1]["id"]); - Assert.AreEqual(1, dt.Rows[1]["applicationId"]); - Assert.AreEqual("user2", dt.Rows[1]["name"]); - Assert.AreEqual(3, dt.Rows[2]["id"]); - Assert.AreEqual(2, dt.Rows[2]["applicationId"]); - Assert.AreEqual("user1", dt.Rows[2]["name"]); - Assert.AreEqual(4, dt.Rows[3]["id"]); - Assert.AreEqual(2, dt.Rows[3]["applicationId"]); - Assert.AreEqual("user2", dt.Rows[3]["name"]); - } - - [Test] - public void CheckRolesUpgrade() - { - DataTable dt = FillTable("SELECT * FROM my_aspnet_roles"); - Assert.AreEqual(4, dt.Rows.Count); - Assert.AreEqual(1, dt.Rows[0]["id"]); - Assert.AreEqual(1, dt.Rows[0]["applicationId"]); - Assert.AreEqual("role1", dt.Rows[0]["name"]); - Assert.AreEqual(2, dt.Rows[1]["id"]); - Assert.AreEqual(1, dt.Rows[1]["applicationId"]); - Assert.AreEqual("role2", dt.Rows[1]["name"]); - Assert.AreEqual(3, dt.Rows[2]["id"]); - Assert.AreEqual(2, dt.Rows[2]["applicationId"]); - Assert.AreEqual("role1", dt.Rows[2]["name"]); - Assert.AreEqual(4, dt.Rows[3]["id"]); - Assert.AreEqual(2, dt.Rows[3]["applicationId"]); - Assert.AreEqual("role2", dt.Rows[3]["name"]); - } - - [Test] - public void CheckMembershipUpgrade() - { - DataTable dt = FillTable("SELECT * FROM my_aspnet_membership"); - Assert.AreEqual(4, dt.Rows.Count); - Assert.AreEqual(1, dt.Rows[0]["userid"]); - Assert.AreEqual(2, dt.Rows[1]["userid"]); - Assert.AreEqual(3, dt.Rows[2]["userid"]); - Assert.AreEqual(4, dt.Rows[3]["userid"]); - } - - [Test] - public void CheckUsersInRolesUpgrade() - { - DataTable dt = FillTable("SELECT * FROM my_aspnet_usersinroles"); - Assert.AreEqual(4, dt.Rows.Count); - Assert.AreEqual(1, dt.Rows[0]["userid"]); - Assert.AreEqual(1, dt.Rows[0]["roleid"]); - Assert.AreEqual(2, dt.Rows[1]["userid"]); - Assert.AreEqual(2, dt.Rows[1]["roleid"]); - Assert.AreEqual(3, dt.Rows[2]["userid"]); - Assert.AreEqual(3, dt.Rows[2]["roleid"]); - Assert.AreEqual(4, dt.Rows[3]["userid"]); - Assert.AreEqual(4, dt.Rows[3]["roleid"]); - } - - /// - /// Bug #39072 Web provider does not work - /// - [Test] - public void AutoGenerateSchema() - { - MySQLMembershipProvider provider = new MySQLMembershipProvider(); - NameValueCollection config = new NameValueCollection(); - config.Add("connectionStringName", "LocalMySqlServer"); - config.Add("autogenerateschema", "true"); - config.Add("applicationName", "/"); - config.Add("passwordFormat", "Clear"); - - provider.Initialize(null, config); - - MembershipCreateStatus status; - MembershipUser user = provider.CreateUser("boo", "password", "email@email.com", - "question", "answer", true, null, out status); - } - - [Test] - public void SchemaTablesUseSameEngine() - { - for (int x = 1; x <= SchemaManager.Version; x++) - LoadSchema(x); - - string query = string.Format("SELECT TABLE_NAME, ENGINE FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = '{0}'", Connection.Database); - MySqlCommand cmd = new MySqlCommand(query, Connection); - string lastEngine = null; - string currentEngine; - - using (MySqlDataReader reader = cmd.ExecuteReader()) - { - while (reader.Read()) - { - currentEngine = reader.GetString("ENGINE"); - - if (string.IsNullOrEmpty(lastEngine)) - { - lastEngine = currentEngine; - } - - Assert.AreEqual(lastEngine, currentEngine); - } - } - } - - [Test] - public void InitializeInvalidConnStringThrowsArgumentException() - { - MySQLMembershipProvider provider = new MySQLMembershipProvider(); - NameValueCollection config = new NameValueCollection(); - var badConnectionString = ConnectionString + ";fookey=boo"; - config.Add("connectionString", badConnectionString); - - Exception ex = Assert.Throws(() => provider.Initialize(null, config)); - Assert.AreEqual("Option not supported.\r\nParameter name: fookey", ex.Message); - } - } -} +// Copyright © 2013, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data.MySqlClient; +using MySql.Web.Common; +using MySql.Web.Security; +using NUnit.Framework; +using NUnit.Framework.Legacy; +using System; +using System.Collections.Specialized; +using System.Configuration.Provider; +using System.Data; +using System.Web.Security; + +namespace MySql.Web.Tests +{ + public class SchemaManagerTests : WebTestBase + { + protected override void InitSchema() + { + // we override this and leave it empty because we don't want + // to init the schema for this test. + } + + [OneTimeSetUp] + public void Setup() + { + LoadData(); + } + + + /// + /// Bug #37469 autogenerateschema optimizing + /// + [Test] + public void SchemaCheck() + { + for (int i = 0; i <= SchemaManager.Version; i++) + { + MySQLMembershipProvider provider = new MySQLMembershipProvider(); + NameValueCollection config = new NameValueCollection(); + config.Add("connectionStringName", "LocalMySqlServer"); + config.Add("applicationName", "/"); + config.Add("passwordFormat", "Clear"); + + if (i > 0) + for (int x = 1; x <= i; x++) + LoadSchema(x); + + try + { + provider.Initialize(null, config); + if (i < SchemaManager.Version) + Assert.That(false, Is.False, "Should have failed"); + } + catch (ProviderException) + { + if (i == SchemaManager.Version) + Assert.That(false, Is.False, "This should not have failed"); + } + } + } + + /// + /// Bug #36444 'autogenerateschema' produces tables with 'random' collations + /// + [Test] + public void CurrentSchema() + { + execSQL(@"set character_set_database=utf8; + ALTER TABLE my_aspnet_membership CONVERT TO CHARACTER SET DEFAULT; + UPDATE my_aspnet_schemaversion SET version=4;"); + + MySqlCommand cmd = new MySqlCommand("SELECT * FROM my_aspnet_schemaversion", Connection); + object ver = cmd.ExecuteScalar(); + Assert.That(ver, Is.EqualTo(4)); + + cmd.CommandText = "SHOW CREATE TABLE my_aspnet_membership"; + using (MySqlDataReader reader = cmd.ExecuteReader()) + { + reader.Read(); + string createSql = reader.GetString(1); + Assert.That(createSql.IndexOf("CHARSET=utf8") != -1); + } + } + + [Test] + public void UpgradeV1ToV2() + { + execSQL(@"CREATE TABLE if not exists mysql_Membership(`PKID` varchar(36) NOT NULL, + Username varchar(255) NOT NULL, + ApplicationName varchar(255) NOT NULL, + Email varchar(128) NOT NULL, + Comment varchar(255) default NULL, + Password varchar(128) NOT NULL, + PasswordQuestion varchar(255) default NULL, + PasswordAnswer varchar(255) default NULL, + IsApproved tinyint(1) default NULL, + LastActivityDate datetime default NULL, + LastLoginDate datetime default NULL, + LastPasswordChangedDate datetime default NULL, + CreationDate datetime default NULL, + IsOnline tinyint(1) default NULL, + IsLockedOut tinyint(1) default NULL, + LastLockedOutDate datetime default NULL, + FailedPasswordAttemptCount int(10) unsigned default NULL, + FailedPasswordAttemptWindowStart datetime default NULL, + FailedPasswordAnswerAttemptCount int(10) unsigned default NULL, + FailedPasswordAnswerAttemptWindowStart datetime default NULL, + PRIMARY KEY (`PKID`)) DEFAULT CHARSET=latin1 COMMENT='1'; + ALTER TABLE mysql_Membership CHANGE Email Email VARCHAR(128), COMMENT='1';"); + + + MySqlCommand cmd = new MySqlCommand("SHOW CREATE TABLE mysql_membership", Connection); + using (MySqlDataReader reader = cmd.ExecuteReader()) + { + reader.Read(); + string createTable = reader.GetString(1); + int index = createTable.IndexOf("COMMENT='1'"); + Assert.That(index, Is.Not.EqualTo(-1)); + } + + execSQL(@" ALTER TABLE mysql_Membership + CHANGE Email Email VARCHAR(128), COMMENT='2';"); + cmd = new MySqlCommand("SHOW CREATE TABLE mysql_membership", Connection); + using (MySqlDataReader reader = cmd.ExecuteReader()) + { + reader.Read(); + string createTable = reader.GetString(1); + int index = createTable.IndexOf("COMMENT='2'"); + Assert.That(index, Is.Not.EqualTo(-1)); + } + } + + private void LoadData() + { + LoadSchema(1); + LoadSchema(2); + execSQL(@"INSERT INTO mysql_membership (pkid, username, password, applicationname, lastactivitydate) + VALUES('1', 'user1', '', 'app1', '2007-01-01')"); + execSQL(@"INSERT INTO mysql_membership (pkid, username, password, applicationname, lastactivitydate) + VALUES('2', 'user2', '', 'app1', '2007-01-01')"); + execSQL(@"INSERT INTO mysql_membership (pkid, username, password, applicationname, lastactivitydate) + VALUES('3', 'user1', '', 'app2', '2007-01-01')"); + execSQL(@"INSERT INTO mysql_membership (pkid, username, password, applicationname, lastactivitydate) + VALUES('4', 'user2', '', 'app2', '2007-01-01')"); + execSQL(@"INSERT INTO mysql_roles VALUES ('role1', 'app1')"); + execSQL(@"INSERT INTO mysql_roles VALUES ('role2', 'app1')"); + execSQL(@"INSERT INTO mysql_roles VALUES ('role1', 'app2')"); + execSQL(@"INSERT INTO mysql_roles VALUES ('role2', 'app2')"); + execSQL(@"INSERT INTO mysql_UsersInRoles VALUES ('user1', 'role1', 'app1')"); + execSQL(@"INSERT INTO mysql_UsersInRoles VALUES ('user2', 'role2', 'app1')"); + execSQL(@"INSERT INTO mysql_UsersInRoles VALUES ('user1', 'role1', 'app2')"); + execSQL(@"INSERT INTO mysql_UsersInRoles VALUES ('user2', 'role2', 'app2')"); + LoadSchema(3); + Assert.That(!TableExists("mysql_membership")); + Assert.That(!TableExists("mysql_roles")); + Assert.That(!TableExists("mysql_usersinroles")); + } + + [Test] + public void CheckAppsUpgrade() + { + DataTable apps = FillTable("SELECT * FROM my_aspnet_applications"); + Assert.That(apps.Rows.Count, Is.EqualTo(2)); + Assert.That(apps.Rows[0]["id"], Is.EqualTo(1)); + Assert.That(apps.Rows[0]["name"], Is.EqualTo("app1")); + Assert.That(apps.Rows[1]["id"], Is.EqualTo(2)); + Assert.That(apps.Rows[1]["name"], Is.EqualTo("app2")); + } + + [Test] + public void CheckUsersUpgrade() + { + DataTable dt = FillTable("SELECT * FROM my_aspnet_users"); + Assert.That(dt.Rows.Count, Is.EqualTo(4)); + Assert.That(dt.Rows[0]["id"], Is.EqualTo(1)); + Assert.That(dt.Rows[0]["applicationId"], Is.EqualTo(1)); + Assert.That(dt.Rows[0]["name"], Is.EqualTo("user1")); + Assert.That(dt.Rows[1]["id"], Is.EqualTo(2)); + Assert.That(dt.Rows[1]["applicationId"], Is.EqualTo(1)); + Assert.That(dt.Rows[1]["name"], Is.EqualTo("user2")); + Assert.That(dt.Rows[2]["id"], Is.EqualTo(3)); + Assert.That(dt.Rows[2]["applicationId"], Is.EqualTo(2)); + Assert.That(dt.Rows[2]["name"], Is.EqualTo("user1")); + Assert.That(dt.Rows[3]["id"], Is.EqualTo(4)); + Assert.That(dt.Rows[3]["applicationId"], Is.EqualTo(2)); + Assert.That(dt.Rows[3]["name"], Is.EqualTo("user2")); + } + + [Test] + public void CheckRolesUpgrade() + { + DataTable dt = FillTable("SELECT * FROM my_aspnet_roles"); + Assert.That(dt.Rows.Count, Is.EqualTo(4)); + Assert.That(dt.Rows[0]["id"], Is.EqualTo(1)); + Assert.That(dt.Rows[0]["applicationId"], Is.EqualTo(1)); + Assert.That(dt.Rows[0]["name"], Is.EqualTo("role1")); + Assert.That(dt.Rows[1]["id"], Is.EqualTo(2)); + Assert.That(dt.Rows[1]["applicationId"], Is.EqualTo(1)); + Assert.That(dt.Rows[1]["name"], Is.EqualTo("role2")); + Assert.That(dt.Rows[2]["id"], Is.EqualTo(3)); + Assert.That(dt.Rows[2]["applicationId"], Is.EqualTo(2)); + Assert.That(dt.Rows[2]["name"], Is.EqualTo("role1")); + Assert.That(dt.Rows[3]["id"], Is.EqualTo(4)); + Assert.That(dt.Rows[3]["applicationId"], Is.EqualTo(2)); + Assert.That(dt.Rows[3]["name"], Is.EqualTo("role2")); + } + + [Test] + public void CheckMembershipUpgrade() + { + DataTable dt = FillTable("SELECT * FROM my_aspnet_membership"); + Assert.That(dt.Rows.Count, Is.EqualTo(4)); + Assert.That(dt.Rows[0]["userid"], Is.EqualTo(1)); + Assert.That(dt.Rows[1]["userid"], Is.EqualTo(2)); + Assert.That(dt.Rows[2]["userid"], Is.EqualTo(3)); + Assert.That(dt.Rows[3]["userid"], Is.EqualTo(4)); + } + + [Test] + public void CheckUsersInRolesUpgrade() + { + DataTable dt = FillTable("SELECT * FROM my_aspnet_usersinroles"); + Assert.That(dt.Rows.Count, Is.EqualTo(4)); + Assert.That(dt.Rows[0]["userid"], Is.EqualTo(1)); + Assert.That(dt.Rows[0]["roleid"], Is.EqualTo(1)); + Assert.That(dt.Rows[1]["userid"], Is.EqualTo(2)); + Assert.That(dt.Rows[1]["roleid"], Is.EqualTo(2)); + Assert.That(dt.Rows[2]["userid"], Is.EqualTo(3)); + Assert.That(dt.Rows[2]["roleid"], Is.EqualTo(3)); + Assert.That(dt.Rows[3]["userid"], Is.EqualTo(4)); + Assert.That(dt.Rows[3]["roleid"], Is.EqualTo(4)); + } + + /// + /// Bug #39072 Web provider does not work + /// + [Test] + public void AutoGenerateSchema() + { + MySQLMembershipProvider provider = new MySQLMembershipProvider(); + NameValueCollection config = new NameValueCollection(); + config.Add("connectionStringName", "LocalMySqlServer"); + config.Add("autogenerateschema", "true"); + config.Add("applicationName", "/"); + config.Add("passwordFormat", "Clear"); + + provider.Initialize(null, config); + + MembershipCreateStatus status; + MembershipUser user = provider.CreateUser("boo", "password", "email@email.com", + "question", "answer", true, null, out status); + } + + [Test] + public void SchemaTablesUseSameEngine() + { + for (int x = 1; x <= SchemaManager.Version; x++) + LoadSchema(x); + + string query = string.Format("SELECT TABLE_NAME, ENGINE FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = '{0}'", Connection.Database); + MySqlCommand cmd = new MySqlCommand(query, Connection); + string lastEngine = null; + string currentEngine; + + using (MySqlDataReader reader = cmd.ExecuteReader()) + { + while (reader.Read()) + { + currentEngine = reader.GetString("ENGINE"); + + if (string.IsNullOrEmpty(lastEngine)) + { + lastEngine = currentEngine; + } + + Assert.That(currentEngine, Is.EqualTo(lastEngine)); + } + } + } + + [Test] + public void InitializeInvalidConnStringThrowsArgumentException() + { + MySQLMembershipProvider provider = new MySQLMembershipProvider(); + NameValueCollection config = new NameValueCollection(); + var badConnectionString = ConnectionString + ";fookey=boo"; + config.Add("connectionString", badConnectionString); + + Exception ex = Assert.Throws(() => provider.Initialize(null, config)); + Assert.That(ex.Message, Is.EqualTo("Option not supported\r\nParameter name: fookey")); + } + } +} diff --git a/MySql.Web/tests/SchemaTests.cs b/MySql.Web/tests/SchemaTests.cs index 600f19c63..6f8558474 100644 --- a/MySql.Web/tests/SchemaTests.cs +++ b/MySql.Web/tests/SchemaTests.cs @@ -1,357 +1,358 @@ -// Copyright (c) 2013, 2020, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data.MySqlClient; -using MySql.Web.Common; -using MySql.Web.Security; -using NUnit.Framework; -using System.Collections.Specialized; -using System.Configuration.Provider; -using System.Data; -using System.Web.Security; - -namespace MySql.Web.Tests -{ - public class SchemaTests : WebTestBase - { - protected override void InitSchema() - { - // we override this and leave it empty because we don't want - // to init the schema for this test. - } - - [OneTimeSetUp] - public void Setup() - { - LoadData(); - } - /// - /// Bug #37469 autogenerateschema optimizing - /// - [Test] - public void SchemaCheck() - { - for (int i = 0; i <= SchemaManager.Version; i++) - { - MySQLMembershipProvider provider = new MySQLMembershipProvider(); - NameValueCollection config = new NameValueCollection(); - config.Add("connectionStringName", "LocalMySqlServer"); - config.Add("applicationName", "/"); - config.Add("passwordFormat", "Clear"); - - if (i > 0) - for (int x = 1; x <= i; x++) - LoadSchema(x); - - try - { - provider.Initialize(null, config); - if (i < SchemaManager.Version) - Assert.False(false, "Should have failed"); - } - catch (ProviderException) - { - if (i == SchemaManager.Version) - Assert.False(false, "This should not have failed"); - } - } - } - - /// - /// Bug #36444 'autogenerateschema' produces tables with 'random' collations - /// - [Test] - public void CurrentSchema() - { - execSQL(@"set character_set_database=utf8; - ALTER TABLE my_aspnet_membership CONVERT TO CHARACTER SET DEFAULT; - UPDATE my_aspnet_schemaversion SET version=4;"); - - MySqlCommand cmd = new MySqlCommand("SELECT * FROM my_aspnet_schemaversion", Connection); - object ver = cmd.ExecuteScalar(); - Assert.AreEqual(4, ver); - - cmd.CommandText = "SHOW CREATE TABLE my_aspnet_membership"; - using (MySqlDataReader reader = cmd.ExecuteReader()) - { - reader.Read(); - string createSql = reader.GetString(1); - Assert.True(createSql.IndexOf("CHARSET=utf8") != -1); - } - } - - [Test] - public void UpgradeV1ToV2() - { - execSQL(@"CREATE TABLE if not exists mysql_Membership(`PKID` varchar(36) NOT NULL, - Username varchar(255) NOT NULL, - ApplicationName varchar(255) NOT NULL, - Email varchar(128) NOT NULL, - Comment varchar(255) default NULL, - Password varchar(128) NOT NULL, - PasswordQuestion varchar(255) default NULL, - PasswordAnswer varchar(255) default NULL, - IsApproved tinyint(1) default NULL, - LastActivityDate datetime default NULL, - LastLoginDate datetime default NULL, - LastPasswordChangedDate datetime default NULL, - CreationDate datetime default NULL, - IsOnline tinyint(1) default NULL, - IsLockedOut tinyint(1) default NULL, - LastLockedOutDate datetime default NULL, - FailedPasswordAttemptCount int(10) unsigned default NULL, - FailedPasswordAttemptWindowStart datetime default NULL, - FailedPasswordAnswerAttemptCount int(10) unsigned default NULL, - FailedPasswordAnswerAttemptWindowStart datetime default NULL, - PRIMARY KEY (`PKID`)) DEFAULT CHARSET=latin1 COMMENT='1'; - ALTER TABLE mysql_Membership CHANGE Email Email VARCHAR(128), COMMENT='1';"); - - - MySqlCommand cmd = new MySqlCommand("SHOW CREATE TABLE mysql_membership", Connection); - using (MySqlDataReader reader = cmd.ExecuteReader()) - { - reader.Read(); - string createTable = reader.GetString(1); - int index = createTable.IndexOf("COMMENT='1'"); - Assert.AreNotEqual(-1, index); - } - - execSQL(@" ALTER TABLE mysql_Membership - CHANGE Email Email VARCHAR(128), COMMENT='2';"); - cmd = new MySqlCommand("SHOW CREATE TABLE mysql_membership", Connection); - using (MySqlDataReader reader = cmd.ExecuteReader()) - { - reader.Read(); - string createTable = reader.GetString(1); - int index = createTable.IndexOf("COMMENT='2'"); - Assert.AreNotEqual(-1, index); - } - } - - private void LoadData() - { - LoadSchema(1); - LoadSchema(2); - execSQL(@"INSERT INTO mysql_membership (pkid, username, password, applicationname, lastactivitydate) - VALUES('1', 'user1', '', 'app1', '2007-01-01')"); - execSQL(@"INSERT INTO mysql_membership (pkid, username, password, applicationname, lastactivitydate) - VALUES('2', 'user2', '', 'app1', '2007-01-01')"); - execSQL(@"INSERT INTO mysql_membership (pkid, username, password, applicationname, lastactivitydate) - VALUES('3', 'user1', '', 'app2', '2007-01-01')"); - execSQL(@"INSERT INTO mysql_membership (pkid, username, password, applicationname, lastactivitydate) - VALUES('4', 'user2', '', 'app2', '2007-01-01')"); - execSQL(@"INSERT INTO mysql_roles VALUES ('role1', 'app1')"); - execSQL(@"INSERT INTO mysql_roles VALUES ('role2', 'app1')"); - execSQL(@"INSERT INTO mysql_roles VALUES ('role1', 'app2')"); - execSQL(@"INSERT INTO mysql_roles VALUES ('role2', 'app2')"); - execSQL(@"INSERT INTO mysql_UsersInRoles VALUES ('user1', 'role1', 'app1')"); - execSQL(@"INSERT INTO mysql_UsersInRoles VALUES ('user2', 'role2', 'app1')"); - execSQL(@"INSERT INTO mysql_UsersInRoles VALUES ('user1', 'role1', 'app2')"); - execSQL(@"INSERT INTO mysql_UsersInRoles VALUES ('user2', 'role2', 'app2')"); - LoadSchema(3); - Assert.False(TableExists("mysql_membership")); - Assert.False(TableExists("mysql_roles")); - Assert.False(TableExists("mysql_usersinroles")); - } - - [Test] - public void CheckAppsUpgrade() - { - DataTable apps = FillTable("SELECT * FROM my_aspnet_applications"); - Assert.AreEqual(2, apps.Rows.Count); - Assert.AreEqual(1, apps.Rows[0]["id"]); - Assert.AreEqual("app1", apps.Rows[0]["name"]); - Assert.AreEqual(2, apps.Rows[1]["id"]); - Assert.AreEqual("app2", apps.Rows[1]["name"]); - } - - //[Test] - //public void CheckUsersUpgrade() - //{ - // LoadData(); - - // DataTable dt = FillTable("SELECT * FROM my_aspnet_users"); - // Assert.AreEqual(4, dt.Rows.Count); - // Assert.AreEqual(1, dt.Rows[0]["id"]); - // Assert.AreEqual(1, dt.Rows[0]["applicationId"]); - // Assert.AreEqual("user1", dt.Rows[0]["name"]); - // Assert.AreEqual(2, dt.Rows[1]["id"]); - // Assert.AreEqual(1, dt.Rows[1]["applicationId"]); - // Assert.AreEqual("user2", dt.Rows[1]["name"]); - // Assert.AreEqual(3, dt.Rows[2]["id"]); - // Assert.AreEqual(2, dt.Rows[2]["applicationId"]); - // Assert.AreEqual("user1", dt.Rows[2]["name"]); - // Assert.AreEqual(4, dt.Rows[3]["id"]); - // Assert.AreEqual(2, dt.Rows[3]["applicationId"]); - // Assert.AreEqual("user2", dt.Rows[3]["name"]); - //} - - // [Test] - // public void CheckRolesUpgrade() - // { - // LoadData(); - - // DataTable dt = FillTable("SELECT * FROM my_aspnet_roles"); - // Assert.AreEqual(4, dt.Rows.Count); - // Assert.AreEqual(1, dt.Rows[0]["id"]); - // Assert.AreEqual(1, dt.Rows[0]["applicationId"]); - // Assert.AreEqual("role1", dt.Rows[0]["name"]); - // Assert.AreEqual(2, dt.Rows[1]["id"]); - // Assert.AreEqual(1, dt.Rows[1]["applicationId"]); - // Assert.AreEqual("role2", dt.Rows[1]["name"]); - // Assert.AreEqual(3, dt.Rows[2]["id"]); - // Assert.AreEqual(2, dt.Rows[2]["applicationId"]); - // Assert.AreEqual("role1", dt.Rows[2]["name"]); - // Assert.AreEqual(4, dt.Rows[3]["id"]); - // Assert.AreEqual(2, dt.Rows[3]["applicationId"]); - // Assert.AreEqual("role2", dt.Rows[3]["name"]); - // } - - // [Test] - // public void CheckMembershipUpgrade() - // { - // LoadData(); - - // DataTable dt = FillTable("SELECT * FROM my_aspnet_membership"); - // Assert.AreEqual(4, dt.Rows.Count); - // Assert.AreEqual(1, dt.Rows[0]["userid"]); - // Assert.AreEqual(2, dt.Rows[1]["userid"]); - // Assert.AreEqual(3, dt.Rows[2]["userid"]); - // Assert.AreEqual(4, dt.Rows[3]["userid"]); - // } - - // [Test] - // public void CheckUsersInRolesUpgrade() - // { - // LoadData(); - - // DataTable dt = FillTable("SELECT * FROM my_aspnet_usersinroles"); - // Assert.AreEqual(4, dt.Rows.Count); - // Assert.AreEqual(1, dt.Rows[0]["userid"]); - // Assert.AreEqual(1, dt.Rows[0]["roleid"]); - // Assert.AreEqual(2, dt.Rows[1]["userid"]); - // Assert.AreEqual(2, dt.Rows[1]["roleid"]); - // Assert.AreEqual(3, dt.Rows[2]["userid"]); - // Assert.AreEqual(3, dt.Rows[2]["roleid"]); - // Assert.AreEqual(4, dt.Rows[3]["userid"]); - // Assert.AreEqual(4, dt.Rows[3]["roleid"]); - // } - - /// - /// Bug #39072 Web provider does not work - /// - [Test] - public void AutoGenerateSchema() - { - MySQLMembershipProvider provider = new MySQLMembershipProvider(); - NameValueCollection config = new NameValueCollection(); - config.Add("ConnectionStringName", "LocalMySqlServer"); - config.Add("autogenerateschema", "true"); - config.Add("applicationName", "/"); - config.Add("passwordFormat", "Clear"); - - provider.Initialize(null, config); - - MembershipCreateStatus status; - MembershipUser user = provider.CreateUser("boo", "password", "email@email.com", - "question", "answer", true, null, out status); - } - - // [Test] - // public void SchemaTablesUseSameEngine() - // { - // DropAllTables(); - - // for (int x = 1; x <= SchemaManager.Version; x++) - // LoadSchema(x); - - // string query = string.Format("SELECT TABLE_NAME, ENGINE FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = '{0}'", st.conn.Database); - // MySqlCommand cmd = new MySqlCommand(query, st.conn); - // string lastEngine = null; - // string currentEngine; - - // using (MySqlDataReader reader = cmd.ExecuteReader()) - // { - // while (reader.Read()) - // { - // currentEngine = reader.GetString("ENGINE"); - - // if (string.IsNullOrEmpty(lastEngine)) - // { - // lastEngine = currentEngine; - // } - - // Assert.AreEqual(lastEngine, currentEngine); - // } - // } - // } - - // [Test] - // public void InitializeInvalidConnStringThrowsArgumentException() - // { - // Configuration configFile = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None); - // string connStr = configFile.ConnectionStrings.ConnectionStrings["LocalMySqlServer"].ConnectionString; - // string fakeConnectionString = connStr.Replace("database", "fooKey"); - // configFile.ConnectionStrings.ConnectionStrings["LocalMySqlServer"].ConnectionString = fakeConnectionString; - // configFile.Save(); - // ConfigurationManager.RefreshSection("connectionStrings"); - - // MySQLMembershipProvider provider = new MySQLMembershipProvider(); - // NameValueCollection config = new NameValueCollection(); - // config.Add("connectionStringName", "LocalMySqlServer"); - - // Exception ex = Assert.Throws(() => provider.Initialize(null, config)); - // Assert.AreEqual(ex.Message, "Keyword not supported.\r\nParameter name: fookey"); - - // configFile.ConnectionStrings.ConnectionStrings["LocalMySqlServer"].ConnectionString = connStr; - // configFile.Save(); - // ConfigurationManager.RefreshSection("connectionStrings"); - - // } - - /// - /// Checking fix for http://bugs.mysql.com/bug.php?id=65144 / http://clustra.no.oracle.com/orabugs/14495292 - /// (Net Connector 6.4.4 Asp.Net Membership Database fails on MySql Db of UTF32). - /// - [Test] - public void AttemptLatestSchemaVersion() - { - execSQL(string.Format("alter database `{0}` character set = 'utf32' collate = 'utf32_general_ci'", Connection.Database)); - for (int i = 1; i <= 4; i++) - { - LoadSchema(i); - } - MySQLRoleProvider roleProvider = new MySQLRoleProvider(); - NameValueCollection config = new NameValueCollection(); - config.Add("connectionStringName", "LocalMySqlServer"); - config.Add("applicationName", "/"); - config.Add("autogenerateschema", "true"); - roleProvider.Initialize(null, config); - } - } -} +// Copyright © 2013, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data.MySqlClient; +using MySql.Web.Common; +using MySql.Web.Security; +using NUnit.Framework; +using NUnit.Framework.Legacy; +using System.Collections.Specialized; +using System.Configuration.Provider; +using System.Data; +using System.Web.Security; + +namespace MySql.Web.Tests +{ + public class SchemaTests : WebTestBase + { + protected override void InitSchema() + { + // we override this and leave it empty because we don't want + // to init the schema for this test. + } + + [OneTimeSetUp] + public void Setup() + { + LoadData(); + } + /// + /// Bug #37469 autogenerateschema optimizing + /// + [Test] + public void SchemaCheck() + { + for (int i = 0; i <= SchemaManager.Version; i++) + { + MySQLMembershipProvider provider = new MySQLMembershipProvider(); + NameValueCollection config = new NameValueCollection(); + config.Add("connectionStringName", "LocalMySqlServer"); + config.Add("applicationName", "/"); + config.Add("passwordFormat", "Clear"); + + if (i > 0) + for (int x = 1; x <= i; x++) + LoadSchema(x); + + try + { + provider.Initialize(null, config); + if (i < SchemaManager.Version) + Assert.That(false, Is.False, "Should have failed"); + } + catch (ProviderException) + { + if (i == SchemaManager.Version) + Assert.That(false, Is.False, "This should not have failed"); + } + } + } + + /// + /// Bug #36444 'autogenerateschema' produces tables with 'random' collations + /// + [Test] + public void CurrentSchema() + { + execSQL(@"set character_set_database=utf8; + ALTER TABLE my_aspnet_membership CONVERT TO CHARACTER SET DEFAULT; + UPDATE my_aspnet_schemaversion SET version=4;"); + + MySqlCommand cmd = new MySqlCommand("SELECT * FROM my_aspnet_schemaversion", Connection); + object ver = cmd.ExecuteScalar(); + Assert.That(ver, Is.EqualTo(4)); + + cmd.CommandText = "SHOW CREATE TABLE my_aspnet_membership"; + using (MySqlDataReader reader = cmd.ExecuteReader()) + { + reader.Read(); + string createSql = reader.GetString(1); + Assert.That(createSql.IndexOf("CHARSET=utf8") != -1); + } + } + + [Test] + public void UpgradeV1ToV2() + { + execSQL(@"CREATE TABLE if not exists mysql_Membership(`PKID` varchar(36) NOT NULL, + Username varchar(255) NOT NULL, + ApplicationName varchar(255) NOT NULL, + Email varchar(128) NOT NULL, + Comment varchar(255) default NULL, + Password varchar(128) NOT NULL, + PasswordQuestion varchar(255) default NULL, + PasswordAnswer varchar(255) default NULL, + IsApproved tinyint(1) default NULL, + LastActivityDate datetime default NULL, + LastLoginDate datetime default NULL, + LastPasswordChangedDate datetime default NULL, + CreationDate datetime default NULL, + IsOnline tinyint(1) default NULL, + IsLockedOut tinyint(1) default NULL, + LastLockedOutDate datetime default NULL, + FailedPasswordAttemptCount int(10) unsigned default NULL, + FailedPasswordAttemptWindowStart datetime default NULL, + FailedPasswordAnswerAttemptCount int(10) unsigned default NULL, + FailedPasswordAnswerAttemptWindowStart datetime default NULL, + PRIMARY KEY (`PKID`)) DEFAULT CHARSET=latin1 COMMENT='1'; + ALTER TABLE mysql_Membership CHANGE Email Email VARCHAR(128), COMMENT='1';"); + + + MySqlCommand cmd = new MySqlCommand("SHOW CREATE TABLE mysql_membership", Connection); + using (MySqlDataReader reader = cmd.ExecuteReader()) + { + reader.Read(); + string createTable = reader.GetString(1); + int index = createTable.IndexOf("COMMENT='1'"); + Assert.That(index, Is.Not.EqualTo(-1)); + } + + execSQL(@" ALTER TABLE mysql_Membership + CHANGE Email Email VARCHAR(128), COMMENT='2';"); + cmd = new MySqlCommand("SHOW CREATE TABLE mysql_membership", Connection); + using (MySqlDataReader reader = cmd.ExecuteReader()) + { + reader.Read(); + string createTable = reader.GetString(1); + int index = createTable.IndexOf("COMMENT='2'"); + Assert.That(index, Is.Not.EqualTo(-1)); + } + } + + private void LoadData() + { + LoadSchema(1); + LoadSchema(2); + execSQL(@"INSERT INTO mysql_membership (pkid, username, password, applicationname, lastactivitydate) + VALUES('1', 'user1', '', 'app1', '2007-01-01')"); + execSQL(@"INSERT INTO mysql_membership (pkid, username, password, applicationname, lastactivitydate) + VALUES('2', 'user2', '', 'app1', '2007-01-01')"); + execSQL(@"INSERT INTO mysql_membership (pkid, username, password, applicationname, lastactivitydate) + VALUES('3', 'user1', '', 'app2', '2007-01-01')"); + execSQL(@"INSERT INTO mysql_membership (pkid, username, password, applicationname, lastactivitydate) + VALUES('4', 'user2', '', 'app2', '2007-01-01')"); + execSQL(@"INSERT INTO mysql_roles VALUES ('role1', 'app1')"); + execSQL(@"INSERT INTO mysql_roles VALUES ('role2', 'app1')"); + execSQL(@"INSERT INTO mysql_roles VALUES ('role1', 'app2')"); + execSQL(@"INSERT INTO mysql_roles VALUES ('role2', 'app2')"); + execSQL(@"INSERT INTO mysql_UsersInRoles VALUES ('user1', 'role1', 'app1')"); + execSQL(@"INSERT INTO mysql_UsersInRoles VALUES ('user2', 'role2', 'app1')"); + execSQL(@"INSERT INTO mysql_UsersInRoles VALUES ('user1', 'role1', 'app2')"); + execSQL(@"INSERT INTO mysql_UsersInRoles VALUES ('user2', 'role2', 'app2')"); + LoadSchema(3); + Assert.That(!TableExists("mysql_membership")); + Assert.That(!TableExists("mysql_roles")); + Assert.That(!TableExists("mysql_usersinroles")); + } + + [Test] + public void CheckAppsUpgrade() + { + DataTable apps = FillTable("SELECT * FROM my_aspnet_applications"); + Assert.That(apps.Rows.Count, Is.EqualTo(2)); + Assert.That(apps.Rows[0]["id"], Is.EqualTo(1)); + Assert.That(apps.Rows[0]["name"], Is.EqualTo("app1")); + Assert.That(apps.Rows[1]["id"], Is.EqualTo(2)); + Assert.That(apps.Rows[1]["name"], Is.EqualTo("app2")); + } + + //[Test] + //public void CheckUsersUpgrade() + //{ + // LoadData(); + + // DataTable dt = FillTable("SELECT * FROM my_aspnet_users"); + // Assert.AreEqual(4, dt.Rows.Count); + // Assert.AreEqual(1, dt.Rows[0]["id"]); + // Assert.AreEqual(1, dt.Rows[0]["applicationId"]); + // Assert.AreEqual("user1", dt.Rows[0]["name"]); + // Assert.AreEqual(2, dt.Rows[1]["id"]); + // Assert.AreEqual(1, dt.Rows[1]["applicationId"]); + // Assert.AreEqual("user2", dt.Rows[1]["name"]); + // Assert.AreEqual(3, dt.Rows[2]["id"]); + // Assert.AreEqual(2, dt.Rows[2]["applicationId"]); + // Assert.AreEqual("user1", dt.Rows[2]["name"]); + // Assert.AreEqual(4, dt.Rows[3]["id"]); + // Assert.AreEqual(2, dt.Rows[3]["applicationId"]); + // Assert.AreEqual("user2", dt.Rows[3]["name"]); + //} + + // [Test] + // public void CheckRolesUpgrade() + // { + // LoadData(); + + // DataTable dt = FillTable("SELECT * FROM my_aspnet_roles"); + // Assert.AreEqual(4, dt.Rows.Count); + // Assert.AreEqual(1, dt.Rows[0]["id"]); + // Assert.AreEqual(1, dt.Rows[0]["applicationId"]); + // Assert.AreEqual("role1", dt.Rows[0]["name"]); + // Assert.AreEqual(2, dt.Rows[1]["id"]); + // Assert.AreEqual(1, dt.Rows[1]["applicationId"]); + // Assert.AreEqual("role2", dt.Rows[1]["name"]); + // Assert.AreEqual(3, dt.Rows[2]["id"]); + // Assert.AreEqual(2, dt.Rows[2]["applicationId"]); + // Assert.AreEqual("role1", dt.Rows[2]["name"]); + // Assert.AreEqual(4, dt.Rows[3]["id"]); + // Assert.AreEqual(2, dt.Rows[3]["applicationId"]); + // Assert.AreEqual("role2", dt.Rows[3]["name"]); + // } + + // [Test] + // public void CheckMembershipUpgrade() + // { + // LoadData(); + + // DataTable dt = FillTable("SELECT * FROM my_aspnet_membership"); + // Assert.AreEqual(4, dt.Rows.Count); + // Assert.AreEqual(1, dt.Rows[0]["userid"]); + // Assert.AreEqual(2, dt.Rows[1]["userid"]); + // Assert.AreEqual(3, dt.Rows[2]["userid"]); + // Assert.AreEqual(4, dt.Rows[3]["userid"]); + // } + + // [Test] + // public void CheckUsersInRolesUpgrade() + // { + // LoadData(); + + // DataTable dt = FillTable("SELECT * FROM my_aspnet_usersinroles"); + // Assert.AreEqual(4, dt.Rows.Count); + // Assert.AreEqual(1, dt.Rows[0]["userid"]); + // Assert.AreEqual(1, dt.Rows[0]["roleid"]); + // Assert.AreEqual(2, dt.Rows[1]["userid"]); + // Assert.AreEqual(2, dt.Rows[1]["roleid"]); + // Assert.AreEqual(3, dt.Rows[2]["userid"]); + // Assert.AreEqual(3, dt.Rows[2]["roleid"]); + // Assert.AreEqual(4, dt.Rows[3]["userid"]); + // Assert.AreEqual(4, dt.Rows[3]["roleid"]); + // } + + /// + /// Bug #39072 Web provider does not work + /// + [Test] + public void AutoGenerateSchema() + { + MySQLMembershipProvider provider = new MySQLMembershipProvider(); + NameValueCollection config = new NameValueCollection(); + config.Add("ConnectionStringName", "LocalMySqlServer"); + config.Add("autogenerateschema", "true"); + config.Add("applicationName", "/"); + config.Add("passwordFormat", "Clear"); + + provider.Initialize(null, config); + + MembershipCreateStatus status; + MembershipUser user = provider.CreateUser("boo", "password", "email@email.com", + "question", "answer", true, null, out status); + } + + // [Test] + // public void SchemaTablesUseSameEngine() + // { + // DropAllTables(); + + // for (int x = 1; x <= SchemaManager.Version; x++) + // LoadSchema(x); + + // string query = string.Format("SELECT TABLE_NAME, ENGINE FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = '{0}'", st.conn.Database); + // MySqlCommand cmd = new MySqlCommand(query, st.conn); + // string lastEngine = null; + // string currentEngine; + + // using (MySqlDataReader reader = cmd.ExecuteReader()) + // { + // while (reader.Read()) + // { + // currentEngine = reader.GetString("ENGINE"); + + // if (string.IsNullOrEmpty(lastEngine)) + // { + // lastEngine = currentEngine; + // } + + // Assert.AreEqual(lastEngine, currentEngine); + // } + // } + // } + + // [Test] + // public void InitializeInvalidConnStringThrowsArgumentException() + // { + // Configuration configFile = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None); + // string connStr = configFile.ConnectionStrings.ConnectionStrings["LocalMySqlServer"].ConnectionString; + // string fakeConnectionString = connStr.Replace("database", "fooKey"); + // configFile.ConnectionStrings.ConnectionStrings["LocalMySqlServer"].ConnectionString = fakeConnectionString; + // configFile.Save(); + // ConfigurationManager.RefreshSection("connectionStrings"); + + // MySQLMembershipProvider provider = new MySQLMembershipProvider(); + // NameValueCollection config = new NameValueCollection(); + // config.Add("connectionStringName", "LocalMySqlServer"); + + // Exception ex = Assert.Throws(() => provider.Initialize(null, config)); + // Assert.AreEqual(ex.Message, "Keyword not supported.\r\nParameter name: fookey"); + + // configFile.ConnectionStrings.ConnectionStrings["LocalMySqlServer"].ConnectionString = connStr; + // configFile.Save(); + // ConfigurationManager.RefreshSection("connectionStrings"); + + // } + + /// + /// Checking fix for http://bugs.mysql.com/bug.php?id=65144 / http://clustra.no.oracle.com/orabugs/14495292 + /// (Net Connector 6.4.4 Asp.Net Membership Database fails on MySql Db of UTF32). + /// + [Test] + public void AttemptLatestSchemaVersion() + { + execSQL(string.Format("alter database `{0}` character set = 'utf32' collate = 'utf32_general_ci'", Connection.Database)); + for (int i = 1; i <= 4; i++) + { + LoadSchema(i); + } + MySQLRoleProvider roleProvider = new MySQLRoleProvider(); + NameValueCollection config = new NameValueCollection(); + config.Add("connectionStringName", "LocalMySqlServer"); + config.Add("applicationName", "/"); + config.Add("autogenerateschema", "true"); + roleProvider.Initialize(null, config); + } + } +} diff --git a/MySql.Web/tests/SessionLocking/Global.asax.cs b/MySql.Web/tests/SessionLocking/Global.asax.cs index ea62fe855..934ba143b 100644 --- a/MySql.Web/tests/SessionLocking/Global.asax.cs +++ b/MySql.Web/tests/SessionLocking/Global.asax.cs @@ -1,16 +1,16 @@ -// Copyright © 2004,2010, Oracle and/or its affiliates. All rights reserved. +// Copyright © 2004, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the diff --git a/MySql.Web/tests/SessionLocking/InitSessionLocking.aspx.cs b/MySql.Web/tests/SessionLocking/InitSessionLocking.aspx.cs index 25a6c40ce..b4ab197ad 100644 --- a/MySql.Web/tests/SessionLocking/InitSessionLocking.aspx.cs +++ b/MySql.Web/tests/SessionLocking/InitSessionLocking.aspx.cs @@ -1,48 +1,48 @@ -// Copyright © 2004, 2013, Oracle and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -// This code was contributed by Sean Wright (srwright@alcor.concordia.ca) on 2007-01-12 -// The copyright was assigned and transferred under the terms of -// the MySQL Contributor License Agreement (CLA) - -using System; -using System.Collections.Generic; -using System.Web; -using System.Web.UI; -using System.Web.UI.WebControls; - -namespace MySql.Web.Tests.SessionLocking -{ - public partial class InitSessionLocking : System.Web.UI.Page - { - protected void Page_Load(object sender, EventArgs e) - { - - } - } -} \ No newline at end of file +// Copyright © 2004, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +// This code was contributed by Sean Wright (srwright@alcor.concordia.ca) on 2007-01-12 +// The copyright was assigned and transferred under the terms of +// the MySQL Contributor License Agreement (CLA) + +using System; +using System.Collections.Generic; +using System.Web; +using System.Web.UI; +using System.Web.UI.WebControls; + +namespace MySql.Web.Tests.SessionLocking +{ + public partial class InitSessionLocking : System.Web.UI.Page + { + protected void Page_Load(object sender, EventArgs e) + { + + } + } +} diff --git a/MySql.Web/tests/SessionLocking/InitSessionLocking.aspx.designer.cs b/MySql.Web/tests/SessionLocking/InitSessionLocking.aspx.designer.cs index 5bb831374..c15fda308 100644 --- a/MySql.Web/tests/SessionLocking/InitSessionLocking.aspx.designer.cs +++ b/MySql.Web/tests/SessionLocking/InitSessionLocking.aspx.designer.cs @@ -1,26 +1,26 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace MySql.Web.Tests.SessionLocking -{ - - - public partial class InitSessionLocking - { - - /// - /// form1 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.HtmlControls.HtmlForm form1; - } -} +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace MySql.Web.Tests.SessionLocking +{ + + + public partial class InitSessionLocking + { + + /// + /// form1 control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.HtmlControls.HtmlForm form1; + } +} diff --git a/MySql.Web/tests/SessionLocking/read.aspx.cs b/MySql.Web/tests/SessionLocking/read.aspx.cs index 5e83e2fa4..fe2865af1 100644 --- a/MySql.Web/tests/SessionLocking/read.aspx.cs +++ b/MySql.Web/tests/SessionLocking/read.aspx.cs @@ -1,52 +1,52 @@ -// Copyright © 2004, 2013, Oracle and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -// This code was contributed by Sean Wright (srwright@alcor.concordia.ca) on 2007-01-12 -// The copyright was assigned and transferred under the terms of -// the MySQL Contributor License Agreement (CLA) - -using System; -using System.Collections.Generic; -using System.Web; -using System.Web.UI; -using System.Web.UI.WebControls; -using System.Threading; -using MySql.Web.Tests; - -namespace MySql.Web.Tests -{ - public partial class read : System.Web.UI.Page - { - protected void Page_Load(object sender, EventArgs e) - { - object o = Session["x"]; - // Signaler -// SessionTests.mtxReader.Set(); - } - } -} \ No newline at end of file +// Copyright © 2004, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +// This code was contributed by Sean Wright (srwright@alcor.concordia.ca) on 2007-01-12 +// The copyright was assigned and transferred under the terms of +// the MySQL Contributor License Agreement (CLA) + +using System; +using System.Collections.Generic; +using System.Web; +using System.Web.UI; +using System.Web.UI.WebControls; +using System.Threading; +using MySql.Web.Tests; + +namespace MySql.Web.Tests +{ + public partial class read : System.Web.UI.Page + { + protected void Page_Load(object sender, EventArgs e) + { + object o = Session["x"]; + // Signaler +// SessionTests.mtxReader.Set(); + } + } +} diff --git a/MySql.Web/tests/SessionLocking/read.aspx.designer.cs b/MySql.Web/tests/SessionLocking/read.aspx.designer.cs index fe385e6b1..44778047d 100644 --- a/MySql.Web/tests/SessionLocking/read.aspx.designer.cs +++ b/MySql.Web/tests/SessionLocking/read.aspx.designer.cs @@ -1,24 +1,24 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace MySql.Web.Tests { - - - public partial class read { - - /// - /// form1 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.HtmlControls.HtmlForm form1; - } -} +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace MySql.Web.Tests { + + + public partial class read { + + /// + /// form1 control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.HtmlControls.HtmlForm form1; + } +} diff --git a/MySql.Web/tests/SessionLocking/write.aspx.cs b/MySql.Web/tests/SessionLocking/write.aspx.cs index 660832260..0d0b2bc1a 100644 --- a/MySql.Web/tests/SessionLocking/write.aspx.cs +++ b/MySql.Web/tests/SessionLocking/write.aspx.cs @@ -1,54 +1,54 @@ -// Copyright © 2004, 2013, Oracle and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -// This code was contributed by Sean Wright (srwright@alcor.concordia.ca) on 2007-01-12 -// The copyright was assigned and transferred under the terms of -// the MySQL Contributor License Agreement (CLA) - -using System; -using System.Collections.Generic; -using System.Web; -using System.Web.UI; -using System.Web.UI.WebControls; -using System.Threading; -using MySql.Web.Tests; - -namespace MySql.Web.Tests -{ - public partial class write : System.Web.UI.Page - { - protected void Page_Load(object sender, EventArgs e) - { - // Make session dirty -// Session["x"] = "x"; - - // SessionTests.mtxWriter.Set(); - // SessionTests.WaitSyncCreation( false ); - } - } -} \ No newline at end of file +// Copyright © 2004, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +// This code was contributed by Sean Wright (srwright@alcor.concordia.ca) on 2007-01-12 +// The copyright was assigned and transferred under the terms of +// the MySQL Contributor License Agreement (CLA) + +using System; +using System.Collections.Generic; +using System.Web; +using System.Web.UI; +using System.Web.UI.WebControls; +using System.Threading; +using MySql.Web.Tests; + +namespace MySql.Web.Tests +{ + public partial class write : System.Web.UI.Page + { + protected void Page_Load(object sender, EventArgs e) + { + // Make session dirty +// Session["x"] = "x"; + + // SessionTests.mtxWriter.Set(); + // SessionTests.WaitSyncCreation( false ); + } + } +} diff --git a/MySql.Web/tests/SessionLocking/write.aspx.designer.cs b/MySql.Web/tests/SessionLocking/write.aspx.designer.cs index b73b0eea1..1035ebd07 100644 --- a/MySql.Web/tests/SessionLocking/write.aspx.designer.cs +++ b/MySql.Web/tests/SessionLocking/write.aspx.designer.cs @@ -1,24 +1,24 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace MySql.Web.Tests { - - - public partial class write { - - /// - /// form1 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.HtmlControls.HtmlForm form1; - } -} +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace MySql.Web.Tests { + + + public partial class write { + + /// + /// form1 control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.HtmlControls.HtmlForm form1; + } +} diff --git a/MySql.Web/tests/SessionLocking/write2.aspx.cs b/MySql.Web/tests/SessionLocking/write2.aspx.cs index 82c01275b..54a33c439 100644 --- a/MySql.Web/tests/SessionLocking/write2.aspx.cs +++ b/MySql.Web/tests/SessionLocking/write2.aspx.cs @@ -1,51 +1,51 @@ -// Copyright © 2004, 2013, Oracle and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -// This code was contributed by Sean Wright (srwright@alcor.concordia.ca) on 2007-01-12 -// The copyright was assigned and transferred under the terms of -// the MySQL Contributor License Agreement (CLA) - -using System; -using System.Collections.Generic; -#if CLR4 - -#endif -using System.Web; -using System.Web.UI; -using System.Web.UI.WebControls; - -namespace MySql.Web.Tests -{ - public partial class write2 : System.Web.UI.Page - { - protected void Page_Load(object sender, EventArgs e) - { - Session["x"] = "x2"; - } - } -} \ No newline at end of file +// Copyright © 2004, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +// This code was contributed by Sean Wright (srwright@alcor.concordia.ca) on 2007-01-12 +// The copyright was assigned and transferred under the terms of +// the MySQL Contributor License Agreement (CLA) + +using System; +using System.Collections.Generic; +#if CLR4 + +#endif +using System.Web; +using System.Web.UI; +using System.Web.UI.WebControls; + +namespace MySql.Web.Tests +{ + public partial class write2 : System.Web.UI.Page + { + protected void Page_Load(object sender, EventArgs e) + { + Session["x"] = "x2"; + } + } +} diff --git a/MySql.Web/tests/SessionLocking/write2.aspx.designer.cs b/MySql.Web/tests/SessionLocking/write2.aspx.designer.cs index 5c0052461..b545ee60b 100644 --- a/MySql.Web/tests/SessionLocking/write2.aspx.designer.cs +++ b/MySql.Web/tests/SessionLocking/write2.aspx.designer.cs @@ -1,24 +1,24 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace MySql.Web.Tests { - - - public partial class write2 { - - /// - /// form1 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.HtmlControls.HtmlForm form1; - } -} +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace MySql.Web.Tests { + + + public partial class write2 { + + /// + /// form1 control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.HtmlControls.HtmlForm form1; + } +} diff --git a/MySql.Web/tests/SessionTests.cs b/MySql.Web/tests/SessionTests.cs index 25cdeea83..b147fea74 100644 --- a/MySql.Web/tests/SessionTests.cs +++ b/MySql.Web/tests/SessionTests.cs @@ -1,381 +1,382 @@ -// Copyright (c) 2013, 2020, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data.MySqlClient; -using MySql.Web.SessionState; -using NUnit.Framework; -using System; -using System.Collections.Specialized; -using System.Configuration; -using System.Diagnostics; -using System.IO; -using System.Net; -using System.Threading; -using System.Web.SessionState; - -namespace MySql.Web.Tests -{ - public class SessionTests : WebTestBase - { - private string strSessionID { get; set; } - private string calledId { get; set; } - private AutoResetEvent _evt { get; set; } - - private byte[] Serialize(SessionStateItemCollection items) - { - MemoryStream ms = new MemoryStream(); - BinaryWriter writer = new BinaryWriter(ms); - if (items != null) - { - items.Serialize(writer); - } - writer.Close(); - return ms.ToArray(); - } - - - private void CreateSessionData(int AppId, DateTime timeCreated) - { - MySqlCommand cmd = new MySqlCommand(); - strSessionID = System.Guid.NewGuid().ToString(); - - //DateTime now = DateTime.Now; - //DateTime lastHour = now.Subtract(new TimeSpan(1, 0, 0)); - - SessionStateItemCollection collection = new SessionStateItemCollection(); - collection["FirstName"] = "Some"; - collection["LastName"] = "Name"; - byte[] items = Serialize(collection); - - string sql = @"INSERT INTO my_aspnet_sessions VALUES ( - @sessionId, @appId, @created, @expires, @lockdate, @lockid, @timeout, - @locked, @items, @flags)"; - - cmd = new MySqlCommand(sql, Connection); - cmd.Parameters.AddWithValue("@sessionId", strSessionID); - cmd.Parameters.AddWithValue("@appId", AppId); - cmd.Parameters.AddWithValue("@created", timeCreated); - cmd.Parameters.AddWithValue("@expires", timeCreated); - cmd.Parameters.AddWithValue("@lockdate", timeCreated); - cmd.Parameters.AddWithValue("@lockid", 1); - cmd.Parameters.AddWithValue("@timeout", 1); - cmd.Parameters.AddWithValue("@locked", 0); - cmd.Parameters.AddWithValue("@items", items); - cmd.Parameters.AddWithValue("@flags", 0); - cmd.ExecuteNonQuery(); - - //create new row on sessioncleanup table - cmd.CommandText = "INSERT IGNORE INTO my_aspnet_sessioncleanup SET" + - " ApplicationId = @ApplicationId, " + - " LastRun = NOW(), " + - " IntervalMinutes = 10"; - cmd.Parameters.Clear(); - cmd.Parameters.AddWithValue("@ApplicationId", AppId); - cmd.ExecuteNonQuery(); - - // set our last run table to 1 hour ago - cmd.CommandText = "UPDATE my_aspnet_sessioncleanup SET LastRun=@lastHour WHERE ApplicationId = @ApplicationId"; - cmd.Parameters.Clear(); - cmd.Parameters.AddWithValue("@lastHour", DateTime.Now.Subtract(new TimeSpan(1, 0, 0))); - cmd.Parameters.AddWithValue("@ApplicationId", AppId); - cmd.ExecuteNonQuery(); - } - - - private void SetSessionItemExpiredCallback(bool includeCallback) - { - _evt = new AutoResetEvent(false); - calledId = null; - - CreateSessionData(1, DateTime.Now.Subtract(new TimeSpan(1, 0, 0))); - - MySqlSessionStateStore session = new MySqlSessionStateStore(); - - NameValueCollection config = new NameValueCollection(); - config.Add("connectionStringName", "LocalMySqlServer"); - config.Add("applicationName", "/"); - config.Add("enableExpireCallback", includeCallback ? "true" : "false"); - session.Initialize("SessionProvTest", config); - if (includeCallback) session.SetItemExpireCallback(expireCallback); - Thread.Sleep(1000); - session.Dispose(); - } - - private long CountSessions() - { - return (long)MySqlHelper.ExecuteScalar(Connection, "SELECT COUNT(*) FROM my_aspnet_sessions"); - } - - public void expireCallback(string id, SessionStateStoreData item) - { - calledId = id; - _evt.Set(); - } - - - [Test] - public void SessionItemWithExpireCallback() - { - execSQL(@"delete from my_aspnet_sessions; - delete from my_aspnet_sessioncleanup;"); - SetSessionItemExpiredCallback(true); - _evt.WaitOne(); - - Assert.AreEqual(strSessionID, calledId); - - int i = 0; - while (((long)CountSessions() != 0) && (i < 10)) - { - Thread.Sleep(500); - i++; - } - - Assert.AreEqual(0, CountSessions()); - } - - - [Test] - public void SessionItemWithoutExpireCallback() - { - execSQL(@"delete from my_aspnet_sessions; - delete from my_aspnet_sessioncleanup;"); - SetSessionItemExpiredCallback(false); - Assert.AreNotEqual(strSessionID, calledId); - - int i = 0; - while (((long)MySqlHelper.ExecuteScalar(Connection, "SELECT Count(*) FROM my_aspnet_sessions;") != 0) && (i < 10)) - { - Thread.Sleep(500); - i++; - } - - Assert.AreEqual(0, CountSessions()); - } - - [Test] - public void DeleteSessionAppSpecific() - { - // create two sessions of different appId - // it should delete only 1 - CreateSessionData(1, DateTime.Now.Subtract(new TimeSpan(1, 10, 0))); - CreateSessionData(2, DateTime.Now.Subtract(new TimeSpan(1, 0, 0))); - - MySqlSessionStateStore session = new MySqlSessionStateStore(); - - NameValueCollection config = new NameValueCollection(); - config.Add("connectionStringName", "LocalMySqlServer"); - config.Add("applicationName", "/"); - config.Add("enableExpireCallback", "false"); - session.Initialize("SessionTests", config); - - int i = 0; - while (CountSessions() == 2 && (i < 10)) - { - Thread.Sleep(500); - i++; - } - - session.Dispose(); - Assert.AreEqual(1, CountSessions()); - session.Dispose(); - } - - public class ThreadRequestData - { - public string pageName; - public ManualResetEvent signal; - public bool FirstDateToUpdate; - } - - delegate WebResponse GetResponse(); - delegate void ThreadRequest(ThreadRequestData data); - - [Ignore("Fix Me")] - public void SessionLocking() - { - // Copy updated configuration file for web server process - Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None); - ConnectionStringSettings css = config.ConnectionStrings.ConnectionStrings["LocalMySqlServer"]; - string curDir = Directory.GetCurrentDirectory(); - string webconfigPath = string.Format(@"{0}\SessionLocking\{1}", Directory.GetCurrentDirectory(), @"web.config"); - string webconfigPathSrc = string.Format(@"{0}\SessionLocking\{1}", Directory.GetCurrentDirectory(), @"web_config_src.txt"); - - string text = File.ReadAllText(webconfigPathSrc); - text = text.Replace("connection_string_here", css.ConnectionString); - Version ver = System.Environment.Version; - if (ver.Major != 4) - { - text = text.Replace("", ""); - } - - File.WriteAllText(webconfigPath, text); - - int port = 12224; - - string webserverPath; - if (ver.Major == 4) - { - webserverPath = @"C:\Program Files (x86)\Common Files\microsoft shared\DevServer\10.0\WebDev.WebServer40.exe"; - } - else - { - webserverPath = @"C:\Program Files (x86)\Common Files\microsoft shared\DevServer\9.0\WebDev.WebServer.exe"; - } - string webserverArgs = string.Format(" /port:{0} /path:{1}\\SessionLocking", port, - Path.GetFullPath(@".")); - - DirectoryInfo di = new DirectoryInfo(Path.GetFullPath(curDir)); - Directory.CreateDirectory(Path.GetFullPath(@".\SessionLocking\bin")); - foreach (FileInfo fi in di.GetFiles("*.dll")) - { - File.Copy(fi.FullName, Path.Combine(Path.GetFullPath(@".\SessionLocking\bin\"), fi.Name), true); - } - - Process webserver = Process.Start(webserverPath, webserverArgs); - System.Threading.Thread.Sleep(2000); - - // This dummy request is just to get the ASP.NET sessionid to reuse. - HttpWebRequest req = (HttpWebRequest)WebRequest.Create("http://localhost:12224/InitSessionLocking.aspx"); - HttpWebResponse res = (HttpWebResponse)req.GetResponse(); - WebHeaderCollection headers = new WebHeaderCollection(); - - string url = res.ResponseUri.ToString().Replace("InitSessionLocking.aspx", ""); - Debug.Write(url); - - try - { - DateTime? firstDt = null; - DateTime? secondDt = null; - - ManualResetEvent[] re = new ManualResetEvent[2]; - re[0] = new ManualResetEvent(false); - re[1] = new ManualResetEvent(false); - ParameterizedThreadStart ts = - (object data1) => - { - ThreadRequestData data = (ThreadRequestData)data1; - Debug.WriteLine(string.Format("Requesting {0}", data.pageName)); - try - { - HttpWebRequest req1 = - (HttpWebRequest)WebRequest.Create(string.Format(@"{0}{1}", url, data.pageName)); - req1.Timeout = 2000000; - WebResponse res1 = req1.GetResponse(); - Debug.WriteLine(string.Format("Response from {0}", data.pageName)); - Stream s = res1.GetResponseStream(); - while (s.ReadByte() != -1) - ; - res1.Close(); - if (data.FirstDateToUpdate) - { - firstDt = DateTime.Now; - } - else - { - secondDt = DateTime.Now; - } - } - catch (Exception e) - { - Debug.WriteLine(string.Format("Server error: {0}", e.ToString())); - throw; - } - finally - { - data.signal.Set(); - } - }; - - Thread t = new Thread(ts); - Thread t2 = new Thread(ts); - t.Start(new ThreadRequestData() - { - pageName = "write.aspx", - FirstDateToUpdate = true, - signal = re[0] - }); - t2.Start(new ThreadRequestData() - { - pageName = "read.aspx", - FirstDateToUpdate = false, - signal = re[1] - }); - WaitHandle.WaitAll(re); - re[0].Reset(); - Thread t3 = new Thread(ts); - t3.Start(new ThreadRequestData() - { - pageName = "write2.aspx", - FirstDateToUpdate = false, - signal = re[0] - }); - WaitHandle.WaitAll(re); - double totalMillisecs = Math.Abs((secondDt.Value - firstDt.Value).TotalMilliseconds); - // OK if wait is less than session timeout - Debug.WriteLine(string.Empty); - Debug.WriteLine(totalMillisecs); - Assert.True(totalMillisecs < 30000); - } - finally - { - webserver.Kill(); - } - } - - public volatile static ManualResetEvent mtxReader = null; - public volatile static ManualResetEvent mtxWriter = null; - - public static void WaitSyncCreation(bool writer) - { - if (writer) - { - while (true) - { - if (mtxWriter == null) - Thread.Sleep(100); - else - break; - } - mtxWriter.WaitOne(); - } - else - { - while (true) - { - if (mtxReader == null) - Thread.Sleep(100); - else - break; - } - mtxReader.WaitOne(); - } - } - - - } -} +// Copyright © 2013, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data.MySqlClient; +using MySql.Web.SessionState; +using NUnit.Framework; +using NUnit.Framework.Legacy; +using System; +using System.Collections.Specialized; +using System.Configuration; +using System.Diagnostics; +using System.IO; +using System.Net; +using System.Threading; +using System.Web.SessionState; + +namespace MySql.Web.Tests +{ + public class SessionTests : WebTestBase + { + private string strSessionID { get; set; } + private string calledId { get; set; } + private AutoResetEvent _evt { get; set; } + + private byte[] Serialize(SessionStateItemCollection items) + { + MemoryStream ms = new MemoryStream(); + BinaryWriter writer = new BinaryWriter(ms); + if (items != null) + { + items.Serialize(writer); + } + writer.Close(); + return ms.ToArray(); + } + + + private void CreateSessionData(int AppId, DateTime timeCreated) + { + MySqlCommand cmd = new MySqlCommand(); + strSessionID = System.Guid.NewGuid().ToString(); + + //DateTime now = DateTime.Now; + //DateTime lastHour = now.Subtract(new TimeSpan(1, 0, 0)); + + SessionStateItemCollection collection = new SessionStateItemCollection(); + collection["FirstName"] = "Some"; + collection["LastName"] = "Name"; + byte[] items = Serialize(collection); + + string sql = @"INSERT INTO my_aspnet_sessions VALUES ( + @sessionId, @appId, @created, @expires, @lockdate, @lockid, @timeout, + @locked, @items, @flags)"; + + cmd = new MySqlCommand(sql, Connection); + cmd.Parameters.AddWithValue("@sessionId", strSessionID); + cmd.Parameters.AddWithValue("@appId", AppId); + cmd.Parameters.AddWithValue("@created", timeCreated); + cmd.Parameters.AddWithValue("@expires", timeCreated); + cmd.Parameters.AddWithValue("@lockdate", timeCreated); + cmd.Parameters.AddWithValue("@lockid", 1); + cmd.Parameters.AddWithValue("@timeout", 1); + cmd.Parameters.AddWithValue("@locked", 0); + cmd.Parameters.AddWithValue("@items", items); + cmd.Parameters.AddWithValue("@flags", 0); + cmd.ExecuteNonQuery(); + + //create new row on sessioncleanup table + cmd.CommandText = "INSERT IGNORE INTO my_aspnet_sessioncleanup SET" + + " ApplicationId = @ApplicationId, " + + " LastRun = NOW(), " + + " IntervalMinutes = 10"; + cmd.Parameters.Clear(); + cmd.Parameters.AddWithValue("@ApplicationId", AppId); + cmd.ExecuteNonQuery(); + + // set our last run table to 1 hour ago + cmd.CommandText = "UPDATE my_aspnet_sessioncleanup SET LastRun=@lastHour WHERE ApplicationId = @ApplicationId"; + cmd.Parameters.Clear(); + cmd.Parameters.AddWithValue("@lastHour", DateTime.Now.Subtract(new TimeSpan(1, 0, 0))); + cmd.Parameters.AddWithValue("@ApplicationId", AppId); + cmd.ExecuteNonQuery(); + } + + + private void SetSessionItemExpiredCallback(bool includeCallback) + { + _evt = new AutoResetEvent(false); + calledId = null; + + CreateSessionData(1, DateTime.Now.Subtract(new TimeSpan(1, 0, 0))); + + MySqlSessionStateStore session = new MySqlSessionStateStore(); + + NameValueCollection config = new NameValueCollection(); + config.Add("connectionStringName", "LocalMySqlServer"); + config.Add("applicationName", "/"); + config.Add("enableExpireCallback", includeCallback ? "true" : "false"); + session.Initialize("SessionProvTest", config); + if (includeCallback) session.SetItemExpireCallback(expireCallback); + Thread.Sleep(1000); + session.Dispose(); + } + + private long CountSessions() + { + return (long)MySqlHelper.ExecuteScalar(Connection, "SELECT COUNT(*) FROM my_aspnet_sessions"); + } + + public void expireCallback(string id, SessionStateStoreData item) + { + calledId = id; + _evt.Set(); + } + + + [Test] + public void SessionItemWithExpireCallback() + { + execSQL(@"delete from my_aspnet_sessions; + delete from my_aspnet_sessioncleanup;"); + SetSessionItemExpiredCallback(true); + _evt.WaitOne(); + + Assert.That(calledId, Is.EqualTo(strSessionID)); + + int i = 0; + while (((long)CountSessions() != 0) && (i < 10)) + { + Thread.Sleep(500); + i++; + } + + Assert.That(CountSessions(), Is.EqualTo(0)); + } + + + [Test] + public void SessionItemWithoutExpireCallback() + { + execSQL(@"delete from my_aspnet_sessions; + delete from my_aspnet_sessioncleanup;"); + SetSessionItemExpiredCallback(false); + Assert.That(calledId, Is.Not.EqualTo(strSessionID)); + + int i = 0; + while (((long)MySqlHelper.ExecuteScalar(Connection, "SELECT Count(*) FROM my_aspnet_sessions;") != 0) && (i < 10)) + { + Thread.Sleep(500); + i++; + } + + Assert.That(CountSessions(), Is.EqualTo(0)); + } + + [Test] + public void DeleteSessionAppSpecific() + { + // create two sessions of different appId + // it should delete only 1 + CreateSessionData(1, DateTime.Now.Subtract(new TimeSpan(1, 10, 0))); + CreateSessionData(2, DateTime.Now.Subtract(new TimeSpan(1, 0, 0))); + + MySqlSessionStateStore session = new MySqlSessionStateStore(); + + NameValueCollection config = new NameValueCollection(); + config.Add("connectionStringName", "LocalMySqlServer"); + config.Add("applicationName", "/"); + config.Add("enableExpireCallback", "false"); + session.Initialize("SessionTests", config); + + int i = 0; + while (CountSessions() == 2 && (i < 10)) + { + Thread.Sleep(500); + i++; + } + + session.Dispose(); + Assert.That(CountSessions(), Is.EqualTo(1)); + session.Dispose(); + } + + public class ThreadRequestData + { + public string pageName; + public ManualResetEvent signal; + public bool FirstDateToUpdate; + } + + delegate WebResponse GetResponse(); + delegate void ThreadRequest(ThreadRequestData data); + + [Ignore("Fix Me")] + public void SessionLocking() + { + // Copy updated configuration file for web server process + Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None); + ConnectionStringSettings css = config.ConnectionStrings.ConnectionStrings["LocalMySqlServer"]; + string curDir = Directory.GetCurrentDirectory(); + string webconfigPath = string.Format(@"{0}\SessionLocking\{1}", Directory.GetCurrentDirectory(), @"web.config"); + string webconfigPathSrc = string.Format(@"{0}\SessionLocking\{1}", Directory.GetCurrentDirectory(), @"web_config_src.txt"); + + string text = File.ReadAllText(webconfigPathSrc); + text = text.Replace("connection_string_here", css.ConnectionString); + Version ver = System.Environment.Version; + if (ver.Major != 4) + { + text = text.Replace("", ""); + } + + File.WriteAllText(webconfigPath, text); + + int port = 12224; + + string webserverPath; + if (ver.Major == 4) + { + webserverPath = @"C:\Program Files (x86)\Common Files\microsoft shared\DevServer\10.0\WebDev.WebServer40.exe"; + } + else + { + webserverPath = @"C:\Program Files (x86)\Common Files\microsoft shared\DevServer\9.0\WebDev.WebServer.exe"; + } + string webserverArgs = string.Format(" /port:{0} /path:{1}\\SessionLocking", port, + Path.GetFullPath(@".")); + + DirectoryInfo di = new DirectoryInfo(Path.GetFullPath(curDir)); + Directory.CreateDirectory(Path.GetFullPath(@".\SessionLocking\bin")); + foreach (FileInfo fi in di.GetFiles("*.dll")) + { + File.Copy(fi.FullName, Path.Combine(Path.GetFullPath(@".\SessionLocking\bin\"), fi.Name), true); + } + + Process webserver = Process.Start(webserverPath, webserverArgs); + System.Threading.Thread.Sleep(2000); + + // This dummy request is just to get the ASP.NET sessionid to reuse. + HttpWebRequest req = (HttpWebRequest)WebRequest.Create("http://localhost:12224/InitSessionLocking.aspx"); + HttpWebResponse res = (HttpWebResponse)req.GetResponse(); + WebHeaderCollection headers = new WebHeaderCollection(); + + string url = res.ResponseUri.ToString().Replace("InitSessionLocking.aspx", ""); + Debug.Write(url); + + try + { + DateTime? firstDt = null; + DateTime? secondDt = null; + + ManualResetEvent[] re = new ManualResetEvent[2]; + re[0] = new ManualResetEvent(false); + re[1] = new ManualResetEvent(false); + ParameterizedThreadStart ts = + (object data1) => + { + ThreadRequestData data = (ThreadRequestData)data1; + Debug.WriteLine(string.Format("Requesting {0}", data.pageName)); + try + { + HttpWebRequest req1 = + (HttpWebRequest)WebRequest.Create(string.Format(@"{0}{1}", url, data.pageName)); + req1.Timeout = 2000000; + WebResponse res1 = req1.GetResponse(); + Debug.WriteLine(string.Format("Response from {0}", data.pageName)); + Stream s = res1.GetResponseStream(); + while (s.ReadByte() != -1) + ; + res1.Close(); + if (data.FirstDateToUpdate) + { + firstDt = DateTime.Now; + } + else + { + secondDt = DateTime.Now; + } + } + catch (Exception e) + { + Debug.WriteLine(string.Format("Server error: {0}", e.ToString())); + throw; + } + finally + { + data.signal.Set(); + } + }; + + Thread t = new Thread(ts); + Thread t2 = new Thread(ts); + t.Start(new ThreadRequestData() + { + pageName = "write.aspx", + FirstDateToUpdate = true, + signal = re[0] + }); + t2.Start(new ThreadRequestData() + { + pageName = "read.aspx", + FirstDateToUpdate = false, + signal = re[1] + }); + WaitHandle.WaitAll(re); + re[0].Reset(); + Thread t3 = new Thread(ts); + t3.Start(new ThreadRequestData() + { + pageName = "write2.aspx", + FirstDateToUpdate = false, + signal = re[0] + }); + WaitHandle.WaitAll(re); + double totalMillisecs = Math.Abs((secondDt.Value - firstDt.Value).TotalMilliseconds); + // OK if wait is less than session timeout + Debug.WriteLine(string.Empty); + Debug.WriteLine(totalMillisecs); + Assert.That(totalMillisecs < 30000); + } + finally + { + webserver.Kill(); + } + } + + public volatile static ManualResetEvent mtxReader = null; + public volatile static ManualResetEvent mtxWriter = null; + + public static void WaitSyncCreation(bool writer) + { + if (writer) + { + while (true) + { + if (mtxWriter == null) + Thread.Sleep(100); + else + break; + } + mtxWriter.WaitOne(); + } + else + { + while (true) + { + if (mtxReader == null) + Thread.Sleep(100); + else + break; + } + mtxReader.WaitOne(); + } + } + + + } +} diff --git a/MySql.Web/tests/SimpleMembership.cs b/MySql.Web/tests/SimpleMembership.cs index 4a7caf8f7..da2b09a37 100644 --- a/MySql.Web/tests/SimpleMembership.cs +++ b/MySql.Web/tests/SimpleMembership.cs @@ -1,228 +1,229 @@ -// Copyright (c) 2014, 2021, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data.MySqlClient; -using MySql.Web.Security; -using NUnit.Framework; -using System; -using System.Collections.Specialized; -using System.Web.Security; - -namespace MySql.Web.Tests -{ - public class SimpleMembership : WebTestBase - { - private readonly string _userTable = "UserProfile"; - private readonly string _userIdColumn = "UserId"; - private readonly string _userNameColumn = "UserName"; - private readonly string _userName = "New User"; - private readonly string _pass = "password"; - private MySqlSimpleMembershipProvider _simpleProvider; - private MySqlSimpleRoleProvider _simpleRoleProvider; - - public SimpleMembership() - { - _simpleProvider = new MySqlSimpleMembershipProvider(); - _simpleRoleProvider = new MySqlSimpleRoleProvider(); - - var _config = new NameValueCollection(); - _config.Add("connectionStringName", "LocalMySqlServer"); - _config.Add("userTableName", "UserProfile"); - _config.Add("userIdColumn", "UserId"); - _config.Add("userNameColumn", "UserName"); - - _simpleProvider.Initialize("Test", _config); - _simpleRoleProvider.Initialize("TestRoleProvider", _config); - - MySqlWebSecurity.InitializeDatabaseConnection(ConnectionString, "MySqlSimpleMembership", _userTable, _userIdColumn, _userNameColumn, true, true); - } - - [TearDown] - public void Cleanup() - { - execSQL(@"delete from userprofile; - delete from webpages_membership;"); - } - - [Test] - public void CheckIfRoleNotExists() - { - var roleExists = _simpleRoleProvider.RoleExists("roleName"); - Assert.False(roleExists); - } - - [Test] - public void CheckIfRoleExists() - { - if (!Roles.RoleExists("Administrator")) - { - _simpleRoleProvider.CreateRole("Administrator"); - var roleExists = _simpleRoleProvider.RoleExists("Administrator"); - Assert.True(roleExists); - } - } - - [Test] - public void CreateUserAndAccountTest() - { - MySqlWebSecurity.CreateUserAndAccount(_userName, _pass); - Assert.True(MySqlWebSecurity.UserExists(_userName)); - var user = MySqlHelper.ExecuteDataRow(ConnectionString, string.Format("select * from {0} where {1} = '{2}'", _userTable, _userNameColumn, _userName)); - Assert.IsNotNull(user); - Assert.AreEqual(_userName, user[_userNameColumn]); - - Assert.True(_simpleProvider.ValidateUser(_userName, _pass)); - //We need to mock the login because in that method there is a call to "FormsAuthentication.SetAuthCookie" which causes an "Object reference not set to an instance of an object" exception, because the test doesn't run on web application context - //Assert.True(MySqlWebSecurity.Login(_userName, _pass)); - } - - //We need to mock this test because there is no data on Membership object, there is no user available because login doesn't add it to the context - //[Test] - public void ChangePasswordTest() - { - string newPass = "newpassword"; - MySqlWebSecurity.CreateUserAndAccount(_userName, _pass); - Assert.True(MySqlWebSecurity.UserExists(_userName)); - - //We need to mock the login because in that method there is a call to "FormsAuthentication.SetAuthCookie" which causes an "Object reference not set to an instance of an object" exception, because the test doesn't run on web application context - - Assert.True(_simpleProvider.ValidateUser(_userName, _pass)); - //Assert.True(MySqlWebSecurity.Login(_userName, _pass)); - - Assert.True(MySqlWebSecurity.ChangePassword(_userName, _pass, newPass)); - - Assert.True(_simpleProvider.ValidateUser(_userName, newPass)); - //Assert.True(MySqlWebSecurity.Login(_userName, newPass)); - } - - [Test] - public void ConfirmAccountWithTokenTest() - { - var token = MySqlWebSecurity.CreateUserAndAccount(_userName, _pass, null, true); - Assert.True(MySqlWebSecurity.UserExists(_userName)); - Assert.True(MySqlWebSecurity.ConfirmAccount(token)); - } - - [Test] - public void ConfirmAccountWithUserAndTokenTest() - { - var token = MySqlWebSecurity.CreateUserAndAccount(_userName, _pass, null, true); - Assert.True(MySqlWebSecurity.UserExists(_userName)); - Assert.True(MySqlWebSecurity.ConfirmAccount(_userName, token)); - } - - [Test] - public void ConfirmAccountWithoutTokenTest() - { - var token = "falsetoken"; - MySqlWebSecurity.CreateUserAndAccount(_userName, _pass); - Assert.True(MySqlWebSecurity.UserExists(_userName)); - Assert.False(MySqlWebSecurity.ConfirmAccount(token)); - } - - [Test] - public void CreatedDateTest() - { - execSQL(@"delete from userprofile; - delete from webpages_membership;"); - MySqlWebSecurity.CreateUserAndAccount(_userName, _pass); - Assert.AreNotEqual(DateTime.MinValue, MySqlWebSecurity.GetCreateDate(_userName)); - } - - [Test] - public void DeleteTest() - { - _simpleProvider.CreateUserAndAccount(_userName, _pass, false, null); - Assert.True(_simpleProvider.DeleteAccount(_userName)); - _simpleProvider.CreateAccount(_userName, _pass, false); - Assert.True(_simpleProvider.DeleteUser(_userName, true)); - } - - [Test] - public void UserIsConfirmedTest() - { - MySqlWebSecurity.CreateUserAndAccount(_userName, _pass, null, true); - Assert.False(MySqlWebSecurity.IsConfirmed(_userName)); - } - - [Test] - public void UserIsLockedOutTest() - { - MySqlWebSecurity.CreateUserAndAccount(_userName, _pass, null, true); - Assert.False(MySqlWebSecurity.IsAccountLockedOut(_userName, 5, 60)); - } - - [Test] - public void PasswordTest() - { - MySqlWebSecurity.CreateUserAndAccount(_userName, _pass); - Assert.AreEqual(DateTime.MinValue, MySqlWebSecurity.GetLastPasswordFailureDate(_userName)); - Assert.AreNotEqual(DateTime.MinValue, MySqlWebSecurity.GetPasswordChangedDate(_userName)); - Assert.AreEqual(0, MySqlWebSecurity.GetPasswordFailuresSinceLastSuccess(_userName)); - } - - //Password reset token must be assigned to the user but that field is not added in any part of the code, so maybe that field must be handled manually by the user - // should we handle this functionality? WebMatrix.WebData.SimpleMembershipProvider doesn't handle it - [Ignore("Fix Me")] - public void PasswordResetTokenTest() - { - var token = MySqlWebSecurity.CreateUserAndAccount(_userName, _pass, null, true); - int userID = MySqlWebSecurity.GetUserId(_userName); - Assert.True(MySqlWebSecurity.ConfirmAccount(token)); - var newToken = MySqlWebSecurity.GeneratePasswordResetToken(_userName, 1440); - Assert.AreNotEqual(null, newToken); - Assert.AreEqual(MySqlWebSecurity.GetUserIdFromPasswordResetToken(newToken), userID); - } - - #region WL14389 - [TestCase(1, "Waren", null)] - [TestCase(2, "Bill", false)] - [TestCase(3, "Steve", true)] - public void CreateUserAccountWithAttributes(int id, string userN, bool? token) - { - //Bug25046364 - switch (token) - { - case null: - MySqlWebSecurity.CreateUserAndAccount(userN, _pass, new {UserId = id, UserName = userN}); - break; - - default: - MySqlWebSecurity.CreateUserAndAccount(userN, _pass, new { UserId = id, UserName = userN }, (bool)token); - break; - } - - Assert.True(MySqlWebSecurity.UserExists(userN)); - var user = MySqlHelper.ExecuteDataRow(ConnectionString, string.Format("select * from {0} where {1} = '{2}'", _userTable, _userNameColumn, userN)); - Assert.IsNotNull(user); - Assert.AreEqual(userN, user[_userNameColumn]); - } - #endregion - - } -} +// Copyright © 2014, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data.MySqlClient; +using MySql.Web.Security; +using NUnit.Framework; +using NUnit.Framework.Legacy; +using System; +using System.Collections.Specialized; +using System.Web.Security; + +namespace MySql.Web.Tests +{ + public class SimpleMembership : WebTestBase + { + private readonly string _userTable = "UserProfile"; + private readonly string _userIdColumn = "UserId"; + private readonly string _userNameColumn = "UserName"; + private readonly string _userName = "New User"; + private readonly string _pass = "password"; + private MySqlSimpleMembershipProvider _simpleProvider; + private MySqlSimpleRoleProvider _simpleRoleProvider; + + public SimpleMembership() + { + _simpleProvider = new MySqlSimpleMembershipProvider(); + _simpleRoleProvider = new MySqlSimpleRoleProvider(); + + var _config = new NameValueCollection(); + _config.Add("connectionStringName", "LocalMySqlServer"); + _config.Add("userTableName", "UserProfile"); + _config.Add("userIdColumn", "UserId"); + _config.Add("userNameColumn", "UserName"); + + _simpleProvider.Initialize("Test", _config); + _simpleRoleProvider.Initialize("TestRoleProvider", _config); + + MySqlWebSecurity.InitializeDatabaseConnection(ConnectionString, "MySqlSimpleMembership", _userTable, _userIdColumn, _userNameColumn, true, true); + } + + [TearDown] + public void Cleanup() + { + execSQL(@"delete from userprofile; + delete from webpages_membership;"); + } + + [Test] + public void CheckIfRoleNotExists() + { + var roleExists = _simpleRoleProvider.RoleExists("roleName"); + Assert.That(!roleExists); + } + + [Test] + public void CheckIfRoleExists() + { + if (!Roles.RoleExists("Administrator")) + { + _simpleRoleProvider.CreateRole("Administrator"); + var roleExists = _simpleRoleProvider.RoleExists("Administrator"); + Assert.That(roleExists); + } + } + + [Test] + public void CreateUserAndAccountTest() + { + MySqlWebSecurity.CreateUserAndAccount(_userName, _pass); + Assert.That(MySqlWebSecurity.UserExists(_userName)); + var user = MySqlHelper.ExecuteDataRow(ConnectionString, string.Format("select * from {0} where {1} = '{2}'", _userTable, _userNameColumn, _userName)); + Assert.That(user, Is.Not.Null); + Assert.That(user[_userNameColumn], Is.EqualTo(_userName)); + + Assert.That(_simpleProvider.ValidateUser(_userName, _pass)); + //We need to mock the login because in that method there is a call to "FormsAuthentication.SetAuthCookie" which causes an "Object reference not set to an instance of an object" exception, because the test doesn't run on web application context + //Assert.True(MySqlWebSecurity.Login(_userName, _pass)); + } + + //We need to mock this test because there is no data on Membership object, there is no user available because login doesn't add it to the context + //[Test] + public void ChangePasswordTest() + { + string newPass = "newpassword"; + MySqlWebSecurity.CreateUserAndAccount(_userName, _pass); + Assert.That(MySqlWebSecurity.UserExists(_userName)); + + //We need to mock the login because in that method there is a call to "FormsAuthentication.SetAuthCookie" which causes an "Object reference not set to an instance of an object" exception, because the test doesn't run on web application context + + Assert.That(_simpleProvider.ValidateUser(_userName, _pass)); + //Assert.True(MySqlWebSecurity.Login(_userName, _pass)); + + Assert.That(MySqlWebSecurity.ChangePassword(_userName, _pass, newPass)); + + Assert.That(_simpleProvider.ValidateUser(_userName, newPass)); + //Assert.True(MySqlWebSecurity.Login(_userName, newPass)); + } + + [Test] + public void ConfirmAccountWithTokenTest() + { + var token = MySqlWebSecurity.CreateUserAndAccount(_userName, _pass, null, true); + Assert.That(MySqlWebSecurity.UserExists(_userName)); + Assert.That(MySqlWebSecurity.ConfirmAccount(token)); + } + + [Test] + public void ConfirmAccountWithUserAndTokenTest() + { + var token = MySqlWebSecurity.CreateUserAndAccount(_userName, _pass, null, true); + Assert.That(MySqlWebSecurity.UserExists(_userName)); + Assert.That(MySqlWebSecurity.ConfirmAccount(_userName, token)); + } + + [Test] + public void ConfirmAccountWithoutTokenTest() + { + var token = "falsetoken"; + MySqlWebSecurity.CreateUserAndAccount(_userName, _pass); + Assert.That(MySqlWebSecurity.UserExists(_userName)); + Assert.That(!MySqlWebSecurity.ConfirmAccount(token)); + } + + [Test] + public void CreatedDateTest() + { + execSQL(@"delete from userprofile; + delete from webpages_membership;"); + MySqlWebSecurity.CreateUserAndAccount(_userName, _pass); + Assert.That(MySqlWebSecurity.GetCreateDate(_userName), Is.Not.EqualTo(DateTime.MinValue)); + } + + [Test] + public void DeleteTest() + { + _simpleProvider.CreateUserAndAccount(_userName, _pass, false, null); + Assert.That(_simpleProvider.DeleteAccount(_userName)); + _simpleProvider.CreateAccount(_userName, _pass, false); + Assert.That(_simpleProvider.DeleteUser(_userName, true)); + } + + [Test] + public void UserIsConfirmedTest() + { + MySqlWebSecurity.CreateUserAndAccount(_userName, _pass, null, true); + Assert.That(!MySqlWebSecurity.IsConfirmed(_userName)); + } + + [Test] + public void UserIsLockedOutTest() + { + MySqlWebSecurity.CreateUserAndAccount(_userName, _pass, null, true); + Assert.That(!MySqlWebSecurity.IsAccountLockedOut(_userName, 5, 60)); + } + + [Test] + public void PasswordTest() + { + MySqlWebSecurity.CreateUserAndAccount(_userName, _pass); + Assert.That(MySqlWebSecurity.GetLastPasswordFailureDate(_userName), Is.EqualTo(DateTime.MinValue)); + Assert.That(MySqlWebSecurity.GetPasswordChangedDate(_userName), Is.Not.EqualTo(DateTime.MinValue)); + Assert.That(MySqlWebSecurity.GetPasswordFailuresSinceLastSuccess(_userName), Is.EqualTo(0)); + } + + //Password reset token must be assigned to the user but that field is not added in any part of the code, so maybe that field must be handled manually by the user + // should we handle this functionality? WebMatrix.WebData.SimpleMembershipProvider doesn't handle it + [Ignore("Fix Me")] + public void PasswordResetTokenTest() + { + var token = MySqlWebSecurity.CreateUserAndAccount(_userName, _pass, null, true); + int userID = MySqlWebSecurity.GetUserId(_userName); + Assert.That(MySqlWebSecurity.ConfirmAccount(token)); + var newToken = MySqlWebSecurity.GeneratePasswordResetToken(_userName, 1440); + Assert.That(newToken, Is.Not.EqualTo(null)); + Assert.That(userID, Is.EqualTo(MySqlWebSecurity.GetUserIdFromPasswordResetToken(newToken))); + } + + #region WL14389 + [TestCase(1, "Waren", null)] + [TestCase(2, "Bill", false)] + [TestCase(3, "Steve", true)] + public void CreateUserAccountWithAttributes(int id, string userN, bool? token) + { + //Bug25046364 + switch (token) + { + case null: + MySqlWebSecurity.CreateUserAndAccount(userN, _pass, new {UserId = id, UserName = userN}); + break; + + default: + MySqlWebSecurity.CreateUserAndAccount(userN, _pass, new { UserId = id, UserName = userN }, (bool)token); + break; + } + + Assert.That(MySqlWebSecurity.UserExists(userN)); + var user = MySqlHelper.ExecuteDataRow(ConnectionString, string.Format("select * from {0} where {1} = '{2}'", _userTable, _userNameColumn, userN)); + Assert.That(user, Is.Not.Null); + Assert.That(user[_userNameColumn], Is.EqualTo(userN)); + } + #endregion + + } +} diff --git a/MySql.Web/tests/SiteMapTests.cs b/MySql.Web/tests/SiteMapTests.cs index 9946dd271..1cde4f895 100644 --- a/MySql.Web/tests/SiteMapTests.cs +++ b/MySql.Web/tests/SiteMapTests.cs @@ -1,118 +1,119 @@ -// Copyright (c) 2014, 2020, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data.MySqlClient; -using MySql.Web.SiteMap; -using NUnit.Framework; -using System; -using System.Collections.Specialized; -using System.IO; -using System.Web; -using System.Web.Hosting; - -namespace MySql.Web.Tests -{ - public class SiteMapTests : WebTestBase - { - private void PopulateSiteMapTable() - { - string sql = @" - insert into my_aspnet_sitemap( Id, Title, Description, Url, Roles, ParentId ) values ( 1, 'Index', 'The Index page', '~/Index.aspx', null, null ); - insert into my_aspnet_sitemap( Id, Title, Description, Url, Roles, ParentId ) values ( 2, 'Chess Openings', 'Collection of Chess openings articles', '~/Openings.aspx', null, 1 ); - insert into my_aspnet_sitemap( Id, Title, Description, Url, Roles, ParentId ) values ( 3, 'King''s Gambit', 'The hyper sharp King''s Gambit', '~/Openings/KingsGambit.aspx', null, 2 ); - insert into my_aspnet_sitemap( Id, Title, Description, Url, Roles, ParentId ) values ( 4, 'Ruy Lopez', 'The spanish opening', '~/RuyLopez.aspx', null, 2 ); - insert into my_aspnet_sitemap( Id, Title, Description, Url, Roles, ParentId ) values ( 5, 'Evan''s Gambit', 'The Funny Italian Game', '~/EvansGambit.aspx', null, 2 ); - insert into my_aspnet_sitemap( Id, Title, Description, Url, Roles, ParentId ) values ( 6, 'Sicilian Defense', 'Sharp Double Edge Defense', '~/Sicilian.aspx', null, 2 ); - insert into my_aspnet_sitemap( Id, Title, Description, Url, Roles, ParentId ) values ( 7, 'Middle Game', 'Middle Game Topics', '~/MiddleGame.aspx', null, 1 ); - insert into my_aspnet_sitemap( Id, Title, Description, Url, Roles, ParentId ) values ( 8, 'Isolated Queen Pawn', 'Isolani Typical Positions', '~/Isolani.aspx', null, 7 ); - insert into my_aspnet_sitemap( Id, Title, Description, Url, Roles, ParentId ) values ( 9, 'Rook vs Two Minor pieces', 'Rook vs Two Minor Pieces', '~/RookVsTwoMinor.aspx', null, 7 ); - insert into my_aspnet_sitemap( Id, Title, Description, Url, Roles, ParentID ) values (10, 'Exchange Sacrifice', 'Sacrifice of Rook per Bishop or Knight', '~/ExchangeSacrifice.aspx', null, 7 ); - insert into my_aspnet_sitemap( Id, Title, Description, Url, Roles, ParentID ) values (11, 'Nd5 Sacrifice in Sicilian', 'Sacrifice Nc3-Nd5 against Schevening like structures', '~/Nd5SacSicilian.aspx', null, 7 ); - insert into my_aspnet_sitemap( Id, Title, Description, Url, Roles, ParentID ) values (12, 'Endings', 'Theory of chess endings & practical endings', '~/Endings.aspx', null, 1 ); - insert into my_aspnet_sitemap( Id, Title, Description, Url, Roles, ParentID ) values (13, 'Rook Endings', 'Rook Endings', '~/RookEndigs.aspx', null, 12 ); - insert into my_aspnet_sitemap( Id, Title, Description, Url, Roles, ParentID ) values (14, 'Queen vs Rook', 'Queen vs Rook, pawnless endings', '~/QueenVsRook.aspx ', null, 12 ); - insert into my_aspnet_sitemap( Id, Title, Description, Url, Roles, ParentID ) values (15, 'Isolated Queen Pawn Ending', 'Endings with queen pawn isolated', '~/IQPending.aspx', null, 12 ); - "; - MySqlScript script = new MySqlScript(Connection, sql); - script.Execute(); - } - - [Test] - public void TestBuildSiteMap() - { - PopulateSiteMapTable(); - - MySqlSiteMapProvider prov = new MySqlSiteMapProvider(); - NameValueCollection config = new NameValueCollection(); - config.Add("connectionStringName", "LocalMySqlServer"); - config.Add("applicationName", "/"); - config.Add("enableExpireCallback", "false"); - - prov.Initialize("SiteMapTests", config); - prov.BuildSiteMap(); - SiteMapNode node = prov.FindSiteMapNodeFromKey("5"); - SimpleWorkerRequest req = new SimpleWorkerRequest("/dummy", Environment.CurrentDirectory, "default.aspx", null, new StringWriter()); - HttpContext.Current = new HttpContext(req); - - Assert.AreEqual(node.Title, "Evan's Gambit"); - SiteMapNode nodep = prov.GetParentNode(node); - Assert.AreEqual(node.Description, "The Funny Italian Game"); - Assert.False(node.HasChildNodes); - SiteMapNode node2 = node.NextSibling; - Assert.IsNotNull(node2); - Assert.AreEqual(node2.Title, "Sicilian Defense"); - Assert.AreEqual(node2.Description, "Sharp Double Edge Defense"); - - node = node.PreviousSibling; - Assert.IsNotNull(node); - Assert.AreEqual(node.Title, "Ruy Lopez"); - Assert.AreEqual(node.Description, "The spanish opening"); - Assert.False(node.HasChildNodes); - Assert.IsNotNull(node.NextSibling); - - node = node.ParentNode; - Assert.AreEqual(node.Title, "Chess Openings"); - - node = node.ParentNode; - Assert.AreEqual(node.Title, "Index"); - - node = node.ParentNode; - Assert.IsNull(node); - - node = prov.RootNode; - Assert.AreEqual(node.Title, "Index"); - string[] childData = new string[] { "Chess Openings", "Middle Game", "Endings" }; - - for (int i = 0; i < node.ChildNodes.Count; i++) - { - SiteMapNode child = node.ChildNodes[i]; - Assert.AreEqual(child.Title, childData[i]); - } - } - } -} +// Copyright © 2014, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data.MySqlClient; +using MySql.Web.SiteMap; +using NUnit.Framework; +using NUnit.Framework.Legacy; +using System; +using System.Collections.Specialized; +using System.IO; +using System.Web; +using System.Web.Hosting; + +namespace MySql.Web.Tests +{ + public class SiteMapTests : WebTestBase + { + private void PopulateSiteMapTable() + { + string sql = @" + insert into my_aspnet_sitemap( Id, Title, Description, Url, Roles, ParentId ) values ( 1, 'Index', 'The Index page', '~/Index.aspx', null, null ); + insert into my_aspnet_sitemap( Id, Title, Description, Url, Roles, ParentId ) values ( 2, 'Chess Openings', 'Collection of Chess openings articles', '~/Openings.aspx', null, 1 ); + insert into my_aspnet_sitemap( Id, Title, Description, Url, Roles, ParentId ) values ( 3, 'King''s Gambit', 'The hyper sharp King''s Gambit', '~/Openings/KingsGambit.aspx', null, 2 ); + insert into my_aspnet_sitemap( Id, Title, Description, Url, Roles, ParentId ) values ( 4, 'Ruy Lopez', 'The spanish opening', '~/RuyLopez.aspx', null, 2 ); + insert into my_aspnet_sitemap( Id, Title, Description, Url, Roles, ParentId ) values ( 5, 'Evan''s Gambit', 'The Funny Italian Game', '~/EvansGambit.aspx', null, 2 ); + insert into my_aspnet_sitemap( Id, Title, Description, Url, Roles, ParentId ) values ( 6, 'Sicilian Defense', 'Sharp Double Edge Defense', '~/Sicilian.aspx', null, 2 ); + insert into my_aspnet_sitemap( Id, Title, Description, Url, Roles, ParentId ) values ( 7, 'Middle Game', 'Middle Game Topics', '~/MiddleGame.aspx', null, 1 ); + insert into my_aspnet_sitemap( Id, Title, Description, Url, Roles, ParentId ) values ( 8, 'Isolated Queen Pawn', 'Isolani Typical Positions', '~/Isolani.aspx', null, 7 ); + insert into my_aspnet_sitemap( Id, Title, Description, Url, Roles, ParentId ) values ( 9, 'Rook vs Two Minor pieces', 'Rook vs Two Minor Pieces', '~/RookVsTwoMinor.aspx', null, 7 ); + insert into my_aspnet_sitemap( Id, Title, Description, Url, Roles, ParentID ) values (10, 'Exchange Sacrifice', 'Sacrifice of Rook per Bishop or Knight', '~/ExchangeSacrifice.aspx', null, 7 ); + insert into my_aspnet_sitemap( Id, Title, Description, Url, Roles, ParentID ) values (11, 'Nd5 Sacrifice in Sicilian', 'Sacrifice Nc3-Nd5 against Schevening like structures', '~/Nd5SacSicilian.aspx', null, 7 ); + insert into my_aspnet_sitemap( Id, Title, Description, Url, Roles, ParentID ) values (12, 'Endings', 'Theory of chess endings & practical endings', '~/Endings.aspx', null, 1 ); + insert into my_aspnet_sitemap( Id, Title, Description, Url, Roles, ParentID ) values (13, 'Rook Endings', 'Rook Endings', '~/RookEndigs.aspx', null, 12 ); + insert into my_aspnet_sitemap( Id, Title, Description, Url, Roles, ParentID ) values (14, 'Queen vs Rook', 'Queen vs Rook, pawnless endings', '~/QueenVsRook.aspx ', null, 12 ); + insert into my_aspnet_sitemap( Id, Title, Description, Url, Roles, ParentID ) values (15, 'Isolated Queen Pawn Ending', 'Endings with queen pawn isolated', '~/IQPending.aspx', null, 12 ); + "; + MySqlScript script = new MySqlScript(Connection, sql); + script.Execute(); + } + + [Test] + public void TestBuildSiteMap() + { + PopulateSiteMapTable(); + + MySqlSiteMapProvider prov = new MySqlSiteMapProvider(); + NameValueCollection config = new NameValueCollection(); + config.Add("connectionStringName", "LocalMySqlServer"); + config.Add("applicationName", "/"); + config.Add("enableExpireCallback", "false"); + + prov.Initialize("SiteMapTests", config); + prov.BuildSiteMap(); + SiteMapNode node = prov.FindSiteMapNodeFromKey("5"); + SimpleWorkerRequest req = new SimpleWorkerRequest("/dummy", Environment.CurrentDirectory, "default.aspx", null, new StringWriter()); + HttpContext.Current = new HttpContext(req); + + Assert.That("Evan's Gambit", Is.EqualTo(node.Title)); + SiteMapNode nodep = prov.GetParentNode(node); + Assert.That("The Funny Italian Game", Is.EqualTo(node.Description)); + Assert.That(!node.HasChildNodes); + SiteMapNode node2 = node.NextSibling; + Assert.That(node2, Is.Not.Null); + Assert.That("Sicilian Defense", Is.EqualTo(node2.Title)); + Assert.That("Sharp Double Edge Defense", Is.EqualTo(node2.Description)); + + node = node.PreviousSibling; + Assert.That(node, Is.Not.Null); + Assert.That("Ruy Lopez", Is.EqualTo(node.Title)); + Assert.That("The spanish opening", Is.EqualTo(node.Description)); + Assert.That(!node.HasChildNodes); + Assert.That(node.NextSibling, Is.Not.Null); + + node = node.ParentNode; + Assert.That("Chess Openings", Is.EqualTo(node.Title)); + + node = node.ParentNode; + Assert.That("Index", Is.EqualTo(node.Title)); + + node = node.ParentNode; + Assert.That(node, Is.Null); + + node = prov.RootNode; + Assert.That("Index", Is.EqualTo(node.Title)); + string[] childData = new string[] { "Chess Openings", "Middle Game", "Endings" }; + + for (int i = 0; i < node.ChildNodes.Count; i++) + { + SiteMapNode child = node.ChildNodes[i]; + Assert.That(childData[i], Is.EqualTo(child.Title)); + } + } + } +} diff --git a/MySql.Web/tests/TestProfile.cs b/MySql.Web/tests/TestProfile.cs index 54b8bfafb..92a352b2b 100644 --- a/MySql.Web/tests/TestProfile.cs +++ b/MySql.Web/tests/TestProfile.cs @@ -1,67 +1,67 @@ -// Copyright (c) 2013, 2020, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using System.Web.Profile; -using System.Web.Security; - -namespace MySql.Web.Tests -{ - public class TestProfile : ProfileBase - { - public static TestProfile GetUserProfile(string username, bool auth) - { - return Create(username, auth) as TestProfile; - } - - public static TestProfile GetUserProfile(bool auth) - { - return Create(Membership.GetUser().UserName, auth) as TestProfile; - } - - [SettingsAllowAnonymous(false)] - public string Description - { - get { return base["Description"] as string; } - set { base["Description"] = value; } - } - - [SettingsAllowAnonymous(false)] - public string Location - { - get { return base["Location"] as string; } - set { base["Location"] = value; } - } - - [SettingsAllowAnonymous(false)] - public string FavoriteMovie - { - get { return base["FavoriteMovie"] as string; } - set { base["FavoriteMovie"] = value; } - } - } -} +// Copyright © 2013, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using System.Web.Profile; +using System.Web.Security; + +namespace MySql.Web.Tests +{ + public class TestProfile : ProfileBase + { + public static TestProfile GetUserProfile(string username, bool auth) + { + return Create(username, auth) as TestProfile; + } + + public static TestProfile GetUserProfile(bool auth) + { + return Create(Membership.GetUser().UserName, auth) as TestProfile; + } + + [SettingsAllowAnonymous(false)] + public string Description + { + get { return base["Description"] as string; } + set { base["Description"] = value; } + } + + [SettingsAllowAnonymous(false)] + public string Location + { + get { return base["Location"] as string; } + set { base["Location"] = value; } + } + + [SettingsAllowAnonymous(false)] + public string FavoriteMovie + { + get { return base["FavoriteMovie"] as string; } + set { base["FavoriteMovie"] = value; } + } + } +} diff --git a/MySql.Web/tests/UserManagement.cs b/MySql.Web/tests/UserManagement.cs index df82bfab5..cd79da523 100644 --- a/MySql.Web/tests/UserManagement.cs +++ b/MySql.Web/tests/UserManagement.cs @@ -1,825 +1,826 @@ -// Copyright (c) 2013, 2020, Oracle and/or its affiliates. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License, version 2.0, as -// published by the Free Software Foundation. -// -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. -// -// Without limiting anything contained in the foregoing, this file, -// which is part of MySQL Connector/NET, is also subject to the -// Universal FOSS Exception, version 1.0, a copy of which can be found at -// http://oss.oracle.com/licenses/universal-foss-exception. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License, version 2.0, for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -using MySql.Data.MySqlClient; -using MySql.Web.Security; -using NUnit.Framework; -using System; -using System.Collections.Specialized; -using System.Configuration.Provider; -using System.Data; -using System.Web.Security; - -namespace MySql.Web.Tests -{ - public class UserManagement : WebTestBase - { - private MySQLMembershipProvider provider { get; set; } - - private void CreateUserWithFormat(MembershipPasswordFormat format) - { - provider = new MySQLMembershipProvider(); - NameValueCollection config = new NameValueCollection(); - config.Add("connectionStringName", "LocalMySqlServer"); - config.Add("applicationName", "/"); - config.Add("passwordStrengthRegularExpression", "bar.*"); - config.Add("passwordFormat", format.ToString()); - provider.Initialize(null, config); - - // create the user - MembershipCreateStatus status; - provider.CreateUser("foo", "barbar!", "foo@bar.com", null, null, true, null, out status); - Assert.AreEqual(MembershipCreateStatus.Success, status); - - // verify that the password format is hashed. - DataTable table = FillTable("SELECT * FROM my_aspnet_membership"); - MembershipPasswordFormat rowFormat = - (MembershipPasswordFormat)Convert.ToInt32(table.Rows[0]["PasswordFormat"]); - Assert.AreEqual(format, rowFormat); - - // then attempt to verify the user - Assert.True(provider.ValidateUser("foo", "barbar!")); - - } - - [Test] - public void CreateUserWithHashedPassword() - { - CreateUserWithFormat(MembershipPasswordFormat.Hashed); - //Cleanup - provider.DeleteUser("foo", true); - } - - [Test] - public void CreateUserWithEncryptedPasswordWithAutoGenKeys() - { - //TODO check this test logic - try - { - CreateUserWithFormat(MembershipPasswordFormat.Encrypted); - } - catch (ProviderException) - { - } - //Cleanup - provider.DeleteUser("foo", true); - } - - [Test] - public void CreateUserWithClearPassword() - { - CreateUserWithFormat(MembershipPasswordFormat.Clear); - //Cleanup - provider.DeleteUser("foo", true); - } - - /// - /// Bug #34792 New User/Changing Password Validation Not working. - /// - [Test] - public void ChangePassword() - { - CreateUserWithFormat(MembershipPasswordFormat.Hashed); - ArgumentException ex = Assert.Throws(() => provider.ChangePassword("foo", "barbar!", "bar2")); - - Assert.AreEqual("newPassword", ex.ParamName); - Assert.True(ex.Message.Contains("length of parameter")); - ArgumentException ex1 = Assert.Throws(() => provider.ChangePassword("foo", "barbar!", "barbar2")); - Assert.AreEqual("newPassword", ex1.ParamName); - Assert.True(ex1.Message.Contains("alpha numeric")); - - // now test regex strength testing - bool result = provider.ChangePassword("foo", "barbar!", "zzzxxx!"); - Assert.False(result); - - // now do one that should work - result = provider.ChangePassword("foo", "barbar!", "barfoo!"); - Assert.True(result); - - provider.ValidateUser("foo", "barfoo!"); - - //Cleanup - provider.DeleteUser("foo", true); - } - - /// - /// Bug #34792 New User/Changing Password Validation Not working. - /// - [Test] - public void CreateUserWithErrors() - { - provider = new MySQLMembershipProvider(); - NameValueCollection config = new NameValueCollection(); - config.Add("connectionStringName", "LocalMySqlServer"); - config.Add("applicationName", "/"); - config.Add("passwordStrengthRegularExpression", "bar.*"); - config.Add("passwordFormat", "Hashed"); - provider.Initialize(null, config); - - // first try to create a user with a password not long enough - MembershipCreateStatus status; - MembershipUser user = provider.CreateUser("foo", "xyz", - "foo@bar.com", null, null, true, null, out status); - Assert.IsNull(user); - Assert.AreEqual(MembershipCreateStatus.InvalidPassword, status); - - // now with not enough non-alphas - user = provider.CreateUser("foo", "xyz1234", - "foo@bar.com", null, null, true, null, out status); - Assert.IsNull(user); - Assert.AreEqual(MembershipCreateStatus.InvalidPassword, status); - - // now one that doesn't pass the regex test - user = provider.CreateUser("foo", "xyzxyz!", - "foo@bar.com", null, null, true, null, out status); - Assert.IsNull(user); - Assert.AreEqual(MembershipCreateStatus.InvalidPassword, status); - - // now one that works - user = provider.CreateUser("foo", "barbar!", - "foo@bar.com", null, null, true, null, out status); - Assert.IsNotNull(user); - Assert.AreEqual(MembershipCreateStatus.Success, status); - - //Cleanup - provider.DeleteUser("foo", true); - - } - - [Test] - public void DeleteUser() - { - execSQL(@"delete from my_aspnet_membership; - delete from my_aspnet_users;"); - CreateUserWithFormat(MembershipPasswordFormat.Hashed); - Assert.True(provider.DeleteUser("foo", true)); - DataTable table = FillTable("SELECT * FROM my_aspnet_membership"); - Assert.AreEqual(0, table.Rows.Count); - table = FillTable("SELECT * FROM my_aspnet_users"); - Assert.AreEqual(0, table.Rows.Count); - - CreateUserWithFormat(MembershipPasswordFormat.Hashed); - provider = new MySQLMembershipProvider(); - NameValueCollection config = new NameValueCollection(); - config.Add("connectionStringName", "LocalMySqlServer"); - config.Add("applicationName", "/"); - provider.Initialize(null, config); - Assert.True(Membership.DeleteUser("foo", false)); - table = FillTable("SELECT * FROM my_aspnet_membership"); - Assert.AreEqual(0, table.Rows.Count); - table = FillTable("SELECT * FROM my_aspnet_users"); - Assert.AreEqual(1, table.Rows.Count); - } - - [Test] - public void FindUsersByName() - { - CreateUserWithFormat(MembershipPasswordFormat.Hashed); - int records; - MembershipUserCollection users = provider.FindUsersByName("F%", 0, 10, out records); - Assert.AreEqual(1, records); - Assert.AreEqual("foo", users["foo"].UserName); - - //Cleanup - provider.DeleteUser("foo", true); - } - - [Test] - public void FindUsersByEmail() - { - CreateUserWithFormat(MembershipPasswordFormat.Hashed); - - int records; - MembershipUserCollection users = provider.FindUsersByEmail("foo@bar.com", 0, 10, out records); - Assert.AreEqual(1, records); - Assert.AreEqual("foo", users["foo"].UserName); - - //Cleanup - provider.DeleteUser("foo", true); - } - - [Test] - public void TestCreateUserOverrides() - { - try - { - MembershipCreateStatus status; - Membership.CreateUser("foo", "barbar!", null, "question", "answer", true, out status); - int records; - MembershipUserCollection users = Membership.FindUsersByName("F%", 0, 10, out records); - Assert.AreEqual(1, records); - Assert.AreEqual("foo", users["foo"].UserName); - - Membership.CreateUser("test", "barbar!", "myemail@host.com", - "question", "answer", true, out status); - users = Membership.FindUsersByName("T%", 0, 10, out records); - Assert.AreEqual(1, records); - Assert.AreEqual("test", users["test"].UserName); - } - catch (Exception ex) - { - Assert.True(ex.Message != String.Empty, ex.Message); - } - - //Cleanup - Membership.DeleteUser("test", true); - Membership.DeleteUser("foo", true); - } - - [Test] - public void NumberOfUsersOnline() - { - int numOnline = Membership.GetNumberOfUsersOnline(); - Assert.AreEqual(0, numOnline); - - MembershipCreateStatus status; - Membership.CreateUser("foo", "barbar!", null, "question", "answer", true, out status); - Membership.CreateUser("foo2", "barbar!", null, "question", "answer", true, out status); - - numOnline = Membership.GetNumberOfUsersOnline(); - Assert.AreEqual(2, numOnline); - - //Cleanup - Membership.DeleteUser("foo"); - Membership.DeleteUser("foo2"); - } - - [Test] - public void UnlockUser() - { - MembershipCreateStatus status; - Membership.CreateUser("foo", "barbar!", null, "question", "answer", true, out status); - Assert.False(Membership.ValidateUser("foo", "bar2")); - Assert.False(Membership.ValidateUser("foo", "bar3")); - Assert.False(Membership.ValidateUser("foo", "bar3")); - Assert.False(Membership.ValidateUser("foo", "bar3")); - Assert.False(Membership.ValidateUser("foo", "bar3")); - - // the user should be locked now so the right password should fail - Assert.False(Membership.ValidateUser("foo", "barbar!")); - - MembershipUser user = Membership.GetUser("foo"); - Assert.True(user.IsLockedOut); - - Assert.True(user.UnlockUser()); - user = Membership.GetUser("foo"); - Assert.False(user.IsLockedOut); - - Assert.True(Membership.ValidateUser("foo", "barbar!")); - - //Cleanup - Membership.DeleteUser("foo"); - } - - [Test] - public void GetUsernameByEmail() - { - MembershipCreateStatus status; - Membership.CreateUser("foo", "barbar!", "foo@bar.com", "question", "answer", true, out status); - string username = Membership.GetUserNameByEmail("foo@bar.com"); - Assert.AreEqual("foo", username); - - username = Membership.GetUserNameByEmail("foo@b.com"); - Assert.IsNull(username); - - username = Membership.GetUserNameByEmail(" foo@bar.com "); - Assert.AreEqual("foo", username); - - //Cleanup - Membership.DeleteUser("foo"); - } - - [Test] - public void UpdateUser() - { - MembershipCreateStatus status; - Membership.CreateUser("foo", "barbar!", "foo@bar.com", "color", "blue", true, out status); - Assert.AreEqual(MembershipCreateStatus.Success, status); - - MembershipUser user = Membership.GetUser("foo"); - - user.Comment = "my comment"; - user.Email = "my email"; - user.IsApproved = false; - user.LastActivityDate = new DateTime(2008, 1, 1); - user.LastLoginDate = new DateTime(2008, 2, 1); - Membership.UpdateUser(user); - - MembershipUser newUser = Membership.GetUser("foo"); - Assert.AreEqual(user.Comment, newUser.Comment); - Assert.AreEqual(user.Email, newUser.Email); - Assert.AreEqual(user.IsApproved, newUser.IsApproved); - Assert.AreEqual(user.LastActivityDate, newUser.LastActivityDate); - Assert.AreEqual(user.LastLoginDate, newUser.LastLoginDate); - - //Cleanup - Membership.DeleteUser("foo"); - } - - private void ChangePasswordQAHelper(MembershipUser user, string pw, string newQ, string newA) - { - try - { - user.ChangePasswordQuestionAndAnswer(pw, newQ, newA); - } - catch (ArgumentNullException ane) - { - Assert.AreEqual("password", ane.ParamName); - } - catch (ArgumentException) - { - Assert.IsNotNull(pw); - } - } - - [Test] - public void ChangePasswordQuestionAndAnswer() - { - MembershipCreateStatus status; - Membership.CreateUser("foo", "barbar!", "foo@bar.com", "color", "blue", true, out status); - Assert.AreEqual(MembershipCreateStatus.Success, status); - - MembershipUser user = Membership.GetUser("foo"); - ChangePasswordQAHelper(user, "", "newQ", "newA"); - ChangePasswordQAHelper(user, "barbar!", "", "newA"); - ChangePasswordQAHelper(user, "barbar!", "newQ", ""); - ChangePasswordQAHelper(user, null, "newQ", "newA"); - - bool result = user.ChangePasswordQuestionAndAnswer("barbar!", "newQ", "newA"); - Assert.True(result); - - user = Membership.GetUser("foo"); - Assert.AreEqual("newQ", user.PasswordQuestion); - - //Cleanup - Membership.DeleteUser("foo"); - - } - - [Test] - public void GetAllUsers() - { - MembershipCreateStatus status; - // first create a bunch of users - for (int i = 0; i < 100; i++) - Membership.CreateUser(String.Format("foo{0}", i), "barbar!", null, - "question", "answer", true, out status); - - MembershipUserCollection users = Membership.GetAllUsers(); - Assert.AreEqual(100, users.Count); - int index = 0; - foreach (MembershipUser user in users) - Assert.AreEqual(String.Format("foo{0}", index++), user.UserName); - - int total; - users = Membership.GetAllUsers(2, 10, out total); - Assert.AreEqual(10, users.Count); - Assert.AreEqual(100, total); - index = 0; - foreach (MembershipUser user in users) - Assert.AreEqual(String.Format("foo2{0}", index++), user.UserName); - - //Cleanup - MySqlHelper.ExecuteScalar(Connection, "DELETE FROM my_aspnet_users"); - MySqlHelper.ExecuteScalar(Connection, "DELETE FROM my_aspnet_membership"); - } - - private void GetPasswordHelper(bool requireQA, bool enablePasswordRetrieval, string answer) - { - MembershipCreateStatus status; - provider = new MySQLMembershipProvider(); - NameValueCollection config = new NameValueCollection(); - config.Add("connectionStringName", "LocalMySqlServer"); - config.Add("requiresQuestionAndAnswer", requireQA ? "true" : "false"); - config.Add("enablePasswordRetrieval", enablePasswordRetrieval ? "true" : "false"); - config.Add("passwordFormat", "clear"); - config.Add("applicationName", "/"); - config.Add("writeExceptionsToEventLog", "false"); - provider.Initialize(null, config); - - provider.CreateUser("foo", "barbar!", "foo@bar.com", "color", "blue", true, null, out status); - - string password = string.Empty; - if (!enablePasswordRetrieval) - { - if (requireQA && answer != null) - { - Exception ex = Assert.Throws(() => provider.GetPassword("foo", answer)); - } - else - { - Exception ex = Assert.Throws(() => provider.GetPassword("foo", answer)); - Assert.AreEqual(ex.Message, "Password Retrieval Not Enabled."); - } - } - else - { - if (requireQA && answer != null) - { - provider.GetPassword("foo", answer); - } - else if (requireQA && answer == null) - { - //Incorrect password answer. - Assert.Throws(() => provider.GetPassword("foo", answer)); - } - else - { - password = provider.GetPassword("foo", answer); - Assert.AreEqual("barbar!", password); - } - } - - //Cleanup - provider.DeleteUser("foo", true); - } - - [Test] - public void GetPassword() - { - GetPasswordHelper(false, false, null); - GetPasswordHelper(false, true, null); - GetPasswordHelper(true, true, null); - GetPasswordHelper(true, true, "blue"); - } - - /// - /// Bug #38939 MembershipUser.GetPassword(string answer) fails when incorrect answer is passed. - /// - [Test] - public void GetPasswordWithWrongAnswer() - { - MembershipCreateStatus status; - provider = new MySQLMembershipProvider(); - NameValueCollection config = new NameValueCollection(); - config.Add("connectionStringName", "LocalMySqlServer"); - config.Add("requiresQuestionAndAnswer", "true"); - config.Add("enablePasswordRetrieval", "true"); - config.Add("passwordFormat", "Encrypted"); - config.Add("applicationName", "/"); - provider.Initialize(null, config); - provider.CreateUser("foo", "barbar!", "foo@bar.com", "color", "blue", true, null, out status); - - MySQLMembershipProvider provider2 = new MySQLMembershipProvider(); - NameValueCollection config2 = new NameValueCollection(); - config2.Add("connectionStringName", "LocalMySqlServer"); - config2.Add("requiresQuestionAndAnswer", "true"); - config2.Add("enablePasswordRetrieval", "true"); - config2.Add("passwordFormat", "Encrypted"); - config2.Add("applicationName", "/"); - provider2.Initialize(null, config2); - Assert.Throws(() => provider2.GetPassword("foo", "wrong")); - - //Cleanup - provider.DeleteUser("foo", true); - } - - [Test] - public void GetUser() - { - //Resetting PK - MySqlHelper.ExecuteScalar(Connection, "ALTER TABLE my_aspnet_users AUTO_INCREMENT = 1;"); - - MembershipCreateStatus status; - Membership.CreateUser("foo", "barbar!", null, "question", "answer", true, out status); - MembershipUser user = Membership.GetUser(1); - Assert.AreEqual("foo", user.UserName); - - // now move the activity date back outside the login - // window - user.LastActivityDate = new DateTime(2008, 1, 1); - Membership.UpdateUser(user); - - user = Membership.GetUser("foo"); - Assert.False(user.IsOnline); - - user = Membership.GetUser("foo", true); - Assert.True(user.IsOnline); - - // now move the activity date back outside the login - // window again - user.LastActivityDate = new DateTime(2008, 1, 1); - Membership.UpdateUser(user); - - user = Membership.GetUser(1); - Assert.False(user.IsOnline); - - user = Membership.GetUser(1, true); - Assert.True(user.IsOnline); - - //Cleanup - Membership.DeleteUser("foo"); - } - - [Ignore("Fix Me")] - public void FindUsers() - { - MembershipCreateStatus status; - for (int i = 0; i < 100; i++) - Membership.CreateUser(String.Format("boo{0}", i), "barbar!", null, - "question", "answer", true, out status); - for (int i = 0; i < 100; i++) - Membership.CreateUser(String.Format("foo{0}", i), "barbar!", null, - "question", "answer", true, out status); - for (int i = 0; i < 100; i++) - Membership.CreateUser(String.Format("schmoo{0}", i), "barbar!", null, - "question", "answer", true, out status); - - - MembershipUserCollection users = Membership.FindUsersByName("fo%"); - Assert.AreEqual(100, users.Count); - - int total; - users = Membership.FindUsersByName("fo%", 2, 10, out total); - Assert.AreEqual(10, users.Count); - Assert.AreEqual(100, total); - int index = 0; - foreach (MembershipUser user in users) - Assert.AreEqual(String.Format("foo2{0}", index++), user.UserName); - - //Cleanup - MySqlHelper.ExecuteScalar(Connection, "DELETE FROM my_aspnet_users"); - MySqlHelper.ExecuteScalar(Connection, "DELETE FROM my_aspnet_membership"); - - } - - [Test] - public void CreateUserWithNoQA() - { - MembershipCreateStatus status; - provider = new MySQLMembershipProvider(); - NameValueCollection config = new NameValueCollection(); - config.Add("connectionStringName", "LocalMySqlServer"); - config.Add("requiresQuestionAndAnswer", "true"); - config.Add("passwordFormat", "clear"); - config.Add("applicationName", "/"); - provider.Initialize(null, config); - - Exception ex = Assert.Throws(() => provider.CreateUser("foo", "barbar!", "foo@bar.com", "color", null, true, null, out status)); - Assert.True(ex.Message.StartsWith("Password answer supplied is invalid", StringComparison.OrdinalIgnoreCase)); - - ex = Assert.Throws(() => provider.CreateUser("foo", "barbar!", "foo@bar.com", "", "blue", true, null, out status)); - Assert.True(ex.Message.StartsWith("Password question supplied is invalid", StringComparison.OrdinalIgnoreCase)); - - } - - [Test] - public void MinRequiredAlpha() - { - provider = new MySQLMembershipProvider(); - NameValueCollection config = new NameValueCollection(); - config.Add("connectionStringName", "LocalMySqlServer"); - config.Add("applicationName", "/"); - config.Add("minRequiredNonalphanumericCharacters", "3"); - provider.Initialize(null, config); - - MembershipCreateStatus status; - MembershipUser user = provider.CreateUser("foo", "pw!pass", "email", null, null, true, null, out status); - Assert.IsNull(user); - - user = provider.CreateUser("foo", "pw!pa!!", "email", null, null, true, null, out status); - Assert.IsNotNull(user); - - //Cleanup - Membership.DeleteUser("foo"); - - } - - /// - /// Bug #35332 GetPassword() don't working (when PasswordAnswer is NULL) - /// - [Test] - public void GetPasswordWithNullValues() - { - MembershipCreateStatus status; - provider = new MySQLMembershipProvider(); - NameValueCollection config = new NameValueCollection(); - config.Add("connectionStringName", "LocalMySqlServer"); - config.Add("requiresQuestionAndAnswer", "false"); - config.Add("enablePasswordRetrieval", "true"); - config.Add("passwordFormat", "clear"); - config.Add("applicationName", "/"); - provider.Initialize(null, config); - - MembershipUser user = provider.CreateUser("foo", "barbar!", "foo@bar.com", null, null, true, null, out status); - Assert.IsNotNull(user); - - string pw = provider.GetPassword("foo", null); - Assert.AreEqual("barbar!", pw); - - //Cleanup - Membership.DeleteUser("foo"); - } - - /// - /// Bug #35336 GetPassword() return wrong password (when format is encrypted) - /// - [Test] - public void GetEncryptedPassword() - { - MembershipCreateStatus status; - provider = new MySQLMembershipProvider(); - NameValueCollection config = new NameValueCollection(); - config.Add("connectionStringName", "LocalMySqlServer"); - config.Add("requiresQuestionAndAnswer", "false"); - config.Add("enablePasswordRetrieval", "true"); - config.Add("passwordFormat", "encrypted"); - config.Add("applicationName", "/"); - provider.Initialize(null, config); - - MembershipUser user = provider.CreateUser("foo", "barbar!", "foo@bar.com", null, null, true, null, out status); - Assert.IsNotNull(user); - - string pw = provider.GetPassword("foo", null); - Assert.AreEqual("barbar!", pw); - - //Cleanup - provider.DeleteUser("foo", true); - } - - /// - /// Bug #42574 ValidateUser does not use the application id, allowing cross application login - /// - [Test] - public void CrossAppLogin() - { - provider = new MySQLMembershipProvider(); - NameValueCollection config = new NameValueCollection(); - config.Add("connectionStringName", "LocalMySqlServer"); - config.Add("applicationName", "/"); - config.Add("passwordStrengthRegularExpression", "bar.*"); - config.Add("passwordFormat", "Clear"); - provider.Initialize(null, config); - MembershipCreateStatus status; - provider.CreateUser("foo", "bar!bar", null, null, null, true, null, out status); - - MySQLMembershipProvider provider2 = new MySQLMembershipProvider(); - NameValueCollection config2 = new NameValueCollection(); - config2.Add("connectionStringName", "LocalMySqlServer"); - config2.Add("applicationName", "/myapp"); - config2.Add("passwordStrengthRegularExpression", ".*"); - config2.Add("passwordFormat", "Clear"); - provider2.Initialize(null, config2); - - bool worked = provider2.ValidateUser("foo", "bar!bar"); - Assert.AreEqual(false, worked); - - //Cleanup - provider.DeleteUser("foo", true); - } - - /// - /// Bug #41408 PasswordReset not possible when requiresQuestionAndAnswer="false" - /// - [Test] - public void ResetPassword() - { - provider = new MySQLMembershipProvider(); - NameValueCollection config = new NameValueCollection(); - config.Add("connectionStringName", "LocalMySqlServer"); - config.Add("applicationName", "/"); - config.Add("passwordStrengthRegularExpression", "bar.*"); - config.Add("passwordFormat", "Clear"); - config.Add("requiresQuestionAndAnswer", "false"); - provider.Initialize(null, config); - - MembershipCreateStatus status; - provider.CreateUser("foo", "bar!bar", null, null, null, true, null, out status); - - MembershipUser u = provider.GetUser("foo", false); - string newpw = provider.ResetPassword("foo", null); - - //Cleanup - provider.DeleteUser("foo", true); - } - - /// - /// Bug #59438 setting Membership.ApplicationName has no effect - /// - [Test] - public void ChangeAppName() - { - provider = new MySQLMembershipProvider(); - NameValueCollection config = new NameValueCollection(); - config.Add("connectionStringName", "LocalMySqlServer"); - config.Add("applicationName", "/"); - config.Add("passwordStrengthRegularExpression", "bar.*"); - config.Add("passwordFormat", "Clear"); - provider.Initialize(null, config); - MembershipCreateStatus status; - provider.CreateUser("foo", "bar!bar", null, null, null, true, null, out status); - Assert.True(status == MembershipCreateStatus.Success); - - MySQLMembershipProvider provider2 = new MySQLMembershipProvider(); - NameValueCollection config2 = new NameValueCollection(); - config2.Add("connectionStringName", "LocalMySqlServer"); - config2.Add("applicationName", "/myapp"); - config2.Add("passwordStrengthRegularExpression", "foo.*"); - config2.Add("passwordFormat", "Clear"); - provider2.Initialize(null, config2); - provider2.CreateUser("foo2", "foo!foo", null, null, null, true, null, out status); - Assert.True(status == MembershipCreateStatus.Success); - - provider.ApplicationName = "/myapp"; - Assert.False(provider.ValidateUser("foo", "bar!bar")); - Assert.True(provider.ValidateUser("foo2", "foo!foo")); - - //Cleanup - //provider.DeleteUser("foo2", true); - //provider.DeleteUser("foo", true); - - //Cleanup - MySqlHelper.ExecuteScalar(Connection, "DELETE FROM my_aspnet_users"); - MySqlHelper.ExecuteScalar(Connection, "DELETE FROM my_aspnet_membership"); - - } - - [Test] - public void GetUserLooksForExactUsername() - { - MembershipCreateStatus status; - Membership.CreateUser("code", "thecode!", null, "question", "answer", true, out status); - - MembershipUser user = Membership.GetUser("code"); - Assert.AreEqual("code", user.UserName); - - user = Membership.GetUser("co_e"); - Assert.IsNull(user); - - //Cleanup - Membership.DeleteUser("code"); - } - - [Test] - public void GetUserNameByEmailLooksForExactEmail() - { - MembershipCreateStatus status; - Membership.CreateUser("code", "thecode!", "code@mysql.com", "question", "answer", true, out status); - - string username = Membership.GetUserNameByEmail("code@mysql.com"); - Assert.AreEqual("code", username); - - username = Membership.GetUserNameByEmail("co_e@mysql.com"); - Assert.IsNull(username); - - //Cleanup - Membership.DeleteUser("code"); - } - - /// - /// MySqlBug 73411, Oracle Bug: 19453313 - /// - [Test] - public void CreateUserWithLeadingAndTrailingSpaces() - { - provider = new MySQLMembershipProvider(); - NameValueCollection config = new NameValueCollection(); - config.Add("connectionStringName", "LocalMySqlServer"); - config.Add("autogenerateschema", "true"); - config.Add("applicationName", "/"); - provider.Initialize(null, config); - - MembershipCreateStatus status; - MembershipUser muser1 = provider.CreateUser(" with trailing space ", "dummypassword1!", "w@w1.w", "yes", "yes", true, null, out status); - Assert.AreNotEqual(null, muser1); - MembershipUser muser2 = provider.GetUser("with trailing space", false); - Assert.AreNotEqual(null, muser1); - - Roles.CreateRole("SomeRole"); - Assert.True(Roles.GetAllRoles().Length > 0); - - bool isInRole = Roles.IsUserInRole(muser2.UserName, "SomeRole"); - Assert.False(isInRole); - - Roles.AddUserToRole(muser2.UserName, "SomeRole"); - - isInRole = Roles.IsUserInRole(muser2.UserName, "SomeRole"); - Assert.True(isInRole); - } - } -} +// Copyright © 2013, 2025, Oracle and/or its affiliates. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0, as +// published by the Free Software Foundation. +// +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. +// +// Without limiting anything contained in the foregoing, this file, +// which is part of MySQL Connector/NET, is also subject to the +// Universal FOSS Exception, version 1.0, a copy of which can be found at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +using MySql.Data.MySqlClient; +using MySql.Web.Security; +using NUnit.Framework; +using NUnit.Framework.Legacy; +using System; +using System.Collections.Specialized; +using System.Configuration.Provider; +using System.Data; +using System.Web.Security; + +namespace MySql.Web.Tests +{ + public class UserManagement : WebTestBase + { + private MySQLMembershipProvider provider { get; set; } + + private void CreateUserWithFormat(MembershipPasswordFormat format) + { + provider = new MySQLMembershipProvider(); + NameValueCollection config = new NameValueCollection(); + config.Add("connectionStringName", "LocalMySqlServer"); + config.Add("applicationName", "/"); + config.Add("passwordStrengthRegularExpression", "bar.*"); + config.Add("passwordFormat", format.ToString()); + provider.Initialize(null, config); + + // create the user + MembershipCreateStatus status; + provider.CreateUser("foo", "barbar!", "foo@bar.com", null, null, true, null, out status); + Assert.That(status, Is.EqualTo(MembershipCreateStatus.Success)); + + // verify that the password format is hashed. + DataTable table = FillTable("SELECT * FROM my_aspnet_membership"); + MembershipPasswordFormat rowFormat = + (MembershipPasswordFormat)Convert.ToInt32(table.Rows[0]["PasswordFormat"]); + Assert.That(rowFormat, Is.EqualTo(format)); + + // then attempt to verify the user + Assert.That(provider.ValidateUser("foo", "barbar!")); + + } + + [Test] + public void CreateUserWithHashedPassword() + { + CreateUserWithFormat(MembershipPasswordFormat.Hashed); + //Cleanup + provider.DeleteUser("foo", true); + } + + [Test] + public void CreateUserWithEncryptedPasswordWithAutoGenKeys() + { + //TODO check this test logic + try + { + CreateUserWithFormat(MembershipPasswordFormat.Encrypted); + } + catch (ProviderException) + { + } + //Cleanup + provider.DeleteUser("foo", true); + } + + [Test] + public void CreateUserWithClearPassword() + { + CreateUserWithFormat(MembershipPasswordFormat.Clear); + //Cleanup + provider.DeleteUser("foo", true); + } + + /// + /// Bug #34792 New User/Changing Password Validation Not working. + /// + [Test] + public void ChangePassword() + { + CreateUserWithFormat(MembershipPasswordFormat.Hashed); + ArgumentException ex = Assert.Throws(() => provider.ChangePassword("foo", "barbar!", "bar2")); + + Assert.That(ex.ParamName, Is.EqualTo("newPassword")); + Assert.That(ex.Message.Contains("length of parameter")); + ArgumentException ex1 = Assert.Throws(() => provider.ChangePassword("foo", "barbar!", "barbar2")); + Assert.That(ex1.ParamName, Is.EqualTo("newPassword")); + Assert.That(ex1.Message.Contains("alpha numeric")); + + // now test regex strength testing + bool result = provider.ChangePassword("foo", "barbar!", "zzzxxx!"); + Assert.That(!result); + + // now do one that should work + result = provider.ChangePassword("foo", "barbar!", "barfoo!"); + Assert.That(result); + + provider.ValidateUser("foo", "barfoo!"); + + //Cleanup + provider.DeleteUser("foo", true); + } + + /// + /// Bug #34792 New User/Changing Password Validation Not working. + /// + [Test] + public void CreateUserWithErrors() + { + provider = new MySQLMembershipProvider(); + NameValueCollection config = new NameValueCollection(); + config.Add("connectionStringName", "LocalMySqlServer"); + config.Add("applicationName", "/"); + config.Add("passwordStrengthRegularExpression", "bar.*"); + config.Add("passwordFormat", "Hashed"); + provider.Initialize(null, config); + + // first try to create a user with a password not long enough + MembershipCreateStatus status; + MembershipUser user = provider.CreateUser("foo", "xyz", + "foo@bar.com", null, null, true, null, out status); + Assert.That(user, Is.Null); + Assert.That(status, Is.EqualTo(MembershipCreateStatus.InvalidPassword)); + + // now with not enough non-alphas + user = provider.CreateUser("foo", "xyz1234", + "foo@bar.com", null, null, true, null, out status); + Assert.That(user, Is.Null); + Assert.That(status, Is.EqualTo(MembershipCreateStatus.InvalidPassword)); + + // now one that doesn't pass the regex test + user = provider.CreateUser("foo", "xyzxyz!", + "foo@bar.com", null, null, true, null, out status); + Assert.That(user, Is.Null); + Assert.That(status, Is.EqualTo(MembershipCreateStatus.InvalidPassword)); + + // now one that works + user = provider.CreateUser("foo", "barbar!", + "foo@bar.com", null, null, true, null, out status); + Assert.That(user, Is.Not.Null); + Assert.That(status, Is.EqualTo(MembershipCreateStatus.Success)); + + //Cleanup + provider.DeleteUser("foo", true); + + } + + [Test] + public void DeleteUser() + { + execSQL(@"delete from my_aspnet_membership; + delete from my_aspnet_users;"); + CreateUserWithFormat(MembershipPasswordFormat.Hashed); + Assert.That(provider.DeleteUser("foo", true)); + DataTable table = FillTable("SELECT * FROM my_aspnet_membership"); + Assert.That(table.Rows.Count, Is.EqualTo(0)); + table = FillTable("SELECT * FROM my_aspnet_users"); + Assert.That(table.Rows.Count, Is.EqualTo(0)); + + CreateUserWithFormat(MembershipPasswordFormat.Hashed); + provider = new MySQLMembershipProvider(); + NameValueCollection config = new NameValueCollection(); + config.Add("connectionStringName", "LocalMySqlServer"); + config.Add("applicationName", "/"); + provider.Initialize(null, config); + Assert.That(Membership.DeleteUser("foo", false)); + table = FillTable("SELECT * FROM my_aspnet_membership"); + Assert.That(table.Rows.Count, Is.EqualTo(0)); + table = FillTable("SELECT * FROM my_aspnet_users"); + Assert.That(table.Rows.Count, Is.EqualTo(1)); + } + + [Test] + public void FindUsersByName() + { + CreateUserWithFormat(MembershipPasswordFormat.Hashed); + int records; + MembershipUserCollection users = provider.FindUsersByName("F%", 0, 10, out records); + Assert.That(records, Is.EqualTo(1)); + Assert.That(users["foo"].UserName, Is.EqualTo("foo")); + + //Cleanup + provider.DeleteUser("foo", true); + } + + [Test] + public void FindUsersByEmail() + { + CreateUserWithFormat(MembershipPasswordFormat.Hashed); + + int records; + MembershipUserCollection users = provider.FindUsersByEmail("foo@bar.com", 0, 10, out records); + Assert.That(records, Is.EqualTo(1)); + Assert.That(users["foo"].UserName, Is.EqualTo("foo")); + + //Cleanup + provider.DeleteUser("foo", true); + } + + [Test] + public void TestCreateUserOverrides() + { + try + { + MembershipCreateStatus status; + Membership.CreateUser("foo", "barbar!", null, "question", "answer", true, out status); + int records; + MembershipUserCollection users = Membership.FindUsersByName("F%", 0, 10, out records); + Assert.That(records, Is.EqualTo(1)); + Assert.That(users["foo"].UserName, Is.EqualTo("foo")); + + Membership.CreateUser("test", "barbar!", "myemail@host.com", + "question", "answer", true, out status); + users = Membership.FindUsersByName("T%", 0, 10, out records); + Assert.That(records, Is.EqualTo(1)); + Assert.That(users["test"].UserName, Is.EqualTo("test")); + } + catch (Exception ex) + { + Assert.That(ex.Message != String.Empty, ex.Message); + } + + //Cleanup + Membership.DeleteUser("test", true); + Membership.DeleteUser("foo", true); + } + + [Test] + public void NumberOfUsersOnline() + { + int numOnline = Membership.GetNumberOfUsersOnline(); + Assert.That(numOnline, Is.EqualTo(0)); + + MembershipCreateStatus status; + Membership.CreateUser("foo", "barbar!", null, "question", "answer", true, out status); + Membership.CreateUser("foo2", "barbar!", null, "question", "answer", true, out status); + + numOnline = Membership.GetNumberOfUsersOnline(); + Assert.That(numOnline, Is.EqualTo(2)); + + //Cleanup + Membership.DeleteUser("foo"); + Membership.DeleteUser("foo2"); + } + + [Test] + public void UnlockUser() + { + MembershipCreateStatus status; + Membership.CreateUser("foo", "barbar!", null, "question", "answer", true, out status); + Assert.That(!Membership.ValidateUser("foo", "bar2")); + Assert.That(!Membership.ValidateUser("foo", "bar3")); + Assert.That(!Membership.ValidateUser("foo", "bar3")); + Assert.That(!Membership.ValidateUser("foo", "bar3")); + Assert.That(!Membership.ValidateUser("foo", "bar3")); + + // the user should be locked now so the right password should fail + Assert.That(!Membership.ValidateUser("foo", "barbar!")); + + MembershipUser user = Membership.GetUser("foo"); + Assert.That(user.IsLockedOut); + + Assert.That(user.UnlockUser()); + user = Membership.GetUser("foo"); + Assert.That(!user.IsLockedOut); + + Assert.That(Membership.ValidateUser("foo", "barbar!")); + + //Cleanup + Membership.DeleteUser("foo"); + } + + [Test] + public void GetUsernameByEmail() + { + MembershipCreateStatus status; + Membership.CreateUser("foo", "barbar!", "foo@bar.com", "question", "answer", true, out status); + string username = Membership.GetUserNameByEmail("foo@bar.com"); + Assert.That(username, Is.EqualTo("foo")); + + username = Membership.GetUserNameByEmail("foo@b.com"); + Assert.That(username, Is.Null); + + username = Membership.GetUserNameByEmail(" foo@bar.com "); + Assert.That(username, Is.EqualTo("foo")); + + //Cleanup + Membership.DeleteUser("foo"); + } + + [Test] + public void UpdateUser() + { + MembershipCreateStatus status; + Membership.CreateUser("foo", "barbar!", "foo@bar.com", "color", "blue", true, out status); + Assert.That(status, Is.EqualTo(MembershipCreateStatus.Success)); + + MembershipUser user = Membership.GetUser("foo"); + + user.Comment = "my comment"; + user.Email = "my email"; + user.IsApproved = false; + user.LastActivityDate = new DateTime(2008, 1, 1); + user.LastLoginDate = new DateTime(2008, 2, 1); + Membership.UpdateUser(user); + + MembershipUser newUser = Membership.GetUser("foo"); + Assert.That(newUser.Comment, Is.EqualTo(user.Comment)); + Assert.That(newUser.Email, Is.EqualTo(user.Email)); + Assert.That(newUser.IsApproved, Is.EqualTo(user.IsApproved)); + Assert.That(newUser.LastActivityDate, Is.EqualTo(user.LastActivityDate)); + Assert.That(newUser.LastLoginDate, Is.EqualTo(user.LastLoginDate)); + + //Cleanup + Membership.DeleteUser("foo"); + } + + private void ChangePasswordQAHelper(MembershipUser user, string pw, string newQ, string newA) + { + try + { + user.ChangePasswordQuestionAndAnswer(pw, newQ, newA); + } + catch (ArgumentNullException ane) + { + Assert.That(ane.ParamName, Is.EqualTo("password")); + } + catch (ArgumentException) + { + Assert.That(pw, Is.Not.Null); + } + } + + [Test] + public void ChangePasswordQuestionAndAnswer() + { + MembershipCreateStatus status; + Membership.CreateUser("foo", "barbar!", "foo@bar.com", "color", "blue", true, out status); + Assert.That(status, Is.EqualTo(MembershipCreateStatus.Success)); + + MembershipUser user = Membership.GetUser("foo"); + ChangePasswordQAHelper(user, "", "newQ", "newA"); + ChangePasswordQAHelper(user, "barbar!", "", "newA"); + ChangePasswordQAHelper(user, "barbar!", "newQ", ""); + ChangePasswordQAHelper(user, null, "newQ", "newA"); + + bool result = user.ChangePasswordQuestionAndAnswer("barbar!", "newQ", "newA"); + Assert.That(result); + + user = Membership.GetUser("foo"); + Assert.That(user.PasswordQuestion, Is.EqualTo("newQ")); + + //Cleanup + Membership.DeleteUser("foo"); + + } + + [Test] + public void GetAllUsers() + { + MembershipCreateStatus status; + // first create a bunch of users + for (int i = 0; i < 100; i++) + Membership.CreateUser(String.Format("foo{0}", i), "barbar!", null, + "question", "answer", true, out status); + + MembershipUserCollection users = Membership.GetAllUsers(); + Assert.That(users.Count, Is.EqualTo(100)); + int index = 0; + foreach (MembershipUser user in users) + Assert.That(user.UserName, Is.EqualTo(String.Format("foo{0}", index++))); + + int total; + users = Membership.GetAllUsers(2, 10, out total); + Assert.That(users.Count, Is.EqualTo(10)); + Assert.That(total, Is.EqualTo(100)); + index = 0; + foreach (MembershipUser user in users) + Assert.That(user.UserName, Is.EqualTo(String.Format("foo2{0}", index++))); + + //Cleanup + MySqlHelper.ExecuteScalar(Connection, "DELETE FROM my_aspnet_users"); + MySqlHelper.ExecuteScalar(Connection, "DELETE FROM my_aspnet_membership"); + } + + private void GetPasswordHelper(bool requireQA, bool enablePasswordRetrieval, string answer) + { + MembershipCreateStatus status; + provider = new MySQLMembershipProvider(); + NameValueCollection config = new NameValueCollection(); + config.Add("connectionStringName", "LocalMySqlServer"); + config.Add("requiresQuestionAndAnswer", requireQA ? "true" : "false"); + config.Add("enablePasswordRetrieval", enablePasswordRetrieval ? "true" : "false"); + config.Add("passwordFormat", "clear"); + config.Add("applicationName", "/"); + config.Add("writeExceptionsToEventLog", "false"); + provider.Initialize(null, config); + + provider.CreateUser("foo", "barbar!", "foo@bar.com", "color", "blue", true, null, out status); + + string password = string.Empty; + if (!enablePasswordRetrieval) + { + if (requireQA && answer != null) + { + Exception ex = Assert.Throws(() => provider.GetPassword("foo", answer)); + } + else + { + Exception ex = Assert.Throws(() => provider.GetPassword("foo", answer)); + Assert.That("Password Retrieval Not Enabled.", Is.EqualTo(ex.Message)); + } + } + else + { + if (requireQA && answer != null) + { + provider.GetPassword("foo", answer); + } + else if (requireQA && answer == null) + { + //Incorrect password answer. + Assert.Throws(() => provider.GetPassword("foo", answer)); + } + else + { + password = provider.GetPassword("foo", answer); + Assert.That(password, Is.EqualTo("barbar!")); + } + } + + //Cleanup + provider.DeleteUser("foo", true); + } + + [Test] + public void GetPassword() + { + GetPasswordHelper(false, false, null); + GetPasswordHelper(false, true, null); + GetPasswordHelper(true, true, null); + GetPasswordHelper(true, true, "blue"); + } + + /// + /// Bug #38939 MembershipUser.GetPassword(string answer) fails when incorrect answer is passed. + /// + [Test] + public void GetPasswordWithWrongAnswer() + { + MembershipCreateStatus status; + provider = new MySQLMembershipProvider(); + NameValueCollection config = new NameValueCollection(); + config.Add("connectionStringName", "LocalMySqlServer"); + config.Add("requiresQuestionAndAnswer", "true"); + config.Add("enablePasswordRetrieval", "true"); + config.Add("passwordFormat", "Encrypted"); + config.Add("applicationName", "/"); + provider.Initialize(null, config); + provider.CreateUser("foo", "barbar!", "foo@bar.com", "color", "blue", true, null, out status); + + MySQLMembershipProvider provider2 = new MySQLMembershipProvider(); + NameValueCollection config2 = new NameValueCollection(); + config2.Add("connectionStringName", "LocalMySqlServer"); + config2.Add("requiresQuestionAndAnswer", "true"); + config2.Add("enablePasswordRetrieval", "true"); + config2.Add("passwordFormat", "Encrypted"); + config2.Add("applicationName", "/"); + provider2.Initialize(null, config2); + Assert.Throws(() => provider2.GetPassword("foo", "wrong")); + + //Cleanup + provider.DeleteUser("foo", true); + } + + [Test] + public void GetUser() + { + //Resetting PK + MySqlHelper.ExecuteScalar(Connection, "ALTER TABLE my_aspnet_users AUTO_INCREMENT = 1;"); + + MembershipCreateStatus status; + Membership.CreateUser("foo", "barbar!", null, "question", "answer", true, out status); + MembershipUser user = Membership.GetUser(1); + Assert.That(user.UserName, Is.EqualTo("foo")); + + // now move the activity date back outside the login + // window + user.LastActivityDate = new DateTime(2008, 1, 1); + Membership.UpdateUser(user); + + user = Membership.GetUser("foo"); + Assert.That(!user.IsOnline); + + user = Membership.GetUser("foo", true); + Assert.That(user.IsOnline); + + // now move the activity date back outside the login + // window again + user.LastActivityDate = new DateTime(2008, 1, 1); + Membership.UpdateUser(user); + + user = Membership.GetUser(1); + Assert.That(!user.IsOnline); + + user = Membership.GetUser(1, true); + Assert.That(user.IsOnline); + + //Cleanup + Membership.DeleteUser("foo"); + } + + [Ignore("Fix Me")] + public void FindUsers() + { + MembershipCreateStatus status; + for (int i = 0; i < 100; i++) + Membership.CreateUser(String.Format("boo{0}", i), "barbar!", null, + "question", "answer", true, out status); + for (int i = 0; i < 100; i++) + Membership.CreateUser(String.Format("foo{0}", i), "barbar!", null, + "question", "answer", true, out status); + for (int i = 0; i < 100; i++) + Membership.CreateUser(String.Format("schmoo{0}", i), "barbar!", null, + "question", "answer", true, out status); + + + MembershipUserCollection users = Membership.FindUsersByName("fo%"); + Assert.That(users.Count, Is.EqualTo(100)); + + int total; + users = Membership.FindUsersByName("fo%", 2, 10, out total); + Assert.That(users.Count, Is.EqualTo(10)); + Assert.That(total, Is.EqualTo(100)); + int index = 0; + foreach (MembershipUser user in users) + Assert.That(user.UserName, Is.EqualTo(String.Format("foo2{0}", index++))); + + //Cleanup + MySqlHelper.ExecuteScalar(Connection, "DELETE FROM my_aspnet_users"); + MySqlHelper.ExecuteScalar(Connection, "DELETE FROM my_aspnet_membership"); + + } + + [Test] + public void CreateUserWithNoQA() + { + MembershipCreateStatus status; + provider = new MySQLMembershipProvider(); + NameValueCollection config = new NameValueCollection(); + config.Add("connectionStringName", "LocalMySqlServer"); + config.Add("requiresQuestionAndAnswer", "true"); + config.Add("passwordFormat", "clear"); + config.Add("applicationName", "/"); + provider.Initialize(null, config); + + Exception ex = Assert.Throws(() => provider.CreateUser("foo", "barbar!", "foo@bar.com", "color", null, true, null, out status)); + Assert.That(ex.Message.StartsWith("Password answer supplied is invalid", StringComparison.OrdinalIgnoreCase)); + + ex = Assert.Throws(() => provider.CreateUser("foo", "barbar!", "foo@bar.com", "", "blue", true, null, out status)); + Assert.That(ex.Message.StartsWith("Password question supplied is invalid", StringComparison.OrdinalIgnoreCase)); + + } + + [Test] + public void MinRequiredAlpha() + { + provider = new MySQLMembershipProvider(); + NameValueCollection config = new NameValueCollection(); + config.Add("connectionStringName", "LocalMySqlServer"); + config.Add("applicationName", "/"); + config.Add("minRequiredNonalphanumericCharacters", "3"); + provider.Initialize(null, config); + + MembershipCreateStatus status; + MembershipUser user = provider.CreateUser("foo", "pw!pass", "email", null, null, true, null, out status); + Assert.That(user, Is.Null); + + user = provider.CreateUser("foo", "pw!pa!!", "email", null, null, true, null, out status); + Assert.That(user, Is.Not.Null); + + //Cleanup + Membership.DeleteUser("foo"); + + } + + /// + /// Bug #35332 GetPassword() don't working (when PasswordAnswer is NULL) + /// + [Test] + public void GetPasswordWithNullValues() + { + MembershipCreateStatus status; + provider = new MySQLMembershipProvider(); + NameValueCollection config = new NameValueCollection(); + config.Add("connectionStringName", "LocalMySqlServer"); + config.Add("requiresQuestionAndAnswer", "false"); + config.Add("enablePasswordRetrieval", "true"); + config.Add("passwordFormat", "clear"); + config.Add("applicationName", "/"); + provider.Initialize(null, config); + + MembershipUser user = provider.CreateUser("foo", "barbar!", "foo@bar.com", null, null, true, null, out status); + Assert.That(user, Is.Not.Null); + + string pw = provider.GetPassword("foo", null); + Assert.That(pw, Is.EqualTo("barbar!")); + + //Cleanup + Membership.DeleteUser("foo"); + } + + /// + /// Bug #35336 GetPassword() return wrong password (when format is encrypted) + /// + [Test] + public void GetEncryptedPassword() + { + MembershipCreateStatus status; + provider = new MySQLMembershipProvider(); + NameValueCollection config = new NameValueCollection(); + config.Add("connectionStringName", "LocalMySqlServer"); + config.Add("requiresQuestionAndAnswer", "false"); + config.Add("enablePasswordRetrieval", "true"); + config.Add("passwordFormat", "encrypted"); + config.Add("applicationName", "/"); + provider.Initialize(null, config); + + MembershipUser user = provider.CreateUser("foo", "barbar!", "foo@bar.com", null, null, true, null, out status); + Assert.That(user, Is.Not.Null); + + string pw = provider.GetPassword("foo", null); + Assert.That(pw, Is.EqualTo("barbar!")); + + //Cleanup + provider.DeleteUser("foo", true); + } + + /// + /// Bug #42574 ValidateUser does not use the application id, allowing cross application login + /// + [Test] + public void CrossAppLogin() + { + provider = new MySQLMembershipProvider(); + NameValueCollection config = new NameValueCollection(); + config.Add("connectionStringName", "LocalMySqlServer"); + config.Add("applicationName", "/"); + config.Add("passwordStrengthRegularExpression", "bar.*"); + config.Add("passwordFormat", "Clear"); + provider.Initialize(null, config); + MembershipCreateStatus status; + provider.CreateUser("foo", "bar!bar", null, null, null, true, null, out status); + + MySQLMembershipProvider provider2 = new MySQLMembershipProvider(); + NameValueCollection config2 = new NameValueCollection(); + config2.Add("connectionStringName", "LocalMySqlServer"); + config2.Add("applicationName", "/myapp"); + config2.Add("passwordStrengthRegularExpression", ".*"); + config2.Add("passwordFormat", "Clear"); + provider2.Initialize(null, config2); + + bool worked = provider2.ValidateUser("foo", "bar!bar"); + Assert.That(worked, Is.EqualTo(false)); + + //Cleanup + provider.DeleteUser("foo", true); + } + + /// + /// Bug #41408 PasswordReset not possible when requiresQuestionAndAnswer="false" + /// + [Test] + public void ResetPassword() + { + provider = new MySQLMembershipProvider(); + NameValueCollection config = new NameValueCollection(); + config.Add("connectionStringName", "LocalMySqlServer"); + config.Add("applicationName", "/"); + config.Add("passwordStrengthRegularExpression", "bar.*"); + config.Add("passwordFormat", "Clear"); + config.Add("requiresQuestionAndAnswer", "false"); + provider.Initialize(null, config); + + MembershipCreateStatus status; + provider.CreateUser("foo", "bar!bar", null, null, null, true, null, out status); + + MembershipUser u = provider.GetUser("foo", false); + string newpw = provider.ResetPassword("foo", null); + + //Cleanup + provider.DeleteUser("foo", true); + } + + /// + /// Bug #59438 setting Membership.ApplicationName has no effect + /// + [Test] + public void ChangeAppName() + { + provider = new MySQLMembershipProvider(); + NameValueCollection config = new NameValueCollection(); + config.Add("connectionStringName", "LocalMySqlServer"); + config.Add("applicationName", "/"); + config.Add("passwordStrengthRegularExpression", "bar.*"); + config.Add("passwordFormat", "Clear"); + provider.Initialize(null, config); + MembershipCreateStatus status; + provider.CreateUser("foo", "bar!bar", null, null, null, true, null, out status); + Assert.That(status == MembershipCreateStatus.Success); + + MySQLMembershipProvider provider2 = new MySQLMembershipProvider(); + NameValueCollection config2 = new NameValueCollection(); + config2.Add("connectionStringName", "LocalMySqlServer"); + config2.Add("applicationName", "/myapp"); + config2.Add("passwordStrengthRegularExpression", "foo.*"); + config2.Add("passwordFormat", "Clear"); + provider2.Initialize(null, config2); + provider2.CreateUser("foo2", "foo!foo", null, null, null, true, null, out status); + Assert.That(status == MembershipCreateStatus.Success); + + provider.ApplicationName = "/myapp"; + Assert.That(!provider.ValidateUser("foo", "bar!bar")); + Assert.That(provider.ValidateUser("foo2", "foo!foo")); + + //Cleanup + //provider.DeleteUser("foo2", true); + //provider.DeleteUser("foo", true); + + //Cleanup + MySqlHelper.ExecuteScalar(Connection, "DELETE FROM my_aspnet_users"); + MySqlHelper.ExecuteScalar(Connection, "DELETE FROM my_aspnet_membership"); + + } + + [Test] + public void GetUserLooksForExactUsername() + { + MembershipCreateStatus status; + Membership.CreateUser("code", "thecode!", null, "question", "answer", true, out status); + + MembershipUser user = Membership.GetUser("code"); + Assert.That(user.UserName, Is.EqualTo("code")); + + user = Membership.GetUser("co_e"); + Assert.That(user, Is.Null); + + //Cleanup + Membership.DeleteUser("code"); + } + + [Test] + public void GetUserNameByEmailLooksForExactEmail() + { + MembershipCreateStatus status; + Membership.CreateUser("code", "thecode!", "code@mysql.com", "question", "answer", true, out status); + + string username = Membership.GetUserNameByEmail("code@mysql.com"); + Assert.That(username, Is.EqualTo("code")); + + username = Membership.GetUserNameByEmail("co_e@mysql.com"); + Assert.That(username, Is.Null); + + //Cleanup + Membership.DeleteUser("code"); + } + + /// + /// MySqlBug 73411, Oracle Bug: 19453313 + /// + [Test] + public void CreateUserWithLeadingAndTrailingSpaces() + { + provider = new MySQLMembershipProvider(); + NameValueCollection config = new NameValueCollection(); + config.Add("connectionStringName", "LocalMySqlServer"); + config.Add("autogenerateschema", "true"); + config.Add("applicationName", "/"); + provider.Initialize(null, config); + + MembershipCreateStatus status; + MembershipUser muser1 = provider.CreateUser(" with trailing space ", "dummypassword1!", "w@w1.w", "yes", "yes", true, null, out status); + Assert.That(muser1, Is.Not.EqualTo(null)); + MembershipUser muser2 = provider.GetUser("with trailing space", false); + Assert.That(muser1, Is.Not.EqualTo(null)); + + Roles.CreateRole("SomeRole"); + Assert.That(Roles.GetAllRoles().Length > 0); + + bool isInRole = Roles.IsUserInRole(muser2.UserName, "SomeRole"); + Assert.That(!isInRole); + + Roles.AddUserToRole(muser2.UserName, "SomeRole"); + + isInRole = Roles.IsUserInRole(muser2.UserName, "SomeRole"); + Assert.That(isInRole); + } + } +} diff --git a/MySql.Web/tests/WebTestBase.cs b/MySql.Web/tests/WebTestBase.cs index c3ba03d5f..c7e06a723 100644 --- a/MySql.Web/tests/WebTestBase.cs +++ b/MySql.Web/tests/WebTestBase.cs @@ -1,16 +1,16 @@ -// Copyright (c) 2013, 2020, Oracle and/or its affiliates. +// Copyright © 2013, 2025, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, as // published by the Free Software Foundation. // -// This program is also distributed with certain software (including -// but not limited to OpenSSL) that is licensed under separate terms, -// as designated in a particular file or component or in included license -// documentation. The authors of MySQL hereby grant you an -// additional permission to link the program and your derivative works -// with the separately licensed software that they have included with -// MySQL. +// This program is designed to work with certain software (including +// but not limited to OpenSSL) that is licensed under separate terms, as +// designated in a particular file or component or in included license +// documentation. The authors of MySQL hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have either included with +// the program or referenced in the documentation. // // Without limiting anything contained in the foregoing, this file, // which is part of MySQL Connector/NET, is also subject to the @@ -31,6 +31,7 @@ using MySql.Web.Common; using MySql.Web.Security; using NUnit.Framework; +using NUnit.Framework.Legacy; using System; using System.Configuration; using System.Data; diff --git a/README b/README index c8a7f1dcb..0a47845c3 100644 --- a/README +++ b/README @@ -1,16 +1,16 @@ -Copyright (c) 2004, 2023, Oracle and/or its affiliates. +Copyright © 2004, 2025, Oracle and/or its affiliates. -This is a release of MySQL Connector/NET, Oracle's fully managed ADO .NET Driver for MySQL. +This is a release of MySQL Connector/NET, Oracle's fully managed ADO .NET Driver +for MySQL. -License information can be found in the LICENSE file. - -This distribution may include materials developed by third parties. -For license and attribution notices for these materials, please refer to the LICENSE file. +License information can be found in the LICENSE file. This distribution may +include materials developed by third parties. For license and attribution +notices for these materials, please refer to the LICENSE file. For more information on MySQL Connector/NET, visit - http://dev.mysql.com/doc/connector-net/en/ +http://dev.mysql.com/doc/connector-net/en/. -For additional downloads and the source of MySQL Connector/NET, visit - http://dev.mysql.com/downloads +For additional downloads and the source of MySQL Connector/NET, visit +http://dev.mysql.com/downloads/. MySQL Connector/NET is brought to you by the MySQL team at Oracle. diff --git a/README.md b/README.md index e3616a5f6..c9d28945f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # MySQL Connector/NET -[![Languages](https://img.shields.io/github/languages/top/mysql/mysql-connector-net)](https://github.com/mysql/mysql-connector-net) [![License: GNU General Public License (GPLv2)](https://img.shields.io/badge/license-GPLv2_with_FOSS_exception-c30014.svg?style=flat)](LICENSE) [![NuGet](https://img.shields.io/nuget/v/MySql.Data)](https://www.nuget.org/profiles/MySQL) +[![GitHub top language](https://img.shields.io/github/languages/top/mysql/mysql-connector-net)](https://github.com/mysql/mysql-connector-net) [![License: GPLv2 with FOSS exception](https://img.shields.io/badge/license-GPLv2_with_FOSS_exception-c30014)](LICENSE) [![NuGet Version](https://img.shields.io/nuget/v/MySQL.Data)](https://www.nuget.org/profiles/MySQL/) MySQL provides connectivity for client applications developed in .NET compatible programming languages with Connector/NET. @@ -8,22 +8,42 @@ MySQL Connector/NET is a library compatible with .NET Framework and .NET Core, f From MySQL Connector/NET 8.0, the driver also contains an implementation of [MySQL X DevAPI](https://dev.mysql.com/doc/x-devapi-userguide/en/), an Application Programming Interface for working with [MySQL as a Document Store](https://dev.mysql.com/doc/refman/8.0/en/document-store.html) through CRUD-based, NoSQL operations. -From MySQL Connector/NET 8.1, the driver contains an implementation of [OpenTelemetry](https://dev.mysql.com/doc/connector-net/en/connector-net-programming-telemetry.html) which requires the use of the [MySql.Data.OpenTelemetry](https://www.nuget.org/profiles/MySQL/) Nuget package to enable the generation of telemetry data. +From MySQL Connector/NET 8.1, the driver contains an implementation of [OpenTelemetry](https://dev.mysql.com/doc/connector-net/en/connector-net-programming-telemetry.html) which requires the use of the [MySql.Data.OpenTelemetry](https://www.nuget.org/packages/MySql.Data.OpenTelemetry/) Nuget package to enable the generation of telemetry data. -From MySQL Connector/NET 8.2, the driver adds support for [WebAuthn authentication](https://dev.mysql.com/doc/dev/connector-net/latest/api/data_api/MySql.Data.MySqlClient.WebAuthnActionCallback.html), the driver also adds support for [.NET 8](https://learn.microsoft.com/en-us/dotnet/core/whats-new/dotnet-8). +From MySQL Connector/NET 8.2, the driver adds support for [WebAuthn authentication](https://dev.mysql.com/doc/dev/connector-net/latest/api/data_api/MySql.Data.MySqlClient.WebAuthnActionCallback.html), the driver also adds support for [.NET 8](https://learn.microsoft.com/en-us/dotnet/core/whats-new/dotnet-8/). -For detailed information please visit the official [MySQL Connector/NET documentation.](https://dev.mysql.com/doc/connector-net/en/) +From MySQL Connector/NET 8.3, the driver also adds support for [.NET 8](https://learn.microsoft.com/en-us/dotnet/core/whats-new/dotnet-8/) and [EFCore 8](https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-8.0/whatsnew/) GA versions. + +From MySQL Connector/NET 8.4, the driver adds support for TLS1.3 and removes support for FIDO authentication plugin. + +From MySQL Connector/NET 9.0, the driver removes support for .NET 7 and EF Core 7. + +From MySQL Connector/NET 9.1, the driver adds support for [.NET 9](https://learn.microsoft.com/en-us/dotnet/core/whats-new/dotnet-9/overview/) and [EF Core 9](https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-9.0/whatsnew/) preview versions. + +From MySQL Connector/NET 9.2, the driver adds support for [.NET 9](https://learn.microsoft.com/en-us/dotnet/core/whats-new/dotnet-9/overview/) and [EF Core 9](https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-9.0/whatsnew/) GA versions. + +From MySQL Connector/NET 9.2, the driver removes support for .NET 6 and EF Core 6. + +From MySQL Connector/NET 9.3, the driver adds fixes to test suite and support for newest versions of EF Core 8 and EF Core 9. + +From MySQL Connector/NET 9.4, the driver adds fixes to test suite and support for preview versions of [EF Core 10](https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-10.0/whatsnew) and [.NET 10](https://learn.microsoft.com/en-us/dotnet/core/whats-new/dotnet-10/overview). + +For detailed information please visit the official [MySQL Connector/NET documentation](https://dev.mysql.com/doc/connector-net/en/). ## Licensing Please refer to files [README](README) and [LICENSE](LICENSE), available in this repository, and [Legal Notices in documentation](https://dev.mysql.com/doc/connector-net/en/preface.html) for further details. +## Security + +Oracle values the independent security research community and believes that responsible disclosure of security vulnerabilities helps us ensure the security and privacy of all our users. Please refer to the [security guidelines](SECURITY.md) document for additional information. + ## Download & Install MySQL Connector/NET can be installed from precompiled libraries by using MySQL installer or download the libraries itself, both can be found at [Connector/NET download page](https://dev.mysql.com/downloads/connector/net/). Also, you can get the latest stable release from the [official Nuget.org feed](https://www.nuget.org/profiles/MySQL). * By using MySQL Installer, you just need to follow the wizard in order to obtain the precompiled library and then add it to your project. -* If you decided to download the precompiled libraries, decompress the folder and then add the library needed to your project as reference. +* If you decided to download the precompiled libraries, decompress the folder and then add the library needed to your project as a reference. * If you go for NuGet, you could use the NuGet Package Manager inside Visual Studio or use the NuGet Command Line Interface (CLI). ### Building from sources @@ -36,16 +56,21 @@ This repository contains the MySQL Connector/NET source code as per latest relea ## Contributing -There are a few ways to contribute to the Connector/NET code. Please refer to the [contributing guidelines](CONTRIBUTING.md) for additional information. +We greatly appreciate feedback from our users, including bug reports and code contributions. Your input helps us improve, and we thank you for any issues you report or code you contribute. Please refer to the [contributing guidelines](CONTRIBUTING.md) document for additional information. ### Additional Resources -* [MySQL](http://www.mysql.com/) * [MySQL Connector/NET Developer Guide](https://dev.mysql.com/doc/connector-net/en/) -* [MySQL Connector/NET API](https://dev.mysql.com/doc/dev/connector-net/8.0/) -* [MySQL Connector/NET Discussion Forum](https://forums.mysql.com/list.php?38) -* [MySQL Public Bug Tracker](https://bugs.mysql.com) -* [`#connectors` channel in MySQL Community Slack](https://mysqlcommunity.slack.com/messages/connectors) ([Sign-up](https://lefred.be/mysql-community-on-slack/) required when not using an Oracle account) -* For more information about this and other MySQL products, please visit [MySQL Contact & Questions](http://www.mysql.com/about/contact/). - -[![Twitter Follow](https://img.shields.io/twitter/follow/MySQL.svg?label=Follow%20%40MySQL&style=social)](https://twitter.com/intent/follow?screen_name=MySQL) \ No newline at end of file +* [MySQL Connector/NET API](https://dev.mysql.com/doc/dev/connector-net/latest/) +* [MySQL NuGet](https://www.nuget.org/profiles/MySQL/) +* [MySQL Connector/NET and C#, Mono, .Net Forum](https://forums.mysql.com/list.php?38) +* [`#connectors` channel on MySQL Community Slack](https://mysqlcommunity.slack.com/messages/connectors/) ([Sign-up](https://lefred.be/mysql-community-on-slack/) required if you do not have an Oracle account.) +* [@MySQL on X](https://x.com/MySQL/). +* [MySQL Blog](https://blogs.oracle.com/mysql/). +* [MySQL Connectors Blog archive](https://dev.mysql.com/blog-archive/?cat=Connectors%20%2F%20Languages). +* [MySQL Newsletter](https://www.mysql.com/news-and-events/newsletter/). +* [MySQL Bugs Tracking System](https://bugs.mysql.com). + +For more information about this and other MySQL products, please visit [MySQL Contact & Questions](https://www.mysql.com/about/contact/). + +[![X (formerly Twitter) Follow](https://img.shields.io/twitter/follow/MySQL.svg?label=Follow%20%40MySQL&style=social)](https://x.com/intent/follow?screen_name=MySQL) diff --git a/Release Notes.txt b/Release Notes.txt index c581b031e..bb3cd1af3 100644 --- a/Release Notes.txt +++ b/Release Notes.txt @@ -1,9 +1,10 @@ -Connector/NET 8.2 Release Notes +Connector/NET 9.4 Release Notes ------------------------------------ -Welcome to the release notes for Connector/NET 8.2 +Welcome to the release notes for Connector/NET 9.4 -What's new in 8.2 +What's new in 9.4 -------------------- -Connector/NET added support for the preview version of .NET 8, if you want know more about .NET 8 see (https://learn.microsoft.com/en-us/dotnet/core/whats-new/dotnet-8). -Connector/NET added support for WebAuthn authentication, if you want to know more about it please visit (https://dev.mysql.com/doc/dev/connector-net/latest/api/data_api/MySql.Data.MySqlClient.WebAuthnActionCallback.html). \ No newline at end of file +Connector/NET now supports the preview version of .NET 10 and EF Core 10. +Connector/NET now supports GSSAPI/Kerberos authentication on windows through authentication_ldap_sasl_client plug-in. +Connector/NET added fixes to testsuite. \ No newline at end of file diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 000000000..d25bea8e0 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,29 @@ +# Reporting security vulnerabilities + +Oracle values the independent security research community and believes that +responsible disclosure of security vulnerabilities helps us ensure the security +and privacy of all our users. + +Please do NOT raise a GitHub Issue to report a security vulnerability. If you +believe you have found a security vulnerability, please submit a report to +secalert_us@oracle.com preferably with a proof of concept. Please review some +additional information [on how to report security vulnerabilities to Oracle](https://www.oracle.com/corporate/security-practices/assurance/vulnerability/reporting.html). +We encourage people who contact Oracle Security to use email encryption using +our [encryption key](https://www.oracle.com/security-alerts/encryptionkey.html). + +We ask that you do not use other channels or contact the project maintainers +directly. + +# Security updates, alerts and bulletins + +Security updates will be released on a regular cadence. Many of our projects +will typically release security fixes in conjunction with the Oracle Critical +Patch Update program. Additional information, including past advisories, is +available on our [security alerts page](https://www.oracle.com/security-alerts/). + +# Security-related information + +We will provide security related information such as a threat model, +considerations for secure use, or any known security issues in our +documentation. Please note that labs and sample code are intended to demonstrate +a concept and may not be sufficiently hardened for production use. diff --git a/global.json b/global.json new file mode 100644 index 000000000..4978943db --- /dev/null +++ b/global.json @@ -0,0 +1,8 @@ +{ + "msbuild-sdks": { + "Microsoft.Build.Traversal": "4.1.0" + }, + "sdk": { + "allowPrerelease": false + } +} \ No newline at end of file