Convert Hex Data in an Image Field to String - sql

We have a database hosted on our SQL Server 2016 server that has email content stored in an IMAGE type column. I am trying to convert the data to its string representation. Everything I've read says that I should be able to just use CONVERT(VARCHAR(MAX), Field, 1) but that's not working. I've tried the following as a test:
declare #body varbinary(max);
select #body = substring(cast(body as varbinary(max)),1,13) from dbo.arc_bodies where id = -2147467502
select #body, convert(varchar(1000), #body, 1), convert(varchar(1000), 0x3C68746D6C3E)
So I take the first 13 bytes (just for testing I kept the data short instead of grabbing the whole column) from the "body" IMAGE field and convert it to VARBINARY. In the last statement, I show the contents of #body, try the convert, and try the convert by just copying the raw data.
This is what I end up with:
(No column name) (No column name) (No column name)
0x3C68746D6C3E0D0A3C68656164 0x3C68746D6C3E0D0A3C68656164 <html>
The convert of the #body returns the exact same data as the raw binary but the convert of the raw data works. What am I doing wrong?

In 3rd column in the last query you don't use any style. Just do the same for the 2nd one:
select #body, convert(varchar(1000), #body), convert(varchar(1000), 0x3C68746D6C3E)
A reference to MS docs

Related

Encrypting and Decrypting String Using SQL's EncryptByPassPhrase

