Skip to content

Add SQL Anywhere 17 support #1854

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 2 commits into from
Nov 15, 2018
Merged

Conversation

pettersoft
Copy link

Added a SQL Anywhere 17 driver and SQL Anywhere 17 dialect.

Copy link
Member

@fredericDelaporte fredericDelaporte left a comment

Choose a reason for hiding this comment

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

Thanks for your contribution.

I have not yet checked all the tests with my local database instance, but so far this looks overall good. (At least I have used the same driver for my own tests some time ago, see 6aef609.)

/// </item>
/// </list>
/// </remarks>
public class SybaseSQLAnywhere17Dialect : SybaseSQLAnywhere12Dialect
Copy link
Member

Choose a reason for hiding this comment

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

It seems to me the name Sybase is phased out. Shouldn't it be named SapSQLAnywhere17Dialect?

Copy link
Author

Choose a reason for hiding this comment

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

Yes, that's correct! It should be renamed to Sap instead.

RegisterKeywords();
}

new protected void RegisterKeywords()
Copy link
Member

Choose a reason for hiding this comment

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

SybaseSQLAnywhere12Dialect implementation is not what we do usually. Maybe that is the right time to fix it: switch these methods (RegisterKeywords and RegisterDateTimeTypeMappings) to override, calling their base implementation, and remove them from constructor call, both in SybaseSQLAnywhere12Dialect and here. SybaseSQLAnywhere10Dialect own constructor will call them, once switched to overrides.

