Skip to content
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

NH-1285 - Drop/Create script with default_schema/default_catalog fix(SqlServer) #448

Merged
merged 2 commits into from
Jan 11, 2018

Conversation

lnu
Copy link
Member

@lnu lnu commented Nov 12, 2015

https://nhibernate.jira.com/browse/NH-1285
related also to https://nhibernate.jira.com/browse/NH-1443 (both already closed) and #987.
In case the Schema is set using the Default_Schema property, the drop script for the generated constraint is wrong: the schema is missing(Sql Server).

@lnu lnu changed the title Drop/Create script with default_schema fix(SqlServer) NH-1285 Drop/Create script with default_schema fix(SqlServer) Nov 12, 2015
@hazzik
Copy link
Member

hazzik commented Dec 3, 2015

@lnu can you please avoid changing method signatures of Dialect class? Preferable create new virtual methods and use them, make old methods using new methods (or vice verse) and mark old methods as obsolete.

@lnu
Copy link
Member Author

lnu commented Dec 3, 2015

Ok i'll check for this

On Thu, Dec 3, 2015 at 2:08 AM, Alexander Zaytsev notifications@github.com
wrote:

@lnu https://github.com/lnu can you please avoid changing method
signatures of Dialect class? Preferable create new virtual methods and
use them, make old methods using new methods (or vice verse) and mark old
methods as obsolete.


Reply to this email directly or view it on GitHub
#448 (comment)
.

@lnu
Copy link
Member Author

lnu commented Dec 3, 2015

I did some changes. Is it what you were thinking about?

@hazzik
Copy link
Member

hazzik commented Dec 3, 2015

Is it what you were thinking about?

Almost,

You forgot about this part: "make old methods using new methods (or vice verse)". The idea is that if you use not updated provider, it should still work as expected.

