Interfacing multiple systems is always a great source of learning. In the various integrations that I have been a part of over the years, one of the many things that I have learnt is that no two systems have the same world view of the data that they store.
To take a very simple example, assume that we are interfacing a home-grown warehousing system with a 3rd party front desk PoS system. One of the first problems that most people will run into is that the supported length for product name is different – the warehousing system might be accepting a product name of let’s say 60 characters whereas the PoS may have a limit of 50 characters.
Integrations need to take care of this sort of a mismatch, but it’s not always easy. Sometimes, the interface specifications are vague or in case of home-grown legacy systems, possibly non-existent. In most enterprise integrations, a pre-production run is often done with a backup of the existing production data. When doing a data load from one system to another, it is quite possible that we run into situations wherein the tests run fine, but a production run fails with the following error:
Msg 8152, Level 16, State 14, Line 17
String or binary data would be truncated.
As the error suggests, it is what can very simply be termed as a buffer overflow – we are attempting to insert a larger string into a smaller container (table column). Because the data was the same, the question that comes up is:
Why was the “String or binary data would be truncated” error random and not reproducible at will?
Connection Settings – ANSI_WARNINGS
The answer to the puzzle lies in the connection settings for the SET option – ANSI_WARNINGS.
If the ANSI_WARNINGS is set to OFF, attempting to insert a longer string into a smaller column automatically truncates the string. The following test confirms the behaviour:
USE tempdb; GO --Create Test table IF OBJECT_ID('dbo.AnsiWarningsTest','U') IS NOT NULL DROP TABLE dbo.AnsiWarningsTest; GO CREATE TABLE dbo.AnsiWarningsTest (FourtyCharacterTest VARCHAR(40)); GO --Default value, resetting for safety SET ANSI_WARNINGS OFF; --Check current value of ANSI_WARNINGS IF (@@OPTIONS & 8) = 8 PRINT 'ANSI_WARNINGS are ON'; ELSE PRINT 'ANSI_WARNINGS are OFF'; --Attempt to insert data longer than available column value --This should work fine INSERT INTO dbo.AnsiWarningsTest (FourtyCharacterTest) SELECT REPLICATE('a',100); GO SELECT AnsiWarningsTest.FourtyCharacterTest FROM dbo.AnsiWarningsTest; GO
As can be seen from the screenshot below, the only 40 characters were successfully inserted into the table – dbo.AnsiWarningsTest. The string truncation was handled automatically by Microsoft SQL Server.
Now, we turn ANSI_WARNINGS OFF and repeat the same test.
--Set ANSI_WARNINGS to ON SET ANSI_WARNINGS ON; --Check current value of ANSI_WARNINGS IF (@@OPTIONS & 8) = 8 PRINT 'ANSI_WARNINGS are ON'; ELSE PRINT 'ANSI_WARNINGS are OFF'; --Attempt to insert data longer than available column value --This SHOULD result into an exception INSERT INTO dbo.AnsiWarningsTest (FourtyCharacterTest) SELECT REPLICATE('b',100); GO
Attempting to execute this immediately results into the following error in the “Messages” tab of the SSMS.
ANSI_WARNINGS are ON
Msg 8152, Level 16, State 14, Line 12
String or binary data would be truncated.
Conclusion
When working with bulk data imports, it is important to know the differences in the storage design of both systems. Once known, mismatches that may result into potential string termination errors should be explicitly handled by the SUSBTRING clause.
Further Reading
Until we meet next time,