Skip to content

Commit 9d83b0c

Browse files
Fix SQLite validation failure on tables with a schema
Fixes #1609
1 parent 25777a3 commit 9d83b0c

File tree

5 files changed

+319
-3
lines changed

5 files changed

+319
-3
lines changed
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
//------------------------------------------------------------------------------
2+
// <auto-generated>
3+
// This code was generated by AsyncGenerator.
4+
//
5+
// Changes to this file may cause incorrect behavior and will be lost if
6+
// the code is regenerated.
7+
// </auto-generated>
8+
//------------------------------------------------------------------------------
9+
10+
11+
using System;
12+
using System.Data;
13+
using NHibernate.Dialect;
14+
using NHibernate.Util;
15+
using NUnit.Framework;
16+
17+
namespace NHibernate.Test.Tools.hbm2ddl.SchemaValidator
18+
{
19+
using System.Threading.Tasks;
20+
[TestFixture]
21+
public class SchemaValidateTableWithSchemaFixtureAsync : TestCase
22+
{
23+
protected override string MappingsAssembly => "NHibernate.Test";
24+
25+
protected override string[] Mappings => new[] { "Tools.hbm2ddl.SchemaValidator.VersionWithSchema.hbm.xml" };
26+
27+
protected override bool AppliesTo(Dialect.Dialect dialect)
28+
{
29+
switch (Dialect)
30+
{
31+
case MsSql2000Dialect _:
32+
case PostgreSQLDialect _:
33+
case SQLiteDialect _:
34+
return true;
35+
default:
36+
return false;
37+
}
38+
}
39+
40+
protected override void CreateSchema()
41+
{
42+
switch (Dialect)
43+
{
44+
case MsSql2000Dialect _:
45+
case PostgreSQLDialect _:
46+
// Must handle the schema manually: mapped database-objects are handled too late.
47+
var cnx = Sfi.ConnectionProvider.GetConnection();
48+
try
49+
{
50+
using (var cmd = cnx.CreateCommand())
51+
{
52+
cmd.CommandText = "create schema Test";
53+
cmd.ExecuteNonQuery();
54+
}
55+
}
56+
catch (Exception ex)
57+
{
58+
// Unfortunateley Assert.Warn and Console.WriteLine at this place seems to be ignored in Rider
59+
// viewer.
60+
Assert.Warn("Creating the schema failed, assuming it already exists. {0}", ex);
61+
Console.WriteLine("Creating the schema failed, assuming it already exists.");
62+
Console.WriteLine(ex);
63+
}
64+
finally
65+
{
66+
Sfi.ConnectionProvider.CloseConnection(cnx);
67+
}
68+
break;
69+
}
70+
base.CreateSchema();
71+
}
72+
73+
protected override void DropSchema()
74+
{
75+
// SQL-Server do not need this call, but Postgres does not accept dropping a schema carrying objects.
76+
base.DropSchema();
77+
78+
switch (Dialect)
79+
{
80+
case MsSql2000Dialect _:
81+
case PostgreSQLDialect _:
82+
var cnx = Sfi.ConnectionProvider.GetConnection();
83+
try
84+
{
85+
using (var cmd = cnx.CreateCommand())
86+
{
87+
cmd.CommandText = "drop schema Test";
88+
cmd.ExecuteNonQuery();
89+
}
90+
}
91+
finally
92+
{
93+
Sfi.ConnectionProvider.CloseConnection(cnx);
94+
}
95+
break;
96+
}
97+
}
98+
99+
[Test]
100+
public async Task ShouldVerifyAsync()
101+
{
102+
var validator = new Tool.hbm2ddl.SchemaValidator(cfg);
103+
try
104+
{
105+
await (validator.ValidateAsync());
106+
}
107+
catch (SchemaValidationException sve)
108+
{
109+
Assert.Fail("Validation failed: {0}.\n{1}", StringHelper.CollectionToString(sve.ValidationErrors), sve);
110+
}
111+
}
112+
}
113+
}
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
using System;
2+
using System.Data;
3+
using NHibernate.Dialect;
4+
using NHibernate.Util;
5+
using NUnit.Framework;
6+
7+
namespace NHibernate.Test.Tools.hbm2ddl.SchemaValidator
8+
{
9+
[TestFixture]
10+
public class SchemaValidateTableWithSchemaFixture : TestCase
11+
{
12+
protected override string MappingsAssembly => "NHibernate.Test";
13+
14+
protected override string[] Mappings => new[] { "Tools.hbm2ddl.SchemaValidator.VersionWithSchema.hbm.xml" };
15+
16+
protected override bool AppliesTo(Dialect.Dialect dialect)
17+
{
18+
switch (Dialect)
19+
{
20+
case MsSql2000Dialect _:
21+
case PostgreSQLDialect _:
22+
case SQLiteDialect _:
23+
return true;
24+
default:
25+
return false;
26+
}
27+
}
28+
29+
protected override void CreateSchema()
30+
{
31+
switch (Dialect)
32+
{
33+
case MsSql2000Dialect _:
34+
case PostgreSQLDialect _:
35+
// Must handle the schema manually: mapped database-objects are handled too late.
36+
var cnx = Sfi.ConnectionProvider.GetConnection();
37+
try
38+
{
39+
using (var cmd = cnx.CreateCommand())
40+
{
41+
cmd.CommandText = "create schema Test";
42+
cmd.ExecuteNonQuery();
43+
}
44+
}
45+
catch (Exception ex)
46+
{
47+
// Unfortunateley Assert.Warn and Console.WriteLine at this place seems to be ignored in Rider
48+
// viewer.
49+
Assert.Warn("Creating the schema failed, assuming it already exists. {0}", ex);
50+
Console.WriteLine("Creating the schema failed, assuming it already exists.");
51+
Console.WriteLine(ex);
52+
}
53+
finally
54+
{
55+
Sfi.ConnectionProvider.CloseConnection(cnx);
56+
}
57+
break;
58+
}
59+
base.CreateSchema();
60+
}
61+
62+
protected override void DropSchema()
63+
{
64+
// SQL-Server do not need this call, but Postgres does not accept dropping a schema carrying objects.
65+
base.DropSchema();
66+
67+
switch (Dialect)
68+
{
69+
case MsSql2000Dialect _:
70+
case PostgreSQLDialect _:
71+
var cnx = Sfi.ConnectionProvider.GetConnection();
72+
try
73+
{
74+
using (var cmd = cnx.CreateCommand())
75+
{
76+
cmd.CommandText = "drop schema Test";
77+
cmd.ExecuteNonQuery();
78+
}
79+
}
80+
finally
81+
{
82+
Sfi.ConnectionProvider.CloseConnection(cnx);
83+
}
84+
break;
85+
}
86+
}
87+
88+
[Test]
89+
public void ShouldVerify()
90+
{
91+
var validator = new Tool.hbm2ddl.SchemaValidator(cfg);
92+
try
93+
{
94+
validator.Validate();
95+
}
96+
catch (SchemaValidationException sve)
97+
{
98+
Assert.Fail("Validation failed: {0}.\n{1}", StringHelper.CollectionToString(sve.ValidationErrors), sve);
99+
}
100+
}
101+
}
102+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?xml version="1.0"?>
2+
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
3+
namespace="NHibernate.Test.Tools.hbm2ddl.SchemaValidator"
4+
assembly="NHibernate.Test">
5+
6+
<class name="Version" schema="Test">
7+
<id name="Id">
8+
<generator class="NHibernate.Id.TableHiLoGenerator">
9+
<param name="table">uid_table</param>
10+
<param name="column">next_hi_value_column</param>
11+
</generator>
12+
</id>
13+
<property name="Description"/>
14+
<many-to-one name="Previous"/>
15+
</class>
16+
</hibernate-mapping>
17+

src/NHibernate/Dialect/SQLiteDialect.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ protected virtual void RegisterDefaultProperties()
190190

191191
public override Schema.IDataBaseSchema GetDataBaseSchema(DbConnection connection)
192192
{
193-
return new Schema.SQLiteDataBaseMetaData(connection);
193+
return new Schema.SQLiteDataBaseMetaData(connection, this);
194194
}
195195

196196
public override string AddColumnString

src/NHibernate/Dialect/Schema/SQLiteMetaData.cs

Lines changed: 86 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,91 @@ namespace NHibernate.Dialect.Schema
66
{
77
public class SQLiteDataBaseMetaData : AbstractDataBaseSchema
88
{
9-
public SQLiteDataBaseMetaData(DbConnection connection) : base(connection) {}
9+
// Since v5.2
10+
[Obsolete("Use overload with dialect argument.")]
11+
public SQLiteDataBaseMetaData(DbConnection connection) : this(connection, Dialect.GetDialect()) {}
12+
13+
public SQLiteDataBaseMetaData(DbConnection connection, Dialect dialect) : base(connection)
14+
{
15+
_dialect = dialect;
16+
}
17+
18+
private readonly Dialect _dialect;
19+
20+
public override DataTable GetTables(string catalog, string schemaPattern, string tableNamePattern, string[] types)
21+
{
22+
if (_dialect is SQLiteDialect)
23+
{
24+
// SQLiteDialect concatenates catalog and schema to the table name.
25+
var actualTablePattern = _dialect.Qualify(catalog, schemaPattern, tableNamePattern);
26+
var tables = base.GetTables(null, null, actualTablePattern, types);
27+
// Caller may check the table name of yielded results, we need to patch them
28+
foreach (DataRow tableRow in tables.Rows)
29+
{
30+
var tableName = Convert.ToString(tableRow[ColumnNameForTableName]);
31+
if (tableName.Equals(actualTablePattern, StringComparison.InvariantCultureIgnoreCase))
32+
{
33+
tableRow[ColumnNameForTableName] = tableNamePattern;
34+
// Columns are looked-up according to the row table name, and schema and catalog data.
35+
// We need to patch schema and catalog for being able to reconstruct the adequate table name.
36+
if (!string.IsNullOrEmpty(catalog))
37+
{
38+
tableRow["TABLE_CATALOG"] = catalog;
39+
}
40+
else
41+
{
42+
// SQLite indicates "main" here by default, wrecking the other Get method
43+
// overrides.
44+
tableRow["TABLE_CATALOG"] = string.Empty;
45+
}
46+
if (!string.IsNullOrEmpty(schemaPattern))
47+
{
48+
tableRow["TABLE_SCHEMA"] = schemaPattern;
49+
}
50+
}
51+
}
52+
53+
return tables;
54+
}
55+
56+
return base.GetTables(catalog, schemaPattern, tableNamePattern, types);
57+
}
58+
59+
public override DataTable GetColumns(string catalog, string schemaPattern, string tableNamePattern, string columnNamePattern)
60+
{
61+
if (_dialect is SQLiteDialect)
62+
{
63+
// SQLiteDialect concatenates catalog and schema to the table name.
64+
var actualTablePattern = _dialect.Qualify(catalog, schemaPattern, tableNamePattern);
65+
return base.GetColumns(null, null, actualTablePattern, columnNamePattern);
66+
}
67+
68+
return base.GetColumns(catalog, schemaPattern, tableNamePattern, columnNamePattern);
69+
}
70+
71+
public override DataTable GetForeignKeys(string catalog, string schema, string table)
72+
{
73+
if (_dialect is SQLiteDialect)
74+
{
75+
// SQLiteDialect concatenates catalog and schema to the table name.
76+
var actualTable = _dialect.Qualify(catalog, schema, table);
77+
return base.GetForeignKeys(null, null, actualTable);
78+
}
79+
80+
return base.GetForeignKeys(catalog, schema, table);
81+
}
82+
83+
public override DataTable GetIndexColumns(string catalog, string schemaPattern, string tableName, string indexName)
84+
{
85+
if (_dialect is SQLiteDialect)
86+
{
87+
// SQLiteDialect concatenates catalog and schema to the table name.
88+
var actualTableName = _dialect.Qualify(catalog, schemaPattern, tableName);
89+
return base.GetIndexColumns(null, null, actualTableName, indexName);
90+
}
91+
92+
return base.GetIndexColumns(catalog, schemaPattern, tableName, indexName);
93+
}
1094

1195
public override ITableMetadata GetTableMetadata(DataRow rs, bool extras)
1296
{
@@ -93,4 +177,4 @@ public SQLiteForeignKeyMetaData(DataRow rs) : base(rs)
93177
Name = Convert.ToString(rs["CONSTRAINT_NAME"]);
94178
}
95179
}
96-
}
180+
}

0 commit comments

Comments
 (0)