Skip to content

Driver/DriverBase: When cloning a parameter, also copy size/scale/pre… #528

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

Closed
wants to merge 1 commit into from

Conversation

oskarb
Copy link
Member

@oskarb oskarb commented Nov 14, 2016

…cision.

@oskarb oskarb added this to the 4.1.0 milestone Nov 14, 2016
@oskarb oskarb self-assigned this Nov 14, 2016
@oskarb
Copy link
Member Author

oskarb commented Nov 19, 2016

This causes NH3567.NH3567Tests.TestFlushModeAuto() to fail on ODBC with MSSQL Server 2016, with error:
[SQL: SELECT this_.Id as Id1_6548_0_, this_.Content as Con2_6548_0_, this_.PostId as Pos3_6548_0_ FROM Post this_ WHERE this_.Content = ?] ----> System.Data.Odbc.OdbcException : ERROR [42000] [Microsoft][SQL Server Native Client 11.0][SQL Server]The data types nvarchar and ntext are incompatible in the equal to operator.

The test uses an entity with a string property defined as length 2000 characters. Initially the parameter for the above SQL is defined with a size of 2000, but without the submitted change to CloneParameter that size is lost in the parameter instance that is actually used (so it will calculate the length as 6 characters itself). This works.

With the change, the size of 2000 is carried over to the cloned parameter. The parameter is initially treated as OdbcType.NVarChar, but eventually we end up in OdbcParameter's private method PrepareForBind() which does this:

            int cbParameterSize = GetParameterSize(value, offset, ordinal);      // count of bytes for the data, for SQLBindParameter
            // here we upgrade the datatypes if the given values size is bigger than the types columnsize
            //
            switch(_bindtype._sql_type) {
                case ODBC32.SQL_TYPE.VARBINARY: // MDAC 74372
                    // Note: per definition DbType.Binary does not support more than 8000 bytes so we change the type for binding
                    if ((cbParameterSize > 8000))
                        { _bindtype = TypeMap._Image; } // will change to LONGVARBINARY
                    break;
                case ODBC32.SQL_TYPE.VARCHAR: // MDAC 74372
                    // Note: per definition DbType.Binary does not support more than 8000 bytes so we change the type for binding
                    if ((cbParameterSize > 8000))
                        { _bindtype = TypeMap._Text; }  // will change to LONGVARCHAR
                    break;
                case ODBC32.SQL_TYPE.WVARCHAR : // MDAC 75099
                    // Note: per definition DbType.Binary does not support more than 8000 bytes so we change the type for binding
                    if ((cbParameterSize > 4000))
                        { _bindtype = TypeMap._NText; }  // will change to WLONGVARCHAR
                    break;
}

Notice it calls GetParameterSize() to convert the size of 2000 characters to 4002 bytes (including two null bytes), which in the third case is or course larger than 4000 so it switches to the NText type, which cannot in fact be used quite like that in the query.

I don't know where exactly the limits of 8000 and 4000 used above come from. I cannot find them in any ODBC document, but of course we can recognize them as MSSQL servers maximum lengths in characters for varchar and nvarchar respectively. If that is the source of the constants it seems like a bug in OdbcParameter to compare the size in bytes of the unicode string to the maxmum size in characters.

Even if the above is a bug and that was fixed (which it probably never will be), we would get the same problem again if the string property is defined with a length of 4000 characters or more. To handle that case there would either need to be a way to make the database interpret the parameter as nvarchar(max), or a cast added in the SQL.

@oskarb oskarb closed this Nov 19, 2016
@oskarb oskarb reopened this Nov 19, 2016
@oskarb oskarb force-pushed the fix-clone-parameter branch from f897e2c to 4d31e88 Compare November 19, 2016 16:25
@oskarb oskarb modified the milestones: 5.0.0, 4.1.0 Nov 20, 2016
@hazzik hazzik modified the milestones: 5.1, 5.0 Sep 1, 2017
@fredericDelaporte
Copy link
Member

The CloneParameter logic has been changed as part of #703, in 612ea36. This renders this PR obsolete.

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