Skip to content

Oracle: schemas extraction fix #228

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Mar 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion ChangeLog/7.0.3_dev.txt
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
[sqlserver] Fixed TimeSpan.Ticks extraction problem
[main] NodeCollection supports different equality comparers for internal name index
[sqlserver] Fixed TimeSpan.Ticks extraction problem
[oracle] Fixed scheme extraction for case-sensitive schema names
4 changes: 2 additions & 2 deletions Orm/Xtensive.Orm.Oracle/Sql.Drivers.Oracle/v09/Extractor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -142,9 +142,9 @@ protected virtual string ToUpperInvariantIfNeeded(string schemaName)

private ExtractionContext CreateContext(string catalogName, string[] schemaNames)
{
var catalog = new Catalog(catalogName);
var catalog = new Catalog(catalogName, true);
for(var i = 0; i < schemaNames.Length; i++) {
schemaNames[i] = schemaNames[i].ToUpperInvariant();
schemaNames[i] = ToUpperInvariantIfNeeded(schemaNames[i]);
}

var replacements = new Dictionary<string, string>();
Expand Down
15 changes: 9 additions & 6 deletions Orm/Xtensive.Orm.Tests.Framework/StorageTestHelper.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright (C) 2003-2010 Xtensive LLC.
// All rights reserved.
// For conditions of distribution and use, see license.
// Copyright (C) 2009-2022 Xtensive LLC.
// This code is distributed under MIT license terms.
// See the License.txt file in the project root for more information.
// Created by: Denis Krjuchkov
// Created: 2009.12.17

Expand Down Expand Up @@ -51,13 +51,16 @@ public static void DemandSchemas(ConnectionInfo connectionInfo, params string[]
var extractionResult = driver.Extract(connection, new[] {extractionTask});
var catalog = extractionResult.Catalogs.Single();
var existingSchemas = catalog.Schemas.Select(s => s.Name);
var schemasToCreate = schemas.Except(existingSchemas, StringComparer.OrdinalIgnoreCase);

// Oracle does not support creating schemas, user should be created instead.
if (connectionInfo.Provider==WellKnown.Provider.Oracle)
if (connectionInfo.Provider == WellKnown.Provider.Oracle) {
var schemasToCreate = schemas.Except(existingSchemas, StringComparer.Ordinal);
CreateUsers(connection, schemasToCreate);
else
}
else {
var schemasToCreate = schemas.Except(existingSchemas, StringComparer.OrdinalIgnoreCase);
CreateSchemas(connection, catalog, schemasToCreate);
}

connection.Close();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// Copyright (C) 2022 Xtensive LLC.
// This code is distributed under MIT license terms.
// See the License.txt file in the project root for more information.

using System.Linq;
using NUnit.Framework;
using Xtensive.Orm.Configuration;
using M = Xtensive.Orm.Tests.Storage.Multimapping.CaseSensitiveSchemasTestModel;

namespace Xtensive.Orm.Tests.Storage.Multimapping.CaseSensitiveSchemasTestModel
{
namespace Schema1
{
[HierarchyRoot]
public class Entity1 : Entity
{
[Field, Key]
public int Id { get; private set; }

[Field]
public string OriginalSchemaName { get; set; }
}
}

namespace Schema2
{
[HierarchyRoot]
public class Entity2 : Entity
{
[Field, Key]
public int Id { get; private set; }

[Field]
public string OriginalSchemaName { get; set; }
}
}
}

namespace Xtensive.Orm.Tests.Storage.Multimapping
{
public sealed class CaseSensitiveSchemasTest : MultimappingTest
{
private const string Schema1Name = WellKnownSchemas.Schema1;

private readonly string schema1UpperCaseName = Schema1Name.ToUpperInvariant();

protected override void CheckRequirements() => Require.ProviderIs(StorageProvider.Oracle);

protected override DomainConfiguration BuildConfiguration()
{
var configuration = base.BuildConfiguration();
configuration.DefaultSchema = Schema1Name;
configuration.Types.Register(typeof(M.Schema1.Entity1));
configuration.Types.Register(typeof(M.Schema2.Entity2));
var rules = configuration.MappingRules;
rules.Map(typeof(M.Schema1.Entity1).Namespace).ToSchema(Schema1Name);
rules.Map(typeof(M.Schema2.Entity2).Namespace).ToSchema(schema1UpperCaseName);
return configuration;
}

[Test]
public void MainTest()
{
BuildInitialDomain();
BuildUpgradedDomain();
}

private void BuildInitialDomain()
{
var config = BuildConfiguration();
PrepareSchema(config.ConnectionInfo);
var domain = Domain.Build(config);
using (domain) {
using (var session = domain.OpenSession())
using (var tx = session.OpenTransaction()) {
_ = new M.Schema1.Entity1 { OriginalSchemaName = Schema1Name };
_ = new M.Schema2.Entity2 { OriginalSchemaName = schema1UpperCaseName };
tx.Complete();
}
}
}

private void BuildUpgradedDomain()
{
var config = BuildConfiguration();
config.UpgradeMode = DomainUpgradeMode.PerformSafely;
var domain = Domain.Build(config);
using (domain) {
using (var session = domain.OpenSession())
using (var tx = session.OpenTransaction()) {
var e1 = session.Query.All<M.Schema1.Entity1>().Single();
var e2 = session.Query.All<M.Schema2.Entity2>().Single();
Assert.That(e1.OriginalSchemaName, Is.EqualTo(Schema1Name));
Assert.That(e2.OriginalSchemaName, Is.EqualTo(schema1UpperCaseName));
tx.Complete();
}
}
}

private void PrepareSchema(ConnectionInfo connectionInfo)
{
StorageTestHelper.DemandSchemas(
connectionInfo, Schema1Name, schema1UpperCaseName);
}
}
}
12 changes: 11 additions & 1 deletion Orm/Xtensive.Orm/Sql/Model/Catalog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -198,10 +198,20 @@ internal string GetActualDbName(IDictionary<string, string> catalogNameMap)

// Constructors

public Catalog(string name) : base(name)
public Catalog(string name)
: base(name)
{
schemas =
new PairedNodeCollection<Catalog, Schema>(this, "Schemas", 1);
}

public Catalog(string name, bool caseSensitiveNames = false)
: base(name)
{
schemas = caseSensitiveNames
? new PairedNodeCollection<Catalog, Schema>(this, "Schemas", 1, StringComparer.Ordinal)
: new PairedNodeCollection<Catalog, Schema>(this, "Schemas", 1, StringComparer.OrdinalIgnoreCase);
}

}
}
11 changes: 11 additions & 0 deletions Orm/Xtensive.Orm/Sql/Model/NodeCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,5 +84,16 @@ public NodeCollection(int capacity)
{
nameIndex = new Dictionary<string, TNode>(capacity, Comparer);
}