@@ -0,0 +1,19 @@
namespace NHibernate.Driver
{
public class SybaseSQLAnywhere17Driver : ReflectionBasedDriver
Copy link
Member

Choose a reason for hiding this comment

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

As for the dialect, it should likely be renamed SapSQLAnywhere17Driver.

RegisterKeyword("limit");
RegisterKeyword("offset");
RegisterKeyword("datetimeoffset");
base.RegisterKeywords();
Copy link
Member

Choose a reason for hiding this comment

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

So, indeed these keywords were already registered in the base dialect. Better remove completely the override then.

{
RegisterColumnType(DbType.DateTimeOffset, "DATETIMEOFFSET");
base.RegisterDateTimeTypeMappings();
Copy link
Member

Choose a reason for hiding this comment

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

Same here.

@fredericDelaporte
Copy link
Member

Numerous tests are failings, and HqlIsThreadSafe_UsingThreads seems to freeze. Granted, previous Anywhere dialects were likely not fixed for all tests either. But now we rather fix tests or at least ignore those due to known limitations of the target database. (This was done for latest dialect additions, see #1662 by example.)

I may directly push here some commits for fixing these tests failures, but of course feel free to fix some of them too.

Copy link
Member

@fredericDelaporte fredericDelaporte left a comment

Choose a reason for hiding this comment

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

Here is a bunch of fixes. Not everything is fixed yet.

I have notably issues with queries selecting a string concatenation or a case as a column result. They work fine in Interactive SQL, but for some reasons, the reader (SADataReader) try to convert such column to numeric (string concatenation case) or integer (case when case), which fails. (Unless the result was by chance convertible to a number.)
I have posted here about this behavior, not finding any information.

@@ -29,7 +29,8 @@ protected override bool AppliesTo(Dialect.Dialect dialect)
return !(dialect is FirebirdDialect) &&
!(dialect is Oracle8iDialect) &&
!(dialect is MsSqlCeDialect) &&
!(dialect is HanaDialectBase);
!(dialect is HanaDialectBase) &&
!(dialect is SybaseSQLAnywhere10Dialect);
Copy link
Member

Choose a reason for hiding this comment

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

This batcher is not supported by SQL Anywhere. It seems it does not supports to have multiple inserts in the same query, as described here.

comp.Property(p => p.Name);
comp.Property(p => p.Dob);
comp.Property(p => p.Name, m => m.NotNullable(true));
comp.Property(p => p.Dob, m => m.NotNullable(true));
comp.Unique(true); // hbm2ddl: Generate a unique constraint in the database
Copy link
Member

Choose a reason for hiding this comment

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

This test does not need those columns to be nullable, so for avoiding troubles with database not supporting null in unique constraint, setting the columns as not nullable.

// SQL Anywhere does not respect usual priorities with the bitwise not. Unfortunately the HQL parser
// furthermore remove "undue" parenthesis according to usual rules. As the bitwise not should have maximal
// priority, we can work around this by using a template forcing parenthesis around it.
RegisterFunction("bnot", new VarArgsSQLFunction(NHibernateUtil.Int64, "(~", "", ")"));
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 not a breaking change, because the function argument will by default be all that follows the ~. But thanks to this change, if parenthesis are used to explicit the priority, they will be taken into account for supplying the "function" argument, instead of being silently removed by the parser.

if (limit == null && offset == null)
throw new ArgumentException("Cannot limit with neither a limit nor an offset");
if (limit == null)
throw new NotSupportedException($"Dialect {this} does not support setting an offset without a limit");
Copy link
Member

Choose a reason for hiding this comment

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

This case was previously blowing with a null reference exception. Overriden in the 17 version since SQL Anywhere 12.0.1 (but not 12.0.0) has a syntax allowing the support of this case.

public SqlStringBuilder Add(SqlString sqlString)
{
sqlString.Visit(AddingVisitor);
sqlString?.Visit(AddingVisitor);
Copy link
Member

Choose a reason for hiding this comment

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

Additional change for avoiding blowing with a null reference exception when the sqlString is null. The usual behavior for string builder being to do nothing on null, doing the same here.

@hazzik
Copy link
Member

hazzik commented Sep 26, 2018

@fredericDelaporte can we setup an automatic build for it?

@fredericDelaporte
Copy link
Member

fredericDelaporte commented Sep 26, 2018

On the TeamCity agent, it should be doable. On AppVeyor or Travis, I do no think there is a reasonably lightweight way to set it up on each build.

Update: it is maybe not possible for TeamCity too: there is no NuGet package as far as I know for the data provider, and I have not checked yet if its license could allow us to put it in NHibernate lib folder in Git.

@fredericDelaporte
Copy link
Member

Update: it is maybe not possible for TeamCity too: there is no NuGet package as far as I know for the data provider, and I have not checked yet if its license could allow us to put it in NHibernate lib folder in Git.

There is a Nuget package, but it is very likely to be unofficial. Looking at the license files available on my local setup, no redistribution is allowed for all components, including client ones. So I do not think we can legally put the data provider in the NHibernate lib folder. (The license allows a single installation for the developer and 25 internal deployments for testing purpose.)

@hazzik
Copy link
Member

hazzik commented Sep 27, 2018

Have you considered installing provider to GAC? We can put a readme file to /lib/teamcity/sqlAnywhere. Explaining how to install the drivers. If it goes with a DbProviderFactory we should be able to instantiate the provider from GAC using the provider name.

@fredericDelaporte
Copy link
Member

It does, and it is installed in GAC by the SQL Anywhere installer. Nothing to tell in lib/teamcity indeed.

@fredericDelaporte
Copy link
Member

Now remain failures due to #1855 and #1859 bugs, and failures due to what seems to be a quite poor type inference done by the data-provider on projected columns, causing it to treat columns resulting from a case when as being integers, columns resulting from a string concatenation using the + operator as being decimal, and columns resulting from arithmetic as being decimal(30,6), causing truncation when there was more than 6 fractional digits.
I consider adding a TestDialect property like HasUnreliableTypeInference.

@fredericDelaporte
Copy link
Member

fredericDelaporte commented Sep 28, 2018

It appears a hack similar to the one done on Firebird parameters in its driver could solve the bad type inference done by the data-provider on projected columns. This trouble seems to occurs only when the projection uses parameter values. And adding a cast around the parameter to explicit its type in the SQL solves the trouble. (At least in the tests here.)

But I do not think it is worth it. Such a hack implies parsing with reg-ex each generated query, and tweaking it with "word replacements". It is brittle and may breaks some query cases not covered by NHibernate tests.

@fredericDelaporte
Copy link
Member

I have setup a SAP SQL Anywhere TeamCity build. Its first almost successful build can be seen in 609f033 checks.

22 tests have failed. With c3597a3, only 14 failing tests should remain. Their fixes are in #1855 and #1859. Either I change them for being ignored, or this PR has to wait for these other PR merges.

The Anywhere build is paused, and I am launching it manually. Enabling it would likely cause all other branches builds to fail, unless they get updated with 0545b45 changes.

@fredericDelaporte
Copy link
Member

fredericDelaporte commented Oct 4, 2018

Rebased for resolving conflicts with latest merges, and test suite fixes squashed together.

hazzik
hazzik previously approved these changes Oct 30, 2018
Copy link
Member

@hazzik hazzik left a comment

Choose a reason for hiding this comment

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

LGTM

@fredericDelaporte
Copy link
Member

It does still depend on #1855 and #1859. I should have switched it to WIP.

@fredericDelaporte fredericDelaporte changed the title Added SQL Anywhere 17 support WIP - Added SQL Anywhere 17 support Oct 31, 2018
@fredericDelaporte fredericDelaporte force-pushed the master branch 2 times, most recently from 683d974 to 3eb4307 Compare November 7, 2018 13:18
@fredericDelaporte fredericDelaporte changed the title WIP - Added SQL Anywhere 17 support Added SQL Anywhere 17 support Nov 7, 2018
@fredericDelaporte
Copy link
Member

Rebased, Anywhere TeamCity build queued.

@fredericDelaporte fredericDelaporte changed the title Added SQL Anywhere 17 support Add SQL Anywhere 17 support Nov 7, 2018
@fredericDelaporte
Copy link
Member

Another fix is required, still due to the lack of support of null values in an unique constraint, see #1900.

This time, I have also locally applied this fix to the AnyWhere branch, and no tests are failing any-more for SQL Anywhere, with #1900 cherry-picked.

@fredericDelaporte fredericDelaporte changed the title Add SQL Anywhere 17 support WIP - Add SQL Anywhere 17 support Nov 11, 2018
Petter and others added 2 commits November 14, 2018 13:23
@fredericDelaporte fredericDelaporte changed the title WIP - Add SQL Anywhere 17 support Add SQL Anywhere 17 support Nov 14, 2018
@fredericDelaporte fredericDelaporte added this to the 5.2 milestone Nov 14, 2018
Copy link
Member

@fredericDelaporte fredericDelaporte left a comment

Choose a reason for hiding this comment

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

Now, the SQL Anywhere build succeeds.

@fredericDelaporte fredericDelaporte merged commit 018cf1c into nhibernate:master Nov 15, 2018
@fredericDelaporte
Copy link
Member

About enabling the build on TeamCity, we should likely wait for having active PR updated first.

@fredericDelaporte
Copy link
Member

fredericDelaporte commented Dec 7, 2018

@hazzik, do you agree for enabling the SAP SQL Anywhere build for all builds?

I think it is time to have all PR targeting master at least up-to-date with 5.2.

It will cause a failure for PR targeting older branches though. I do not see how to avoid that. (Excepted back-porting this PR here to the older branches, which I would rather avoid.)

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.

3 participants