I have a need to Encrypt text, transmit the encrypted text, and decrypt the text ... using SQL.
I tried EncryptByPassPhrase which returns a VARBINARY. I convert it to VARCHAR (for easier transmitting), and when I try to convert it back to VARBINARY, it fails. From what I can see, the CONVERT from VarBinary to VarChar, truncates the string, appears like the second half of the VarBinary value gets dropped when converting to VarChar. So when converting back from that VarChar value, it is incomplete and fails.
Here is sample code:
DECLARE #binEncryptedText VARBINARY(MAX) = EncryptByPassPhrase('Password', 'My Text')
DECLARE #strEncryptedText VARCHAR(MAX) = CONVERT(VARCHAR, #binEncryptedText, 2)
DECLARE #binDecryptedText VARBINARY(MAX) = CONVERT(VARBINARY, #strEncryptedText, 2)
DECLARE #strDecryptedText VARCHAR(MAX) = CONVERT(VARCHAR, DecryptByPassPhrase('Password', #binDecryptedText))
SELECT 1 As RowNumber,
#binEncryptedText AS EncryptedBinary,
#strEncryptedText AS EncryptedBinaryAsText
UNION
SELECT 2 As RowNumber,
#binDecryptedText AS EncryptedBinary,
#strDecryptedText AS EncryptedBinaryAsText
As you can see in the screenshot of my results above... In Row #1, the Binary that was converted to Text ... is shorter than the original Binary (truncated roughly halfway). So when converting that truncated text back to Binary, it fails to return the complete value ... which then causes the Decrypt to fail.
How can I get the encrypted text's VarBinary converted to "text" and then have the "text" converted back to the correct VarBinary value so it can be decrypted?
MSSQL has a well hidden Base64 encoder and decoder - within the XML subsystem. Convert the encrypted varbinary to Base64 for transmission, it will become an ASCII string, transmit the string, then decode back to a varbinary. The encoder/decoder is an XPath function, so you need an XML context to run it, but you can provide a dummy one. So the code for encoding goes:
cast('' as xml).value('xs:base64Binary(sql:variable("#b"))', 'varchar(max)')
where #b is your varbinary.
To decode:
cast('' as xml).value('xs:base64Binary(sql:variable("#s"))', 'varbinary(max)')
where #s is the Base64 string.
It's kind of funky that the encoder and the decoder is the same function, but I guess it knows what to do by the datatype of the argument. I haven't used this technique extensively myself, but I've tried it and it worked as expected. MSSQL 2019.
You can also use xs:hexBinary to encode the binary data as hex. Base64 representation is smaller, though; 4 characters for 3 bytes vs. 2 for 1.
So I actually ended up figuring out what my problem was. In SQL, some of my commands were "incomplete" ... in a manner of speaking.
DECLARE #binEncryptedText VARBINARY(MAX) = EncryptByPassPhrase('Password', 'My Text')
DECLARE #strEncryptedText VARCHAR(MAX) = CONVERT(VARCHAR(MAX), #binEncryptedText, 2)
DECLARE #binDecryptedText VARBINARY(MAX) = CONVERT(VARBINARY(MAX), #strEncryptedText, 2)
DECLARE #strDecryptedText VARCHAR(MAX) = CONVERT(VARCHAR(MAX), DecryptByPassPhrase('Password', #binDecryptedText))
SELECT 1 As RowNumber,
#binEncryptedText AS EncryptedBinary,
#strEncryptedText AS EncryptedBinaryAsText
UNION
SELECT 2 As RowNumber,
#binDecryptedText AS EncryptedBinary,
#strDecryptedText AS EncryptedBinaryAsText
As you can see in the code above, in the CONVERT statements ... I needed to add the additional "size" of the returning VARCHAR I was converting to. Previously my convert commands said ...
...CONVERT(VARCHAR, ...
... when they should have said ...
...CONVERT(VARCHAR(MAX), ...
Once I made that change, the returning HEX String was no longer being truncated.

How to Perform a Replace on Varbinary data in SQL

I've never had to do this before but I'm looking to do a SQL replace on varbinary data. I'm trying this but it's not successfully replacing, I think because it's treating the data as varchar and then cast back to varbinary. This stemmed from blank spaces at the end of these values but are not actual 'spaces' so RTRIM doesn't work in this scenario (bold below).
Example of Data trying to change:
0x457874656368203430304120414320636C616D70206D657465722C2041432063757272656E74206D6F64656C20746F206D65657420796F7572206170706C69636174696F6E206E656564732E20203230303020636F756E74204C434420646973706C61792E20204869676820616363757261637920666F722063757272656E74206D6561737572656D656E74732E2020302E3922202832336D6D29206A61772073697A65206163636F6D6D6F646174657320636F6E647563746F727320757020746F203330304D434D2E2020436F6E74696E756974792062656570657220616E642064696F646520746573742E20204461746120686F6C6420616E64206D617820686F6C642E20204F7665726C6F61642070726F74656374696F6E20666F7220616C6C2072616E6765732E20204F76657272616E676520616E64206C6F77206261747465727920696E64696361746F72732E20204175746F72616E67696E672077697468206175746F20706F776572206F66662E0D0A090909090909090909090D0A090909090909090909090D0A090909090909090909090D0A09090909090909090909
Script:
update digitalassetcontent
set content = (CAST(REPLACE(content, '0D0A09090909090909090909', '') as varbinary(MAX)))
update digitalassetcontent
set content = REPLACE(content,0x0D0A09090909090909090909,0x)

Display hindi data store in nvarchar datatype without N prefix

SQL Server 2008 - Table contains nvarchar(max) datatype and store hindi & english data without N' prefix. like - "मांगलिक welcome" but in table store as "×梻çÜ·¤ welcome".
Please guide how to display the data from SQL server in .net.
The N prefix only denotes the string is NVARCHAR as opposed to VARCHAR
See this for more info
C# is Unicode by default so your data will be ok.
In fact re-reading your question I'm not sure what you are asking.
Are you saying you store the data in the database WITHOUT the N prefix ? Is this done via .net ?
Can you please make your question clearer ?
** EDIT
I'm not sure you can. The data outside of the non Unicode code page will be lost.
Check this page here for further details
First try to create a table as shown:
Create table TestLang (strText nvarchar(max))
Next try to insert values
insert into TestLang values ( N'मांगलिक')
insert into TestLang values ( N'Welcome')
Now try to search the name as shown:
SELECT * FROM TestLang WHERE strText LIKE N'मां%'
UPDATE:
If you want to display the data try this way:
string input = "0928;0940;0932;092E;";
Regex rx = new Regex(#"([0-9A-Fa-f]{4});");
string output = rx.Replace(input, match => ((char)Int32.Parse(match.Groups[1].Value, NumberStyles.HexNumber)).ToString());
Output: "नीलम"
Took from here

Varbinary and image conversion

I have an Access front end that links to a SQL Server backend.
There are 3 fields in a table that I am trying to convert to text from the backend:
o_name varbinary(2000)
O_PropertyBinary1 varbinary(2000)
O_PropertyBinary2 image
I can convert the o_name field using:
convert(varchar([max]),[O_Name])
and that works fine.
e.g. 4153534554 = ASSET
However, what can I use for the other two fields, as it seems I can't convert an image field and converting the O_PropertyBinary1 comes out with garbage characters.
The output is depended on the stored data an the appropriate conversion.
If the stored data is binary e.g. Bitmaps, converting to text will never give a usable result.
If data stored is text, it could be Varchar or NVarchar and kind conversion is depending.
in the example below VC_VB2NVarchar and VC_IMG2NVarchar would display your described garbage characters
Declare #tab Table(nvc NVarchar(100),vc Varchar(100)
,img image,vb VarBinary(200),img2 image,vb2 VarBinary(200))
Insert into #tab (nvc,vc) Values ('123456789','123456789')
Update #tab set vb=Convert(VarBinary(200),nvc),img=Convert(Image,Convert(Varbinary(max),nvc))
,vb2=Convert(VarBinary(200),vc),img2=Convert(Image,Convert(Varbinary(max),vc))
Select nvc,vc
,CONVERT(Nvarchar(100),vb) as NVC_VB2NVarchar
,CONVERT(Varchar(200),vb) as NVC_VB2Varchar
,CONVERT(Nvarchar(100),Convert(VarBinary(max),img)) as NVC_IMG2NVarchar
,CONVERT(Varchar(200),Convert(VarBinary(max),img)) as NVC_IMG2Varchar
,CONVERT(Nvarchar(100),vb2) as VC_VB2NVarchar
,CONVERT(Varchar(200),vb2) as VC_VB2Varchar
,CONVERT(Nvarchar(100),Convert(VarBinary(max),img2)) as VC_IMG2NVarchar
,CONVERT(Varchar(200),Convert(VarBinary(max),img2)) as VC_IMG2Varchar
from #Tab

String or binary data would be truncated. -- even though length shorter than field length

Trying to prefix a string field on a table by using the UPDATE command. For some reason I'm getting the
String or binary data would be truncated.
exception, even though the length of my data would easily fit in the field.
Using SQL Server 2008 R2 Standard Edition and SSMS 2008 R2.
Template: Learner is a nvarchar(60)
Template: Learner is a nvarchar(30) using 60 bytes as shown in sp_help
select LEN('Aaaaaaaa' + LEFT(learner, 52)) myLen from Template order by myLen desc
>>> max len = 31
update Template set learner = 'Aaaaaaaa' + LEFT(learner, 52)
>>> String or binary data would be truncated.
update Template set learner = 'Aaaaaaaa' + LEFT(learner, 52)
>>> String or binary data would be truncated.
update Template set learner = CAST('Aaaaaaaa' + LEFT(learner, 52) AS NVARCHAR(60))
>>> String or binary data would be truncated.
Whereas the following works:
SELECT CAST('Aaaaaaaa' + LEFT(learner, 52) AS NVARCHAR(60)) FROM Template
You can try to ignore this message by
SET ANSI_WARNINGS OFF
update ...
SET ANSI_WARNINGS ON
Thanks for your responses.
Looks like I was fooled by the length value on sp_help and sp_columns. As it's a NVARCHAR column the length means the length in bytes and not the number of characters. This is because NVARCHAR = Unicode (UTF-16) => 2 Bytes per character.
Looking at the CREATE script revealed the truth. Also the PRECISION field on sp_columns shows the number of characters too.
My problem was having another log table (for audit trail), filled by a trigger on the main table, where the column size also had to be changed.
Another possible reason could be having a nonsensical column CONSTRAINT with a Default Value that is longer than the max value.
Example:
The error would occur when inserting without specifying this column in the insert statement.