/// <summary>
/// Initializes new instance of this type.
/// </summary>
/// <param name="capacity">The initial collection capacity.</param>
/// <param name="comparer">Comparer for inner name index.</param>
public NodeCollection(int capacity, IEqualityComparer<string> comparer)
: base(capacity)
{
nameIndex = new Dictionary<string, TNode>(capacity, comparer);
}
}
}
19 changes: 19 additions & 0 deletions Orm/Xtensive.Orm/Sql/Model/PairedNodeCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

using System;
using System.Collections;
using System.Collections.Generic;
using Xtensive.Core;

namespace Xtensive.Sql.Model
Expand Down Expand Up @@ -73,6 +74,24 @@ public PairedNodeCollection(TOwner owner, string property, int capacity)
this.property = property;
}

/// <summary>
/// Initializes a new instance of the <see cref="PairedNodeCollection{TOwner,TNode}"/> class.
/// </summary>
/// <param name="owner">The collection owner.</param>
/// <param name="property">Owner collection property.</param>
/// <param name="capacity">The initial collection capacity.</param>
/// <param name="equalityComparer">Comparer for inner name index.</param>
public PairedNodeCollection(TOwner owner, string property, int capacity, IEqualityComparer<string> equalityComparer)
: base(capacity, equalityComparer)
{
ArgumentValidator.EnsureArgumentNotNull(owner, nameof(owner));
ArgumentValidator.EnsureArgumentNotNullOrEmpty(property, nameof(property));
ArgumentValidator.EnsureArgumentNotNull(equalityComparer, nameof(equalityComparer));

this.owner = owner;
this.property = property;
}

#endregion
}
}