DataAction / AdoNetCore.AseClient

AdoNetCore.AseClient - a .NET Core DB Provider for SAP ASE
Apache License 2.0
108 stars 45 forks source link

Connection fails to database with 'disable character set conversions' parameter set and client charset #110

Closed driseley closed 5 years ago

driseley commented 5 years ago

When trying to connect to a Sybase database that has had the following parameter enabled:

sp_configure 'disable character set conversions', 1

http://infocenter.sybase.com/help/index.jsp?topic=/com.sybase.infocenter.dc31654.1600/doc/html/san1360629067891.html

and a Charset is specified on the login string, the connection fails with the following error:

AdoNetCore.AseClient.AseException : Server environment changed to unsupported charset ''. To add support for this charset, register an EncodingProvider to handle targeting ''.

This can be reproduced by running the AdoNetCore.AseClient.Tests.Integration.Connection.CharsetTests.OpenConnection_WithCharsetCp850_PlusEncodingProvider_Succeeds test against a database with this parameter set.

This fails with the following error:

Test Name:  OpenConnection_WithCharsetCp850_PlusEncodingProvider_Succeeds
Test FullName:  AdoNetCore.AseClient.Tests.Integration.Connection.CharsetTests.OpenConnection_WithCharsetCp850_PlusEncodingProvider_Succeeds
Test Source:    C:\Users\dev\Documents\git-repos\AdoNetCore.AseClient\test\AdoNetCore.AseClient.Tests\Integration\Connection\CharsetTests.cs : line 31
Test Outcome:   Failed
Test Duration:  0:00:00.045

Result StackTrace:  at AdoNetCore.AseClient.Internal.Handler.EnvChangeTokenHandler.Handle(IToken token) in C:\Users\dev\Documents\git-repos\AdoNetCore.AseClient\src\AdoNetCore.AseClient\Internal\Handler\EnvChangeTokenHandler.cs:line 74
   at AdoNetCore.AseClient.Internal.InternalConnection.ReceiveTokens(ITokenHandler[] handlers) in C:\Users\dev\Documents\git-repos\AdoNetCore.AseClient\src\AdoNetCore.AseClient\Internal\InternalConnection.cs:line 101
   at AdoNetCore.AseClient.Internal.InternalConnection.Login() in C:\Users\dev\Documents\git-repos\AdoNetCore.AseClient\src\AdoNetCore.AseClient\Internal\InternalConnection.cs:line 127
   at AdoNetCore.AseClient.Internal.InternalConnectionFactory.GetNewConnection(CancellationToken token, IInfoMessageEventNotifier eventNotifier) in C:\Users\dev\Documents\git-repos\AdoNetCore.AseClient\src\AdoNetCore.AseClient\Internal\InternalConnectionFactory.cs:line 38
   at AdoNetCore.AseClient.Internal.ConnectionPool.<CreateNewPooledConnection>d__15.MoveNext() in C:\Users\dev\Documents\git-repos\AdoNetCore.AseClient\src\AdoNetCore.AseClient\Internal\ConnectionPool.cs:line 159
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at AdoNetCore.AseClient.Internal.ConnectionPool.<ReservePooledConnection>d__13.MoveNext() in C:\Users\dev\Documents\git-repos\AdoNetCore.AseClient\src\AdoNetCore.AseClient\Internal\ConnectionPool.cs:line 114
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at AdoNetCore.AseClient.Internal.ConnectionPool.Reserve(IInfoMessageEventNotifier eventNotifier) in C:\Users\dev\Documents\git-repos\AdoNetCore.AseClient\src\AdoNetCore.AseClient\Internal\ConnectionPool.cs:line 81
   at AdoNetCore.AseClient.Internal.ConnectionPoolManager.Reserve(String connectionString, IConnectionParameters parameters, IInfoMessageEventNotifier eventNotifier) in C:\Users\dev\Documents\git-repos\AdoNetCore.AseClient\src\AdoNetCore.AseClient\Internal\ConnectionPoolManager.cs:line 15
   at AdoNetCore.AseClient.AseConnection.Open() in C:\Users\dev\Documents\git-repos\AdoNetCore.AseClient\src\AdoNetCore.AseClient\AseConnection.cs:line 275
   at AdoNetCore.AseClient.Tests.Integration.Connection.CharsetTests.OpenConnection_WithCharsetCp850_PlusEncodingProvider_Succeeds() in C:\Users\dev\Documents\git-repos\AdoNetCore.AseClient\test\AdoNetCore.AseClient.Tests\Integration\Connection\CharsetTests.cs:line 38
Result Message: AdoNetCore.AseClient.AseException : Server environment changed to unsupported charset ''. To add support for this charset, register an EncodingProvider to handle targeting ''.

From the TDS Specification:

TDS_ENVCHANGE - 

NewValLen: This gives the length, in bytes, of the new value for the
variable. The length may be 0.

NewValue: This is the new value of the environment variable. Its length is
given by the preceding argument. If length is 0, it will be omitted from the
datastream

It looks to me like https://github.com/DataAction/AdoNetCore.AseClient/blob/82a0df85793b76f3062a10f5c327e3a7e400b712/src/AdoNetCore.AseClient/Internal/Handler/EnvChangeTokenHandler.cs#L57-L76 does not correctly handle an empty NewValue.

In my opinion, when this occurs the requested client encoding should be set anyway (if the encoding is resolvable) otherwise it will incorrectly use the default ASCII encoding.

This appears to be the behaviour of the Java jTDS and jConnect drivers if the CHARSET driver property is specified and the 'disable character set conversions' parameter is set

driseley commented 5 years ago

Debug from the driver when this occurs:

---------- Receive Tokens ----------

<- TDS_LOGINACK: TDS 5.0.0.0, ASE 16.0.3
<- TDS_DONE: TDS_DONE_FINAL (24)
TDS_ENVCHANGE: TDS_ENV_CHARSET - iso_1 -> 
INFO  [10] [L:0]: Changed client character set setting to '<NULL>'.
TDS_ENVCHANGE: TDS_ENV_DB - master -> master
INFO  [10] [L:0]: Changed database context to 'master'.
TDS_ENVCHANGE: TDS_ENV_LANG -  -> us_english
INFO  [10] [L:0]: Changed language setting to 'us_english'.
TDS_ENVCHANGE: TDS_ENV_PACKSIZE -  -> 2048

Partial hexdump:

00000000   E3 08 00 03 00 05 69 73  6F 5F 31 E5 51 00 48 16   ã.....iso_1åQ.H.
00000010   00 00 02 0A 05 5A 5A 5A  5A 5A 00 01 00 32 00 43   .....ZZZZZ...2.C
00000020   68 61 6E 67 65 64 20 63  6C 69 65 6E 74 20 63 68   hanged client ch
00000030   61 72 61 63 74 65 72 20  73 65 74 20 73 65 74 74   aracter set sett
00000040   69 6E 67 20 74 6F 20 27  3C 4E 55 4C 4C 3E 27 2E   ing to '<NULL>'.