REPLACE function in T-SQL 2008 is different from T-SQL 2005 - sql

I am on project of migrating databases from SQL Server 2005 to 2008.
During test I found one inconsistency. In accordance to BOL http://msdn.microsoft.com/en-us/library/ms186862(v=SQL.100).aspx (2008) and http://msdn.microsoft.com/en-us/library/ms186862(v=SQL.90).aspx (2005) returns varchar. So far both are the same. However if we pass to REPLACE function column type char then difference comes out. Look at this code
declare #test table
(
testcharstring char(25)
)
insert into #test
select 'Hello'
union
select 'World'
union
select 'Hello world '
select
'"'+testcharstring+'"' as original
,'"'+replace(testcharstring,'a','A')+'"' as afterreplace
--,'"'+replace(rtrim(testcharstring),'a','A')+'"'
from #test
Result from SQL Server 2005
original afterreplace
--------------------------- ---------------------------
"Hello " "Hello"
"Hello world " "Hello world"
"World " "World"
Result from SQL Server 2008
original afterreplace
--------------------------- ---------------------------
"Hello " "Hello "
"Hello world " "Hello world "
"World " "World "
T-SQL in SQL Server 2005 removes even legitimate trailing space, not to say that it threats char(25) as varchar(25). T-SQL in SQL Server 2008 approaches type more carefully and returns results in accordance of type which it receives for transformation
I have number places in different T-SQL objects, mostly in triggers. Main idea just to make minimal changes to keep same behaviour in SQL Server 2008
Possible ways to do it
Override built-in REPLACE function Quick search suggests that it impossible however my teammate wants to research that option
Use Rtrim() functions together with REPLACE. This will require replacement in exact places in code in multiple routines (where char columns are used)
Creating own version Replace in CLR to see that CLR allows me to keep SQL Server 2005 behaviour and then again search and replace function in exact location
I would like to ask everybody if somebody came across of this issue, how did you worked out?
Also any suggestion is also welcome, may be I just do not know what settings on server instance or database level can change behaviour.
Thank you in advance!

You have different SET ANSI_PADDING options, which can also be controlled by SET ANSI_DEFAULTS
As it stands, REPLACE behaves the same in both editions. Both (2005, 2008) say:
Returns nvarchar if one of the input arguments is of the nvarchar data type; otherwise, REPLACE returns varchar.
Edit: there are 2 Connect bugs/features
My answer above is probably wrong
http://connect.microsoft.com/SQLServer/feedback/details/259840/trailing-spaces-are-lost-when-a-char-value-is-fed-to-replace
Check DB compatible level:
http://connect.microsoft.com/SQLServer/feedback/details/126092/t-sql-replace-function-seems-to-be-broken-for-char-x-variables
And as a fix, sorry, I'd use rtrim, however is it a fix? You can't override replace, and if you plan on a clr urgent, why not wrap the replace/rtrim in a SQL udf

according to MS this is a correct behavior and SQL2005 had it wrong.
in you code you are using Replace() not only as corection function (Find a pattern and replace with another pattern) but also as Trim() function (if nothing found at least trim the incoming value)
but this is wrong when you are working with Char(). the only reason to use Char() as data type is to preserve the values data length at all cost.(IMHO) as in you need to ensure that returning Value length is ALWAYS the same regardless of actual stored character count.
this is important when you need to build some kind of structure using string concatenation
as in fixed length file for output, and do not care to bother with data length checks or conversions.
otherwise you might as well use varchar() or nvarchar()
http://msdn.microsoft.com/en-us/library/ms143359(v=sql.100).aspx
In SQL Server 2005, trailing spaces specified in the first input parameter to the REPLACE function are trimmed when the parameter is of type char. For example, in the statement SELECT '<' + REPLACE(CONVERT(char(6), 'ABC '), ' ', 'L') + '>', the value 'ABC ' is incorrectly evaluated as 'ABC'.
In SQL Server 2008, trailing spaces are always preserved. For applications that rely on the previous behavior of the function, use the RTRIM function when specifying the first input parameter for the function. For example, the following syntax will reproduce the SQL Server 2005 behavior SELECT '<' + REPLACE(RTRIM(CONVERT(char(6), 'ABC ')), ' ', 'L') + '>'.

Related

SQLSyntaxErrorException Using LTRIM to trim character 'x' in query

I using TRIM function to trim some characters in query, I using hibernate following is my query.
from ABean s where s.cId in (select ca.id from CBean ca where LTRIM(ca.refNumber,'0') = LTRIM('$ref$','0') and ca.valid = 0)
$ref$ is replace with actual value in query.
I am seeing a different behaviour when I am running with DB2 and When I am running with Mockito test (Using In memory DB).
With DB2 this query is working fine but with Mockito in memory db I am getting java.sql.SQLSyntaxErrorException, Error is something like this.
Syntax error: Encountered "," at line 1, column {column_number_in_actual_query}.
I am not able to make it working with in memory db, Is there anything wrong I am doing?
Thanks.
in IBM DB2, in the SYSIMB schema, LTRIM takes a second argument of characters being trimmed like you have (see here). However, in the SYSFUN schema (and in most other SQL implementations) it only takes one argument and assumes you are trimming whitespace (see here).
Based on the error it looks like the interpreter wasn't expecting a comma, so it's probably trying to use the more standard version of the function and failing when it sees the second argument.
based on the documentation for function references you should be able to replace LTRIM with SYSIBM.LTRIM

