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

Added limitation of allowed input value #2527

Closed
wants to merge 1 commit into from

Conversation

gotqn
Copy link
Contributor

@gotqn gotqn commented Jul 16, 2019

The value which is converted to the target type is limited to 8000 bytes. If it exceed this limit a String or binary data would be truncated. is thrown. I believe this need to be known because one can add LEFT() for example to solve such case. Here are some example demonstrating this limitation with varchar and nvarchar inputs.

-- does not work

DECLARE @test VARCHAR(MAX);

SELECT @test = CAST(REPLICATE('a', 8000) AS VARCHAR(MAX)) + '1';

SELECT DATALENGTH(@test)

SELECT TRY_CAST(@test AS INT)

GO

-- does work

DECLARE @test VARCHAR(MAX);

SELECT @test = CAST(REPLICATE('a', 8000) AS VARCHAR(MAX));

SELECT DATALENGTH(@test)

SELECT TRY_CAST(@test AS INT)

GO

-- does not work

DECLARE @test NVARCHAR(MAX);

SELECT @test = CAST(REPLICATE('a', 4000) AS NVARCHAR(MAX)) + '1';

SELECT DATALENGTH(@test)

SELECT TRY_CAST(@test AS INT)

GO

-- does work

DECLARE @test NVARCHAR(MAX);

SELECT @test = CAST(REPLICATE('a', 4000) AS NVARCHAR(MAX));

SELECT DATALENGTH(@test)

SELECT TRY_CAST(@test AS INT)

GO

The value which is converted to the target type is limited to 8000 bytes. If it exceed this limit a String or binary data would be truncated. is thrown. I believe this need to be known because one can add LEFT() for example to solve such case. Here are some example demonstrating this limitation with varchar and nvarchar inputs.

-- does not work

DECLARE @test VARCHAR(MAX);

SELECT @test =  CAST(REPLICATE('a', 8000) AS VARCHAR(MAX)) + '1';

SELECT DATALENGTH(@test)

SELECT TRY_CAST(@test AS INT)

GO

-- does work 

DECLARE @test VARCHAR(MAX);

SELECT @test =  CAST(REPLICATE('a', 8000) AS VARCHAR(MAX));

SELECT DATALENGTH(@test)

SELECT TRY_CAST(@test AS INT)

GO

-- does not work

DECLARE @test NVARCHAR(MAX);

SELECT @test =  CAST(REPLICATE('a', 4000) AS NVARCHAR(MAX)) + '1';

SELECT DATALENGTH(@test)

SELECT TRY_CAST(@test AS INT)

GO

-- does work 

DECLARE @test NVARCHAR(MAX);

SELECT @test =  CAST(REPLICATE('a', 4000) AS NVARCHAR(MAX));

SELECT DATALENGTH(@test)

SELECT TRY_CAST(@test AS INT)

GO
@PRMerger15
Copy link
Contributor

@gotqn : Thanks for your contribution! The author(s) have been notified to review your proposed change.

@MikeRayMSFT
Copy link
Contributor

I believe this is already documented in the article:

Large-value data types

Large-value data types have the same implicit and explicit conversion behavior as their smaller counterparts - specifically, the nvarchar, varbinary, and varchar data types. However, consider the following guidelines:

  • Conversion from image to varbinary(max), and vice-versa, operates as an implicit conversion, as do conversions between text and varchar(max), and ntext and nvarchar(max).
  • Conversion from large-value data types, such as varchar(max), to a smaller counterpart data type, such as varchar, is an implicit conversion, but truncation occurs if the size of the large value exceeds the specified length of the smaller data type.
  • Conversion from nvarchar, varbinary, or varchar to their corresponding large-value data types happens implicitly.
  • Conversion from the sql_variant data type to the large-value data types is an explicit conversion.
  • Large-value data types cannot be converted to the sql_variant data type.

@gotqn
Copy link
Contributor Author

gotqn commented Jul 22, 2019

@MikeRayMSFT I am not seeing this information in the official docs . The only thing we have here is a note, that:

However if you request a conversion that is explicitly not permitted, then TRY_CAST fails with an error.

OK, but if you check the following examples:

-- does not work
DECLARE @test VARCHAR(MAX);
SELECT @test = CAST(REPLICATE('0', 8000) AS VARCHAR(MAX)) + '1';
SELECT DATALENGTH(@test)
SELECT TRY_CAST(@test AS INT)
GO

-- does work
DECLARE @test VARCHAR(MAX);
SELECT @test = CAST(REPLICATE('0', 8000) AS VARCHAR(MAX));
SELECT DATALENGTH(@test)
SELECT TRY_CAST(@test AS INT)
GO

You can check that the engine is able to convert string of 0s to 0, but not a one exceeding 8000 bytes.. So, it is not a limitation of the logic, but on the function.

Also, it seems to be a practice in the docs to point if there a limit of the input parameters. Many examples like this and this :

For SQL Server 2014 (12.x) and earlier, allowed input values are limited to 8000 bytes.

pattern is limited to 8000 characters.

Personally, I have never know that the input of TRY_CONVERT and TRY_CAST is limited in such way. But actually, the edit is not good, because if you try:

-- does not work
DECLARE @test VARCHAR(MAX);
SELECT @test = CAST(REPLICATE('0', 8000) AS VARCHAR(MAX)) + '00000';
SELECT DATALENGTH(@test)
SELECT DATALENGTH(TRY_CAST(@test AS VARCHAR(MAX)))
GO

You will see that this limitations is set only for particular types, because there is not a issue (or truncation) when 8000+ bytes string is converting to string.

Maybe, we need to have a note in the remarks saying that for numeric types the input value is limited to 8000 bytes.

Imagine where in VARCHAR(MAX) column you may have text and numbers (yes, it is bad design) and one is using TRY_CAST in WHERE clause to get only records containing a number - the query will be broken if one of the text value is larger then 8000 bytes.

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.

None yet

4 participants