From 4f2255300073f33f3f6b3c4647a6d6759941d197 Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Fri, 22 Oct 2021 10:10:04 +0500 Subject: [PATCH 01/13] Draft Driver for v4.0 --- .../Sql.Drivers.Firebird/DriverFactory.cs | 15 +- .../Sql.Drivers.Firebird/v4_0/Compiler.cs | 14 + .../Sql.Drivers.Firebird/v4_0/Driver.cs | 47 + .../Sql.Drivers.Firebird/v4_0/Extractor.cs | 873 ++++++++++++++++++ .../v4_0/ServerInfoProvider.cs | 14 + .../Sql.Drivers.Firebird/v4_0/Translator.cs | 17 + .../Sql.Drivers.Firebird/v4_0/TypeMapper.cs | 14 + 7 files changed, 985 insertions(+), 9 deletions(-) create mode 100644 Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/Compiler.cs create mode 100644 Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/Driver.cs create mode 100644 Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/Extractor.cs create mode 100644 Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/ServerInfoProvider.cs create mode 100644 Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/Translator.cs create mode 100644 Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/TypeMapper.cs diff --git a/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/DriverFactory.cs b/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/DriverFactory.cs index 6a272eb8e0..953fdbeabd 100644 --- a/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/DriverFactory.cs +++ b/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/DriverFactory.cs @@ -68,15 +68,12 @@ private static SqlDriver CreateDriverInstance( DefaultSchemaName = defaultSchema.Schema, }; - if (coreServerInfo.ServerVersion < new Version(2, 5)) { - throw new NotSupportedException(Strings.ExFirebirdBelow25IsNotSupported); - } - - if (coreServerInfo.ServerVersion.Major == 2 && coreServerInfo.ServerVersion.Minor == 5) { - return new v2_5.Driver(coreServerInfo); - } - - return null; + return coreServerInfo.ServerVersion switch { + ({ Major: 2 } and { Minor: < 5 }) or { Major: < 2 } => throw new NotSupportedException(Strings.ExFirebirdBelow25IsNotSupported), + { Major: 2 } and { Minor: 5 } => new v2_5.Driver(coreServerInfo), + { Major: 4 } => new v4_0.Driver(coreServerInfo), + _ => throw new NotSupportedException() + }; } /// diff --git a/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/Compiler.cs b/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/Compiler.cs new file mode 100644 index 0000000000..85af0e9806 --- /dev/null +++ b/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/Compiler.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Xtensive.Sql.Drivers.Firebird.v4_0 +{ + internal class Compiler : v2_5.Compiler + { + protected internal Compiler(SqlDriver driver) + : base(driver) + { + } + } +} diff --git a/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/Driver.cs b/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/Driver.cs new file mode 100644 index 0000000000..6419a1bead --- /dev/null +++ b/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/Driver.cs @@ -0,0 +1,47 @@ +// Copyright (C) 2003-2010 Xtensive LLC. +// All rights reserved. +// For conditions of distribution and use, see license. +// Created by: Csaba Beer +// Created: 2011.01.10 + +using System; +using Xtensive.Sql.Info; +using Xtensive.Sql.Compiler; + +namespace Xtensive.Sql.Drivers.Firebird.v4_0 +{ + internal class Driver : v2_5.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) + { + } + } +} \ No newline at end of file diff --git a/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/Extractor.cs b/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/Extractor.cs new file mode 100644 index 0000000000..d75496013b --- /dev/null +++ b/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/Extractor.cs @@ -0,0 +1,873 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Data.Common; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Xtensive.Core; +using Xtensive.Sql.Dml; +using Xtensive.Sql.Drivers.Firebird.Resources; +using Xtensive.Sql.Model; +using Constraint = Xtensive.Sql.Model.Constraint; +using Index = Xtensive.Sql.Model.Index; + +namespace Xtensive.Sql.Drivers.Firebird.v4_0 +{ + internal partial class Extractor : v2_5.Extractor + { + #region States + + private struct ColumnReaderState + { + public readonly Schema Schema; + public TOwner Owner; + public int LastColumnIndex; + + public ColumnReaderState(Schema schema) : this() + { + Schema = schema; + LastColumnIndex = int.MaxValue; + } + } + + private struct IndexReaderState + { + public readonly Schema Schema; + public string IndexName; + public string LastIndexName; + public Table Table; + public Index Index; + + public IndexReaderState(Schema schema) : this() + { + Schema = schema; + LastIndexName = IndexName = string.Empty; + } + } + + private struct ForeignKeyReaderState + { + public readonly Schema ReferencingSchema; + public readonly Schema ReferencedSchema; + public Table ReferencingTable; + public Table ReferencedTable; + public ForeignKey ForeignKey; + public int LastColumnIndex; + + public ForeignKeyReaderState(Schema referencingSchema, Schema referencedSchema) : this() + { + ReferencingSchema = referencingSchema; + ReferencedSchema = referencedSchema; + LastColumnIndex = int.MaxValue; + } + } + + private struct PrimaryKeyReaderState + { + public readonly Schema Schema; + public readonly List Columns; + public Table Table; + public string ConstraintName; + public string ConstraintType; + public int LastColumnIndex; + + public PrimaryKeyReaderState(Schema schema) : this() + { + Schema = schema; + Columns = new List(); + LastColumnIndex = -1; + } + } + + #endregion + + public override Catalog ExtractCatalog(string catalogName) => + ExtractSchemes(catalogName, Array.Empty()); + + public override Task ExtractCatalogAsync(string catalogName, CancellationToken token = default) => + ExtractSchemesAsync(catalogName, Array.Empty(), token); + + public override Catalog ExtractSchemes(string catalogName, string[] schemaNames) + { + ArgumentValidator.EnsureArgumentNotNullOrEmpty(catalogName, nameof(catalogName)); + ArgumentValidator.EnsureArgumentNotNull(schemaNames, nameof(schemaNames)); + + var targetSchema = schemaNames.Length > 0 ? schemaNames[0] : null; + var catalog = new Catalog(catalogName); + ExtractSchemas(catalog, targetSchema); + ExtractCatalogContents(catalog); + return catalog; + } + + public override async Task ExtractSchemesAsync( + string catalogName, string[] schemaNames, CancellationToken token = default) + { + ArgumentValidator.EnsureArgumentNotNullOrEmpty(catalogName, nameof(catalogName)); + ArgumentValidator.EnsureArgumentNotNull(schemaNames, nameof(schemaNames)); + + var targetSchema = schemaNames.Length > 0 ? schemaNames[0] : null; + var catalog = new Catalog(catalogName); + ExtractSchemas(catalog, targetSchema); + await ExtractCatalogContentsAsync(catalog, token).ConfigureAwait(false); + return catalog; + } + + private void ExtractCatalogContents(Catalog catalog) + { + ExtractTables(catalog); + ExtractTableColumns(catalog); + ExtractViews(catalog); + ExtractViewColumns(catalog); + ExtractIndexes(catalog); + ExtractForeignKeys(catalog); + ExtractCheckConstraints(catalog); + ExtractUniqueAndPrimaryKeyConstraints(catalog); + ExtractSequences(catalog); + } + + private async Task ExtractCatalogContentsAsync(Catalog catalog, CancellationToken token) + { + await ExtractTablesAsync(catalog, token).ConfigureAwait(false); + await ExtractTableColumnsAsync(catalog, token).ConfigureAwait(false); + await ExtractViewsAsync(catalog, token).ConfigureAwait(false); + await ExtractViewColumnsAsync(catalog, token).ConfigureAwait(false); + await ExtractIndexesAsync(catalog, token).ConfigureAwait(false); + await ExtractForeignKeysAsync(catalog, token).ConfigureAwait(false); + await ExtractCheckConstraintsAsync(catalog, token).ConfigureAwait(false); + await ExtractUniqueAndPrimaryKeyConstraintsAsync(catalog, token).ConfigureAwait(false); + await ExtractSequencesAsync(catalog, token).ConfigureAwait(false); + } + + private void ExtractSchemas(Catalog catalog, string targetSchema) + { + if (targetSchema == null) { + var defaultSchemaName = Driver.CoreServerInfo.DefaultSchemaName.ToUpperInvariant(); + var defaultSchema = catalog.CreateSchema(defaultSchemaName); + catalog.DefaultSchema = defaultSchema; + } + else { + // since target schema is the only schema to extract + // it will be set as default for catalog + _ = catalog.CreateSchema(targetSchema); + } + } + + private void ExtractTables(Catalog catalog) + { + var query = GetExtractTablesQuery(); + using var command = Connection.CreateCommand(query); + using var reader = command.ExecuteReader(CommandBehavior.SingleResult); + while (reader.Read()) { + ReadTableData(reader, catalog.DefaultSchema); + } + } + + private async Task ExtractTablesAsync(Catalog catalog, CancellationToken token) + { + var query = GetExtractTablesQuery(); + var command = Connection.CreateCommand(query); + await using (command.ConfigureAwait(false)) { + var reader = await command.ExecuteReaderAsync(CommandBehavior.SingleResult, token).ConfigureAwait(false); + await using (reader.ConfigureAwait(false)) { + while (await reader.ReadAsync(token).ConfigureAwait(false)) { + ReadTableData(reader, catalog.DefaultSchema); + } + } + } + } + + private void ExtractTableColumns(Catalog catalog) + { + using var command = Connection.CreateCommand(GetExtractTableColumnsQuery()); + using var reader = command.ExecuteReader(CommandBehavior.SingleResult); + var readerState = new ColumnReaderState(catalog.DefaultSchema); + while (reader.Read()) { + ReadTableColumnData(reader, ref readerState); + } + } + + private async Task ExtractTableColumnsAsync(Catalog catalog, CancellationToken token) + { + var command = Connection.CreateCommand(GetExtractTableColumnsQuery()); + await using (command.ConfigureAwait(false)) { + var reader = await command.ExecuteReaderAsync(CommandBehavior.SingleResult, token).ConfigureAwait(false); + await using (reader.ConfigureAwait(false)) { + var readerState = new ColumnReaderState
(catalog.DefaultSchema); + while (await reader.ReadAsync(token).ConfigureAwait(false)) { + ReadTableColumnData(reader, ref readerState); + } + } + } + } + + private void ExtractViews(Catalog catalog) + { + using var command = Connection.CreateCommand(GetExtractViewsQuery()); + using var reader = command.ExecuteReader(CommandBehavior.SingleResult); + while (reader.Read()) { + ReadViewData(reader, catalog.DefaultSchema); + } + } + + private async Task ExtractViewsAsync(Catalog catalog, CancellationToken token) + { + var command = Connection.CreateCommand(GetExtractViewsQuery()); + await using (command.ConfigureAwait(false)) { + var reader = await command.ExecuteReaderAsync(CommandBehavior.SingleResult, token).ConfigureAwait(false); + await using (reader.ConfigureAwait(false)) { + while (await reader.ReadAsync(token).ConfigureAwait(false)) { + ReadViewData(reader, catalog.DefaultSchema); + } + } + } + } + + private void ExtractViewColumns(Catalog catalog) + { + using var command = Connection.CreateCommand(GetExtractViewColumnsQuery()); + using var reader = command.ExecuteReader(CommandBehavior.SingleResult); + var readerState = new ColumnReaderState(catalog.DefaultSchema); + while (reader.Read()) { + ReadViewColumnData(reader, ref readerState); + } + } + + private async Task ExtractViewColumnsAsync(Catalog catalog, CancellationToken token) + { + var command = Connection.CreateCommand(GetExtractViewColumnsQuery()); + await using (command.ConfigureAwait(false)) { + var reader = await command.ExecuteReaderAsync(CommandBehavior.SingleResult, token).ConfigureAwait(false); + await using (reader.ConfigureAwait(false)) { + var readerState = new ColumnReaderState(catalog.DefaultSchema); + while (await reader.ReadAsync(token).ConfigureAwait(false)) { + ReadViewColumnData(reader, ref readerState); + } + } + } + } + + private void ExtractIndexes(Catalog catalog) + { + using var command = Connection.CreateCommand(GetExtractIndexesQuery()); + using var reader = command.ExecuteReader(CommandBehavior.SingleResult); + var readerState = new IndexReaderState(catalog.DefaultSchema); + while (reader.Read()) { + ReadIndexColumnData(reader, ref readerState); + } + } + + private async Task ExtractIndexesAsync(Catalog catalog, CancellationToken token) + { + var command = Connection.CreateCommand(GetExtractIndexesQuery()); + await using (command.ConfigureAwait(false)) { + var reader = await command.ExecuteReaderAsync(CommandBehavior.SingleResult, token).ConfigureAwait(false); + await using (reader.ConfigureAwait(false)) { + var readerState = new IndexReaderState(catalog.DefaultSchema); + while (await reader.ReadAsync(token).ConfigureAwait(false)) { + ReadIndexColumnData(reader, ref readerState); + } + } + } + } + + private void ExtractForeignKeys(Catalog catalog) + { + using var command = Connection.CreateCommand(GetExtractForeignKeysQuery()); + using var reader = command.ExecuteReader(CommandBehavior.SingleResult); + var readerState = new ForeignKeyReaderState(catalog.DefaultSchema, catalog.DefaultSchema); + while (reader.Read()) { + ReadForeignKeyColumnData(reader, ref readerState); + } + } + + private async Task ExtractForeignKeysAsync(Catalog catalog, CancellationToken token) + { + var command = Connection.CreateCommand(GetExtractForeignKeysQuery()); + await using (command.ConfigureAwait(false)) { + var reader = await command.ExecuteReaderAsync(CommandBehavior.SingleResult, token).ConfigureAwait(false); + await using (reader.ConfigureAwait(false)) { + var readerState = new ForeignKeyReaderState(catalog.DefaultSchema, catalog.DefaultSchema); + while (await reader.ReadAsync(token).ConfigureAwait(false)) { + ReadForeignKeyColumnData(reader, ref readerState); + } + } + } + } + + private void ExtractUniqueAndPrimaryKeyConstraints(Catalog catalog) + { + using var command = Connection.CreateCommand(GetExtractUniqueAndPrimaryKeyConstraintsQuery()); + using var reader = command.ExecuteReader(CommandBehavior.SingleResult); + var readerState = new PrimaryKeyReaderState(catalog.DefaultSchema); + bool readingCompleted; + do { + readingCompleted = !reader.Read(); + ReadPrimaryKeyColumn(reader, readingCompleted, ref readerState); + } while (!readingCompleted); + } + + private async Task ExtractUniqueAndPrimaryKeyConstraintsAsync(Catalog catalog, CancellationToken token) + { + var command = Connection.CreateCommand(GetExtractUniqueAndPrimaryKeyConstraintsQuery()); + await using (command.ConfigureAwait(false)) { + var reader = await command.ExecuteReaderAsync(CommandBehavior.SingleResult, token).ConfigureAwait(false); + await using (reader.ConfigureAwait(false)) { + var readerState = new PrimaryKeyReaderState(catalog.DefaultSchema); + bool readingCompleted; + do { + readingCompleted = !await reader.ReadAsync(token).ConfigureAwait(false); + ReadPrimaryKeyColumn(reader, readingCompleted, ref readerState); + } while (!readingCompleted); + } + } + } + + private void ExtractCheckConstraints(Catalog catalog) + { + using var command = Connection.CreateCommand(GetExtractCheckConstraintsQuery()); + using var reader = command.ExecuteReader(CommandBehavior.SingleResult); + while (reader.Read()) { + ReadCheckConstraintData(reader, catalog.DefaultSchema); + } + } + + private async Task ExtractCheckConstraintsAsync(Catalog catalog, CancellationToken token) + { + var command = Connection.CreateCommand(GetExtractCheckConstraintsQuery()); + await using (command.ConfigureAwait(false)) { + var reader = await command.ExecuteReaderAsync(CommandBehavior.SingleResult, token).ConfigureAwait(false); + await using (reader.ConfigureAwait(false)) { + while (await reader.ReadAsync(token).ConfigureAwait(false)) { + ReadCheckConstraintData(reader, catalog.DefaultSchema); + } + } + } + } + + private void ExtractSequences(Catalog catalog) + { + using (var command = Connection.CreateCommand(GetExtractSequencesQuery())) + using (var reader = command.ExecuteReader(CommandBehavior.SingleResult)) { + while (reader.Read()) { + ReadSequenceData(reader, catalog.DefaultSchema); + } + } + + foreach (var sequence in catalog.DefaultSchema.Sequences) { + var query = string.Format(GetExtractSequenceValueQuery(), Driver.Translator.QuoteIdentifier(sequence.Name)); + using var command = Connection.CreateCommand(query); + using var reader = command.ExecuteReader(CommandBehavior.SingleResult); + while (reader.Read()) { + sequence.SequenceDescriptor.MinValue = reader.GetInt64(0); + } + } + } + + private async Task ExtractSequencesAsync(Catalog catalog, CancellationToken token) + { + var command = Connection.CreateCommand(GetExtractSequencesQuery()); + await using (command.ConfigureAwait(false)) { + var reader = await command.ExecuteReaderAsync(CommandBehavior.SingleResult, token).ConfigureAwait(false); + await using (reader.ConfigureAwait(false)) { + while (await reader.ReadAsync(token).ConfigureAwait(false)) { + ReadSequenceData(reader, catalog.DefaultSchema); + } + } + } + + foreach (var sequence in catalog.DefaultSchema.Sequences) { + var query = string.Format(GetExtractSequenceValueQuery(), Driver.Translator.QuoteIdentifier(sequence.Name)); + command = Connection.CreateCommand(query); + await using (command.ConfigureAwait(false)) { + var reader = await command.ExecuteReaderAsync(CommandBehavior.SingleResult, token).ConfigureAwait(false); + await using (reader.ConfigureAwait(false)) { + while (await reader.ReadAsync(token).ConfigureAwait(false)) { + sequence.SequenceDescriptor.MinValue = reader.GetInt64(0); + } + } + } + } + } + + private void ReadTableData(DbDataReader reader, Schema schema) + { + var tableName = reader.GetString(1).Trim(); + int tableType = reader.GetInt16(2); + var isTemporary = tableType == 4 || tableType == 5; + if (isTemporary) { + var table = schema.CreateTemporaryTable(tableName); + table.PreserveRows = tableType == 4; + table.IsGlobal = true; + } + else { + _ = schema.CreateTable(tableName); + } + } + + private void ReadTableColumnData(DbDataReader reader, ref ColumnReaderState
state) + { + var columnIndex = reader.GetInt16(2); + if (columnIndex <= state.LastColumnIndex) { + state.Owner = state.Schema.Tables[reader.GetString(1).Trim()]; + } + state.LastColumnIndex = columnIndex; + var column = state.Owner.CreateColumn(reader.GetString(3)); + column.DataType = CreateValueType(reader, 4, 5, 7, 8, 9); + column.IsNullable = ReadBool(reader, 10); + var defaultValue = ReadStringOrNull(reader, 11); + if (!string.IsNullOrEmpty(defaultValue)) { + defaultValue = defaultValue.TrimStart(' '); + if (defaultValue.StartsWith("DEFAULT", StringComparison.OrdinalIgnoreCase)) { + defaultValue = defaultValue.Substring(7).TrimStart(' '); + } + if (!string.IsNullOrEmpty(defaultValue)) { + column.DefaultValue = SqlDml.Native(defaultValue); + } + } + } + + private void ReadViewData(DbDataReader reader, Schema schema) + { + var view = reader.GetString(1).Trim(); + var definition = ReadStringOrNull(reader, 2); + if (string.IsNullOrEmpty(definition)) { + _ = schema.CreateView(view); + } + else { + _ = schema.CreateView(view, SqlDml.Native(definition)); + } + } + + private static void ReadViewColumnData(DbDataReader reader, ref ColumnReaderState state) + { + var columnIndex = reader.GetInt16(3); + if (columnIndex <= state.LastColumnIndex) { + state.Owner = state.Schema.Views[reader.GetString(1).Trim()]; + } + state.LastColumnIndex = columnIndex; + _ = state.Owner.CreateColumn(reader.GetString(2).Trim()); + } + + private static void ReadIndexColumnData(DbDataReader reader, ref IndexReaderState state) + { + SqlExpression expression = null; + state.IndexName = reader.GetString(2).Trim(); + if (state.IndexName != state.LastIndexName) { + state.Table = state.Schema.Tables[reader.GetString(1).Trim()]; + state.Index = state.Table.CreateIndex(state.IndexName); + state.Index.IsUnique = ReadBool(reader, 5); + state.Index.IsBitmap = false; + state.Index.IsClustered = false; + if (!reader.IsDBNull(8)) { + // expression index + expression = SqlDml.Native(reader.GetString(8).Trim()); + } + } + + if (expression == null) { + var column = state.Table.TableColumns[reader.GetString(6).Trim()]; + var isDescending = ReadBool(reader, 4); + _ = state.Index.CreateIndexColumn(column, !isDescending); + } + else { + var isDescending = ReadBool(reader, 4); + _ = state.Index.CreateIndexColumn(expression, !isDescending); + } + + state.LastIndexName = state.IndexName; + } + + private static void ReadForeignKeyColumnData(DbDataReader reader, ref ForeignKeyReaderState state) + { + int columnPosition = reader.GetInt16(7); + if (columnPosition <= state.LastColumnIndex) { + state.ReferencingTable = state.ReferencingSchema.Tables[reader.GetString(1).Trim()]; + state.ForeignKey = state.ReferencingTable.CreateForeignKey(reader.GetString(2).Trim()); + ReadConstraintProperties(state.ForeignKey, reader, 3, 4); + ReadCascadeAction(state.ForeignKey, reader, 5); + state.ReferencedTable = state.ReferencedSchema.Tables[reader.GetString(9).Trim()]; + state.ForeignKey.ReferencedTable = state.ReferencedTable; + } + + var referencingColumn = state.ReferencingTable.TableColumns[reader.GetString(6).Trim()]; + var referencedColumn = state.ReferencedTable.TableColumns[reader.GetString(10).Trim()]; + state.ForeignKey.Columns.Add(referencingColumn); + state.ForeignKey.ReferencedColumns.Add(referencedColumn); + state.LastColumnIndex = columnPosition; + } + + private static void ReadPrimaryKeyColumn(DbDataReader reader, bool readingCompleted, ref PrimaryKeyReaderState state) + { + if (readingCompleted) { + if (state.Columns.Count > 0) { + CreateIndexBasedConstraint(state.Table, state.ConstraintName, state.ConstraintType, state.Columns); + } + return; + } + + int columnPosition = reader.GetInt16(5); + if (columnPosition <= state.LastColumnIndex) { + CreateIndexBasedConstraint(state.Table, state.ConstraintName, state.ConstraintType, state.Columns); + state.Columns.Clear(); + } + + if (state.Columns.Count == 0) { + state.Table = state.Schema.Tables[reader.GetString(1).Trim()]; + state.ConstraintName = reader.GetString(2).Trim(); + state.ConstraintType = reader.GetString(3).Trim(); + } + + state.Columns.Add(state.Table.TableColumns[reader.GetString(4).Trim()]); + state.LastColumnIndex = columnPosition; + } + + private void ReadCheckConstraintData(DbDataReader reader, Schema schema) + { + var table = schema.Tables[reader.GetString(1).Trim()]; + var name = reader.GetString(2).Trim(); + var condition = reader.GetString(3).Trim(); + _ = table.CreateCheckConstraint(name, condition); + } + + private void ReadSequenceData(DbDataReader reader, Schema schema) + { + var sequence = schema.CreateSequence(reader.GetString(1).Trim()); + var descriptor = sequence.SequenceDescriptor; + descriptor.MinValue = 0; + // TODO: Firebird quickfix, we must implement support for arbitrary incr. in comparer + descriptor.Increment = 128; + } + + private SqlValueType CreateValueType(IDataRecord row, + int majorTypeIndex, int minorTypeIndex, int precisionIndex, int scaleIndex, int charLengthIndex) + { + var majorType = row.GetInt16(majorTypeIndex); + var minorType = row.GetValue(minorTypeIndex) == DBNull.Value ? (short?) null : row.GetInt16(minorTypeIndex); + var typeName = GetTypeName(majorType, minorType).Trim(); + + if (typeName == "NUMERIC" || typeName == "DECIMAL") { + var precision = Convert.ToInt32(row[precisionIndex]); + var scale = Convert.ToInt32(row[scaleIndex]); + return new SqlValueType(SqlType.Decimal, precision, scale); + } + if (typeName.StartsWith("TIMESTAMP")) { + return new SqlValueType(SqlType.DateTime); + } + + if (typeName == "VARCHAR" || typeName == "CHAR") { + var length = Convert.ToInt32(row[charLengthIndex]); + var sqlType = typeName.Length == 4 ? SqlType.Char : SqlType.VarChar; + return new SqlValueType(sqlType, length); + } + + if (typeName == "BLOB SUB TYPE 0") { + return new SqlValueType(SqlType.VarCharMax); + } + + if (typeName == "BLOB SUB TYPE 1") { + return new SqlValueType(SqlType.VarBinaryMax); + } + + var typeInfo = Driver.ServerInfo.DataTypes[typeName]; + return typeInfo != null + ? new SqlValueType(typeInfo.Type) + : new SqlValueType(typeName); + } + + private static void CreateIndexBasedConstraint( + Table table, string constraintName, string constraintType, List columns) + { + switch (constraintType.Trim()) { + case "PRIMARY KEY": + _ = table.CreatePrimaryKey(constraintName, columns.ToArray()); + return; + case "UNIQUE": + _ = table.CreateUniqueConstraint(constraintName, columns.ToArray()); + return; + default: + throw new ArgumentOutOfRangeException(nameof(constraintType)); + } + } + + private static bool ReadBool(IDataRecord row, int index) + { + var value = row.IsDBNull(index) ? (short) 0 : Convert.ToInt16(row.GetString(index) ?? "0"); + switch (value) { + case 1: + return true; + case 0: + return false; + default: + throw new ArgumentOutOfRangeException(string.Format(Strings.ExInvalidBooleanSmallintValue, value)); + } + } + + private static string ReadStringOrNull(IDataRecord row, int index) => + row.IsDBNull(index) ? null : row.GetString(index).Trim(); + + private static void ReadConstraintProperties(Constraint constraint, + IDataRecord row, int isDeferrableIndex, int isInitiallyDeferredIndex) + { + constraint.IsDeferrable = ReadStringOrNull(row, isDeferrableIndex) == "YES"; + constraint.IsInitiallyDeferred = ReadStringOrNull(row, isInitiallyDeferredIndex) == "YES"; + } + + private static void ReadCascadeAction(ForeignKey foreignKey, IDataRecord row, int deleteRuleIndex) + { + var deleteRule = ReadStringOrNull(row, deleteRuleIndex); + switch (deleteRule) { + case "CASCADE": + foreignKey.OnDelete = ReferentialAction.Cascade; + return; + case "SET NULL": + foreignKey.OnDelete = ReferentialAction.SetNull; + return; + case "NO ACTION": + foreignKey.OnDelete = ReferentialAction.NoAction; + return; + case "RESTRICT": // behaves like NO ACTION + foreignKey.OnDelete = ReferentialAction.NoAction; + return; + case "SET DEFAULT": + foreignKey.OnDelete = ReferentialAction.SetDefault; + return; + } + } + + private static string GetTypeName(int majorTypeIdentifier, int? minorTypeIdentifier) + { + switch (majorTypeIdentifier) { + case 7: + return minorTypeIdentifier == 2 + ? "NUMERIC" + : minorTypeIdentifier == 1 + ? "DECIMAL" + : "SMALLINT"; + case 8: + return minorTypeIdentifier == 2 + ? "NUMERIC" + : minorTypeIdentifier == 1 + ? "DECIMAL" + : "INTEGER"; + case 10: + return "FLOAT"; + case 12: + return "DATE"; + case 13: + return "TIME"; + case 14: + return "CHAR"; + case 16: + return minorTypeIdentifier == 2 + ? "NUMERIC" + : minorTypeIdentifier == 1 + ? "DECIMAL" + : "BIGINT"; + case 27: + return "DOUBLE PRECISION"; + case 35: + return "TIMESTAMP"; + case 37: + return "VARCHAR"; + case 261: + return minorTypeIdentifier == 0 + ? "BLOB SUB TYPE 1" + : minorTypeIdentifier == 1 + ? "BLOB SUB TYPE 0" + : string.Empty; + default: + return string.Empty; + } + } + + protected override DbDataReader ExecuteReader(ISqlCompileUnit statement) + { + var commandText = Connection.Driver.Compile(statement).GetCommandText(); + // base.ExecuteReader(...) cannot be used because it disposes the DbCommand so it makes returned DbDataReader unusable + return Connection.CreateCommand(commandText).ExecuteReader(); + } + + // Constructors + + public Extractor(SqlDriver driver) + : base(driver) + { + } + } + + internal partial class Extractor + { + protected virtual string GetExtractSchemasQuery() + { + return @"select " + Constants.DefaultSchemaName + @"from rdb$database"; + } + + protected virtual string GetExtractTablesQuery() + { + return @" +select cast(null as varchar(30)) as schema + ,trim(rdb$relation_name) as table_name + ,rdb$relation_type as table_type +from rdb$relations +where rdb$relation_type in (0, 5, 4) and rdb$relation_name not starts with 'RDB$' and rdb$relation_name not starts with 'MON$'"; + } + + protected virtual string GetExtractTableColumnsQuery() + { + return @" +select schema + ,table_name + ,ordinal_position + ,column_name + ,field_type + ,column_subtype + ,column_size + ,numeric_precision + ,-numeric_scale as numeric_scale + ,character_max_length + ,(1 - coalesce(column_nullable,0)) as column_nullable + ,column_default + ,relation_type +from (select cast(null as varchar(30)) as schema + ,trim(rfr.rdb$relation_name) as table_name + ,trim(rfr.rdb$field_name) as column_name + ,fld.rdb$field_sub_type as column_subtype + ,cast(fld.rdb$field_length as integer) as column_size + ,cast(fld.rdb$field_precision as integer) as numeric_precision + ,cast(fld.rdb$field_scale as integer) as numeric_scale + ,cast(fld.rdb$character_length as integer) as character_max_length + ,cast(fld.rdb$field_length as integer) as character_octet_length + ,rfr.rdb$field_position as ordinal_position + ,trim(rfr.rdb$field_source) as domain_name + ,trim(rfr.rdb$default_source) as column_default + ,trim(fld.rdb$computed_source) as computed_source + ,fld.rdb$dimensions as column_array + ,coalesce(fld.rdb$null_flag, rfr.rdb$null_flag) as column_nullable + ,0 as is_readonly + ,fld.rdb$field_type as field_type + ,trim(cs.rdb$character_set_name) as character_set_name + ,trim(coll.rdb$collation_name) as collation_name + ,trim(rfr.rdb$description) as description + ,cast(rr.rdb$relation_type as integer) as relation_type + from rdb$relations rr join rdb$relation_fields rfr on rfr.rdb$relation_name = rr.rdb$relation_name + left join rdb$fields fld on rfr.rdb$field_source = fld.rdb$field_name + left join rdb$character_sets cs + on cs.rdb$character_set_id = fld.rdb$character_set_id + left join rdb$collations coll + on (coll.rdb$collation_id = fld.rdb$collation_id + and coll.rdb$character_set_id = fld.rdb$character_set_id) + where rr.rdb$relation_type in (0, 4, 5) and rr.rdb$relation_name not starts with 'RDB$' and rr.rdb$relation_name not starts with 'MON$' + order by table_name, ordinal_position)"; + } + + protected virtual string GetExtractViewsQuery() + { + return @" +select cast(null as varchar(30)) as schema + ,trim(rdb$relation_name) as table_name + ,rdb$view_source as view_source +from rdb$relations +where rdb$relation_type = 1"; + } + + protected virtual string GetExtractViewColumnsQuery() + { + return @" +select cast(null as varchar(30)) as schema + ,trim(rfr.rdb$relation_name) as table_name + ,trim(rfr.rdb$field_name) as column_name + ,rfr.rdb$field_position as ordinal_position +from rdb$relations rr join rdb$relation_fields rfr on rfr.rdb$relation_name = rr.rdb$relation_name +where rr.rdb$relation_type = 1 +order by rfr.rdb$relation_name, rfr.rdb$field_position"; + } + + protected virtual string GetExtractIndexesQuery() + { + return @" +select cast(null as varchar(30)) as schema + ,trim(ri.rdb$relation_name) as table_name + ,trim(ri.rdb$index_name) as index_name + ,ri.rdb$index_id as index_seq + ,ri.rdb$index_type as descend + ,ri.rdb$unique_flag as unique_flag + ,trim(ris.rdb$field_name) as column_name + ,ris.rdb$field_position as column_position + ,ri.rdb$expression_source as expression_source +from rdb$indices ri left join rdb$index_segments ris on ris.rdb$index_name = ri.rdb$index_name +where ri.rdb$system_flag = 0 + and not exists + (select 1 + from rdb$relation_constraints rc + where rc.rdb$constraint_type in ('PRIMARY KEY', 'FOREIGN KEY') + and rc.rdb$relation_name = ri.rdb$relation_name + and rc.rdb$index_name = ri.rdb$index_name) +order by ri.rdb$relation_name, ri.rdb$index_id, ris.rdb$field_position"; + } + + protected virtual string GetExtractForeignKeysQuery() + { + return @" +select cast(null as varchar(30)) as schema + ,trim(co.rdb$relation_name) as table_name + ,trim(co.rdb$constraint_name) as constraint_name + ,trim(co.rdb$deferrable) as is_deferrable + ,trim(co.rdb$initially_deferred) as deferred + ,trim(ref.rdb$delete_rule) as delete_rule + ,trim(coidxseg.rdb$field_name) as column_name + ,coidxseg.rdb$field_position as column_position + ,cast(null as varchar(30)) as referenced_schema + ,trim(refidx.rdb$relation_name) as referenced_table_name + ,trim(refidxseg.rdb$field_name) as referenced_column_name + ,trim(ref.rdb$match_option) as match_option + ,trim(ref.rdb$update_rule) as update_rule +from rdb$relation_constraints co join rdb$ref_constraints ref on co.rdb$constraint_name = ref.rdb$constraint_name + join rdb$indices tempidx + on co.rdb$index_name = tempidx.rdb$index_name + join rdb$index_segments coidxseg + on co.rdb$index_name = coidxseg.rdb$index_name + join rdb$relation_constraints unqc + on ref.rdb$const_name_uq = unqc.rdb$constraint_name and unqc.rdb$constraint_type in ('UNIQUE', 'PRIMARY KEY') + join rdb$indices refidx + on refidx.rdb$index_name = unqc.rdb$index_name and refidx.rdb$relation_name not starts with 'RDB$' + join rdb$index_segments refidxseg + on refidx.rdb$index_name = refidxseg.rdb$index_name + and coidxseg.rdb$field_position = refidxseg.rdb$field_position +where co.rdb$constraint_type = 'FOREIGN KEY' +order by co.rdb$relation_name, co.rdb$constraint_name, coidxseg.rdb$field_position"; + } + + protected override string GetExtractUniqueAndPrimaryKeyConstraintsQuery() + { + return @" +select cast(null as varchar(30)) as schema + ,trim(rel.rdb$relation_name) as table_name + ,trim(rel.rdb$constraint_name) as constraint_name + ,trim(rel.rdb$constraint_type) constraint_type + ,trim(seg.rdb$field_name) as column_name + ,seg.rdb$field_position as column_position +from rdb$relation_constraints rel +left join rdb$indices idx on rel.rdb$index_name = idx.rdb$index_name +left join rdb$index_segments seg on idx.rdb$index_name = seg.rdb$index_name +where rel.rdb$constraint_type in ('PRIMARY KEY', 'UNIQUE') + and rel.rdb$relation_name not starts with 'RDB$' + and rel.rdb$relation_name not starts with 'MON$' +order by rel.rdb$relation_name, rel.rdb$constraint_name, seg.rdb$field_position"; + } + + protected virtual string GetExtractCheckConstraintsQuery() + { + return @" +select cast(null as varchar(30)) as schema + ,trim(chktb.rdb$relation_name) as table_name + ,trim(chktb.rdb$constraint_name) as constraint_name + ,trim(trig.rdb$trigger_source) as check_clausule +from rdb$relation_constraints chktb inner join rdb$check_constraints chk + on (chktb.rdb$constraint_name = chk.rdb$constraint_name and chktb.rdb$constraint_type = 'CHECK') + inner join rdb$triggers trig + on chk.rdb$trigger_name = trig.rdb$trigger_name and trig.rdb$trigger_type = 1 +order by chktb.rdb$relation_name, chktb.rdb$constraint_name"; + } + } +} diff --git a/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/ServerInfoProvider.cs b/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/ServerInfoProvider.cs new file mode 100644 index 0000000000..e616e389ea --- /dev/null +++ b/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/ServerInfoProvider.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Xtensive.Sql.Drivers.Firebird.v4_0 +{ + internal class ServerInfoProvider : v2_5.ServerInfoProvider + { + public ServerInfoProvider(SqlDriver driver) + : base(driver) + { + } + } +} diff --git a/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/Translator.cs b/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/Translator.cs new file mode 100644 index 0000000000..f919e39c9d --- /dev/null +++ b/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/Translator.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Xtensive.Sql.Drivers.Firebird.v4_0 +{ + internal class Translator : v2_5.Translator + { + // Constructors + + /// + public Translator(SqlDriver driver) + : base(driver) + { + } + } +} diff --git a/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/TypeMapper.cs b/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/TypeMapper.cs new file mode 100644 index 0000000000..da2dce7d7a --- /dev/null +++ b/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/TypeMapper.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Xtensive.Sql.Drivers.Firebird.v4_0 +{ + internal class TypeMapper : v2_5.TypeMapper + { + public TypeMapper(SqlDriver driver) + : base(driver) + { + } + } +} From 32e89a85b9b702687e3a28e38071dd4a67769f13 Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Fri, 29 Oct 2021 19:56:40 +0500 Subject: [PATCH 02/13] Update driver package --- Orm/Xtensive.Orm.Firebird/Xtensive.Orm.Firebird.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Orm/Xtensive.Orm.Firebird/Xtensive.Orm.Firebird.csproj b/Orm/Xtensive.Orm.Firebird/Xtensive.Orm.Firebird.csproj index 44a66c30c2..1c5b118167 100644 --- a/Orm/Xtensive.Orm.Firebird/Xtensive.Orm.Firebird.csproj +++ b/Orm/Xtensive.Orm.Firebird/Xtensive.Orm.Firebird.csproj @@ -15,7 +15,7 @@ 2 - + From 868bb6cd1affc32a2f96bbfdff760d790a9dd862 Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Fri, 3 Dec 2021 11:30:06 +0500 Subject: [PATCH 03/13] firebird40 connection settings --- Orm/Xtensive.Orm.Tests.Framework/Orm.config | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Orm/Xtensive.Orm.Tests.Framework/Orm.config b/Orm/Xtensive.Orm.Tests.Framework/Orm.config index 4afb0474a7..8f0185b2b6 100644 --- a/Orm/Xtensive.Orm.Tests.Framework/Orm.config +++ b/Orm/Xtensive.Orm.Tests.Framework/Orm.config @@ -84,6 +84,9 @@ + + @@ -166,6 +169,9 @@ + + From 38da18a8c2dee9ae6900fada9203e6c04ef1c163 Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Fri, 3 Dec 2021 11:30:23 +0500 Subject: [PATCH 04/13] Fix reading of some values --- .../Sql.Drivers.Firebird/v4_0/TypeMapper.cs | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/TypeMapper.cs b/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/TypeMapper.cs index da2dce7d7a..c5ae3e8df0 100644 --- a/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/TypeMapper.cs +++ b/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/TypeMapper.cs @@ -1,11 +1,91 @@ using System; using System.Collections.Generic; +using System.Data.Common; +using System.Numerics; using System.Text; +using FirebirdSql.Data.FirebirdClient; namespace Xtensive.Sql.Drivers.Firebird.v4_0 { internal class TypeMapper : v2_5.TypeMapper { + private static readonly Type BigIntegerType = typeof(BigInteger); + + private static readonly BigInteger MaxIntAsBigInteger = new(int.MaxValue); + private static readonly BigInteger MinIntAsBigInteger = new(int.MinValue); + + private static readonly BigInteger MaxUIntAsBigInteger = new(uint.MaxValue); + private static readonly BigInteger MinUIntAsBigInteger = new(uint.MinValue); + + private static readonly BigInteger MaxLongAsBigInteger = new(long.MaxValue); + private static readonly BigInteger MinLongAsBigInteger = new(long.MinValue); + + private static readonly BigInteger MaxULongAsBigInteger = new(ulong.MaxValue); + private static readonly BigInteger MinULongAsBigInteger = new(ulong.MinValue); + + private static readonly BigInteger MaxDoubleAsBigInteger = new(double.MaxValue); + private static readonly BigInteger MinDoubleAsBigInteger = new(double.MinValue); + + public override object ReadInt(DbDataReader reader, int index) + { + var typeOfValue = reader.GetFieldType(index); + if (typeOfValue == BigIntegerType) { + var value = reader.GetFieldValue(index); + if (value > MaxIntAsBigInteger || value < MinIntAsBigInteger) + throw new ArgumentOutOfRangeException(); + return (int) value; + } + return base.ReadInt(reader, index); + } + + public override object ReadUInt(DbDataReader reader, int index) + { + var typeOfValue = reader.GetFieldType(index); + if (typeOfValue == BigIntegerType) { + var value = reader.GetFieldValue(index); + if (value > MaxUIntAsBigInteger || value < MinUIntAsBigInteger) + throw new ArgumentOutOfRangeException(); + return (uint) value; + } + return base.ReadUInt(reader, index); + } + + public override object ReadLong(DbDataReader reader, int index) + { + var typeOfValue = reader.GetFieldType(index); + if(typeOfValue == BigIntegerType) { + var value = reader.GetFieldValue(index); + if (value > MaxLongAsBigInteger || value < MinLongAsBigInteger) + throw new ArgumentOutOfRangeException(); + return (long) value; + } + return base.ReadLong(reader, index); + } + + public override object ReadULong(DbDataReader reader, int index) + { + var typeOfValue = reader.GetFieldType(index); + if (typeOfValue == BigIntegerType) { + var value = reader.GetFieldValue(index); + if (value > MaxULongAsBigInteger || value < MinULongAsBigInteger) + throw new ArgumentOutOfRangeException(); + return (ulong) value; + } + return base.ReadULong(reader, index); + } + + public override object ReadDouble(DbDataReader reader, int index) + { + var typeOfValue = reader.GetFieldType(index); + if (typeOfValue == BigIntegerType) { + var value = reader.GetFieldValue(index); + if (value > MaxDoubleAsBigInteger || value < MinDoubleAsBigInteger) + throw new ArgumentOutOfRangeException(); + return (double) value; + } + return base.ReadDouble(reader, index); + } + public TypeMapper(SqlDriver driver) : base(driver) { From fc258e4a5da030ac4cf646c6db06bc1993647a14 Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Thu, 23 Dec 2021 19:43:39 +0500 Subject: [PATCH 05/13] Small provider improvements --- .../Sql.Drivers.Firebird/Connection.cs | 42 +++++++++---------- .../Sql.Drivers.Firebird/v4_0/Driver.cs | 25 +++-------- 2 files changed, 26 insertions(+), 41 deletions(-) diff --git a/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/Connection.cs b/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/Connection.cs index c54db3567f..eb238b3deb 100644 --- a/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/Connection.cs +++ b/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/Connection.cs @@ -13,8 +13,8 @@ namespace Xtensive.Sql.Drivers.Firebird { internal class Connection : SqlConnection { - private FbConnection underlyingConnection; - private FbTransaction activeTransaction; + protected FbConnection underlyingConnection; + protected FbTransaction activeTransaction; /// public override DbConnection UnderlyingConnection => underlyingConnection; @@ -36,26 +36,26 @@ public override void BeginTransaction(IsolationLevel isolationLevel) var transactionOptions = CreateTransactionOptions(isolationLevel); activeTransaction = underlyingConnection.BeginTransaction(transactionOptions); - } - private static FbTransactionOptions CreateTransactionOptions(IsolationLevel isolationLevel) - { - var transactionOptions = new FbTransactionOptions {WaitTimeout = TimeSpan.FromSeconds(10)}; - switch (SqlHelper.ReduceIsolationLevel(isolationLevel)) { - case IsolationLevel.ReadCommitted: - transactionOptions.TransactionBehavior = FbTransactionBehavior.ReadCommitted - | FbTransactionBehavior.NoRecVersion - | FbTransactionBehavior.Write - | FbTransactionBehavior.NoWait; - break; - case IsolationLevel.Serializable: - transactionOptions.TransactionBehavior = FbTransactionBehavior.Concurrency - | FbTransactionBehavior.Write - | FbTransactionBehavior.Wait; - break; - } + static FbTransactionOptions CreateTransactionOptions(IsolationLevel isolationLevel) + { + var transactionOptions = new FbTransactionOptions { WaitTimeout = TimeSpan.FromSeconds(10) }; + switch (SqlHelper.ReduceIsolationLevel(isolationLevel)) { + case IsolationLevel.ReadCommitted: + transactionOptions.TransactionBehavior = FbTransactionBehavior.ReadCommitted + | FbTransactionBehavior.NoRecVersion + | FbTransactionBehavior.Write + | FbTransactionBehavior.NoWait; + break; + case IsolationLevel.Serializable: + transactionOptions.TransactionBehavior = FbTransactionBehavior.Concurrency + | FbTransactionBehavior.Write + | FbTransactionBehavior.Wait; + break; + } - return transactionOptions; + return transactionOptions; + } } /// @@ -85,4 +85,4 @@ public Connection(SqlDriver driver) underlyingConnection = new FbConnection(); } } -} ; +} \ No newline at end of file diff --git a/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/Driver.cs b/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/Driver.cs index 6419a1bead..6aae5286cd 100644 --- a/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/Driver.cs +++ b/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/Driver.cs @@ -12,30 +12,15 @@ namespace Xtensive.Sql.Drivers.Firebird.v4_0 { internal class Driver : v2_5.Driver { - protected override Sql.TypeMapper CreateTypeMapper() - { - return new TypeMapper(this); - } + protected override Sql.TypeMapper CreateTypeMapper() => new TypeMapper(this); - protected override SqlCompiler CreateCompiler() - { - return new Compiler(this); - } + protected override SqlCompiler CreateCompiler() => new Compiler(this); - protected override SqlTranslator CreateTranslator() - { - return new Translator(this); - } + protected override SqlTranslator CreateTranslator() => new Translator(this); - protected override Model.Extractor CreateExtractor() - { - return new Extractor(this); - } + protected override Model.Extractor CreateExtractor() => new Extractor(this); - protected override Info.ServerInfoProvider CreateServerInfoProvider() - { - return new ServerInfoProvider(this); - } + protected override Info.ServerInfoProvider CreateServerInfoProvider() => new ServerInfoProvider(this); // Constructors From bef0b537f7af865d74dc18b0620a8e8dacd21996 Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Thu, 23 Dec 2021 19:46:30 +0500 Subject: [PATCH 06/13] Offtop: avoid tests to have domain instance as field --- .../UpgradeTest.cs | 70 ++++----- .../UpgradeTest.cs | 47 +++--- .../UpgradeTest.cs | 93 ++++++------ .../UpgradeTest.cs | 38 ++--- .../UpgradeTest.cs | 123 ++++++++-------- .../UpgradeTest.cs | 63 ++++---- .../UpgradeTest.cs | 47 +++--- .../UpgradeTest.cs | 39 +++-- .../UpgradeTest.cs | 48 +++---- .../UpgradeTest.cs | 48 +++---- .../UpgradeTest.cs | 43 +++--- .../Upgrade/DataUpgrade/DataUpgradeTest.cs | 6 +- .../Upgrade/EntitySetUpgrade/UpgradeTest.cs | 11 +- .../Upgrade/Recycled/RecycledUpgradeTest.cs | 136 +++++++++--------- .../Upgrade/Sample3/Sample3UpgradeTest.cs | 67 ++++----- .../UpgradeAndNamingRules/UpgradeTest.cs | 39 +++-- .../Upgrade/UpgradeToStructure/UpgradeTest.cs | 37 ++--- 17 files changed, 414 insertions(+), 541 deletions(-) diff --git a/Orm/Xtensive.Orm.Tests/Issues/IssueJira0180_ChangeNullabilityViaUpgradeHints/UpgradeTest.cs b/Orm/Xtensive.Orm.Tests/Issues/IssueJira0180_ChangeNullabilityViaUpgradeHints/UpgradeTest.cs index 313b69de44..61df2fbad7 100644 --- a/Orm/Xtensive.Orm.Tests/Issues/IssueJira0180_ChangeNullabilityViaUpgradeHints/UpgradeTest.cs +++ b/Orm/Xtensive.Orm.Tests/Issues/IssueJira0180_ChangeNullabilityViaUpgradeHints/UpgradeTest.cs @@ -19,64 +19,46 @@ namespace Xtensive.Orm.Tests.Issues.IssueJira0180_ChangeNullabilityViaUpgradeHin [TestFixture] public class UpgradeTest { - private Domain domain; - [Test] - public void NoneTest() - { - RunTest(NamingRules.None); - } + public void NoneTest() => RunTest(NamingRules.None); [Test] - public void UnderscoreDotsTest() - { - RunTest(NamingRules.UnderscoreDots); - } + public void UnderscoreDotsTest() => RunTest(NamingRules.UnderscoreDots); [Test] - public void UnderscoreHyphensTest() - { - RunTest(NamingRules.UnderscoreHyphens); - } + public void UnderscoreHyphensTest() => RunTest(NamingRules.UnderscoreHyphens); [Test] - public void UnderscoreDotsAndHyphensTest() - { - RunTest(NamingRules.UnderscoreDots | NamingRules.UnderscoreHyphens); - } + public void UnderscoreDotsAndHyphensTest() => RunTest(NamingRules.UnderscoreDots | NamingRules.UnderscoreHyphens); private void RunTest(NamingRules namingRules) { - BuildDomain("1", DomainUpgradeMode.Recreate, namingRules); - using (var session = domain.OpenSession()) { - using (var tx = session.OpenTransaction()) { - var person = new M1.Person { - Name = "Vasya", - Weight = 80, - Age = 20, - Phone = new M1.Phone(), - }; - tx.Complete(); - } + using (var domain = BuildDomain("1", DomainUpgradeMode.Recreate, namingRules)) + using (var session = domain.OpenSession()) + using (var tx = session.OpenTransaction()) { + var person = new M1.Person { + Name = "Vasya", + Weight = 80, + Age = 20, + Phone = new M1.Phone(), + }; + tx.Complete(); } - BuildDomain("2", DomainUpgradeMode.PerformSafely, namingRules); - using (var session = domain.OpenSession()) { - using (var tx = session.OpenTransaction()) { - var vasya = session.Query.All().Single(); - Assert.AreEqual("Vasya", vasya.Name); - Assert.AreEqual(80, vasya.Weight); - Assert.IsNotNull(vasya.Phone); - } + + using (var domain = BuildDomain("2", DomainUpgradeMode.PerformSafely, namingRules)) + using (var session = domain.OpenSession()) + using (var tx = session.OpenTransaction()) { + var vasya = session.Query.All().Single(); + Assert.AreEqual("Vasya", vasya.Name); + Assert.AreEqual(80, vasya.Weight); + Assert.IsNotNull(vasya.Phone); } } - private void BuildDomain(string version, DomainUpgradeMode upgradeMode, NamingRules namingRules) + private Domain BuildDomain(string version, DomainUpgradeMode upgradeMode, NamingRules namingRules) { - if (domain != null) - domain.DisposeSafely(); - - string ns = typeof(M1.Person).Namespace; - string nsPrefix = ns.Substring(0, ns.Length - 1); + var ns = typeof(M1.Person).Namespace; + var nsPrefix = ns.Substring(0, ns.Length - 1); var configuration = DomainConfigurationFactory.Create(); configuration.UpgradeMode = upgradeMode; @@ -85,7 +67,7 @@ private void BuildDomain(string version, DomainUpgradeMode upgradeMode, NamingRu configuration.NamingConvention.NamingRules = namingRules; using (Upgrader.Enable(version)) { - domain = Domain.Build(configuration); + return Domain.Build(configuration); } } } diff --git a/Orm/Xtensive.Orm.Tests/Issues/IssueJira0208_IncorrectUpgradeSequence/UpgradeTest.cs b/Orm/Xtensive.Orm.Tests/Issues/IssueJira0208_IncorrectUpgradeSequence/UpgradeTest.cs index bfc1450197..87d6d3e095 100644 --- a/Orm/Xtensive.Orm.Tests/Issues/IssueJira0208_IncorrectUpgradeSequence/UpgradeTest.cs +++ b/Orm/Xtensive.Orm.Tests/Issues/IssueJira0208_IncorrectUpgradeSequence/UpgradeTest.cs @@ -18,45 +18,38 @@ namespace Xtensive.Orm.Tests.Issues.IssueJira0208_IncorrectUpgradeSequence [TestFixture] public class UpgradeTest { - private Domain domain; - [SetUp] public void SetUp() { - BuildDomain("1", DomainUpgradeMode.Recreate); - using (var session = domain.OpenSession()) { - using (var tx = session.OpenTransaction()) { - var toRemove1 = new M1.EntityToRemove1(); - var toKeep1 = new M1.EntityToKeep1(toRemove1); - var toRemove2 = new M1.EntityToRemove2(); - var toKeep2 = new M1.EntityToKeep2(toRemove2); - new M1.VeryUniqueEntity(); - new M1.VeryUniqueEntity(); - tx.Complete(); - } + using (var domain = BuildDomain("1", DomainUpgradeMode.Recreate)) + using (var session = domain.OpenSession()) + using (var tx = session.OpenTransaction()) { + var toRemove1 = new M1.EntityToRemove1(); + var toKeep1 = new M1.EntityToKeep1(toRemove1); + var toRemove2 = new M1.EntityToRemove2(); + var toKeep2 = new M1.EntityToKeep2(toRemove2); + _ = new M1.VeryUniqueEntity(); + _ = new M1.VeryUniqueEntity(); + tx.Complete(); } } [Test] public void UpgradeToVersion2Test() { - BuildDomain("2", DomainUpgradeMode.PerformSafely); - using (var session = domain.OpenSession()) { - using (var tx = session.OpenTransaction()) { - var toKeep1 = session.Query.All().Single(); - var toKeep2 = session.Query.All().Single(); - Assert.AreEqual(2, session.Query.All().Count()); - } + using (var domain = BuildDomain("2", DomainUpgradeMode.PerformSafely)) + using (var session = domain.OpenSession()) + using (var tx = session.OpenTransaction()) { + var toKeep1 = session.Query.All().Single(); + var toKeep2 = session.Query.All().Single(); + Assert.AreEqual(2, session.Query.All().Count()); } } - private void BuildDomain(string version, DomainUpgradeMode upgradeMode) + private Domain BuildDomain(string version, DomainUpgradeMode upgradeMode) { - if (domain != null) - domain.DisposeSafely(); - - string ns = typeof(M1.EntityToKeep1).Namespace; - string nsPrefix = ns.Substring(0, ns.Length - 1); + var ns = typeof(M1.EntityToKeep1).Namespace; + var nsPrefix = ns.Substring(0, ns.Length - 1); var configuration = DomainConfigurationFactory.Create(); configuration.UpgradeMode = upgradeMode; @@ -65,7 +58,7 @@ private void BuildDomain(string version, DomainUpgradeMode upgradeMode) configuration.Types.Register(typeof(Upgrader)); using (Upgrader.Enable(version)) { - domain = Domain.Build(configuration); + return Domain.Build(configuration); } } } diff --git a/Orm/Xtensive.Orm.Tests/Issues/Issue_0694_SchemaUpgradeBug/UpgradeTest.cs b/Orm/Xtensive.Orm.Tests/Issues/Issue_0694_SchemaUpgradeBug/UpgradeTest.cs index 3d55f32612..fe5f16dd32 100644 --- a/Orm/Xtensive.Orm.Tests/Issues/Issue_0694_SchemaUpgradeBug/UpgradeTest.cs +++ b/Orm/Xtensive.Orm.Tests/Issues/Issue_0694_SchemaUpgradeBug/UpgradeTest.cs @@ -22,88 +22,79 @@ namespace Xtensive.Orm.Tests.Issues.Issue_0694_SchemaUpgradeBug [TestFixture] public class UpgradeTest { - private Domain domain; - [SetUp] public void SetUp() { - BuildDomain("1", DomainUpgradeMode.Recreate); - using (var session = domain.OpenSession()) { - using (var tx = session.OpenTransaction()) { - var status = new Status() {Title = "Status"}; - var media = new Media() {Title = "Media", Data = "Data"}; - media.Statuses.Add(status); - tx.Complete(); - } + using (var domain = BuildDomain("1", DomainUpgradeMode.Recreate)) + using (var session = domain.OpenSession()) + using (var tx = session.OpenTransaction()) { + var status = new Status() { Title = "Status" }; + var media = new Media() { Title = "Media", Data = "Data" }; + _ = media.Statuses.Add(status); + tx.Complete(); } } [Test] public void UpgradeToVersion2Test() { - BuildDomain("2", DomainUpgradeMode.Perform); + using (var domain = BuildDomain("2", DomainUpgradeMode.Perform)) using (var session = domain.OpenSession()) - { - using (session.OpenTransaction()) - { - var status = session.Query.All().SingleOrDefault(); - var newMedia = session.Query.All().SingleOrDefault(); - var newMediaTricky = session.Query.All().Where(c => c.Title == "Media").SingleOrDefault(); + using (session.OpenTransaction()) { + var status = session.Query.All().SingleOrDefault(); + var newMedia = session.Query.All().SingleOrDefault(); + var newMediaTricky = session.Query.All().Where(c => c.Title == "Media").SingleOrDefault(); - int statusCount = session.Query.All().Count(); - int statusAssociationCount = status != null ? status.AssociatedContent.Count() : 0; - int newMediaCount = session.Query.All().Count(); + var statusCount = session.Query.All().Count(); + var statusAssociationCount = status != null ? status.AssociatedContent.Count() : 0; + var newMediaCount = session.Query.All().Count(); - Assert.IsNotNull(status); - Assert.IsNull(newMedia); - Assert.IsNull(newMediaTricky); - Assert.AreEqual(1, statusCount); - Assert.AreEqual(0, newMediaCount); - Assert.AreEqual(0, statusAssociationCount); - } + Assert.IsNotNull(status); + Assert.IsNull(newMedia); + Assert.IsNull(newMediaTricky); + Assert.AreEqual(1, statusCount); + Assert.AreEqual(0, newMediaCount); + Assert.AreEqual(0, statusAssociationCount); } } [Test, Ignore("Default behavior changed. Namespace-only renames are tracked automatically.")] public void UpgradeToVersion3Test() { - BuildDomain("3", DomainUpgradeMode.Perform); - using (var session = domain.OpenSession()) { - using (session.OpenTransaction()) { - // No version-to-version hints, so all the types are removed - var status = session.Query.All().FirstOrDefault(); - var newMedia = session.Query.All().FirstOrDefault(); - var newMediaTricky = session.Query.All().FirstOrDefault(); + using (var domain = BuildDomain("3", DomainUpgradeMode.Perform)) + using (var session = domain.OpenSession()) + using (session.OpenTransaction()) { + // No version-to-version hints, so all the types are removed + var status = session.Query.All().FirstOrDefault(); + var newMedia = session.Query.All().FirstOrDefault(); + var newMediaTricky = session.Query.All().FirstOrDefault(); - int statusCount = session.Query.All().Count(); - int statusAssociationCount = status!=null ? status.AssociatedContent.Count() : 0; - int newMediaCount = session.Query.All().Count(); + var statusCount = session.Query.All().Count(); + var statusAssociationCount = status != null ? status.AssociatedContent.Count() : 0; + var newMediaCount = session.Query.All().Count(); - Assert.IsNull(status); - Assert.IsNull(newMedia); - Assert.IsNull(newMediaTricky); - Assert.AreEqual(0, statusCount); - Assert.AreEqual(0, newMediaCount); - Assert.AreEqual(0, statusAssociationCount); - } + Assert.IsNull(status); + Assert.IsNull(newMedia); + Assert.IsNull(newMediaTricky); + Assert.AreEqual(0, statusCount); + Assert.AreEqual(0, newMediaCount); + Assert.AreEqual(0, statusAssociationCount); } } - private void BuildDomain(string version, DomainUpgradeMode upgradeMode) + private Domain BuildDomain(string version, DomainUpgradeMode upgradeMode) { - if (domain != null) - domain.DisposeSafely(); - - string ns = typeof(Model.Version1.Content).Namespace; - string nsPrefix = ns.Substring(0, ns.Length - 1); + var ns = typeof(Model.Version1.Content).Namespace; + var nsPrefix = ns.Substring(0, ns.Length - 1); var configuration = DomainConfigurationFactory.Create(); configuration.UpgradeMode = upgradeMode; + configuration.BuildInParallel = false; configuration.Types.Register(Assembly.GetExecutingAssembly(), nsPrefix + version); configuration.Types.Register(typeof(Upgrader)); using (Upgrader.Enable(version)) { - domain = Domain.Build(configuration); + return Domain.Build(configuration); } } } diff --git a/Orm/Xtensive.Orm.Tests/Issues/Issue_0716_UpgradeFailsInValidateMode/UpgradeTest.cs b/Orm/Xtensive.Orm.Tests/Issues/Issue_0716_UpgradeFailsInValidateMode/UpgradeTest.cs index a62368f492..9617dc9bb2 100644 --- a/Orm/Xtensive.Orm.Tests/Issues/Issue_0716_UpgradeFailsInValidateMode/UpgradeTest.cs +++ b/Orm/Xtensive.Orm.Tests/Issues/Issue_0716_UpgradeFailsInValidateMode/UpgradeTest.cs @@ -24,44 +24,34 @@ namespace Xtensive.Orm.Tests.Issues.Issue_0716_UpgradeFailsInValidateMode // cases when cross-namespace movements appear. public class UpgradeTest { - private Domain domain; - [OneTimeSetUp] - public void TestSetUp() - { - Require.AllFeaturesSupported(ProviderFeatures.FullText); - } + public void TestSetUp() => Require.AllFeaturesSupported(ProviderFeatures.FullText); [SetUp] public void SetUp() { - BuildDomain("1", DomainUpgradeMode.Recreate); - using (var session = domain.OpenSession()) { - using (var tx = session.OpenTransaction()) { - var acticle = new Article(); - tx.Complete(); - } + using (var domain = BuildDomain("1", DomainUpgradeMode.Recreate)) + using (var session = domain.OpenSession()) + using (var tx = session.OpenTransaction()) { + var acticle = new Article(); + tx.Complete(); } } [Test] public void UpgradeToVersion2Test() { - BuildDomain("2", DomainUpgradeMode.Validate); - using (var session = domain.OpenSession()) { - using (session.OpenTransaction()) { - Assert.AreEqual(1, session.Query.All().Count()); - } + using (var domain = BuildDomain("2", DomainUpgradeMode.Validate)) + using (var session = domain.OpenSession()) + using (session.OpenTransaction()) { + Assert.AreEqual(1, session.Query.All().Count()); } } - private void BuildDomain(string version, DomainUpgradeMode upgradeMode) + private Domain BuildDomain(string version, DomainUpgradeMode upgradeMode) { - if (domain != null) - domain.DisposeSafely(); - - string ns = typeof(Article).Namespace; - string nsPrefix = ns.Substring(0, ns.Length - 1); + var ns = typeof(Article).Namespace; + var nsPrefix = ns.Substring(0, ns.Length - 1); var configuration = DomainConfigurationFactory.Create(); configuration.UpgradeMode = upgradeMode; @@ -69,7 +59,7 @@ private void BuildDomain(string version, DomainUpgradeMode upgradeMode) configuration.Types.Register(typeof(Upgrader)); using (Upgrader.Enable(version)) { - domain = Domain.Build(configuration); + return Domain.Build(configuration); } } } diff --git a/Orm/Xtensive.Orm.Tests/Issues/Issue_0743_UpgradeToNonNullableTypes/UpgradeTest.cs b/Orm/Xtensive.Orm.Tests/Issues/Issue_0743_UpgradeToNonNullableTypes/UpgradeTest.cs index 8d840bf558..e49bd97200 100644 --- a/Orm/Xtensive.Orm.Tests/Issues/Issue_0743_UpgradeToNonNullableTypes/UpgradeTest.cs +++ b/Orm/Xtensive.Orm.Tests/Issues/Issue_0743_UpgradeToNonNullableTypes/UpgradeTest.cs @@ -20,90 +20,83 @@ namespace Xtensive.Orm.Tests.Issues.Issue_0743_UpgradeToNonNullableTypes [TestFixture] public class UpgradeTest { - private Domain domain; - [SetUp] public void SetUp() { - BuildDomain("1", DomainUpgradeMode.Recreate); - using (var session = domain.OpenSession()) { - using (var tx = session.OpenTransaction()) { - var person1 = new Model.Version1.Person { - Name = "Person", - Age = 30, - Bytes = new byte[] {1,2,3} - }; - var person2 = new Model.Version1.Person(); - person1.Friend = person2; - person2.Friend = person1; - tx.Complete(); - } + using (var domain = BuildDomain("1", DomainUpgradeMode.Recreate)) + using (var session = domain.OpenSession()) + using (var tx = session.OpenTransaction()) { + var person1 = new Model.Version1.Person { + Name = "Person", + Age = 30, + Bytes = new byte[] { 1, 2, 3 } + }; + var person2 = new Model.Version1.Person(); + person1.Friend = person2; + person2.Friend = person1; + tx.Complete(); } } [Test] public void UpgradeToVersion2Test() { - BuildDomain("2", DomainUpgradeMode.Perform); - using (var session = domain.OpenSession()) { - using (session.OpenTransaction()) { - var persons = ( - from p in session.Query.All() - orderby p.Name - select p - ).ToList(); - Assert.AreEqual(3, persons.Count); - - var none = persons[1]; - var person1 = persons[2]; - var person2 = persons[0]; - var person3 = new Person() {Friend = person1}; - - Assert.IsNull(person3.Name); - person3.Name = string.Empty; + using (var domain = BuildDomain("2", DomainUpgradeMode.Perform)) + using (var session = domain.OpenSession()) + using (session.OpenTransaction()) { + var persons = ( + from p in session.Query.All() + orderby p.Name + select p + ).ToList(); + Assert.AreEqual(3, persons.Count); + + var none = persons[1]; + var person1 = persons[2]; + var person2 = persons[0]; + var person3 = new Person() { Friend = person1 }; - persons.Add(person3); - Session.Demand().SaveChanges(); + Assert.IsNull(person3.Name); + person3.Name = string.Empty; - Assert.AreEqual("Person", person1.Name); - Assert.AreEqual(30, person1.Age); - Assert.AreEqual(person2, person1.Friend); - AssertEx.HasSameElements(new byte[] {1,2,3}, person1.Bytes); + persons.Add(person3); + Session.Demand().SaveChanges(); - Assert.AreEqual(string.Empty, person2.Name); - Assert.AreEqual(-1, person2.Age); - Assert.AreEqual(person1, person2.Friend); + Assert.AreEqual("Person", person1.Name); + Assert.AreEqual(30, person1.Age); + Assert.AreEqual(person2, person1.Friend); + AssertEx.HasSameElements(new byte[] { 1, 2, 3 }, person1.Bytes); - Assert.AreEqual(string.Empty, person3.Name); - Assert.AreEqual(-1, person3.Age); - Assert.AreEqual(person1, person3.Friend); + Assert.AreEqual(string.Empty, person2.Name); + Assert.AreEqual(-1, person2.Age); + Assert.AreEqual(person1, person2.Friend); - Assert.AreEqual("None", none.Name); - Assert.AreEqual(-1, none.Age); - Assert.AreEqual(none, none.Friend); + Assert.AreEqual(string.Empty, person3.Name); + Assert.AreEqual(-1, person3.Age); + Assert.AreEqual(person1, person3.Friend); - foreach (var person in persons) { - Assert.AreEqual("A", person.DefaultTest1); - Assert.AreEqual(1, person.DefaultTest2); - Assert.AreEqual(new DateTime(1900,01,01), person.DefaultTest3); - if (person.Bytes.Length!=3) - AssertEx.HasSameElements(new byte[] {0}, person.Bytes); - // Structure defaults test - Assert.AreEqual("A", person.DefaultTest4.DefaultTest1); - Assert.AreEqual(1, person.DefaultTest4.DefaultTest2); - Assert.AreEqual(new DateTime(1900,01,01), person.DefaultTest4.DefaultTest3); - } + Assert.AreEqual("None", none.Name); + Assert.AreEqual(-1, none.Age); + Assert.AreEqual(none, none.Friend); + + foreach (var person in persons) { + Assert.AreEqual("A", person.DefaultTest1); + Assert.AreEqual(1, person.DefaultTest2); + Assert.AreEqual(new DateTime(1900, 01, 01), person.DefaultTest3); + if (person.Bytes.Length != 3) + AssertEx.HasSameElements(new byte[] { 0 }, person.Bytes); + // Structure defaults test + Assert.AreEqual("A", person.DefaultTest4.DefaultTest1); + Assert.AreEqual(1, person.DefaultTest4.DefaultTest2); + Assert.AreEqual(new DateTime(1900, 01, 01), person.DefaultTest4.DefaultTest3); } } } - private void BuildDomain(string version, DomainUpgradeMode upgradeMode) + private Domain BuildDomain(string version, DomainUpgradeMode upgradeMode) { - if (domain != null) - domain.DisposeSafely(); - - string ns = typeof(Model.Version1.Person).Namespace; - string nsPrefix = ns.Substring(0, ns.Length - 1); + var ns = typeof(Model.Version1.Person).Namespace; + var nsPrefix = ns.Substring(0, ns.Length - 1); var configuration = DomainConfigurationFactory.Create(); configuration.UpgradeMode = upgradeMode; @@ -111,7 +104,7 @@ private void BuildDomain(string version, DomainUpgradeMode upgradeMode) configuration.Types.Register(typeof(Upgrader)); using (Upgrader.Enable(version)) { - domain = Domain.Build(configuration); + return Domain.Build(configuration); } } } diff --git a/Orm/Xtensive.Orm.Tests/Issues/Issue_0769_ByteArrayColumnUpgrade/UpgradeTest.cs b/Orm/Xtensive.Orm.Tests/Issues/Issue_0769_ByteArrayColumnUpgrade/UpgradeTest.cs index 718aee3ca4..08916f1eb6 100644 --- a/Orm/Xtensive.Orm.Tests/Issues/Issue_0769_ByteArrayColumnUpgrade/UpgradeTest.cs +++ b/Orm/Xtensive.Orm.Tests/Issues/Issue_0769_ByteArrayColumnUpgrade/UpgradeTest.cs @@ -17,48 +17,41 @@ namespace Xtensive.Orm.Tests.Issues.Issue_0769_ByteArrayColumnUpgrade [TestFixture] public class UpgradeTest { - private Domain domain; - [OneTimeSetUp] - public void TestSetUp() - { - Require.ProviderIsNot(StorageProvider.Firebird); - } + public void TestSetUp() => Require.ProviderIsNot(StorageProvider.Firebird); [SetUp] public void SetUp() { - BuildDomain("1", DomainUpgradeMode.Recreate); - using (var session = domain.OpenSession()) { - using (var tx = session.OpenTransaction()) { - var person = new Person { - Name = "Person", - Bytes = new byte[] {1, 2, 3} - }; + using (var domain = BuildDomain("1", DomainUpgradeMode.Recreate)) + using (var session = domain.OpenSession()) + using (var tx = session.OpenTransaction()) { + var person = new Person { + Name = "Person", + Bytes = new byte[] { 1, 2, 3 } + }; - var bytesColumn = GetColumnInfo(Upgrader.TargetStorageModel, person.TypeInfo, "Bytes"); - var driver = TestSqlDriver.Create(domain.Configuration.ConnectionInfo); - var expected = driver.TypeMappings[typeof (byte[])].MapType().Length; - Assert.AreEqual(expected, bytesColumn.Type.Length); + var bytesColumn = GetColumnInfo(Upgrader.TargetStorageModel, person.TypeInfo, "Bytes"); + var driver = TestSqlDriver.Create(domain.Configuration.ConnectionInfo); + var expected = driver.TypeMappings[typeof(byte[])].MapType().Length; + Assert.AreEqual(expected, bytesColumn.Type.Length); - tx.Complete(); - } + tx.Complete(); } } [Test] public void UpgradeToVersion2Test() { - BuildDomain("2", DomainUpgradeMode.Perform); - using (var session = domain.OpenSession()) { - using (session.OpenTransaction()) { - var person = session.Query.All().Single(); - AssertEx.HasSameElements("Person", person.Name); - AssertEx.HasSameElements(new byte[] {1, 2, 3}, person.Bytes); + using (var domain = BuildDomain("2", DomainUpgradeMode.Perform)) + using (var session = domain.OpenSession()) + using (session.OpenTransaction()) { + var person = session.Query.All().Single(); + AssertEx.HasSameElements("Person", person.Name); + AssertEx.HasSameElements(new byte[] { 1, 2, 3 }, person.Bytes); - var bytesColumn = GetColumnInfo(Upgrader.TargetStorageModel, person.TypeInfo, "Bytes"); - Assert.AreEqual(null, bytesColumn.Type.Length); - } + var bytesColumn = GetColumnInfo(Upgrader.TargetStorageModel, person.TypeInfo, "Bytes"); + Assert.AreEqual(null, bytesColumn.Type.Length); } } @@ -70,21 +63,19 @@ private StorageColumnInfo GetColumnInfo(StorageModel model, TypeInfo type, strin return table.Columns[field.MappingName]; } - private void BuildDomain(string version, DomainUpgradeMode upgradeMode) + private Domain BuildDomain(string version, DomainUpgradeMode upgradeMode) { - if (domain!=null) - domain.DisposeSafely(); - - string ns = typeof (Person).Namespace; - string nsPrefix = ns.Substring(0, ns.Length - 1); + var ns = typeof (Person).Namespace; + var nsPrefix = ns.Substring(0, ns.Length - 1); var configuration = DomainConfigurationFactory.Create(); configuration.UpgradeMode = upgradeMode; configuration.Types.Register(Assembly.GetExecutingAssembly(), nsPrefix + version); configuration.Types.Register(typeof (Upgrader)); - using (Upgrader.Enable(version)) - domain = Domain.Build(configuration); + using (Upgrader.Enable(version)) { + return Domain.Build(configuration); + } } } } \ No newline at end of file diff --git a/Orm/Xtensive.Orm.Tests/Issues/Issue_0837_HintGeneratorBug/UpgradeTest.cs b/Orm/Xtensive.Orm.Tests/Issues/Issue_0837_HintGeneratorBug/UpgradeTest.cs index 7970f18009..86559abb3a 100644 --- a/Orm/Xtensive.Orm.Tests/Issues/Issue_0837_HintGeneratorBug/UpgradeTest.cs +++ b/Orm/Xtensive.Orm.Tests/Issues/Issue_0837_HintGeneratorBug/UpgradeTest.cs @@ -17,46 +17,39 @@ namespace Xtensive.Orm.Tests.Issues.Issue_0834_HintGeneratorBug [TestFixture] public class UpgradeTest { - private Domain domain; - [SetUp] public void SetUp() { - BuildDomain("1", DomainUpgradeMode.Recreate); - using (var session = domain.OpenSession()) { - using (var tx = session.OpenTransaction()) { - var a = new M1.Base() { BaseTitle = "a.Base"}; - var b = new M1.Derived() { BaseTitle = "b.Base", DerivedTitle = "b.Derived" }; - tx.Complete(); - } + using (var domain = BuildDomain("1", DomainUpgradeMode.Recreate)) + using (var session = domain.OpenSession()) + using (var tx = session.OpenTransaction()) { + _ = new M1.Base() { BaseTitle = "a.Base" }; + _ = new M1.Derived() { BaseTitle = "b.Base", DerivedTitle = "b.Derived" }; + tx.Complete(); } } [Test] public void UpgradeToVersion2Test() { - BuildDomain("2", DomainUpgradeMode.Perform); - using (var session = domain.OpenSession()) { - using (session.OpenTransaction()) { - var a = session.Query.All().SingleOrDefault(); - Assert.IsNotNull(a); - Assert.AreEqual("a.Base", a.BaseTitle); + using (var domain = BuildDomain("2", DomainUpgradeMode.Perform)) + using (var session = domain.OpenSession()) + using (session.OpenTransaction()) { + var a = session.Query.All().SingleOrDefault(); + Assert.IsNotNull(a); + Assert.AreEqual("a.Base", a.BaseTitle); - var b = session.Query.All().SingleOrDefault(); - Assert.IsNotNull(b); - Assert.AreEqual("b.Base", b.BaseTitle); - Assert.AreEqual("b.Derived", b.DerivedTitle); - } + var b = session.Query.All().SingleOrDefault(); + Assert.IsNotNull(b); + Assert.AreEqual("b.Base", b.BaseTitle); + Assert.AreEqual("b.Derived", b.DerivedTitle); } } - private void BuildDomain(string version, DomainUpgradeMode upgradeMode) + private Domain BuildDomain(string version, DomainUpgradeMode upgradeMode) { - if (domain != null) - domain.DisposeSafely(); - - string ns = typeof(M1.Base).Namespace; - string nsPrefix = ns.Substring(0, ns.Length - 1); + var ns = typeof(M1.Base).Namespace; + var nsPrefix = ns.Substring(0, ns.Length - 1); var configuration = DomainConfigurationFactory.Create(); configuration.UpgradeMode = upgradeMode; @@ -64,7 +57,7 @@ private void BuildDomain(string version, DomainUpgradeMode upgradeMode) configuration.Types.Register(typeof(Upgrader)); using (Upgrader.Enable(version)) { - domain = Domain.Build(configuration); + return Domain.Build(configuration); } } } diff --git a/Orm/Xtensive.Orm.Tests/Issues/Issue_0841_HintGeneratorBug/UpgradeTest.cs b/Orm/Xtensive.Orm.Tests/Issues/Issue_0841_HintGeneratorBug/UpgradeTest.cs index 656eee400d..a3666f0afd 100644 --- a/Orm/Xtensive.Orm.Tests/Issues/Issue_0841_HintGeneratorBug/UpgradeTest.cs +++ b/Orm/Xtensive.Orm.Tests/Issues/Issue_0841_HintGeneratorBug/UpgradeTest.cs @@ -17,41 +17,34 @@ namespace Xtensive.Orm.Tests.Issues.Issue_0841_HintGeneratorBug [TestFixture] public class UpgradeTest { - private Domain domain; - [SetUp] public void SetUp() { - BuildDomain("1", DomainUpgradeMode.Recreate); - using (var session = domain.OpenSession()) { - using (var tx = session.OpenTransaction()) { - var a = new M1.Base(); - var b = new M1.Derived() { Text = "B" }; - tx.Complete(); - } + using (var domain = BuildDomain("1", DomainUpgradeMode.Recreate)) + using (var session = domain.OpenSession()) + using (var tx = session.OpenTransaction()) { + _ = new M1.Base(); + _ = new M1.Derived() { Text = "B" }; + tx.Complete(); } } [Test] public void UpgradeToVersion2Test() { - BuildDomain("2", DomainUpgradeMode.Perform); - using (var session = domain.OpenSession()) { - using (session.OpenTransaction()) { - var b = session.Query.All().SingleOrDefault(); - Assert.IsNotNull(b); - Assert.AreEqual("B", b.Text); - } + using (var domain = BuildDomain("2", DomainUpgradeMode.Perform)) + using (var session = domain.OpenSession()) + using (session.OpenTransaction()) { + var b = session.Query.All().SingleOrDefault(); + Assert.IsNotNull(b); + Assert.AreEqual("B", b.Text); } } - private void BuildDomain(string version, DomainUpgradeMode upgradeMode) + private Domain BuildDomain(string version, DomainUpgradeMode upgradeMode) { - if (domain != null) - domain.DisposeSafely(); - - string ns = typeof(M1.Base).Namespace; - string nsPrefix = ns.Substring(0, ns.Length - 1); + var ns = typeof(M1.Base).Namespace; + var nsPrefix = ns.Substring(0, ns.Length - 1); var configuration = DomainConfigurationFactory.Create(); configuration.UpgradeMode = upgradeMode; @@ -59,7 +52,7 @@ private void BuildDomain(string version, DomainUpgradeMode upgradeMode) configuration.Types.Register(typeof(Upgrader)); using (Upgrader.Enable(version)) { - domain = Domain.Build(configuration); + return Domain.Build(configuration); } } } diff --git a/Orm/Xtensive.Orm.Tests/Issues/Issue_0841_HintGeneratorBug2/UpgradeTest.cs b/Orm/Xtensive.Orm.Tests/Issues/Issue_0841_HintGeneratorBug2/UpgradeTest.cs index b152fe2408..56fc14be32 100644 --- a/Orm/Xtensive.Orm.Tests/Issues/Issue_0841_HintGeneratorBug2/UpgradeTest.cs +++ b/Orm/Xtensive.Orm.Tests/Issues/Issue_0841_HintGeneratorBug2/UpgradeTest.cs @@ -18,49 +18,39 @@ namespace Xtensive.Orm.Tests.Issues.Issue_0841_HintGeneratorBug2 [TestFixture] public class UpgradeTest { - private Domain domain; - [OneTimeSetUp] - public void TestSetUp() - { - Require.AllFeaturesSupported(ProviderFeatures.UpdateFrom); - } + public void TestSetUp() => Require.AllFeaturesSupported(ProviderFeatures.UpdateFrom); [SetUp] public void SetUp() { - BuildDomain("1", DomainUpgradeMode.Recreate); - using (var session = domain.OpenSession()) { - using (var tx = session.OpenTransaction()) { - var a = new M1.Base(); - var b = new M1.Derived() { Text = "B" }; - tx.Complete(); - } + using (var domain = BuildDomain("1", DomainUpgradeMode.Recreate)) + using (var session = domain.OpenSession()) + using (var tx = session.OpenTransaction()) { + _ = new M1.Base(); + _ = new M1.Derived() { Text = "B" }; + tx.Complete(); } } [Test] public void UpgradeToVersion2Test() { - BuildDomain("2", DomainUpgradeMode.Perform); - using (var session = domain.OpenSession()) { - using (session.OpenTransaction()) { - var a = session.Query.All().SingleOrDefault(e => e.Text==null); - var b = session.Query.All().SingleOrDefault(e => e.Text!=null); - Assert.IsNotNull(a); - Assert.IsNotNull(b); - Assert.AreEqual("B", b.Text); - } + using (var domain = BuildDomain("2", DomainUpgradeMode.Perform)) + using (var session = domain.OpenSession()) + using (session.OpenTransaction()) { + var a = session.Query.All().SingleOrDefault(e => e.Text == null); + var b = session.Query.All().SingleOrDefault(e => e.Text != null); + Assert.IsNotNull(a); + Assert.IsNotNull(b); + Assert.AreEqual("B", b.Text); } } - private void BuildDomain(string version, DomainUpgradeMode upgradeMode) + private Domain BuildDomain(string version, DomainUpgradeMode upgradeMode) { - if (domain != null) - domain.DisposeSafely(); - - string ns = typeof(M1.Base).Namespace; - string nsPrefix = ns.Substring(0, ns.Length - 1); + var ns = typeof(M1.Base).Namespace; + var nsPrefix = ns.Substring(0, ns.Length - 1); var configuration = DomainConfigurationFactory.Create(); configuration.UpgradeMode = upgradeMode; @@ -68,7 +58,7 @@ private void BuildDomain(string version, DomainUpgradeMode upgradeMode) configuration.Types.Register(typeof(Upgrader)); using (Upgrader.Enable(version)) { - domain = Domain.Build(configuration); + return Domain.Build(configuration); } } } diff --git a/Orm/Xtensive.Orm.Tests/Issues/Issue_0841_HintGeneratorBug3/UpgradeTest.cs b/Orm/Xtensive.Orm.Tests/Issues/Issue_0841_HintGeneratorBug3/UpgradeTest.cs index 0273dc4c4a..8331744350 100644 --- a/Orm/Xtensive.Orm.Tests/Issues/Issue_0841_HintGeneratorBug3/UpgradeTest.cs +++ b/Orm/Xtensive.Orm.Tests/Issues/Issue_0841_HintGeneratorBug3/UpgradeTest.cs @@ -17,49 +17,39 @@ namespace Xtensive.Orm.Tests.Issues.Issue_0841_HintGeneratorBug3 [TestFixture] public class UpgradeTest { - private Domain domain; - [OneTimeSetUp] - public void TestSetUp() - { - Require.ProviderIs(StorageProvider.SqlServer); - } + public void TestSetUp() => Require.ProviderIs(StorageProvider.SqlServer); [SetUp] public void SetUp() { - BuildDomain("1", DomainUpgradeMode.Recreate); - using (var session = domain.OpenSession()) { - using (var tx = session.OpenTransaction()) { - var a = new M1.Base(); - var b = new M1.Derived() { Text = "B" }; - tx.Complete(); - } + using (var domain = BuildDomain("1", DomainUpgradeMode.Recreate)) + using (var session = domain.OpenSession()) + using (var tx = session.OpenTransaction()) { + _ = new M1.Base(); + _ = new M1.Derived() { Text = "B" }; + tx.Complete(); } } [Test] public void UpgradeToVersion2Test() { - BuildDomain("2", DomainUpgradeMode.Perform); - using (var session = domain.OpenSession()) { - using (session.OpenTransaction()) { - var a = session.Query.All().SingleOrDefault(e => e.Text==null); - var b = session.Query.All().SingleOrDefault(e => e.Text!=null); - Assert.IsNotNull(a); - Assert.IsNotNull(b); - Assert.AreEqual("B", b.Text); - } + using (var domain = BuildDomain("2", DomainUpgradeMode.Perform)) + using (var session = domain.OpenSession()) + using (session.OpenTransaction()) { + var a = session.Query.All().SingleOrDefault(e => e.Text == null); + var b = session.Query.All().SingleOrDefault(e => e.Text != null); + Assert.IsNotNull(a); + Assert.IsNotNull(b); + Assert.AreEqual("B", b.Text); } } - private void BuildDomain(string version, DomainUpgradeMode upgradeMode) + private Domain BuildDomain(string version, DomainUpgradeMode upgradeMode) { - if (domain != null) - domain.DisposeSafely(); - - string ns = typeof(M1.Base).Namespace; - string nsPrefix = ns.Substring(0, ns.Length - 1); + var ns = typeof(M1.Base).Namespace; + var nsPrefix = ns.Substring(0, ns.Length - 1); var configuration = DomainConfigurationFactory.Create(); configuration.UpgradeMode = upgradeMode; @@ -67,7 +57,7 @@ private void BuildDomain(string version, DomainUpgradeMode upgradeMode) configuration.Types.Register(typeof(Upgrader)); using (Upgrader.Enable(version)) { - domain = Domain.Build(configuration); + return Domain.Build(configuration); } } } diff --git a/Orm/Xtensive.Orm.Tests/Issues/Issue_0841_HintGeneratorBug4/UpgradeTest.cs b/Orm/Xtensive.Orm.Tests/Issues/Issue_0841_HintGeneratorBug4/UpgradeTest.cs index 16f332c393..bd386e596e 100644 --- a/Orm/Xtensive.Orm.Tests/Issues/Issue_0841_HintGeneratorBug4/UpgradeTest.cs +++ b/Orm/Xtensive.Orm.Tests/Issues/Issue_0841_HintGeneratorBug4/UpgradeTest.cs @@ -17,43 +17,36 @@ namespace Xtensive.Orm.Tests.Issues.Issue_0841_HintGeneratorBug4 [TestFixture] public class UpgradeTest { - private Domain domain; - [SetUp] public void SetUp() { - BuildDomain("1", DomainUpgradeMode.Recreate); - using (var session = domain.OpenSession()) { - using (var tx = session.OpenTransaction()) { - var a = new M1.Base(); - var b = new M1.Derived() { Text = "B" }; - tx.Complete(); - } + using (var domain = BuildDomain("1", DomainUpgradeMode.Recreate)) + using (var session = domain.OpenSession()) + using (var tx = session.OpenTransaction()) { + _ = new M1.Base(); + _ = new M1.Derived() { Text = "B" }; + tx.Complete(); } } [Test] public void UpgradeToVersion2Test() { - BuildDomain("2", DomainUpgradeMode.Perform); - using (var session = domain.OpenSession()) { - using (session.OpenTransaction()) { - var a = session.Query.All().SingleOrDefault(e => e.Text==null); - var b = session.Query.All().SingleOrDefault(e => e.Text!=null); - Assert.IsNotNull(a); - Assert.IsNotNull(b); - Assert.AreEqual("B", b.Text); - } + using (var domain = BuildDomain("2", DomainUpgradeMode.Perform)) + using (var session = domain.OpenSession()) + using (session.OpenTransaction()) { + var a = session.Query.All().SingleOrDefault(e => e.Text == null); + var b = session.Query.All().SingleOrDefault(e => e.Text != null); + Assert.IsNotNull(a); + Assert.IsNotNull(b); + Assert.AreEqual("B", b.Text); } } - private void BuildDomain(string version, DomainUpgradeMode upgradeMode) + private Domain BuildDomain(string version, DomainUpgradeMode upgradeMode) { - if (domain != null) - domain.DisposeSafely(); - - string ns = typeof(M1.Base).Namespace; - string nsPrefix = ns.Substring(0, ns.Length - 1); + var ns = typeof(M1.Base).Namespace; + var nsPrefix = ns.Substring(0, ns.Length - 1); var configuration = DomainConfigurationFactory.Create(); configuration.UpgradeMode = upgradeMode; @@ -61,7 +54,7 @@ private void BuildDomain(string version, DomainUpgradeMode upgradeMode) configuration.Types.Register(typeof(Upgrader)); using (Upgrader.Enable(version)) { - domain = Domain.Build(configuration); + return Domain.Build(configuration); } } } diff --git a/Orm/Xtensive.Orm.Tests/Upgrade/DataUpgrade/DataUpgradeTest.cs b/Orm/Xtensive.Orm.Tests/Upgrade/DataUpgrade/DataUpgradeTest.cs index df25aa1352..a44067244b 100644 --- a/Orm/Xtensive.Orm.Tests/Upgrade/DataUpgrade/DataUpgradeTest.cs +++ b/Orm/Xtensive.Orm.Tests/Upgrade/DataUpgrade/DataUpgradeTest.cs @@ -160,9 +160,9 @@ private void FillData(Domain domain) c1.RefA = a1; c1.RefB = b1; c2.RefA = b1; - d1.RefA.Add(a1); - d1.RefA.Add(b1); - d1.RefA.Add(c1); + _ = d1.RefA.Add(a1); + _ = d1.RefA.Add(b1); + _ = d1.RefA.Add(c1); t.Complete(); } } diff --git a/Orm/Xtensive.Orm.Tests/Upgrade/EntitySetUpgrade/UpgradeTest.cs b/Orm/Xtensive.Orm.Tests/Upgrade/EntitySetUpgrade/UpgradeTest.cs index 2502a4da61..b880d09f1d 100644 --- a/Orm/Xtensive.Orm.Tests/Upgrade/EntitySetUpgrade/UpgradeTest.cs +++ b/Orm/Xtensive.Orm.Tests/Upgrade/EntitySetUpgrade/UpgradeTest.cs @@ -56,8 +56,8 @@ public async Task UpgradeToVersion2AsyncTest() private Domain BuildDomain(string version, DomainUpgradeMode upgradeMode) { - string ns = typeof(Person).Namespace; - string nsPrefix = ns.Substring(0, ns.Length - 1); + var ns = typeof(Person).Namespace; + var nsPrefix = ns.Substring(0, ns.Length - 1); var configuration = DomainConfigurationFactory.Create(); configuration.UpgradeMode = upgradeMode; @@ -65,15 +65,14 @@ private Domain BuildDomain(string version, DomainUpgradeMode upgradeMode) configuration.Types.Register(typeof(Upgrader)); using (Upgrader.Enable(version)) { - var domain = Domain.Build(configuration); - return domain; + return Domain.Build(configuration); } } private async Task BuildDomainAsync(string version, DomainUpgradeMode upgradeMode) { - string ns = typeof(Person).Namespace; - string nsPrefix = ns.Substring(0, ns.Length - 1); + var ns = typeof(Person).Namespace; + var nsPrefix = ns.Substring(0, ns.Length - 1); var configuration = DomainConfigurationFactory.Create(); configuration.UpgradeMode = upgradeMode; diff --git a/Orm/Xtensive.Orm.Tests/Upgrade/Recycled/RecycledUpgradeTest.cs b/Orm/Xtensive.Orm.Tests/Upgrade/Recycled/RecycledUpgradeTest.cs index 7200f70ef5..569e568602 100644 --- a/Orm/Xtensive.Orm.Tests/Upgrade/Recycled/RecycledUpgradeTest.cs +++ b/Orm/Xtensive.Orm.Tests/Upgrade/Recycled/RecycledUpgradeTest.cs @@ -19,104 +19,98 @@ namespace Xtensive.Orm.Tests.Upgrade.Recycled [TestFixture, Category("Upgrade")] public class RecycledUpgradeTest { - private Domain domain; - [SetUp] public void SetUp() { - BuildDomain("1", DomainUpgradeMode.Recreate); - FillData(); + using (var domain = BuildDomain("1", DomainUpgradeMode.Recreate)) { + FillData(domain); + } } [Test] public void UpgradeToVersion2Test() { - BuildDomain("2", DomainUpgradeMode.Perform); - using (var session = domain.OpenSession()) { - using (session.OpenTransaction()) { - Assert.AreEqual(4, session.Query.All().Count()); - Assert.AreEqual(2, session.Query.All().Count()); - Assert.AreEqual(2, session.Query.All().Count()); + using (var domain = BuildDomain("2", DomainUpgradeMode.Perform)) + using (var session = domain.OpenSession()) + using (session.OpenTransaction()) { + Assert.AreEqual(4, session.Query.All().Count()); + Assert.AreEqual(2, session.Query.All().Count()); + Assert.AreEqual(2, session.Query.All().Count()); + + Assert.AreEqual("Island Trading", session.Query.All() + .First(employee => employee.Name == "Nancy Davolio").CompanyName); + Assert.AreEqual("Cowes, UK", session.Query.All() + .First(customer => customer.Name == "Helen Bennett").Address); - Assert.AreEqual("Island Trading", session.Query.All() - .First(employee => employee.Name=="Nancy Davolio").CompanyName); - Assert.AreEqual("Cowes, UK", session.Query.All() - .First(customer => customer.Name=="Helen Bennett").Address); - - Assert.AreEqual(4, session.Query.All().Count()); - Assert.AreEqual("Maxilaku", session.Query.All().First(order => - order.Employee.Name=="Michael Suyama" && order.Customer.Name=="Helen Bennett") - .ProductName); - } + Assert.AreEqual(4, session.Query.All().Count()); + Assert.AreEqual("Maxilaku", session.Query.All().First(order => + order.Employee.Name == "Michael Suyama" && order.Customer.Name == "Helen Bennett") + .ProductName); } } - private void BuildDomain(string version, DomainUpgradeMode upgradeMode) + private Domain BuildDomain(string version, DomainUpgradeMode upgradeMode) { - if (domain != null) - domain.DisposeSafely(); - var configuration = DomainConfigurationFactory.Create(); configuration.UpgradeMode = upgradeMode; configuration.Types.Register(Assembly.GetExecutingAssembly(), "Xtensive.Orm.Tests.Upgrade.Recycled.Model.Version" + version); configuration.Types.Register(typeof(Upgrader)); using (Upgrader.Enable(version)) { - domain = Domain.Build(configuration); + return Domain.Build(configuration); } } #region Data filler - private void FillData() + private void FillData(Domain domain) { - using (var session = domain.OpenSession()) { - using (var transactionScope = session.OpenTransaction()) { - // BusinessContacts - var helen = new Model.Version1.Customer() { - Address = "Cowes, UK", - Name = "Helen Bennett" - }; - var philip = new Model.Version1.Customer { - Address = "Brandenburg, Germany", - Name = "Philip Cramer" - }; + using (var session = domain.OpenSession()) + using (var transactionScope = session.OpenTransaction()) { + // BusinessContacts + var helen = new Model.Version1.Customer() { + Address = "Cowes, UK", + Name = "Helen Bennett" + }; + var philip = new Model.Version1.Customer { + Address = "Brandenburg, Germany", + Name = "Philip Cramer" + }; + + // Employies + var nancy = new Model.Version1.Employee { + CompanyName = "Island Trading", + Name = "Nancy Davolio", + }; + var michael = new Model.Version1.Employee { + CompanyName = "Koniglich Essen", + Name = "Michael Suyama", + }; - // Employies - var nancy = new Model.Version1.Employee { - CompanyName = "Island Trading", - Name = "Nancy Davolio", - }; - var michael = new Model.Version1.Employee { - CompanyName = "Koniglich Essen", - Name = "Michael Suyama", - }; + // Orders + _ = new Model.Version1.Order { + Customer = helen, + Employee = michael, + ProductName = "Maxilaku" + }; + _ = new Model.Version1.Order { + Customer = helen, + Employee = nancy, + ProductName = "Filo Mix" + }; + _ = new Model.Version1.Order { + Customer = philip, + Employee = michael, + ProductName = "Tourtiere" + }; + _ = new Model.Version1.Order { + Customer = philip, + Employee = nancy, + ProductName = "Pate chinois" + }; - // Orders - new Model.Version1.Order { - Customer = helen, - Employee = michael, - ProductName = "Maxilaku" - }; - new Model.Version1.Order { - Customer = helen, - Employee = nancy, - ProductName = "Filo Mix" - }; - new Model.Version1.Order { - Customer = philip, - Employee = michael, - ProductName = "Tourtiere" - }; - new Model.Version1.Order { - Customer = philip, - Employee = nancy, - ProductName = "Pate chinois" - }; - - // Commiting changes - transactionScope.Complete(); - } + // Commiting changes + transactionScope.Complete(); } } diff --git a/Orm/Xtensive.Orm.Tests/Upgrade/Sample3/Sample3UpgradeTest.cs b/Orm/Xtensive.Orm.Tests/Upgrade/Sample3/Sample3UpgradeTest.cs index 76cdff1c04..feca61c76a 100644 --- a/Orm/Xtensive.Orm.Tests/Upgrade/Sample3/Sample3UpgradeTest.cs +++ b/Orm/Xtensive.Orm.Tests/Upgrade/Sample3/Sample3UpgradeTest.cs @@ -21,66 +21,61 @@ namespace Xtensive.Orm.Tests.Upgrade.Sample3 [TestFixture, Category("Upgrade")] public class Sample3UpgradeTest { - private Domain domain; - [SetUp] public void SetUp() { - BuildDomain("1", DomainUpgradeMode.Recreate); - FillData(); + using (var domain = BuildDomain("1", DomainUpgradeMode.Recreate)) { + FillData(domain); + } } [Test] public void UpgradeToVersion2Test() { - BuildDomain("2", DomainUpgradeMode.Perform); - using (var session = domain.OpenSession()) { - using (session.OpenTransaction()) { - Assert.AreEqual(1, session.Query.All().Count()); - var emp = session.Query.All().FirstOrDefault(); - Assert.AreEqual("Sales", emp.DepartmentName); - var order = session.Query.All().FirstOrDefault(); - var productNames = order.Items.Select(item => item.ProductName).ToCommaDelimitedString(); - Console.WriteLine(string.Format("Order {{\tSeller = {0}\n\tProducts = {1}\n}}", - order.Seller.FullName, productNames)); - // Console.WriteLine(order); - Assert.AreEqual(1, order.Items.Count); - } + using (var domain = BuildDomain("2", DomainUpgradeMode.Perform)) + using (var session = domain.OpenSession()) + using (session.OpenTransaction()) { + Assert.AreEqual(1, session.Query.All().Count()); + var emp = session.Query.All().FirstOrDefault(); + Assert.AreEqual("Sales", emp.DepartmentName); + var order = session.Query.All().FirstOrDefault(); + var productNames = order.Items.Select(item => item.ProductName).ToCommaDelimitedString(); + Console.WriteLine($"Order {{\tSeller = {order.Seller.FullName}\n\tProducts = {productNames}\n}}"); + // Console.WriteLine(order); + Assert.AreEqual(1, order.Items.Count); } } - private void BuildDomain(string version, DomainUpgradeMode upgradeMode) + private Domain BuildDomain(string version, DomainUpgradeMode upgradeMode) { - if (domain != null) - domain.DisposeSafely(); - var configuration = DomainConfigurationFactory.Create(); configuration.UpgradeMode = upgradeMode; configuration.Types.Register(Assembly.GetExecutingAssembly(), "Xtensive.Orm.Tests.Upgrade.Sample3.Model.Version" + version); configuration.Types.Register(typeof(Upgrader)); using (Upgrader.Enable(version)) { - domain = Domain.Build(configuration); + return Domain.Build(configuration); } } #region Data filler - private void FillData() + private void FillData(Domain domain) { - using (var session = domain.OpenSession()) { - using (var transactionScope = session.OpenTransaction()) { - var e1 =new Model.Version1.Employee { - FirstName = "Andrew", - LastName = "Fuller", - Department = "Sales", - IsHead = false - }; - new Model.Version1.Order { - Amount = 1, ProductName = "P1", Seller = e1 - }; - transactionScope.Complete(); - } + using (var session = domain.OpenSession()) + using (var transactionScope = session.OpenTransaction()) { + var e1 = new Model.Version1.Employee { + FirstName = "Andrew", + LastName = "Fuller", + Department = "Sales", + IsHead = false + }; + _ = new Model.Version1.Order { + Amount = 1, + ProductName = "P1", + Seller = e1 + }; + transactionScope.Complete(); } } diff --git a/Orm/Xtensive.Orm.Tests/Upgrade/UpgradeAndNamingRules/UpgradeTest.cs b/Orm/Xtensive.Orm.Tests/Upgrade/UpgradeAndNamingRules/UpgradeTest.cs index 3eb2135a71..62f13f6c01 100644 --- a/Orm/Xtensive.Orm.Tests/Upgrade/UpgradeAndNamingRules/UpgradeTest.cs +++ b/Orm/Xtensive.Orm.Tests/Upgrade/UpgradeAndNamingRules/UpgradeTest.cs @@ -18,41 +18,34 @@ namespace Xtensive.Orm.Tests.Upgrade.UpgradeAndNamingRules [TestFixture] public class UpgradeTest { - private Domain domain; - [SetUp] public void SetUp() { - BuildDomain("1", DomainUpgradeMode.Recreate); - using (domain.OpenSession()) { - using (var tx = Session.Current.OpenTransaction()) { - var person = new M1.Person(); - person.Friend = person; - tx.Complete(); - } + using (var domain = BuildDomain("1", DomainUpgradeMode.Recreate)) + using (var session = domain.OpenSession()) + using (var tx = session.OpenTransaction()) { + var person = new M1.Person(); + person.Friend = person; + tx.Complete(); } } [Test] public void UpgradeToVersion2Test() { - BuildDomain("2", DomainUpgradeMode.Perform); - using (domain.OpenSession()) { - using (Session.Current.OpenTransaction()) { - var person = Query.All().SingleOrDefault(); - Assert.NotNull(person); - Assert.AreSame(person, person.NewFriend); - } + using (var domain = BuildDomain("2", DomainUpgradeMode.Perform)) + using (var session = domain.OpenSession()) + using (var tx = session.OpenTransaction()) { + var person = session.Query.All().SingleOrDefault(); + Assert.NotNull(person); + Assert.AreSame(person, person.NewFriend); } } - private void BuildDomain(string version, DomainUpgradeMode upgradeMode) + private Domain BuildDomain(string version, DomainUpgradeMode upgradeMode) { - if (domain != null) - domain.DisposeSafely(); - - string ns = typeof(M1.Person).Namespace; - string nsPrefix = ns.Substring(0, ns.Length - 1); + var ns = typeof(M1.Person).Namespace; + var nsPrefix = ns.Substring(0, ns.Length - 1); var configuration = DomainConfigurationFactory.Create(); configuration.UpgradeMode = upgradeMode; @@ -61,7 +54,7 @@ private void BuildDomain(string version, DomainUpgradeMode upgradeMode) configuration.NamingConvention.NamingRules = NamingRules.UnderscoreDots; using (Upgrader.Enable(version)) { - domain = Domain.Build(configuration); + return Domain.Build(configuration); } } } diff --git a/Orm/Xtensive.Orm.Tests/Upgrade/UpgradeToStructure/UpgradeTest.cs b/Orm/Xtensive.Orm.Tests/Upgrade/UpgradeToStructure/UpgradeTest.cs index e1ebbcb1fb..09f8d7c12d 100644 --- a/Orm/Xtensive.Orm.Tests/Upgrade/UpgradeToStructure/UpgradeTest.cs +++ b/Orm/Xtensive.Orm.Tests/Upgrade/UpgradeToStructure/UpgradeTest.cs @@ -18,40 +18,33 @@ namespace Xtensive.Orm.Tests.Upgrade.UpgradeToStructure [Explicit("This functionality was requested internally + there is a workaround with custom upgrade handler.")] public class UpgradeTest { - private Domain domain; - [SetUp] public void SetUp() { - BuildDomain("1", DomainUpgradeMode.Recreate); - using (domain.OpenSession()) { - using (var tx = Session.Current.OpenTransaction()) { - var person = new M1.Person {Title = "Alex"}; - tx.Complete(); - } + using (var domain = BuildDomain("1", DomainUpgradeMode.Recreate)) + using (domain.OpenSession()) + using (var tx = Session.Current.OpenTransaction()) { + var person = new M1.Person { Title = "Alex" }; + tx.Complete(); } } [Test] public void UpgradeToVersion2Test() { - BuildDomain("2", DomainUpgradeMode.Perform); - using (domain.OpenSession()) { - using (Session.Current.OpenTransaction()) { - var person = Query.All().SingleOrDefault(); - Assert.NotNull(person); - Assert.AreEqual("Alex", person.Info.Title); - } + using (var domain = BuildDomain("2", DomainUpgradeMode.Perform)) + using (var session = domain.OpenSession()) + using (var tx = session.OpenTransaction()) { + var person = session.Query.All().SingleOrDefault(); + Assert.NotNull(person); + Assert.AreEqual("Alex", person.Info.Title); } } - private void BuildDomain(string version, DomainUpgradeMode upgradeMode) + private Domain BuildDomain(string version, DomainUpgradeMode upgradeMode) { - if (domain != null) - domain.DisposeSafely(); - - string ns = typeof(M1.Person).Namespace; - string nsPrefix = ns.Substring(0, ns.Length - 1); + var ns = typeof(M1.Person).Namespace; + var nsPrefix = ns.Substring(0, ns.Length - 1); var configuration = DomainConfigurationFactory.Create(); configuration.UpgradeMode = upgradeMode; @@ -59,7 +52,7 @@ private void BuildDomain(string version, DomainUpgradeMode upgradeMode) configuration.Types.Register(typeof(Upgrader)); using (Upgrader.Enable(version)) { - domain = Domain.Build(configuration); + return Domain.Build(configuration); } } } From 886992fa5066005a88da6167d9a0d3ea55359c0e Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Fri, 24 Dec 2021 17:32:36 +0500 Subject: [PATCH 07/13] Cross appy support --- .../v4_0/ServerInfoProvider.cs | 15 ++++++-- .../Sql.Drivers.Firebird/v4_0/Translator.cs | 35 +++++++++++++++++-- 2 files changed, 44 insertions(+), 6 deletions(-) diff --git a/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/ServerInfoProvider.cs b/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/ServerInfoProvider.cs index e616e389ea..519176fe1f 100644 --- a/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/ServerInfoProvider.cs +++ b/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/ServerInfoProvider.cs @@ -1,11 +1,20 @@ -using System; -using System.Collections.Generic; -using System.Text; +// Copyright (C) 2021 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. + +using Xtensive.Sql.Info; namespace Xtensive.Sql.Drivers.Firebird.v4_0 { internal class ServerInfoProvider : v2_5.ServerInfoProvider { + public override QueryInfo GetQueryInfo() + { + var info = base.GetQueryInfo(); + info.Features |= QueryFeatures.CrossApply; + return info; + } + public ServerInfoProvider(SqlDriver driver) : base(driver) { diff --git a/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/Translator.cs b/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/Translator.cs index f919e39c9d..6751999ec9 100644 --- a/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/Translator.cs +++ b/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/Translator.cs @@ -1,11 +1,40 @@ -using System; -using System.Collections.Generic; -using System.Text; +// Copyright (C) 2021 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. + +using Xtensive.Sql.Compiler; +using Xtensive.Sql.Dml; namespace Xtensive.Sql.Drivers.Firebird.v4_0 { internal class Translator : v2_5.Translator { + public override string Translate(SqlCompilerContext context, SqlJoinExpression node, JoinSection section) + { + switch (section) { + case JoinSection.Specification: { + if (node.Expression == null) { + switch (node.JoinType) { + case SqlJoinType.CrossApply: + return "CROSS JOIN LATERAL"; + case SqlJoinType.LeftOuterApply: + return "LEFT JOIN LATERAL"; + default: + return base.Translate(context, node, section); + } + } + return Translate(node.JoinType) + " JOIN"; + } + case JoinSection.Exit: { + if (node.JoinType == SqlJoinType.LeftOuterApply) { + return "ON TRUE"; + } + return string.Empty; + } + } + return base.Translate(context, node, section); + } + // Constructors /// From 27caa63db1909ec7714680372a6fb3444d464247 Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Fri, 24 Dec 2021 17:40:03 +0500 Subject: [PATCH 08/13] Summaries of v4 provider files --- .../Sql.Drivers.Firebird/v4_0/Compiler.cs | 4 ++++ .../Sql.Drivers.Firebird/v4_0/Driver.cs | 8 +++----- .../Sql.Drivers.Firebird/v4_0/Extractor.cs | 6 ++++++ .../Sql.Drivers.Firebird/v4_0/TypeMapper.cs | 5 ++++- 4 files changed, 17 insertions(+), 6 deletions(-) diff --git a/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/Compiler.cs b/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/Compiler.cs index 85af0e9806..749d2f39cc 100644 --- a/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/Compiler.cs +++ b/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/Compiler.cs @@ -1,3 +1,7 @@ +// Copyright (C) 2021 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. + using System; using System.Collections.Generic; using System.Text; diff --git a/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/Driver.cs b/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/Driver.cs index 6aae5286cd..20263c375f 100644 --- a/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/Driver.cs +++ b/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/Driver.cs @@ -1,8 +1,6 @@ -// Copyright (C) 2003-2010 Xtensive LLC. -// All rights reserved. -// For conditions of distribution and use, see license. -// Created by: Csaba Beer -// Created: 2011.01.10 +// Copyright (C) 2021 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. using System; using Xtensive.Sql.Info; diff --git a/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/Extractor.cs b/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/Extractor.cs index d75496013b..42aa57f862 100644 --- a/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/Extractor.cs +++ b/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/Extractor.cs @@ -1,3 +1,7 @@ +// Copyright (C) 2021 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. + using System; using System.Collections.Generic; using System.Data; @@ -666,6 +670,8 @@ private static string GetTypeName(int majorTypeIdentifier, int? minorTypeIdentif : "BIGINT"; case 27: return "DOUBLE PRECISION"; + case 29: + return "TIMESTAMP WITH WITH TIME ZONE"; case 35: return "TIMESTAMP"; case 37: diff --git a/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/TypeMapper.cs b/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/TypeMapper.cs index c5ae3e8df0..3d7388f059 100644 --- a/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/TypeMapper.cs +++ b/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/TypeMapper.cs @@ -1,5 +1,8 @@ +// Copyright (C) 2021 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. + using System; -using System.Collections.Generic; using System.Data.Common; using System.Numerics; using System.Text; From 8dde67f7cb3cb8b3b8170c87899f4ea37738e08d Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Fri, 21 Jan 2022 17:04:56 +0500 Subject: [PATCH 09/13] Improved Apply support Fixed errors when apply used table ref instead of subquery --- .../Sql.Drivers.Firebird/v4_0/ServerInfoProvider.cs | 2 +- .../Sql.Drivers.PostgreSql/v10_0/ServerInfoProvider.cs | 2 +- Orm/Xtensive.Orm/Orm/Providers/SqlCompiler.cs | 2 +- Orm/Xtensive.Orm/Sql/Info/QueryFeatures.cs | 5 +++++ 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/ServerInfoProvider.cs b/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/ServerInfoProvider.cs index 519176fe1f..d3ac696b42 100644 --- a/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/ServerInfoProvider.cs +++ b/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/ServerInfoProvider.cs @@ -11,7 +11,7 @@ internal class ServerInfoProvider : v2_5.ServerInfoProvider public override QueryInfo GetQueryInfo() { var info = base.GetQueryInfo(); - info.Features |= QueryFeatures.CrossApply; + info.Features |= QueryFeatures.CrossApplyForSubqueriesOnly; return info; } diff --git a/Orm/Xtensive.Orm.PostgreSql/Sql.Drivers.PostgreSql/v10_0/ServerInfoProvider.cs b/Orm/Xtensive.Orm.PostgreSql/Sql.Drivers.PostgreSql/v10_0/ServerInfoProvider.cs index 326ffa7772..18e62ef5bc 100644 --- a/Orm/Xtensive.Orm.PostgreSql/Sql.Drivers.PostgreSql/v10_0/ServerInfoProvider.cs +++ b/Orm/Xtensive.Orm.PostgreSql/Sql.Drivers.PostgreSql/v10_0/ServerInfoProvider.cs @@ -13,7 +13,7 @@ internal class ServerInfoProvider : v9_0.ServerInfoProvider public override QueryInfo GetQueryInfo() { var info = base.GetQueryInfo(); - info.Features |= QueryFeatures.CrossApply; + info.Features |= QueryFeatures.CrossApplyForSubqueriesOnly; return info; } diff --git a/Orm/Xtensive.Orm/Orm/Providers/SqlCompiler.cs b/Orm/Xtensive.Orm/Orm/Providers/SqlCompiler.cs index 82f8d03a67..b2f7b830bb 100644 --- a/Orm/Xtensive.Orm/Orm/Providers/SqlCompiler.cs +++ b/Orm/Xtensive.Orm/Orm/Providers/SqlCompiler.cs @@ -563,7 +563,7 @@ public SqlCompiler(HandlerAccessor handlers, CompilerConfiguration configuration providerInfo = Handlers.ProviderInfo; temporaryTablesSupported = DomainHandler.TemporaryTableManager.Supported; - forceApplyViaReference = handlers.ProviderInfo.ProviderName.Equals(WellKnown.Provider.PostgreSql); + forceApplyViaReference = Handlers.StorageDriver.ServerInfo.Query.Features.HasFlag(Sql.Info.QueryFeatures.CrossApplyForSubqueriesOnly); if (!providerInfo.Supports(ProviderFeatures.FullFeaturedBooleanExpressions)) booleanExpressionConverter = new BooleanExpressionConverter(Driver); diff --git a/Orm/Xtensive.Orm/Sql/Info/QueryFeatures.cs b/Orm/Xtensive.Orm/Sql/Info/QueryFeatures.cs index 00c28c9ec0..41b867b9c8 100644 --- a/Orm/Xtensive.Orm/Sql/Info/QueryFeatures.cs +++ b/Orm/Xtensive.Orm/Sql/Info/QueryFeatures.cs @@ -147,6 +147,11 @@ public enum QueryFeatures /// DeleteLimit = 1 << 25, + /// + /// Indicates that RDBMS supports CROSS APPLY and OUTER APPLY operators but only for subqueries. + /// + CrossApplyForSubqueriesOnly = CrossApply | (1 << 26), + /// /// Indicates that RDBMS supports paging operators ( and ). /// From 48e030ced420044b7dccd7943958d94b6d4598eb Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Tue, 25 Jan 2022 13:39:46 +0500 Subject: [PATCH 10/13] Tests made compatible with Firebird 4 - one test was failed due to difference of oredering locally and on server side - the rest just suppose to be ignored as they were for 2.5 --- Orm/Xtensive.Orm.Tests/Linq/SelectManyTest.cs | 12 ++++++++---- Orm/Xtensive.Orm.Tests/Linq/SetOperationsTest.cs | 2 ++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/Orm/Xtensive.Orm.Tests/Linq/SelectManyTest.cs b/Orm/Xtensive.Orm.Tests/Linq/SelectManyTest.cs index 56a6dcb821..de6d03f14a 100644 --- a/Orm/Xtensive.Orm.Tests/Linq/SelectManyTest.cs +++ b/Orm/Xtensive.Orm.Tests/Linq/SelectManyTest.cs @@ -392,6 +392,8 @@ from c2 in Session.Query.All() public void IntersectBetweenFilterAndApplyTest() { Require.AllFeaturesSupported(ProviderFeatures.Apply); + Require.ProviderIsNot(StorageProvider.Firebird); + var expected = Session.Query.All().Count(i => i.DesignatedEmployee.FirstName.StartsWith("A")); IQueryable result = Session.Query.All() .SelectMany(c => Session.Query.All().Where(i => i.Customer==c).Intersect(Session.Query.All()) @@ -458,14 +460,14 @@ public void TwoCalculateWithApplyTest() Require.AllFeaturesSupported(ProviderFeatures.Apply); var actual = from c in Session.Query.All() - from n in (c.Invoices.Select(i => c.FirstName + i.BillingAddress.StreetAddress)) - .Union(c.Invoices.Select(i => c.FirstName + i.BillingAddress.StreetAddress)) + from n in (c.Invoices.Select(i => c.FirstName + i.BillingAddress.StreetAddress).Where(x => x.StartsWith("M"))) + .Union(c.Invoices.Select(i => c.FirstName + i.BillingAddress.StreetAddress).Where(x => x.StartsWith("N"))) orderby n select n; var expected = from c in Customers - from n in (c.Invoices.Select(i => c.FirstName + i.BillingAddress.StreetAddress)) - .Union(c.Invoices.Select(i => c.FirstName + i.BillingAddress.StreetAddress)) + from n in (c.Invoices.Select(i => c.FirstName + i.BillingAddress.StreetAddress).Where(x => x.StartsWith("M"))) + .Union(c.Invoices.Select(i => c.FirstName + i.BillingAddress.StreetAddress).Where(x => x.StartsWith("N"))) orderby n select n; @@ -477,6 +479,8 @@ orderby n public void TwoFilterWithApplyTest() { Require.AllFeaturesSupported(ProviderFeatures.Apply); + Require.ProviderIsNot(StorageProvider.Firebird); + var actual = from c in Session.Query.All() from i in (c.Invoices.Where(x => x.BillingAddress.StreetAddress.StartsWith("A")) .Intersect(c.Invoices.Where(x => x.BillingAddress.StreetAddress.StartsWith("A")))) diff --git a/Orm/Xtensive.Orm.Tests/Linq/SetOperationsTest.cs b/Orm/Xtensive.Orm.Tests/Linq/SetOperationsTest.cs index 25b5c9bd4d..2f78310d42 100644 --- a/Orm/Xtensive.Orm.Tests/Linq/SetOperationsTest.cs +++ b/Orm/Xtensive.Orm.Tests/Linq/SetOperationsTest.cs @@ -237,6 +237,8 @@ public void UnionStructureTest() public void IntersectWithoutOneOfSelect() { Require.AllFeaturesSupported(ProviderFeatures.Apply); + Require.ProviderIsNot(StorageProvider.Firebird); + var actual = from c in Session.Query.All() from r in (c.Invoices) .Intersect(c.Invoices).Select(o => o.PaymentDate) From 440365780c0bc23d9a8683267d62ff9548a2eddf Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Wed, 26 Jan 2022 14:04:35 +0500 Subject: [PATCH 11/13] Fix tag test case for providers with no batches support --- Orm/Xtensive.Orm.Tests/Linq/TagTest.cs | 34 +++++++++++++++++++++----- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/Orm/Xtensive.Orm.Tests/Linq/TagTest.cs b/Orm/Xtensive.Orm.Tests/Linq/TagTest.cs index d9db2b3676..eb1ea0dc38 100644 --- a/Orm/Xtensive.Orm.Tests/Linq/TagTest.cs +++ b/Orm/Xtensive.Orm.Tests/Linq/TagTest.cs @@ -884,6 +884,7 @@ void SqlCapturer(object sender, DbCommandEventArgs args) public void SessionTagPrefetchEntitySet() { var allCommands = new List(); + var batchesSupported = Domain.Handlers.ProviderInfo.Supports(Providers.ProviderFeatures.Batches); using (var session = Domain.OpenSession()) using (var tx = session.OpenTransaction()) { @@ -907,8 +908,15 @@ public void SessionTagPrefetchEntitySet() _ = session.Query.All().Prefetch(a => a.Books).ToArray(); session.Events.DbCommandExecuting -= SqlCapturer; - Assert.That(allCommands.Count, Is.EqualTo(2)); - Assert.IsTrue(allCommands[1].StartsWith("/*outermost*/")); + if (batchesSupported) { + Assert.That(allCommands.Count, Is.EqualTo(2)); + Assert.IsTrue(allCommands[1].StartsWith("/*outermost*/")); + } + else { + Assert.That(allCommands.Count, Is.EqualTo(3)); + Assert.IsTrue(allCommands[1].StartsWith("/*outermost*/")); + Assert.IsTrue(allCommands[2].StartsWith("/*outermost*/")); + } allCommands.Clear(); } @@ -922,8 +930,15 @@ public void SessionTagPrefetchEntitySet() _ = session.Query.All().Prefetch(a => a.Books).ToArray(); session.Events.DbCommandExecuting -= SqlCapturer; - Assert.That(allCommands.Count, Is.EqualTo(2)); - Assert.IsTrue(allCommands[1].StartsWith("/*outermost in-between*/")); + if (batchesSupported) { + Assert.That(allCommands.Count, Is.EqualTo(2)); + Assert.IsTrue(allCommands[1].StartsWith("/*outermost in-between*/")); + } + else { + Assert.That(allCommands.Count, Is.EqualTo(3)); + Assert.IsTrue(allCommands[1].StartsWith("/*outermost in-between*/")); + Assert.IsTrue(allCommands[2].StartsWith("/*outermost in-between*/")); + } allCommands.Clear(); } @@ -939,8 +954,15 @@ public void SessionTagPrefetchEntitySet() _ = session.Query.All().Prefetch(a => a.Books).ToArray(); session.Events.DbCommandExecuting -= SqlCapturer; - Assert.That(allCommands.Count, Is.EqualTo(2)); - Assert.IsTrue(allCommands[1].StartsWith("/*outermost in-between deepest*/")); + if (batchesSupported) { + Assert.That(allCommands.Count, Is.EqualTo(2)); + Assert.IsTrue(allCommands[1].StartsWith("/*outermost in-between deepest*/")); + } + else { + Assert.That(allCommands.Count, Is.EqualTo(3)); + Assert.IsTrue(allCommands[1].StartsWith("/*outermost in-between deepest*/")); + Assert.IsTrue(allCommands[2].StartsWith("/*outermost in-between deepest*/")); + } allCommands.Clear(); } From 1a1fc142475278068994f723f75b03279e91f085 Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Wed, 26 Jan 2022 15:57:38 +0500 Subject: [PATCH 12/13] Improve changelog --- ChangeLog/7.1.0-dev.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog/7.1.0-dev.txt b/ChangeLog/7.1.0-dev.txt index 29360f0d5c..1c3c0e899a 100644 --- a/ChangeLog/7.1.0-dev.txt +++ b/ChangeLog/7.1.0-dev.txt @@ -68,4 +68,5 @@ [main] CompositePreCompiler.Items became readonly field and changed its type to IReadOnlyList [main] SqlCompilerConfiguration's SchemaMapping and DatabaseMapping changed return types to IReadOnlyDictionary [main] TypeMappingRegistry.Mappings and .ReverseMappings changed return types to IReadOnlyDictionary +[firebird] Add support for Firebird 4 [sqlserver] Microsoft.Data.SqlClient is updated to verson 4.0.0 \ No newline at end of file From 7839a1a18e685c8f0d5b8090917109ef5a1bdbcb Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Wed, 26 Jan 2022 16:05:54 +0500 Subject: [PATCH 13/13] Files copyright update --- .../Sql.Drivers.Firebird/v4_0/ServerInfoProvider.cs | 2 +- .../Sql.Drivers.PostgreSql/v10_0/ServerInfoProvider.cs | 2 +- Orm/Xtensive.Orm.Tests.Sql/PostgreSql/SqlDomTests.cs | 2 +- Orm/Xtensive.Orm.Tests/Linq/SelectManyTest.cs | 2 +- Orm/Xtensive.Orm.Tests/Linq/TagTest.cs | 2 +- Orm/Xtensive.Orm/Orm/Providers/SqlCompiler.cs | 2 +- Orm/Xtensive.Orm/Sql/Info/QueryFeatures.cs | 6 +++--- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/ServerInfoProvider.cs b/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/ServerInfoProvider.cs index d3ac696b42..695d632fae 100644 --- a/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/ServerInfoProvider.cs +++ b/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v4_0/ServerInfoProvider.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2021 Xtensive LLC. +// Copyright (C) 2021-2022 Xtensive LLC. // This code is distributed under MIT license terms. // See the License.txt file in the project root for more information. diff --git a/Orm/Xtensive.Orm.PostgreSql/Sql.Drivers.PostgreSql/v10_0/ServerInfoProvider.cs b/Orm/Xtensive.Orm.PostgreSql/Sql.Drivers.PostgreSql/v10_0/ServerInfoProvider.cs index 18e62ef5bc..fcfdd327f7 100644 --- a/Orm/Xtensive.Orm.PostgreSql/Sql.Drivers.PostgreSql/v10_0/ServerInfoProvider.cs +++ b/Orm/Xtensive.Orm.PostgreSql/Sql.Drivers.PostgreSql/v10_0/ServerInfoProvider.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2019-2021 Xtensive LLC. +// Copyright (C) 2019-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 diff --git a/Orm/Xtensive.Orm.Tests.Sql/PostgreSql/SqlDomTests.cs b/Orm/Xtensive.Orm.Tests.Sql/PostgreSql/SqlDomTests.cs index 80e718f600..d73b31ebfb 100644 --- a/Orm/Xtensive.Orm.Tests.Sql/PostgreSql/SqlDomTests.cs +++ b/Orm/Xtensive.Orm.Tests.Sql/PostgreSql/SqlDomTests.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2009-2020 Xtensive LLC. +// 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. diff --git a/Orm/Xtensive.Orm.Tests/Linq/SelectManyTest.cs b/Orm/Xtensive.Orm.Tests/Linq/SelectManyTest.cs index de6d03f14a..381acae2a8 100644 --- a/Orm/Xtensive.Orm.Tests/Linq/SelectManyTest.cs +++ b/Orm/Xtensive.Orm.Tests/Linq/SelectManyTest.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2009-2021 Xtensive LLC. +// 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 diff --git a/Orm/Xtensive.Orm.Tests/Linq/TagTest.cs b/Orm/Xtensive.Orm.Tests/Linq/TagTest.cs index eb1ea0dc38..f53175a6bd 100644 --- a/Orm/Xtensive.Orm.Tests/Linq/TagTest.cs +++ b/Orm/Xtensive.Orm.Tests/Linq/TagTest.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2021 Xtensive LLC. +// Copyright (C) 2021-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: Edgar Isajanyan diff --git a/Orm/Xtensive.Orm/Orm/Providers/SqlCompiler.cs b/Orm/Xtensive.Orm/Orm/Providers/SqlCompiler.cs index ef54cdd981..63c69371fc 100644 --- a/Orm/Xtensive.Orm/Orm/Providers/SqlCompiler.cs +++ b/Orm/Xtensive.Orm/Orm/Providers/SqlCompiler.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2009-2021 Xtensive LLC. +// 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: Vakhtina Elena diff --git a/Orm/Xtensive.Orm/Sql/Info/QueryFeatures.cs b/Orm/Xtensive.Orm/Sql/Info/QueryFeatures.cs index 41b867b9c8..bb49a378de 100644 --- a/Orm/Xtensive.Orm/Sql/Info/QueryFeatures.cs +++ b/Orm/Xtensive.Orm/Sql/Info/QueryFeatures.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-2021 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. using System;