INSERT Statement in SQL Server Strips Characters, but using nchar(xxx) works - why?

I have to store some strange characters in my SQL Server DB which are used by an Epson Receipt Printer code page.
Using an INSERT statement, all are stored correctly except one - [SCI] (nchar(154)). I realise that this is a control character that isn't representable in a string, but the character is replaced by a '?' in the stored DB string, suggesting that it is being parsed (unsuccessfully) somewhere.
The collation of the database is LATIN1_GENERAL_CI_AS so it should be able to cope with it.
So, for example, if I run this INSERT:
INSERT INTO Table(col1) VALUES ('abc[SCI]123')
Where [SCI] is the character, a resulting SELECT query will return 'abc?123'.
However, if I use NCHAR(154), by directly inserting or by using a REPLACE command such as:
UPDATE Table SET col1 = REPLACE(col1, '?', NCHAR(154))
The character is stored correctly.
My question is, why? And how can I store it directly from an INSERT statement? The latter is preferable as I am writing from an existing application that produces the INSERT statement that I don't really want to have to change.
Thank you in advance for any information that may be useful.
When you write a literal string in SQL is is created as a VARCHAR unless you prefix is with N. This means if you include any Unicode characters, they will be removed. Instead write your INSERT statement like this:
INSERT INTO Table(col1) VALUES (N'abc[SCI]123')

right to left string in SQL server

Consider below query containing both Persian(a right to left language) and English(a left to right language):
SELECT 'نرم افزار SQL سرور'
the required result is this string :
سرور SQL نرم افزار
Is there any function or any other way to converting string from ltr to rtl??
It is required to add N before string literal: SELECT N'نرم افزار SQL سرور'. This is needed to correctly interpret contained Unicode characters. (Source)
Important: In some cases, please avoid using standard copy-paste in order to put SELECT into SSMS command window. This could affect the RTL/LTR order. Instead, try to open correctly composed file using File > Open.
And regarding your comment:
the result should be : سرور SQL نرم افزار`
I admit I understand RTL writing system only partially, but from what I can see, Persian words are put to the output exactly in order as you entered them (even if reading right to left). Could you show me based on Unicode Bidirectional Algorithm or similar standards document why the word order should be changed by SQL Server? Shouldn't be change you expect made by preprocessing on another place, sending expected string form SELECT N'سرور SQL نرم افزار'? I see no point why just SQL SELECT should perform the change. If it did, what would happen if you feed result of such a SELECT into another SELECT? Another transformation? I have reasons to think that SQL server is interpreting your input technically correctly.
Hint: maybe you can try to surround your RTL text by different Directional formatting characters.
Please try the same SELECT with MySQL server at SQL Fiddle. Different server and technology, but the same result as Microsoft SQL Server gave.
Result from SSMS with MS SQL Server:
Conclusion: in order to get expected result, please form the input accordingly.
Related: Transformation of word order you expected can be done by appropriate settings in user interface.
When we add digit with english this will again not work following solution will work
SELECT nchar(8234)+ N' 33-M ' + N'کلینک کمرہ نمبر' +nchar(8236) + N'میں تشریف لائیں'

Adding a quote character in a Delphi String

I am writing a SQL program in Delphi 7 and came across a problem.
If you add an SQL command you have to use ' to indicate it is a Variable or String, but I want to build up my SQL statement because it is coming from different If statements and thus have to build it up. Therefore, I wanted to know if anyone knows a trick to add a ' into a string.
Don't make the same mistake like many before you and lookup parametrized queries or else you will be open for SQL injection attacks. If you need to include string constants in your query then use 2 single quotes ('') or the QuotedStr() function from the SysUtils unit.
Try two quotes to represent one i.e. ''

Can you explain this SQL injection?

The website i worked was recently attempted to be hacked by the following SQL injection script
boys' and 3=8 union
select 1,
concat(0x232425,ifnull(`table_name`,0x30),char(9),ifnull(`table_rows`,0x30), char(9),0x252423),
3,4,5,6,7,8,9
from `information_schema`.`tables`
where table_schema=0x62646B3032 limit 44,1 -- And '8'='8
This injection returned the mysql table name. This was reported by the error reporting system on that website and we managed to fix that part however I am not able to understand what does the above injection mean?
Anyone can explain this?
Penuel
They're using a select from the Information Schema views in mysql server :
http://dev.mysql.com/doc/refman/5.0/en/information-schema.html
They use some clever hacks to rout out simple sql injection prevention techniques.
According to this the MySQL concat()
Returns the string that results from
concatenating the arguments. May have
one or more arguments. If all
arguments are nonbinary strings, the
result is a nonbinary string. If the
arguments include any binary strings,
the result is a binary string. A
numeric argument is converted to its
equivalent binary string form
So 0x232425 is converted to #$% which is simply added to the begining and end of the table_name field. Maybe just to make it easier for them to pull out the Table names later using Regex.
Later on the char(9) is equivalent to a tab as you can see here and is just there to format the output nicer.
The 3,4,5,6,7,8,9 is just there so that the columns match the boys table that they are performing the Union on.
This injection returned the mysql table name.
Do you mean that your website displayed the table name when you gave it this input, or that the query returns that when run from the mysql client? If it showed on your website, then the attacker has the ability to inject much more harmful queries. Check your data.