/// <returns></returns>
public virtual string GetIfNotExistsCreateConstraint(Table table, string name, string defaultSchema)
{
return "";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here you need to call GetIfExistsDropConstraintEnd(table, name), for example

@hazzik hazzik modified the milestone: 4.1.0 Dec 3, 2015
@hazzik
Copy link
Member

hazzik commented Dec 3, 2015

@lnu does it actually work for SQL2000? Shouldn't it be the same?

@lnu
Copy link
Member Author

lnu commented Dec 3, 2015

There is no schema in SqlServer 2000. It was introduced in 2005. no?
How does it work if you use a schema with sql 2000?

@hazzik
Copy link
Member

hazzik commented Dec 3, 2015

@lnu true, it does not have a schema.

Also, the same issue exists with defaultCatalog, so, i think the code of ForeignKey and other constraints should be changed to something like this:

public override string SqlDropString(Dialect.Dialect dialect, string defaultCatalog, string defaultSchema)
{
    var tableName = Table.GetQualifiedName(dialect, defaultCatalog, defaultSchema);

    var ifExists = dialect.GetIfExistsDropConstraint(tableName, Name);
    string drop = string.Format("alter table {0} {1}", tableName, dialect.GetDropForeignKeyConstraintString(Name));
    string end = dialect.GetIfExistsDropConstraintEnd(tableName, Name);
    return ifExists + System.Environment.NewLine + drop + System.Environment.NewLine + end;
}

@lnu
Copy link
Member Author

lnu commented Dec 3, 2015

Ok...
I've checked multiple scenarios with catalog and schema and there are definitely more bugs than my initial one.
For example, the catalog is not quoted correctly if defined in mapping but works with default_catalog

@lnu lnu force-pushed the SqlServerDefaultSchema branch from 7a111c9 to d3536ac Compare March 8, 2016 13:37
@lnu
Copy link
Member Author

lnu commented Mar 8, 2016

@hazzik Does it look for you now?
Now everything is quoted correctly including the catalog (default or not). The catalog is also used when querying, which was not the case before.
ps:I rebased and squashed everything.

@lnu lnu force-pushed the SqlServerDefaultSchema branch from 4b78752 to b53b7b0 Compare March 8, 2016 14:05
var tableName = Table.GetQualifiedName(dialect, defaultCatalog, defaultSchema);
string ifExists = dialect.GetIfExistsDropConstraint(Table, Name, defaultCatalog, defaultSchema);
string drop = string.Format("alter table {0} drop constraint {1}", Table.GetQualifiedName(dialect, defaultCatalog, defaultSchema), Name);
string end = dialect.GetIfExistsDropConstraintEnd(Table, tableName, defaultCatalog, defaultSchema);

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Loud thinking:

Hi @lnu. can we move all this to the Dialect? We really need to have one method, which will generate the constraint. Reason for that, is that MS SQL does support "if exist" statement natively. Also the GetIfExistsDropConstraintEnd method looks more like a workaround than a solution.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It could be part of a refactoring. I think we should just close this one with the current solution.

@hazzik hazzik changed the title NH-1285 Drop/Create script with default_schema fix(SqlServer) NH-1285 - Drop/Create script with default_schema fix(SqlServer) Mar 8, 2016
@hazzik
Copy link
Member

hazzik commented Mar 8, 2016

Looks good. I will review the PR shortly. Please ignore my last comment for now, as it is just a loud thinking.

@hazzik
Copy link
Member

hazzik commented Mar 8, 2016

NH-2288 tests are failing now

/// <param name="name">The schema name</param>
/// <param name="dialect">The instance of dicalect to use</param>
/// <returns></returns>
private string GetQuotedName(string name, Dialect.Dialect dialect)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this necessary to quote everything?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if the catalog/schema is not quoted and a reserved keyword is used it will fail. Don't you think?

Copy link
Member

@fredericDelaporte fredericDelaporte Sep 13, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems to me this code only handles conversion from NHibernate back-tilt quoting to dialect quoting. It will not quote an unquoted string. So if a reserved word is used without native quoting nor NHibernate quoting, it will fail. But that is not much an issue, the user just have to add quotes himself for such case. Otherwise if you want to handle that case, you need to look at the auto-quoting option, which, if enabled, does quote according to the dictionary of reserved words for the dialect.

By the way it looks strange to me to have to code that here. Some method should already supply that quote conversion somewhere else in NHibernate.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's kind-of correct behavior. On the Hibernate side they started conversion to "quotable identifier" value object for names (but did not finish, as usual)

@lnu lnu changed the title NH-1285 - Drop/Create script with default_schema fix(SqlServer) NH-1285 - Drop/Create script with default_schema/default_catalog fix(SqlServer) Mar 9, 2016
@lnu lnu force-pushed the SqlServerDefaultSchema branch 2 times, most recently from 2348667 to 1c3ce42 Compare March 9, 2016 07:50
@oskarb
Copy link
Member

oskarb commented Dec 10, 2016

I kind of wish this had been done as a series of commits - I get the impression there are multiple issues and quoting of catalog doesn't really concern if schema is missing or not, does it? Not saying it's worth the effort to split it up now though.

I'm unsure what the repercussions of changing the signature of the overloads in the concrete dialects with regards to API stability. Any idea if that could be an issue?

Does Hibernate have the same bugs, or how have they been fixed there?

@hazzik
Copy link
Member

hazzik commented Dec 11, 2016

There are some divergences between NHibernate and Hibernate. This feature was heavily modified to enable it for SQL Server. Another issue, that we need to refactor the feature to enable Sql Server 2016 native if exist clause.

/// </summary>
/// <param name="aliasName">Name of the alias.</param>
/// <returns>A name with back-tilt quotes converted if any.</returns>
public virtual string ConvertQuotesForAliasName(string aliasName)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having X methods doing the same isn't necessary.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is done for consistency with the QuoteFor series, which does exactly the same. I think the idea is to allow a dialect to override some but not all of them with a different implementation, in case a database may have different quoting rules depending of the quoted object type.

If we consider this as not necessary, then we should obsolete the QuoteFor series by the way and keep only a general purpose QuoteFor.

We may improve the pattern by calling the corresponding QuoteFor from ConvertQuotesFor, in order to allow to override only one method instead of both. (But this will cause the convert to do the additional check done in quote for, which it does not need.)

@hazzik
Copy link
Member

hazzik commented Dec 9, 2017

Could the unnecessary whitespace changes be reverted (especially in Configuration.cs)?
Also if we want #956 then this would require more systematic approach.

@fredericDelaporte fredericDelaporte removed their assignment Dec 10, 2017
@fredericDelaporte
Copy link
Member

Could the unnecessary whitespace changes be reverted (especially in Configuration.cs)?

I have taken the time to review them all. I am favorable to let them.

@lnu lnu force-pushed the SqlServerDefaultSchema branch 2 times, most recently from f045652 to efbc1a1 Compare December 20, 2017 06:20
…SqlServer)

