|
create or alter function dbo.fn_toHex( |
|
@number numeric(38) |
|
, @powers dbo.udt_tbl_powers READONLY -- Result of fn_powers(). |
|
) |
|
returns |
|
varchar(24) |
|
-- @debugOutput table |
|
-- ( |
|
-- position int, |
|
-- divisor numeric(38), |
|
-- quotient numeric(38), |
|
-- scratch numeric(38), |
|
-- digit char, |
|
-- finalResult varchar(24) |
|
-- ) |
|
as |
|
/** |
|
Converts a large decimal number (assumed to fit within 24 hex digits, though) to a hexadecimal string. |
|
*/ |
|
begin |
|
declare @hexDigits table |
|
( |
|
position int primary key, |
|
digit char |
|
); |
|
declare @scratch numeric(38) = @number; |
|
-- For @position, could optimize by setting to (select max(p.exponent) from @powers p where p.power < @number), |
|
-- but I happen to know we'll be dealing with large numbers, so no need at this time. |
|
declare @position int = 23; |
|
declare @quotient numeric(38) |
|
declare @divisor numeric(38) |
|
declare @digit char; |
|
while @position >= 0 |
|
begin |
|
set @divisor = (select top (1) p.power from @powers p where p.exponent = @position); |
|
set @quotient = floor( @scratch / @divisor); |
|
set @scratch = @scratch % @divisor; |
|
set @digit = case |
|
when @quotient < 10 then char(48 + @quotient) |
|
else char(97 - 10 + @quotient) |
|
end; |
|
insert @hexDigits (position, digit) values (@position, @digit) |
|
-- insert @debugOutput (position, divisor, quotient, scratch, digit) |
|
-- values (@position, @divisor, @quotient, @scratch, @digit) |
|
set @position = @position - 1 |
|
end |
|
-- And now we do Something Horrible: select the characters into a JSON string and munge it up in place. |
|
declare @digitString varchar(max); |
|
set @digitString = |
|
(select hd.digit d from @hexDigits hd order by hd.position desc for json path, without_array_wrapper); |
|
-- @digitString looks like this: {"d":"a"},{"d":"b"},{"d":"c"} |
|
set @digitString = replace(replace(@digitString, '{"d":"', ''), '"},', ''); |
|
-- @digitString looks like this: abc"} |
|
set @digitString = substring(@digitString, 1, len(@digitString) - 2); |
|
-- insert @debugOutput (finalResult) values (@digitString) |
|
return cast(@digitString as varchar(24)); |
|
end; |
Prolly shouldn't use max here, maybe varchar(240) or so?