From ad708b716e293ed5fe17efd0d023a4efef3f8a8a Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Fri, 4 Feb 2022 19:08:13 +0500 Subject: [PATCH 01/14] Ignore tests for mysql --- Orm/Xtensive.Orm.Tests/Linq/TagTest.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Orm/Xtensive.Orm.Tests/Linq/TagTest.cs b/Orm/Xtensive.Orm.Tests/Linq/TagTest.cs index f53175a6bd..a8ca49b994 100644 --- a/Orm/Xtensive.Orm.Tests/Linq/TagTest.cs +++ b/Orm/Xtensive.Orm.Tests/Linq/TagTest.cs @@ -662,8 +662,9 @@ void SqlCapturer(object sender, DbCommandEventArgs args) [Test] public void SessionTagSingle() { - var allCommands = new List(); + Require.ProviderIsNot(StorageProvider.MySql); + var allCommands = new List(); var id = 0L; using (var populateSession = Domain.OpenSession()) @@ -735,6 +736,8 @@ void SqlCapturer(object sender, DbCommandEventArgs args) [Test] public void SessionTagSingleOrDefault() { + Require.ProviderIsNot(StorageProvider.MySql); + var allCommands = new List(); var id = 0L; @@ -806,6 +809,7 @@ void SqlCapturer(object sender, DbCommandEventArgs args) [Test] public void SessionTagPrefetchEntity() { + Require.ProviderIsNot(StorageProvider.MySql); var allCommands = new List(); using (var populateSession = Domain.OpenSession()) From f33b11b58f911ce0d84ccacf0ca040218b4b28e5 Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Mon, 7 Feb 2022 18:41:14 +0500 Subject: [PATCH 02/14] MySql v5.7 and v8.0 drivers Also several incompatibilities fixed: - UNION operation was broken for some cases due to lack of round brackets so they were added, it seems to be compatible with v5.5 and v5.6; - auto_increment value info in INFORMATION_SCHEMA happened to be different for v8.0, if no value generated it returns NULL. Since v5.7 and older versions automatically inserts 1 as start value for just created table with auto-increment, NULLs were treated as 1. Since v5.7 and older always return value the changes should work with them too. --- .../Sql.Drivers.MySql/DriverFactory.cs | 6 +- .../Sql.Drivers.MySql/v5_0/Compiler.cs | 6 +- .../Sql.Drivers.MySql/v5_0/Extractor.cs | 71 ++++++------------- .../Sql.Drivers.MySql/v5_7/Compiler.cs | 18 +++++ .../Sql.Drivers.MySql/v5_7/Driver.cs | 46 ++++++++++++ .../Sql.Drivers.MySql/v5_7/Extractor.cs | 18 +++++ .../v5_7/ServerInfoProvider.cs | 18 +++++ .../Sql.Drivers.MySql/v5_7/Translator.cs | 37 ++++++++++ .../Sql.Drivers.MySql/v5_7/TypeMapper.cs | 18 +++++ .../Sql.Drivers.MySql/v8_0/Compiler.cs | 18 +++++ .../Sql.Drivers.MySql/v8_0/Driver.cs | 46 ++++++++++++ .../Sql.Drivers.MySql/v8_0/Extractor.cs | 18 +++++ .../v8_0/ServerInfoProvider.cs | 18 +++++ .../Sql.Drivers.MySql/v8_0/Translator.cs | 37 ++++++++++ .../Sql.Drivers.MySql/v8_0/TypeMapper.cs | 18 +++++ 15 files changed, 339 insertions(+), 54 deletions(-) create mode 100644 Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v5_7/Compiler.cs create mode 100644 Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v5_7/Driver.cs create mode 100644 Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v5_7/Extractor.cs create mode 100644 Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v5_7/ServerInfoProvider.cs create mode 100644 Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v5_7/Translator.cs create mode 100644 Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v5_7/TypeMapper.cs create mode 100644 Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v8_0/Compiler.cs create mode 100644 Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v8_0/Driver.cs create mode 100644 Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v8_0/Extractor.cs create mode 100644 Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v8_0/ServerInfoProvider.cs create mode 100644 Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v8_0/Translator.cs create mode 100644 Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v8_0/TypeMapper.cs diff --git a/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/DriverFactory.cs b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/DriverFactory.cs index dd3c5e24c4..db4c3343fa 100644 --- a/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/DriverFactory.cs +++ b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/DriverFactory.cs @@ -122,7 +122,11 @@ private static SqlDriver CreateDriverInstance(string connectionString, Version v 5 when version.Minor == 1 => new v5_1.Driver(coreServerInfo), 5 when version.Minor == 5 => new v5_5.Driver(coreServerInfo), 5 when version.Minor == 6 => new v5_6.Driver(coreServerInfo), - _ => new v5_6.Driver(coreServerInfo) + 5 when version.Major == 7 => new v5_7.Driver(coreServerInfo), + 6 => throw new NotSupportedException(), + 7 => throw new NotSupportedException(), + 8 => new v8_0.Driver(coreServerInfo), + _ => new v8_0.Driver(coreServerInfo) }; } diff --git a/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v5_0/Compiler.cs b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v5_0/Compiler.cs index 9b1ca2bfc0..27290279dd 100644 --- a/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v5_0/Compiler.cs +++ b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v5_0/Compiler.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2011-2021 Xtensive LLC. +// Copyright (C) 2011-2022 Xtensive LLC. // This code is distributed under MIT license terms. // See the License.txt file in the project root for more information. // Created by: Malisa Ncube @@ -124,8 +124,8 @@ protected virtual SqlExpression DateTimeAddInterval(SqlExpression date, SqlExpre public override void Visit(SqlQueryExpression node) { using (context.EnterScope(node)) { - bool needOpeningParenthesis = false; - bool needClosingParenthesis = false; + var needOpeningParenthesis = node.NodeType == SqlNodeType.Union; + var needClosingParenthesis = needOpeningParenthesis; context.Output.AppendText(translator.Translate(context, node, QueryExpressionSection.Entry)); if (needOpeningParenthesis) context.Output.AppendText("("); diff --git a/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v5_0/Extractor.cs b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v5_0/Extractor.cs index e908319bd3..4a4a2aa5ae 100644 --- a/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v5_0/Extractor.cs +++ b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v5_0/Extractor.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2011-2020 Xtensive LLC. +// Copyright (C) 2011-2022 Xtensive LLC. // This code is distributed under MIT license terms. // See the License.txt file in the project root for more information. // Created by: Malisa Ncube @@ -400,7 +400,7 @@ private static void ReadTableData(DbDataReader reader, Catalog catalog) var schemaName = reader.GetString(0); var schema = catalog.Schemas[schemaName]; var tableName = reader.GetString(1); - schema.CreateTable(tableName); + _ = schema.CreateTable(tableName); } // ---- ReadTableColumnData @@ -451,8 +451,8 @@ private void ReadTableColumnData(DbDataReader reader, ref ColumnReaderState true, + "N" or "NO" or "DISABLED" or "NONUNIQUE" => false, + _ => throw new ArgumentOutOfRangeException(string.Format(Strings.ExInvalidBooleanStringX, value)), + }; } - private static bool IsFullTextIndex(IDataRecord row, int index) - { - var value = ReadStringOrNull(row, index); - if (!string.IsNullOrEmpty(value)) { - value = value.ToUpperInvariant(); - return value == "FULLTEXT"; - } - return false; - } + private static bool IsFullTextIndex(IDataRecord row, int index) => + ReadStringOrNull(row, index).Equals("FULLTEXT", StringComparison.OrdinalIgnoreCase); - private static bool ReadAutoIncrement(IDataRecord row, int index) - { - var value = ReadStringOrNull(row, index); - if (!string.IsNullOrEmpty(value)) { - value = value.ToUpperInvariant(); - return value == "AUTO_INCREMENT"; - } - return false; - } + private static bool ReadIfAutoIncrement(IDataRecord row, int index) => + ReadStringOrNull(row, index).Equals("AUTO_INCREMENT", StringComparison.OrdinalIgnoreCase); - private static long ReadLong(IDataRecord row, int index) - { - var value = row.GetDecimal(index); - return value > long.MaxValue ? long.MaxValue : (long) value; - } + private static int ReadAutoIncrementValue(IDataRecord row, int index) => + row.IsDBNull(index) ? 1 : ReadInt(row, index); private static int ReadInt(IDataRecord row, int index) { diff --git a/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v5_7/Compiler.cs b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v5_7/Compiler.cs new file mode 100644 index 0000000000..b12423abd2 --- /dev/null +++ b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v5_7/Compiler.cs @@ -0,0 +1,18 @@ +// Copyright (C) 2022 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. +// Created by: Alexey Kulakov +// Created: 2022.02.03 + +namespace Xtensive.Sql.Drivers.MySql.v5_7 +{ + internal class Compiler : v5_6.Compiler + { + // Constructors + + public Compiler(SqlDriver driver) + : base(driver) + { + } + } +} diff --git a/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v5_7/Driver.cs b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v5_7/Driver.cs new file mode 100644 index 0000000000..7719d0cafd --- /dev/null +++ b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v5_7/Driver.cs @@ -0,0 +1,46 @@ +// Copyright (C) 2022 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. +// Created by: Alexey Kulakov +// Created: 2022.02.03 + +using Xtensive.Sql.Compiler; +using Xtensive.Sql.Info; + +namespace Xtensive.Sql.Drivers.MySql.v5_7 +{ + internal class Driver : MySql.Driver + { + protected override Sql.TypeMapper CreateTypeMapper() + { + return new TypeMapper(this); + } + + protected override SqlCompiler CreateCompiler() + { + return new Compiler(this); + } + + protected override SqlTranslator CreateTranslator() + { + return new Translator(this); + } + + protected override Model.Extractor CreateExtractor() + { + return new Extractor(this); + } + + protected override Info.ServerInfoProvider CreateServerInfoProvider() + { + return new ServerInfoProvider(this); + } + + // Constructors + + public Driver(CoreServerInfo coreServerInfo) + : base(coreServerInfo) + { + } + } +} diff --git a/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v5_7/Extractor.cs b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v5_7/Extractor.cs new file mode 100644 index 0000000000..512dd5e064 --- /dev/null +++ b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v5_7/Extractor.cs @@ -0,0 +1,18 @@ +// Copyright (C) 2022 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. +// Created by: Alexey Kulakov +// Created: 2022.02.03 + +namespace Xtensive.Sql.Drivers.MySql.v5_7 +{ + internal class Extractor : v5_6.Extractor + { + // Constructors + + public Extractor(SqlDriver driver) + : base(driver) + { + } + } +} \ No newline at end of file diff --git a/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v5_7/ServerInfoProvider.cs b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v5_7/ServerInfoProvider.cs new file mode 100644 index 0000000000..7e1b076b64 --- /dev/null +++ b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v5_7/ServerInfoProvider.cs @@ -0,0 +1,18 @@ +// Copyright (C) 2022 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. +// Created by: Alexey Kulakov +// Created: 2022.02.03 + +namespace Xtensive.Sql.Drivers.MySql.v5_7 +{ + internal class ServerInfoProvider : v5_6.ServerInfoProvider + { + // Constructors + + public ServerInfoProvider(SqlDriver driver) + : base(driver) + { + } + } +} \ No newline at end of file diff --git a/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v5_7/Translator.cs b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v5_7/Translator.cs new file mode 100644 index 0000000000..346a61a098 --- /dev/null +++ b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v5_7/Translator.cs @@ -0,0 +1,37 @@ +// Copyright (C) 2022 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. +// Created by: Alexey Kulakov +// Created: 2022.02.03 + +using System; +using Xtensive.Sql.Compiler; +using Xtensive.Sql.Dml; + +namespace Xtensive.Sql.Drivers.MySql.v5_7 +{ + internal class Translator : v5_6.Translator + { + /// + public override string Translate(SqlCompilerContext context, SqlCast node, NodeSection section) + { + if (node.Type.Type==SqlType.DateTime) + switch (section) { + case NodeSection.Entry: + return "CAST("; + case NodeSection.Exit: + return "AS " + Translate(node.Type) + "(6))"; + default: + throw new ArgumentOutOfRangeException("section"); + } + return base.Translate(context, node, section); + } + + // Constructors + + public Translator(SqlDriver driver) + : base(driver) + { + } + } +} \ No newline at end of file diff --git a/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v5_7/TypeMapper.cs b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v5_7/TypeMapper.cs new file mode 100644 index 0000000000..2a0d6f655a --- /dev/null +++ b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v5_7/TypeMapper.cs @@ -0,0 +1,18 @@ +// Copyright (C) 2022 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. +// Created by: Alexey Kulakov +// Created: 2022.02.03 + +namespace Xtensive.Sql.Drivers.MySql.v5_7 +{ + internal class TypeMapper : v5_6.TypeMapper + { + // Constructors + + public TypeMapper(SqlDriver driver) + : base(driver) + { + } + } +} diff --git a/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v8_0/Compiler.cs b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v8_0/Compiler.cs new file mode 100644 index 0000000000..5fc7f46b43 --- /dev/null +++ b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v8_0/Compiler.cs @@ -0,0 +1,18 @@ +// Copyright (C) 2022 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. +// Created by: Alexey Kulakov +// Created: 2022.02.03 + +namespace Xtensive.Sql.Drivers.MySql.v8_0 +{ + internal class Compiler : v5_7.Compiler + { + // Constructors + + public Compiler(SqlDriver driver) + : base(driver) + { + } + } +} diff --git a/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v8_0/Driver.cs b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v8_0/Driver.cs new file mode 100644 index 0000000000..4e508f6309 --- /dev/null +++ b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v8_0/Driver.cs @@ -0,0 +1,46 @@ +// Copyright (C) 2022 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. +// Created by: Alexey Kulakov +// Created: 2022.02.03 + +using Xtensive.Sql.Compiler; +using Xtensive.Sql.Info; + +namespace Xtensive.Sql.Drivers.MySql.v8_0 +{ + internal class Driver : MySql.Driver + { + protected override Sql.TypeMapper CreateTypeMapper() + { + return new TypeMapper(this); + } + + protected override SqlCompiler CreateCompiler() + { + return new Compiler(this); + } + + protected override SqlTranslator CreateTranslator() + { + return new Translator(this); + } + + protected override Model.Extractor CreateExtractor() + { + return new Extractor(this); + } + + protected override Info.ServerInfoProvider CreateServerInfoProvider() + { + return new ServerInfoProvider(this); + } + + // Constructors + + public Driver(CoreServerInfo coreServerInfo) + : base(coreServerInfo) + { + } + } +} diff --git a/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v8_0/Extractor.cs b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v8_0/Extractor.cs new file mode 100644 index 0000000000..9c34206d51 --- /dev/null +++ b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v8_0/Extractor.cs @@ -0,0 +1,18 @@ +// Copyright (C) 2022 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. +// Created by: Alexey Kulakov +// Created: 2022.02.03 + +namespace Xtensive.Sql.Drivers.MySql.v8_0 +{ + internal class Extractor : v5_7.Extractor + { + // Constructors + + public Extractor(SqlDriver driver) + : base(driver) + { + } + } +} \ No newline at end of file diff --git a/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v8_0/ServerInfoProvider.cs b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v8_0/ServerInfoProvider.cs new file mode 100644 index 0000000000..ddc9d1f1ab --- /dev/null +++ b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v8_0/ServerInfoProvider.cs @@ -0,0 +1,18 @@ +// Copyright (C) 2022 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. +// Created by: Alexey Kulakov +// Created: 2022.02.03 + +namespace Xtensive.Sql.Drivers.MySql.v8_0 +{ + internal class ServerInfoProvider : v5_7.ServerInfoProvider + { + // Constructors + + public ServerInfoProvider(SqlDriver driver) + : base(driver) + { + } + } +} \ No newline at end of file diff --git a/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v8_0/Translator.cs b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v8_0/Translator.cs new file mode 100644 index 0000000000..ecea47bab2 --- /dev/null +++ b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v8_0/Translator.cs @@ -0,0 +1,37 @@ +// Copyright (C) 2022 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. +// Created by: Alexey Kulakov +// Created: 2022.02.03 + +using System; +using Xtensive.Sql.Compiler; +using Xtensive.Sql.Dml; + +namespace Xtensive.Sql.Drivers.MySql.v8_0 +{ + internal class Translator : v5_7.Translator + { + /// + public override string Translate(SqlCompilerContext context, SqlCast node, NodeSection section) + { + if (node.Type.Type==SqlType.DateTime) + switch (section) { + case NodeSection.Entry: + return "CAST("; + case NodeSection.Exit: + return "AS " + Translate(node.Type) + "(6))"; + default: + throw new ArgumentOutOfRangeException("section"); + } + return base.Translate(context, node, section); + } + + // Constructors + + public Translator(SqlDriver driver) + : base(driver) + { + } + } +} \ No newline at end of file diff --git a/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v8_0/TypeMapper.cs b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v8_0/TypeMapper.cs new file mode 100644 index 0000000000..ce4bb1815a --- /dev/null +++ b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v8_0/TypeMapper.cs @@ -0,0 +1,18 @@ +// Copyright (C) 2022 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. +// Created by: Alexey Kulakov +// Created: 2022.02.03 + +namespace Xtensive.Sql.Drivers.MySql.v8_0 +{ + internal class TypeMapper : v5_7.TypeMapper + { + // Constructors + + public TypeMapper(SqlDriver driver) + : base(driver) + { + } + } +} From 03e7b07301c56b2b10499285d4da34d6c540b4b4 Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Wed, 9 Feb 2022 18:41:11 +0500 Subject: [PATCH 03/14] Update MySQL supported versions --- ReadMe.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ReadMe.md b/ReadMe.md index 5d50d06e25..51a3c362c9 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -7,7 +7,7 @@ Supported databases: - MS Azure SQL Database - Oracle 10g, 11g - PostgreSQL 8.3, 8.4, 9.0, 9.1, 9.2, 10, 11 -- MySQL 5.5, 5.6 +- MySQL 5.5, 5.6, 5.7, 8.0 - Firebird 2.5 - Sqlite 3 From 4f8a30e7f4ec37e859bd64edf7f0213842d495f6 Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Wed, 1 Jun 2022 17:37:22 +0500 Subject: [PATCH 04/14] Removed copy of cast translation + Fixed Set translation --- .../Sql.Drivers.MySql/v8_0/Compiler.cs | 24 +++++++++++++++++++ .../Sql.Drivers.MySql/v8_0/Translator.cs | 15 ------------ 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v8_0/Compiler.cs b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v8_0/Compiler.cs index 5fc7f46b43..e98d666a59 100644 --- a/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v8_0/Compiler.cs +++ b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v8_0/Compiler.cs @@ -4,10 +4,34 @@ // Created by: Alexey Kulakov // Created: 2022.02.03 +using Xtensive.Sql.Compiler; +using Xtensive.Sql.Dml; + namespace Xtensive.Sql.Drivers.MySql.v8_0 { internal class Compiler : v5_7.Compiler { + /// + public override void Visit(SqlQueryExpression node) + { + using (context.EnterScope(node)) { + bool needOpeningParenthesis = true; + bool needClosingParenthesis = true; + + AppendTranslatedEntry(node); + _ = context.Output.Append("("); + node.Left.AcceptVisitor(this); + _ = context.Output.Append(")"); + AppendTranslated(node.NodeType); + AppendTranslated(node, QueryExpressionSection.All); + _ = context.Output.Append("("); + node.Right.AcceptVisitor(this); + _ = context.Output.Append(")"); + AppendTranslatedExit(node); + } + } + + // Constructors public Compiler(SqlDriver driver) diff --git a/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v8_0/Translator.cs b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v8_0/Translator.cs index ecea47bab2..11d884df68 100644 --- a/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v8_0/Translator.cs +++ b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v8_0/Translator.cs @@ -12,21 +12,6 @@ namespace Xtensive.Sql.Drivers.MySql.v8_0 { internal class Translator : v5_7.Translator { - /// - public override string Translate(SqlCompilerContext context, SqlCast node, NodeSection section) - { - if (node.Type.Type==SqlType.DateTime) - switch (section) { - case NodeSection.Entry: - return "CAST("; - case NodeSection.Exit: - return "AS " + Translate(node.Type) + "(6))"; - default: - throw new ArgumentOutOfRangeException("section"); - } - return base.Translate(context, node, section); - } - // Constructors public Translator(SqlDriver driver) From 2f102502c2f5ea4a01d93edc9921e4339e66a1a1 Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Tue, 7 Jun 2022 18:07:01 +0500 Subject: [PATCH 05/14] Fix wrong choice of driver --- Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/DriverFactory.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/DriverFactory.cs b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/DriverFactory.cs index db4c3343fa..c810ad1c4b 100644 --- a/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/DriverFactory.cs +++ b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/DriverFactory.cs @@ -122,7 +122,7 @@ private static SqlDriver CreateDriverInstance(string connectionString, Version v 5 when version.Minor == 1 => new v5_1.Driver(coreServerInfo), 5 when version.Minor == 5 => new v5_5.Driver(coreServerInfo), 5 when version.Minor == 6 => new v5_6.Driver(coreServerInfo), - 5 when version.Major == 7 => new v5_7.Driver(coreServerInfo), + 5 when version.Minor == 7 => new v5_7.Driver(coreServerInfo), 6 => throw new NotSupportedException(), 7 => throw new NotSupportedException(), 8 => new v8_0.Driver(coreServerInfo), From 86665849d68420ead8b88dff949ea5bc87c9d69d Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Wed, 8 Jun 2022 20:27:31 +0500 Subject: [PATCH 06/14] Tests for UNION wrapping in new MySql v8 --- .../MySQL/ChinookTest.cs | 257 ++++++++++++++++++ 1 file changed, 257 insertions(+) diff --git a/Orm/Xtensive.Orm.Tests.Sql/MySQL/ChinookTest.cs b/Orm/Xtensive.Orm.Tests.Sql/MySQL/ChinookTest.cs index 1695460888..41ee3c306b 100644 --- a/Orm/Xtensive.Orm.Tests.Sql/MySQL/ChinookTest.cs +++ b/Orm/Xtensive.Orm.Tests.Sql/MySQL/ChinookTest.cs @@ -957,5 +957,262 @@ public void Test052() Assert.IsTrue(CompareExecuteNonQuery(nativeSql, select)); } + + [Test] + public void Test053() + { + Require.ProviderVersionAtLeast(new Version(8, 0)); + + var nativeSql = + "SELECT `a`.`ArtistId` FROM ((SELECT ArtistId FROM dotest.album where AlbumId >= 0 and AlbumId < 50 LIMIT 10)" + + " UNION (SELECT ArtistId FROM dotest.album where AlbumId >= 50 and AlbumId < 100 LIMIT 10)" + + " UNION (SELECT ArtistId FROM dotest.album where AlbumId >= 100 and AlbumId < 200 LIMIT 10)" + + " UNION (SELECT ArtistId FROM dotest.album where AlbumId >= 20 and AlbumId < 300 LIMIT 10)) `a`;"; + + var albums = SqlDml.TableRef(schema.Tables["album"]); + + var s1 = SqlDml.Select(albums); + s1.Columns.Add(albums.Columns["ArtistId"]); + s1.Where = albums.Columns["AlbumId"] >= 0 && albums.Columns["AlbumId"] < 50; + s1.Limit = 10; + + albums = SqlDml.TableRef(schema.Tables["album"]); + var s2 = SqlDml.Select(albums); + s2.Columns.Add(albums.Columns["ArtistId"]); + s2.Where = albums.Columns["AlbumId"] >= 50 && albums.Columns["AlbumId"] < 100; + s2.Limit = 10; + + albums = SqlDml.TableRef(schema.Tables["album"]); + var s3 = SqlDml.Select(albums); + s3.Columns.Add(albums.Columns["ArtistId"]); + s3.Where = albums.Columns["AlbumId"] >= 100 && albums.Columns["AlbumId"] < 200; + s3.Limit = 10; + + albums = SqlDml.TableRef(schema.Tables["album"]); + var s4 = SqlDml.Select(albums); + s4.Columns.Add(albums.Columns["ArtistId"]); + s4.Where = albums.Columns["AlbumId"] >= 200 && albums.Columns["AlbumId"] < 300; + s4.Limit = 10; + + var qr = SqlDml.QueryRef(s1.Union(s2).Union(s3.Union(s4)), "a"); + var select = SqlDml.Select(qr); + select.Columns.Add(qr["ArtistId"]); + + Assert.IsTrue(CompareExecuteNonQuery(nativeSql, select)); + } + + [Test] + public void Test054() + { + Require.ProviderVersionAtLeast(new Version(8, 0)); + + var nativeSql = + "SELECT `a`.`ArtistId` FROM ((SELECT ArtistId FROM dotest.album where AlbumId >= 0 and AlbumId < 50 LIMIT 10 OFFSET 10)" + + " UNION (SELECT ArtistId FROM dotest.album where AlbumId >= 50 and AlbumId < 100 LIMIT 10 OFFSET 10)" + + " UNION (SELECT ArtistId FROM dotest.album where AlbumId >= 100 and AlbumId < 200 LIMIT 10 OFFSET 10)" + + " UNION (SELECT ArtistId FROM dotest.album where AlbumId >= 20 and AlbumId < 300 LIMIT 10 OFFSET 10)) `a`;"; + + var albums = SqlDml.TableRef(schema.Tables["album"]); + + var s1 = SqlDml.Select(albums); + s1.Columns.Add(albums.Columns["ArtistId"]); + s1.Where = albums.Columns["AlbumId"] >= 0 && albums.Columns["AlbumId"] < 50; + s1.Limit = 10; + s1.Offset = 10; + + albums = SqlDml.TableRef(schema.Tables["album"]); + var s2 = SqlDml.Select(albums); + s2.Columns.Add(albums.Columns["ArtistId"]); + s2.Where = albums.Columns["AlbumId"] >= 50 && albums.Columns["AlbumId"] < 100; + s2.Limit = 10; + s2.Offset = 10; + + albums = SqlDml.TableRef(schema.Tables["album"]); + var s3 = SqlDml.Select(albums); + s3.Columns.Add(albums.Columns["ArtistId"]); + s3.Where = albums.Columns["AlbumId"] >= 100 && albums.Columns["AlbumId"] < 200; + s3.Limit = 10; + s3.Offset = 10; + + albums = SqlDml.TableRef(schema.Tables["album"]); + var s4 = SqlDml.Select(albums); + s4.Columns.Add(albums.Columns["ArtistId"]); + s4.Where = albums.Columns["AlbumId"] >= 200 && albums.Columns["AlbumId"] < 300; + s4.Limit = 10; + s4.Offset = 10; + + var qr = SqlDml.QueryRef(s1.Union(s2).Union(s3.Union(s4)), "a"); + var select = SqlDml.Select(qr); + select.Columns.Add(qr["ArtistId"]); + + Assert.IsTrue(CompareExecuteNonQuery(nativeSql, select)); + } + + [Test] + public void Test055() + { + Require.ProviderVersionAtLeast(new Version(8, 0)); + + var nativeSql = + "SELECT `a`.`ArtistId` FROM ((SELECT ArtistId FROM dotest.album where AlbumId >= 0 and AlbumId < 50 FOR SHARE)" + + " UNION (SELECT ArtistId FROM dotest.album where AlbumId >= 50 and AlbumId < 100 FOR SHARE)" + + " UNION (SELECT ArtistId FROM dotest.album where AlbumId >= 100 and AlbumId < 200 FOR SHARE)" + + " UNION (SELECT ArtistId FROM dotest.album where AlbumId >= 20 and AlbumId < 300 FOR SHARE)) `a`;"; + + var albums = SqlDml.TableRef(schema.Tables["album"]); + + var s1 = SqlDml.Select(albums); + s1.Columns.Add(albums.Columns["ArtistId"]); + s1.Where = albums.Columns["AlbumId"] >= 0 && albums.Columns["AlbumId"] < 50; + s1.Lock = SqlLockType.Shared; + + albums = SqlDml.TableRef(schema.Tables["album"]); + var s2 = SqlDml.Select(albums); + s2.Columns.Add(albums.Columns["ArtistId"]); + s2.Where = albums.Columns["AlbumId"] >= 50 && albums.Columns["AlbumId"] < 100; + s2.Lock = SqlLockType.Shared; + + albums = SqlDml.TableRef(schema.Tables["album"]); + var s3 = SqlDml.Select(albums); + s3.Columns.Add(albums.Columns["ArtistId"]); + s3.Where = albums.Columns["AlbumId"] >= 100 && albums.Columns["AlbumId"] < 200; + s3.Lock = SqlLockType.Shared; + + albums = SqlDml.TableRef(schema.Tables["album"]); + var s4 = SqlDml.Select(albums); + s4.Columns.Add(albums.Columns["ArtistId"]); + s4.Where = albums.Columns["AlbumId"] >= 200 && albums.Columns["AlbumId"] < 300; + s4.Lock = SqlLockType.Shared; + + var qr = SqlDml.QueryRef(s1.Union(s2).Union(s3.Union(s4)), "a"); + var select = SqlDml.Select(qr); + select.Columns.Add(qr["ArtistId"]); + + Assert.IsTrue(CompareExecuteNonQuery(nativeSql, select)); + } + + [Test] + public void Test056() + { + Require.ProviderVersionAtLeast(new Version(8, 0)); + + var nativeSql = + "SELECT `a`.`ArtistId` FROM ((SELECT ArtistId FROM dotest.album where AlbumId >= 0 and AlbumId < 50 ORDER BY ArtistId)" + + " UNION (SELECT ArtistId FROM dotest.album where AlbumId >= 50 and AlbumId < 100 ORDER BY ArtistId)" + + " UNION (SELECT ArtistId FROM dotest.album where AlbumId >= 100 and AlbumId < 200 ORDER BY ArtistId)" + + " UNION (SELECT ArtistId FROM dotest.album where AlbumId >= 20 and AlbumId < 300 ORDER BY ArtistId)) `a`;"; + + var albums = SqlDml.TableRef(schema.Tables["album"]); + + var s1 = SqlDml.Select(albums); + s1.Columns.Add(albums.Columns["ArtistId"]); + s1.Where = albums.Columns["AlbumId"] >= 0 && albums.Columns["AlbumId"] < 50; + s1.OrderBy.Add(albums.Columns["ArtistId"]); + + albums = SqlDml.TableRef(schema.Tables["album"]); + var s2 = SqlDml.Select(albums); + s2.Columns.Add(albums.Columns["ArtistId"]); + s2.Where = albums.Columns["AlbumId"] >= 50 && albums.Columns["AlbumId"] < 100; + s2.OrderBy.Add(albums.Columns["ArtistId"]); + + albums = SqlDml.TableRef(schema.Tables["album"]); + var s3 = SqlDml.Select(albums); + s3.Columns.Add(albums.Columns["ArtistId"]); + s3.Where = albums.Columns["AlbumId"] >= 100 && albums.Columns["AlbumId"] < 200; + s3.OrderBy.Add(albums.Columns["ArtistId"]); + + albums = SqlDml.TableRef(schema.Tables["album"]); + var s4 = SqlDml.Select(albums); + s4.Columns.Add(albums.Columns["ArtistId"]); + s4.Where = albums.Columns["AlbumId"] >= 200 && albums.Columns["AlbumId"] < 300; + s4.OrderBy.Add(albums.Columns["ArtistId"]); + + var qr = SqlDml.QueryRef(s1.Union(s2).Union(s3.Union(s4)), "a"); + var select = SqlDml.Select(qr); + select.Columns.Add(qr["ArtistId"]); + + Assert.IsTrue(CompareExecuteNonQuery(nativeSql, select)); + } + + + [Test] + public void Test057() + { + Require.ProviderVersionAtLeast(new Version(8, 0)); + + var nativeSql = + "SELECT `a`.`ArtistId` FROM (SELECT ArtistId FROM dotest.album where AlbumId >= 0 and AlbumId < 50 GROUP BY ArtistId" + + " UNION SELECT ArtistId FROM dotest.album where AlbumId >= 50 and AlbumId < 100 GROUP BY ArtistId" + + " UNION SELECT ArtistId FROM dotest.album where AlbumId >= 100 and AlbumId < 200 GROUP BY ArtistId" + + " UNION SELECT ArtistId FROM dotest.album where AlbumId >= 20 and AlbumId < 300 GROUP BY ArtistId) `a`;"; + + var albums = SqlDml.TableRef(schema.Tables["album"]); + + var s1 = SqlDml.Select(albums); + s1.Columns.Add(albums.Columns["ArtistId"]); + s1.Where = albums.Columns["AlbumId"] >= 0 && albums.Columns["AlbumId"] < 50; + s1.GroupBy.Add(albums.Columns["ArtistId"]); + + albums = SqlDml.TableRef(schema.Tables["album"]); + var s2 = SqlDml.Select(albums); + s2.Columns.Add(albums.Columns["ArtistId"]); + s2.Where = albums.Columns["AlbumId"] >= 50 && albums.Columns["AlbumId"] < 100; + s2.GroupBy.Add(albums.Columns["ArtistId"]); + + albums = SqlDml.TableRef(schema.Tables["album"]); + var s3 = SqlDml.Select(albums); + s3.Columns.Add(albums.Columns["ArtistId"]); + s3.Where = albums.Columns["AlbumId"] >= 100 && albums.Columns["AlbumId"] < 200; + s3.GroupBy.Add(albums.Columns["ArtistId"]); + + albums = SqlDml.TableRef(schema.Tables["album"]); + var s4 = SqlDml.Select(albums); + s4.Columns.Add(albums.Columns["ArtistId"]); + s4.Where = albums.Columns["AlbumId"] >= 200 && albums.Columns["AlbumId"] < 300; + s4.GroupBy.Add(albums.Columns["ArtistId"]); + + var qr = SqlDml.QueryRef(s1.Union(s2).Union(s3.Union(s4)), "a"); + var select = SqlDml.Select(qr); + select.Columns.Add(qr["ArtistId"]); + + Assert.IsTrue(CompareExecuteNonQuery(nativeSql, select)); + } + + [Test] + public void Test058() + { + var nativeSql = + "SELECT `a`.`AlbumId` FROM (SELECT AlbumId FROM dotest.album where AlbumId >= 0 and AlbumId < 50" + + " UNION SELECT AlbumId FROM dotest.album where AlbumId >= 50 and AlbumId< 100" + + " UNION SELECT AlbumId FROM dotest.album where AlbumId >= 100 and AlbumId< 200" + + " UNION SELECT AlbumId FROM dotest.album where AlbumId >= 20 and AlbumId< 300) `a`;"; + + var albums = SqlDml.TableRef(schema.Tables["album"]); + + var s1 = SqlDml.Select(albums); + s1.Columns.Add(albums.Columns["AlbumId"]); + s1.Where = albums.Columns["AlbumId"] >= 0 && albums.Columns["AlbumId"] < 50; + + albums = SqlDml.TableRef(schema.Tables["album"]); + var s2 = SqlDml.Select(albums); + s2.Columns.Add(albums.Columns["AlbumId"]); + s2.Where = albums.Columns["AlbumId"] >= 50 && albums.Columns["AlbumId"] < 100; + + albums = SqlDml.TableRef(schema.Tables["album"]); + var s3 = SqlDml.Select(albums); + s3.Columns.Add(albums.Columns["AlbumId"]); + s3.Where = albums.Columns["AlbumId"] >= 100 && albums.Columns["AlbumId"] < 200; + + albums = SqlDml.TableRef(schema.Tables["album"]); + var s4 = SqlDml.Select(albums); + s4.Columns.Add(albums.Columns["AlbumId"]); + s4.Where = albums.Columns["AlbumId"] >= 200 && albums.Columns["AlbumId"] < 300; + + var qr = SqlDml.QueryRef(s1.Union(s2).Union(s3.Union(s4)), "a"); + var select = SqlDml.Select(qr); + select.Columns.Add(qr["AlbumId"]); + + Assert.IsTrue(CompareExecuteNonQuery(nativeSql, select)); + } } } From ba977c36d0f550e6dfd63b68dca976a44130e891 Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Wed, 8 Jun 2022 20:43:07 +0500 Subject: [PATCH 07/14] New wrapping algorithm for SubQueries --- .../Sql.Drivers.MySql/v8_0/Compiler.cs | 30 ++++++++++++++----- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v8_0/Compiler.cs b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v8_0/Compiler.cs index e98d666a59..d8be540c24 100644 --- a/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v8_0/Compiler.cs +++ b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v8_0/Compiler.cs @@ -15,18 +15,32 @@ internal class Compiler : v5_7.Compiler public override void Visit(SqlQueryExpression node) { using (context.EnterScope(node)) { - bool needOpeningParenthesis = true; - bool needClosingParenthesis = true; + var wrapLeft = node.Left is SqlSelect sL + && (sL.OrderBy.Count > 0 || !sL.HasLimit || sL.Lock != SqlLockType.Empty); + var wrapRight = node.Left is SqlSelect sR + && (sR.OrderBy.Count > 0 || !sR.HasLimit || sR.Lock != SqlLockType.Empty); AppendTranslatedEntry(node); - _ = context.Output.Append("("); - node.Left.AcceptVisitor(this); - _ = context.Output.Append(")"); + if (wrapLeft) { + _ = context.Output.Append("("); + node.Left.AcceptVisitor(this); + _ = context.Output.Append(")"); + } + else { + node.Left.AcceptVisitor(this); + } + AppendTranslated(node.NodeType); AppendTranslated(node, QueryExpressionSection.All); - _ = context.Output.Append("("); - node.Right.AcceptVisitor(this); - _ = context.Output.Append(")"); + + if (wrapRight) { + _ = context.Output.Append("("); + node.Right.AcceptVisitor(this); + _ = context.Output.Append(")"); + } + else { + node.Right.AcceptVisitor(this); + } AppendTranslatedExit(node); } } From c4b83e97188a869948686768ac930554176447a2 Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Wed, 8 Jun 2022 20:45:12 +0500 Subject: [PATCH 08/14] SqlLockType proper translation for MySql v8.0 --- .../Sql.Drivers.MySql/v8_0/Translator.cs | 19 +++++++++++++++++++ Orm/Xtensive.Orm/Sql/Dml/Extensions.cs | 5 +++++ 2 files changed, 24 insertions(+) diff --git a/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v8_0/Translator.cs b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v8_0/Translator.cs index 11d884df68..e69cd1edbc 100644 --- a/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v8_0/Translator.cs +++ b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v8_0/Translator.cs @@ -12,6 +12,25 @@ namespace Xtensive.Sql.Drivers.MySql.v8_0 { internal class Translator : v5_7.Translator { + /// + public override void Translate(IOutput output, SqlLockType lockType) + { + var forShare = lockType.Supports(SqlLockType.Shared); + var forUpdate = lockType.SupportsAny(SqlLockType.Update | SqlLockType.Exclusive); + + if (!forShare && !forUpdate) { + throw new NotSupportedException($"Lock '{lockType.ToString(true)}' is not supported."); + } + + _ = output + .Append(forShare ? "FOR SHARE" : "FOR UPDATE") + .Append(lockType.Supports(SqlLockType.SkipLocked) + ? " SKIP LOCKED" + : lockType.Supports(SqlLockType.ThrowIfLocked) + ? " NOWAIT" + : string.Empty); + } + // Constructors public Translator(SqlDriver driver) diff --git a/Orm/Xtensive.Orm/Sql/Dml/Extensions.cs b/Orm/Xtensive.Orm/Sql/Dml/Extensions.cs index f08ceb74d5..a1eb6b44f4 100644 --- a/Orm/Xtensive.Orm/Sql/Dml/Extensions.cs +++ b/Orm/Xtensive.Orm/Sql/Dml/Extensions.cs @@ -33,6 +33,11 @@ public static bool Supports(this SqlLockType available, SqlLockType required) return (available & required)==required; } + public static bool SupportsAny(this SqlLockType available, SqlLockType required) + { + return (available | required) == required; + } + public static string ToString(this SqlLockType lockType, bool humanReadable) { if (!humanReadable) From 07c040a719d95c672b44d9760ea9a23ed3838c74 Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Thu, 9 Jun 2022 10:40:27 +0500 Subject: [PATCH 09/14] Fix incorrect condition --- Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v8_0/Compiler.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v8_0/Compiler.cs b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v8_0/Compiler.cs index d8be540c24..0e2fa17ca5 100644 --- a/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v8_0/Compiler.cs +++ b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v8_0/Compiler.cs @@ -16,9 +16,9 @@ public override void Visit(SqlQueryExpression node) { using (context.EnterScope(node)) { var wrapLeft = node.Left is SqlSelect sL - && (sL.OrderBy.Count > 0 || !sL.HasLimit || sL.Lock != SqlLockType.Empty); + && (sL.OrderBy.Count > 0 || sL.HasLimit || sL.Lock != SqlLockType.Empty); var wrapRight = node.Left is SqlSelect sR - && (sR.OrderBy.Count > 0 || !sR.HasLimit || sR.Lock != SqlLockType.Empty); + && (sR.OrderBy.Count > 0 || sR.HasLimit || sR.Lock != SqlLockType.Empty); AppendTranslatedEntry(node); if (wrapLeft) { From 95436f9021c136e4582dbbf073c8f49776b58ca0 Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Thu, 9 Jun 2022 19:16:34 +0500 Subject: [PATCH 10/14] Round brackets for SqlQueryExpression for MySql v5.7 --- .../Sql.Drivers.MySql/v5_7/Compiler.cs | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v5_7/Compiler.cs b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v5_7/Compiler.cs index b12423abd2..383b42888b 100644 --- a/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v5_7/Compiler.cs +++ b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v5_7/Compiler.cs @@ -4,10 +4,47 @@ // Created by: Alexey Kulakov // Created: 2022.02.03 +using Xtensive.Sql.Compiler; +using Xtensive.Sql.Dml; + namespace Xtensive.Sql.Drivers.MySql.v5_7 { internal class Compiler : v5_6.Compiler { + /// + public override void Visit(SqlQueryExpression node) + { + using (context.EnterScope(node)) { + var wrapLeft = node.Left is SqlSelect sL + && (sL.OrderBy.Count > 0 || sL.HasLimit || sL.Lock != SqlLockType.Empty); + var wrapRight = node.Left is SqlSelect sR + && (sR.OrderBy.Count > 0 || sR.HasLimit || sR.Lock != SqlLockType.Empty); + + AppendTranslatedEntry(node); + if (wrapLeft) { + _ = context.Output.Append("("); + node.Left.AcceptVisitor(this); + _ = context.Output.Append(")"); + } + else { + node.Left.AcceptVisitor(this); + } + + AppendTranslated(node.NodeType); + AppendTranslated(node, QueryExpressionSection.All); + + if (wrapRight) { + _ = context.Output.Append("("); + node.Right.AcceptVisitor(this); + _ = context.Output.Append(")"); + } + else { + node.Right.AcceptVisitor(this); + } + AppendTranslatedExit(node); + } + } + // Constructors public Compiler(SqlDriver driver) From de91fe0aced8052413e63fe23c1f025f6a909c93 Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Fri, 10 Jun 2022 10:54:31 +0500 Subject: [PATCH 11/14] Remove the v8.0's overriding method, the v5.7's is enough --- .../Sql.Drivers.MySql/v8_0/Compiler.cs | 37 ------------------- 1 file changed, 37 deletions(-) diff --git a/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v8_0/Compiler.cs b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v8_0/Compiler.cs index 0e2fa17ca5..d67a0840b1 100644 --- a/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v8_0/Compiler.cs +++ b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v8_0/Compiler.cs @@ -4,47 +4,10 @@ // Created by: Alexey Kulakov // Created: 2022.02.03 -using Xtensive.Sql.Compiler; -using Xtensive.Sql.Dml; - namespace Xtensive.Sql.Drivers.MySql.v8_0 { internal class Compiler : v5_7.Compiler { - /// - public override void Visit(SqlQueryExpression node) - { - using (context.EnterScope(node)) { - var wrapLeft = node.Left is SqlSelect sL - && (sL.OrderBy.Count > 0 || sL.HasLimit || sL.Lock != SqlLockType.Empty); - var wrapRight = node.Left is SqlSelect sR - && (sR.OrderBy.Count > 0 || sR.HasLimit || sR.Lock != SqlLockType.Empty); - - AppendTranslatedEntry(node); - if (wrapLeft) { - _ = context.Output.Append("("); - node.Left.AcceptVisitor(this); - _ = context.Output.Append(")"); - } - else { - node.Left.AcceptVisitor(this); - } - - AppendTranslated(node.NodeType); - AppendTranslated(node, QueryExpressionSection.All); - - if (wrapRight) { - _ = context.Output.Append("("); - node.Right.AcceptVisitor(this); - _ = context.Output.Append(")"); - } - else { - node.Right.AcceptVisitor(this); - } - AppendTranslatedExit(node); - } - } - // Constructors From 3aa9d48b63ffe83212dd94d973c2dfecbedc886f Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Wed, 15 Jun 2022 14:50:27 +0500 Subject: [PATCH 12/14] Remove accidentally added new line at the end of file --- Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v5_0/Compiler.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v5_0/Compiler.cs b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v5_0/Compiler.cs index 9020a1acba..3aa8feb24a 100644 --- a/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v5_0/Compiler.cs +++ b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/v5_0/Compiler.cs @@ -275,4 +275,4 @@ protected internal Compiler(SqlDriver driver) { } } -} +} \ No newline at end of file From 130c53c4af5b8df4f3d4bc4007c12fd0c775e0a6 Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Wed, 15 Jun 2022 15:16:04 +0500 Subject: [PATCH 13/14] Summaries for files and methods --- .../Sql.Drivers.MySql/DriverFactory.cs | 2 +- Orm/Xtensive.Orm/Sql/Dml/Extensions.cs | 24 ++++++++++++++++--- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/DriverFactory.cs b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/DriverFactory.cs index c810ad1c4b..8c6993157c 100644 --- a/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/DriverFactory.cs +++ b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/DriverFactory.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2011-2021 Xtensive LLC. +// Copyright (C) 2011-2022 Xtensive LLC. // This code is distributed under MIT license terms. // See the License.txt file in the project root for more information. // Created by: Malisa Ncube diff --git a/Orm/Xtensive.Orm/Sql/Dml/Extensions.cs b/Orm/Xtensive.Orm/Sql/Dml/Extensions.cs index a1eb6b44f4..be14016706 100644 --- a/Orm/Xtensive.Orm/Sql/Dml/Extensions.cs +++ b/Orm/Xtensive.Orm/Sql/Dml/Extensions.cs @@ -1,6 +1,6 @@ -// Copyright (C) 2003-2010 Xtensive LLC. -// All rights reserved. -// For conditions of distribution and use, see license. +// Copyright (C) 2009-2022 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. // Created by: Denis Krjuchkov // Created: 2009.08.24 @@ -28,11 +28,29 @@ public static bool IsNullReference(this SqlExpression expression) return ReferenceEquals(expression, null); } + /// + /// Checks whether contains all flags of given . + /// + /// All flags. + /// Flags to check existance. + /// + /// if contains all flags of , + /// otherwise, . + /// public static bool Supports(this SqlLockType available, SqlLockType required) { return (available & required)==required; } + /// + /// Checks whether contains any flag of given . + /// + /// All flags. + /// Flags to check existance. + /// + /// if contains any flag of , + /// otherwise, . + /// public static bool SupportsAny(this SqlLockType available, SqlLockType required) { return (available | required) == required; From 65947a7f21b13493067c768cd598479926cb1bfc Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Wed, 15 Jun 2022 16:08:25 +0500 Subject: [PATCH 14/14] Message for exception --- .../Sql.Drivers.MySql/DriverFactory.cs | 3 +-- .../Resources/Strings.Designer.cs | 11 ++++++++++- .../Sql.Drivers.MySql/Resources/Strings.resx | 3 +++ .../Xtensive.Orm.MySql.csproj | 18 ++++++++++++------ 4 files changed, 26 insertions(+), 9 deletions(-) diff --git a/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/DriverFactory.cs b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/DriverFactory.cs index 8c6993157c..8be25beb36 100644 --- a/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/DriverFactory.cs +++ b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/DriverFactory.cs @@ -123,8 +123,7 @@ private static SqlDriver CreateDriverInstance(string connectionString, Version v 5 when version.Minor == 5 => new v5_5.Driver(coreServerInfo), 5 when version.Minor == 6 => new v5_6.Driver(coreServerInfo), 5 when version.Minor == 7 => new v5_7.Driver(coreServerInfo), - 6 => throw new NotSupportedException(), - 7 => throw new NotSupportedException(), + 6 or 7 => throw new NotSupportedException(string.Format(Strings.ExVersionXOfMySQLIsNotSupported, version)), 8 => new v8_0.Driver(coreServerInfo), _ => new v8_0.Driver(coreServerInfo) }; diff --git a/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/Resources/Strings.Designer.cs b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/Resources/Strings.Designer.cs index ee0df2c30d..82f4da2092 100644 --- a/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/Resources/Strings.Designer.cs +++ b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/Resources/Strings.Designer.cs @@ -19,7 +19,7 @@ namespace Xtensive.Sql.Drivers.MySql.Resources { // 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", "15.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Strings { @@ -113,5 +113,14 @@ internal static string ExUserNameRequired { return ResourceManager.GetString("ExUserNameRequired", resourceCulture); } } + + /// + /// Looks up a localized string similar to Version {0} of MySQL is not supported.. + /// + internal static string ExVersionXOfMySQLIsNotSupported { + get { + return ResourceManager.GetString("ExVersionXOfMySQLIsNotSupported", resourceCulture); + } + } } } diff --git a/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/Resources/Strings.resx b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/Resources/Strings.resx index b8e8b5ec35..aec58aa70e 100644 --- a/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/Resources/Strings.resx +++ b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/Resources/Strings.resx @@ -135,4 +135,7 @@ MySQL Username is required. + + Version {0} of MySQL is not supported. + \ No newline at end of file diff --git a/Orm/Xtensive.Orm.MySql/Xtensive.Orm.MySql.csproj b/Orm/Xtensive.Orm.MySql/Xtensive.Orm.MySql.csproj index d2b6fc6ca7..68c6b51e0c 100644 --- a/Orm/Xtensive.Orm.MySql/Xtensive.Orm.MySql.csproj +++ b/Orm/Xtensive.Orm.MySql/Xtensive.Orm.MySql.csproj @@ -1,4 +1,4 @@ - + true $(OutputPath)$(TargetFramework)\$(AssemblyName).xml @@ -23,15 +23,21 @@ - - True - True - Strings.resx - + + ResXFileCodeGenerator + Strings.Designer.cs + + + + True + True + Strings.resx + +