NH-2288 - Test updated (fully qualified name)
Typo fixed
feedbacks, new test, comments
previous version restored(failing tests)

Refactor quoting out of Configuration.

Adjust obsoletes, avoid breaking changes.

Missing async regen.

Refactor get schema/catalog.
@lnu lnu force-pushed the SqlServerDefaultSchema branch from efbc1a1 to df8b0c7 Compare January 5, 2018 06:09
@fredericDelaporte fredericDelaporte self-assigned this Jan 10, 2018
@fredericDelaporte fredericDelaporte merged commit f5aa820 into nhibernate:master Jan 11, 2018
/// <returns></returns>
public virtual string GetIfNotExistsCreateConstraint(string catalog, string schema, string table, string name)
{
return "";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I realize a bit late that we have a breaking change here.
virtual string GetIfNotExistsCreateConstraint(Table table, string name) has been obsoleted in favor of this new virtual string GetIfNotExistsCreateConstraint(string catalog, string schema, string table, string name) method, which is now used instead of the old in NHibernate code base.

So dialects overriding the obsolete method will cease working as expected, because their override will now just be ignored. It means that such dialects will return an empty string for the new GetIfNotExistsCreateConstraint, since they do not override it. And so such dialects will no more be able to create constraints.

So when obsoleting overridable methods, we cause a breaking change by ceasing using them.

In the present case, since the new default implementation is indeed "no-op", we could try avoiding the breaking change by calling the old obsolete method instead. The old method should then, of course, be reverted to its old "no-op" behavior instead of calling the new implementation. So furthermore all its removed overrides would have to be put in place again for avoiding another breaking change.

But this does not stops here. If we do that, how should we then consider overrides of the new method? These overrides would then be somewhat breaking change too, since they would cause another dialect further down the inheritance chain and overriding itself the obsolete method to cease achieving its override...
But in the case of this PR, removing these new overrides cannot be done without undoing the PR.

So either we fully revert this PR to avoid this kind of breaking change, or we add this as possible breaking change in 5.1, or we bump version to 6.0 (and still add this as possible breaking change).

An additional conclusion to this is that obsoleting overridable methods is in most cases a breaking change. (It could be done without breaking changes only if the new method call the old one and is not overridden in an exposed descendant, unless the new override also call the old method.)

@fredericDelaporte
Copy link
Member

fredericDelaporte commented Jan 21, 2018

Possible breaking changes:

  • Overridable methods have been obsoleted and their overrides will no more have effects. Overrides of their replacements must be added in the impacted deriving classes. Obsoleted overridable methods are:
    • Dialect.GetIfNotExistsCreateConstraint(Table table, string name), replaced by GetIfNotExistsCreateConstraint(string catalog, string schema, string table, string name).
    • Dialect.GetIfNotExistsCreateConstraintEnd(Table table, string name), replaced by GetIfNotExistsCreateConstraintEnd(string catalog, string schema, string table, string name).
    • Dialect.GetIfExistsDropConstraint(Table table, string name), replaced by GetIfExistsDropConstraint(string catalog, string schema, string table, string name).
    • Dialect.GetIfExistsDropConstraintEnd(Table table, string name), replaced by GetIfExistsDropConstraintEnd(string catalog, string schema, string table, string name).
    • MsSql2000Dialect.GetSelectExistingObject(string name, Table table), replaced by GetSelectExistingObject(string catalog, string schema, string table, string name).

fredericDelaporte added a commit to fredericDelaporte/nhibernate-core that referenced this pull request Jan 21, 2018
fredericDelaporte added a commit to fredericDelaporte/nhibernate-core that referenced this pull request Jan 21, 2018
fredericDelaporte added a commit to fredericDelaporte/nhibernate-core that referenced this pull request Feb 28, 2018
fredericDelaporte added a commit to fredericDelaporte/nhibernate-core that referenced this pull request Mar 11, 2018
fredericDelaporte added a commit to fredericDelaporte/nhibernate-core that referenced this pull request Mar 12, 2018
fredericDelaporte added a commit to fredericDelaporte/nhibernate-core that referenced this pull request Mar 12, 2018
fredericDelaporte added a commit to fredericDelaporte/nhibernate-core that referenced this pull request Mar 14, 2018
fredericDelaporte added a commit to fredericDelaporte/nhibernate-core that referenced this pull request Mar 14, 2018
fredericDelaporte added a commit to fredericDelaporte/nhibernate-core that referenced this pull request Mar 14, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants