Ko Ga
Ko Ga

Reputation: 916

Convert payload from VARBINARY into VARCHAR in SQL

I am trying to convert the following payload into a readable string. It is a log containing information I want to use afterwards to analyze and process.

This is the payload message:

0x234453006AD2C3005B71436C6173733A2061203A3A204173696D6F764661636164652E63616C6C28292072656672657368207B746F6B656E3D65303466663731622D336265342D343836632D623339622D3663633762396365646236397D10070D02040256

I know that the protocol is as follows:

Header: 3 bytes
ID: 4 bytes
Length: 2 bytes
LogDebug: 1 byte
LogData: N
Timestamp: 6 bytes
CS: 1 byte

I tried using:

CONVERT(VARCHAR(MAX), SUBSTRING(payload, 0, 3) + SUBSTRING(payload, 3, 4) + ...)

but couldn't get it to work. I saw in the SSMS documentation that SUBSTRING accepts only certain data types where I typed payload, such as character, binary, text, ntext, or image. I tried

CONVERT(VARCHAR(MAX), (SUBSTRING(CONVERT(BINARY,Payload),0, 3)) + (SUBSTRING(CONVERT(BINARY,Payload),3, 4)))

as well but no luck :(

Any suggestions?

EDIT: The expected log should look like this:

000: ← 2016/07/13 00:04:02, (0x71)U2H.LOGDEBUG - Class: a :: AsimovFacade.call() refresh {token=e04ff71b-3be4-486c-b39b-6cc7b9cedb69}

I get:

#DS

Upvotes: 3

Views: 932

Answers (2)

beercohol
beercohol

Reputation: 2587

Try the code below. You pretty much just need to substring the varbinary into the fields in your protocol, then convert to an appropriate type.

I've assumed your 4 byte ID is an int, and it seems that your length field includes the timestamp and "cs" fields at the end, so you need to deduct 7 from the value.

DECLARE @payload varbinary(MAX) = 0x234453006AD2C3005B71436C6173733A2061203A3A204173696D6F764661636164652E63616C6C28292072656672657368207B746F6B656E3D65303466663731622D336265342D343836632D623339622D3663633762396365646236397D10070D02040256

DECLARE @header char(3),
        @id     int,
        @length smallint,
        @logdebug char(1),
        @logdata    varchar(MAX),
        @timestamp  char(6),
        @cs         char(1)

SET @header = convert(char(3), substring(@payload, 1, 3))
SET @id = convert(int, substring(@payload, 4, 4))
SET @length = convert(smallint, substring(@payload, 8, 2)) - 7
SET @logdebug = convert(char(1), substring(@payload, 10, 1))
SET @logdata = convert(varchar(MAX), substring(@payload, 11, @length))
SET @timestamp = convert(char(6), substring(@payload, @length + 11, 6))
SET @cs = convert(char(1), substring(@payload, @length + 17, 1))



SELECT @header,@id,@length, @logdebug, @logdata, @timestamp, @cs

Upvotes: 0

Alex K.
Alex K.

Reputation: 176016

Substring works fine for varbinary and will return varbinary.

Seems the data length field includes the last 2 fields in addition to the LogData length.

The string U2H.LOGDEBUG does not appear in your input.

declare @b varbinary(max) = 0x234453006AD2C3005B71436C6173733A2061203A3A204173696D6F764661636164652E63616C6C28292072656672657368207B746F6B656E3D65303466663731622D336265342D343836632D623339622D3663633762396365646236397D10070D02040256

select cast(substring(@b, 1, 3) as char(3)) as hdr
select cast(substring(@b, 4, 4) as int) as id

-- store length of the payload
declare @len int = cast(substring(@b, 8, 2) as int)
select @len as length

select cast(substring(@b, 10, 1) as binary(1)) as logdebug

-- read payload for the read length, less 7 bytes for the timestamp & cs
select cast(substring(@b, 11, @len - 7) as varchar(max)) as logdata

-- read past payload for 6 bytes for the timestamp (whatever format that is - not epoch)
select substring(@b, @len + 11 - 7, 6) as timestamp

select substring(@b, @len + 11 - 7 + 6, 1) as cs

For

hdr
----
#DS


id
-----------
7000771


length
-----------
91


logdebug
--------
0x71


logdata
----
Class: a :: AsimovFacade.call() refresh {token=e04ff71b-3be4-486c-b39b-6cc7b9cedb69}


timestamp
----
0x10070D020402


cs
----
0x56

Upvotes: 1

Related Questions