Store such characters in SQL Server 2008 R2 - sql-server

I'm storing encrypted passwords in the database, It worked perfect so far on MachineA. Now that I moved to MachineB it seems like the results gets corrupted in the table.
For example: ù9qÆæ\2 Ý-³Å¼]ó will change to ?9q??\2 ?-³?¼]? in the table.
That's the query I use:
ALTER PROC [Employees].[pRegister](#UserName NVARCHAR(50),#Password VARCHAR(150))
AS
BEGIN
DECLARE #Id UNIQUEIDENTIFIER
SET #Id = NEWID()
SET #password = HashBytes('MD5', #password + CONVERT(VARCHAR(50),#Id))
SELECT #Password
INSERT INTO Employees.Registry (Id,[Name],[Password]) VALUES (#Id, #UserName,#Password)
END
Collation: SQL_Latin1_General_CP1_CI_AS
ProductVersion: 10.50.1600.1
Thanks

You are mixing 2 datatypes:
password need to be nvarchar to support non-Western European characters
literals need N prefix
Demo:
DECLARE #pwdgood nvarchar(150), #pwdbad varchar(150)
SET #pwdgood = N'ù9qÆæ\2 Ý-³Å¼]ó'
SET #pwdbad = N'?9q??\2 ?-³?¼]?'
SELECT #pwdgood, #pwdbad
HashBytes gives varbinary(8000) so you need this in the table
Note: I'd also consider salting the stored password with something other than ID column for that row

If you want to store such characters, you need to:
use NVARCHAR as the datatype for your columns and parameters (#Password isn't NVARCHAR and the CAST you're using to assign the password in the database table isn't using NVARCHAR either, in your sample ...)
use the N'....' syntax for indicating Unicode string literals
With those two in place, you should absolutely be able to store and retrieve any valid Unicode character

Related

How to store a string along with Syllabication in varchar column

Is there any way to store āre exactly in SQL server table.
I hardcoded the same value in varchar column. It is saving are. I wanted to store along with special symbols
Use Nvarchar - Nvarchar stores UNICODE data. If you have requirements to store UNICODE or multilingual data, Nvarchar is the choice. You need an N prefix when inserts data. Varchar stores ASCII data.
Refer below sample code
declare #data table
(field1 nvarchar(10))
insert into #data
values
(N'āre')
select * from #data
You need to declare your string assignment using the N prefix (the N
stands for "National Character") as you need to explicitly say you are
passing a string containing unicode characters here (or an nchar,
ntext etc if you were using those).
NVarchar variable are denoted by N' so it would be
DECLARE #objname nvarchar(255)
set #objname=N'漢字'
select #objname
Now the output will be 漢字 as it has been set. Run above code.

Stored procedure Inserts Hebrew characters into an NVARCHAR column, but SELECT shows "?"

When I SELECT from the table, the data that I stored is stored as question marks.
#word is a parameter in my stored procedure, and the value comes from the C# code:
string word = this.Request.Form["word"].ToString();
cmd.Parameters.Add("#word", System.Data.SqlDbType.NVarChar).Value = word;
My stored procedure is like this:
CREATE PROCEDURE ....
(
#word nvarchar(500)
...
)
Insert into rub_translate (language_id,name)
values (8 ,#word COLLATE HEBREW_CI_AS )
My database, and the column, is using the SQL_Latin1_General_CP1_CI_AS collation and I cannot change them.
Can anybody give me a solution how can I solve this problem just by modifying the column or the table?
In order for this to work you need to do the following:
Declare the input parameter in the app code as NVARCHAR (you have done this)
Declare the input parameter in the stored procedure as NVARCHAR (no code is shown for this)
Insert or Update a column in a table that is defined as NVARCHAR (you claim that this is the case)
When using NVARCHAR it does not matter what the default Collation of the Database is. And actually, when using NVARCHAR, it won't matter what the Collation of the column in the table is, at least not for properly inserting the characters.
Also, specifying the COLLATE keyword in the INSERT statement is unnecessary and wouldn't help anyway. If you have the stored procedure input parameter defined as VARCHAR, then the characters are already converted to ? upon coming into the stored procedure. And if the column is actually defined as VARCHAR (you haven't provided the table's DDL) then if the Collation isn't Hebrew_* then there is nothing you can do (besides change either the datatype to NVARCHAR or the Collation to a Hebrew_ one).
If those three items listed at the top are definitely in place, then the last thing to check is the input value itself. Since this is a web app, it is possible that the encoding of the page itself is not set correctly. You need to set a break point just at the cmd.Parameters.Add("#word", System.Data.SqlDbType.NVarChar).Value = word; line and confirm that the value held in the word variable contains Hebrew characters instead of ?s.
ALSO: you should never create a string parameter without specifying the max length/size. The default is 30 (in this case, sometimes it's 1), yet the parameter in the stored procedure is defined as NVARCHAR(500). This could result in silent truncation ("silent" meaning that it will not cause an error, it will just truncate the value). Instead, you should always specify the size. For example:
cmd.Parameters.Add("#word", System.Data.SqlDbType.NVarChar, 500).Value = word;
You could just insert it as-is, since it's unicode and then select it with a proper collation:
declare #test table([name] nvarchar(500) collate Latin1_General_CI_AS);
declare #word nvarchar(500) = N'זה טקסט.';
insert into #test ( [name] ) values ( #word );
select [t].[name] collate Hebrew_CI_AS from #test as [t]
Or you can change the collation of that one column in the table all together. But remember that there is a drawback of having a different collation from your database in one or more columns: you will need to add the collate statement to queries when you need to compare data between different collations.

collation as function argument

I have a database that is supposed to store data in any language, there is going to be a column that tells me which locale it is, so i can't rely on database collation and will have to specify collation at runtime in queries.
I also have the problem that i want to use EF for dataaccess, as we know using EF one cannot specify collation at runtime. I am thinking about creating a sql function that takes collation as argument and apply that function in all of the Linq Queries.
but this fails
CREATE FUNCTION fn_Compare
(
#TextValue nvarchar(max),
#Culture varchar(10)
)
RETURNS nvarchar(max)
AS
BEGIN
RETURN #TextValue COLLATE #Culture
END
GO
does anyone know if this can be done ?
You cannot do this. The collation returned by the function needs to be consistent across all the return values. For instance, the following generates an error:
create function testfn (#test varchar(100), #i int)
returns varchar(100)
as
begin
return(case when #i = 0 then #test collate SQL_Latin1_General_CP1_CS_AS
else #test collate SQL_Latin1_General_CP1_CI_AS
end)
end;
The error is due to a collation conflict.
What you can do is use:
alter database collate <whatever>
Or, alternatively, create a new working database with the collation you want.

How to convert varbinary to GUID in TSQL stored procedure?

how can I convert the HASHBYTES return value to a GUID?
This is what I have so far.
CREATE PROCEDURE [dbo].[Login]
#email nvarchar,
#password varchar
AS
BEGIN
DECLARE #passHashBinary varbinary;
DECLARE #newPassHashBinary varbinary;
-- Create a unicode (utf-16) password
Declare #unicodePassword nvarchar;
Set #unicodePassword = CAST(#password as nvarchar);
SET #passHashBinary = HASHBYTES('md5', #password);
SET #newPassHashBinary = HASHBYTES('md5', #unicodePassword);
Simply cast it:
select cast(hashbytes('md5','foo') as uniqueidentifier)
But there are two questions lingering:
why cast HASHBYTES to guid? Why not use the appropriate type for storage, namely BINARY(16)
I hope you are aware that MD5 hashing passwords is basically useless, right? Because of rainbow tables. You need to use a secure hashing scheme, like an HMAC or the HA1 of Digest.

Compare Varchar and UniqueIdentifier

Due to a rather brilliant oversight in my current project, we have some guids getting stored in a varchar column in one table, which need to be compared to a uniqueidentifier column in another.
How can I do this? SQL server simply says it cannot convert from a character string to a uniqueidentifier.
If SQL complains it cannot cast it means not only you stored the uniqueidentifier as varchar, you used a different format than SQL Server (eg. you added the '{' and '}'). SQL is perfectly capable of casting string to uniqueidentifier when properly formatted:
declare #u uniqueidentifier;
declare #s varchar(64);
select #u = NEWID();
select #s = CAST(#u as varchar(64));
select CAST(#s as uniqueidentifier), #u, #s;
Depending on how you actualy stored the uniqueidentifier, you will most likely have tomodify the data and your code to match the SQL format (no {}).
Convert the uniqueidentifier to varchar:
CAST( uniqueidentifier_col_name as varchar)
I just worked up the following test script:
DECLARE
#Foo Uniqueidentifier
,#Foo2 varchar(50)
SET #Foo = newid()
SET #Foo2 = newId()
print #Foo
print #Foo2
if #Foo = #Foo2
print 'Yes'
else
print 'No'
set #Foo = #Foo2
if #Foo = #Foo2
print 'Yes'
else
print 'No'
Run in an SSMS window or via slqcmd -i file, the results are the same -- SQL (2005) does implicit conversion. This supports what I recall from SQL 2000 when I had a similar problem years ago.
The key thing is that the varchar string has to match the guid pattern:
8 hex digits
dash
4 hex digits
dash
4 hex digits
dash
4 hex digits
dash
12 hex digits
You'll have to cast the other uniqueidentifier to varchar.
SQL Server is probably tryng to cast things like "bob" to uniqueidentifier and it fails.
According to CAST/CONVERT it's allowed, so it must be the values in the varchar column.

Resources