Enterprise Resource Planning Blogs by Members
Gain new perspectives and knowledge about enterprise resource planning in blog posts from community members. Share your own comments and ERP insights today!
cancel
Showing results for 
Search instead for 
Did you mean: 
JoergAldinger
Active Contributor
Recently I had to work around some limitations in SAP Business One's Service Layer. As a result, I had to decode some BASE64 string that was stored in our customer's database, modify the (unencoded) string and then save it back, all from within a native SAP HANA Stored Procedure.

To my surprise, there is no native function to achieve this, at least not that I could find in my couple of hours of investigation.

So I set out to build my own function to allow for decoding Base64 strings on the database level.

I am posting this function here, so that others can save themselves a few hours if they are ever presented with the same problem.

Note: This is probably not the most performant way of doing this, but since it's not going to be executed massively it is good enough for our purpose. The function returns the decoded value of a 400-character string in 1-2 ms on our test server. If you do have have performance improvements, please share!
CREATE OR REPLACE FUNCTION "CEODO_FN_Base64Decode"
(
base64 varchar(8000)
)
RETURNS decoded nvarchar(4000)
LANGUAGE SQLSCRIPT
SQL SECURITY INVOKER
DETERMINISTIC
AS
BEGIN

declare i int;
declare binstring varchar(16);

binstring = '';
decoded = '';

FOR i IN 1..LENGTH(:base64) DO

binstring := binstring ||
CASE
SUBSTRING(:base64, i, 1)
WHEN 'A' THEN '000000'
WHEN 'B' THEN '000001'
WHEN 'C' THEN '000010'
WHEN 'D' THEN '000011'
WHEN 'E' THEN '000100'
WHEN 'F' THEN '000101'
WHEN 'G' THEN '000110'
WHEN 'H' THEN '000111'
WHEN 'I' THEN '001000'
WHEN 'J' THEN '001001'
WHEN 'K' THEN '001010'
WHEN 'L' THEN '001011'
WHEN 'M' THEN '001100'
WHEN 'N' THEN '001101'
WHEN 'O' THEN '001110'
WHEN 'P' THEN '001111'
WHEN 'Q' THEN '010000'
WHEN 'R' THEN '010001'
WHEN 'S' THEN '010010'
WHEN 'T' THEN '010011'
WHEN 'U' THEN '010100'
WHEN 'V' THEN '010101'
WHEN 'W' THEN '010110'
WHEN 'X' THEN '010111'
WHEN 'Y' THEN '011000'
WHEN 'Z' THEN '011001'
WHEN 'a' THEN '011010'
WHEN 'b' THEN '011011'
WHEN 'c' THEN '011100'
WHEN 'd' THEN '011101'
WHEN 'e' THEN '011110'
WHEN 'f' THEN '011111'
WHEN 'g' THEN '100000'
WHEN 'h' THEN '100001'
WHEN 'i' THEN '100010'
WHEN 'j' THEN '100011'
WHEN 'k' THEN '100100'
WHEN 'l' THEN '100101'
WHEN 'm' THEN '100110'
WHEN 'n' THEN '100111'
WHEN 'o' THEN '101000'
WHEN 'p' THEN '101001'
WHEN 'q' THEN '101010'
WHEN 'r' THEN '101011'
WHEN 's' THEN '101100'
WHEN 't' THEN '101101'
WHEN 'u' THEN '101110'
WHEN 'v' THEN '101111'
WHEN 'w' THEN '110000'
WHEN 'x' THEN '110001'
WHEN 'y' THEN '110010'
WHEN 'z' THEN '110011'
WHEN '0' THEN '110100'
WHEN '1' THEN '110101'
WHEN '2' THEN '110110'
WHEN '3' THEN '110111'
WHEN '4' THEN '111000'
WHEN '5' THEN '111001'
WHEN '6' THEN '111010'
WHEN '7' THEN '111011'
WHEN '8' THEN '111100'
WHEN '9' THEN '111101'
WHEN '+' THEN '111110'
WHEN '/' THEN '111111'
ELSE '' END;

IF (LENGTH(:binstring) >= 😎 THEN

decoded := decoded || CHAR(
TO_INT(SUBSTRING(:binstring, 1, 1)) * 128 +
TO_INT(SUBSTRING(:binstring, 2, 1)) * 64 +
TO_INT(SUBSTRING(:binstring, 3, 1)) * 32 +
TO_INT(SUBSTRING(:binstring, 4, 1)) * 16 +
TO_INT(SUBSTRING(:binstring, 5, 1)) * 8 +
TO_INT(SUBSTRING(:binstring, 6, 1)) * 4 +
TO_INT(SUBSTRING(:binstring, 7, 1)) * 2 +
TO_INT(SUBSTRING(:binstring, 8, 1)) * 1);

binstring := SUBSTRING(:binstring, 9);

END IF;

END FOR;

END;

Happy coding!

Joerg
2 Comments
JoergAldinger
Active Contributor
0 Kudos
If anybody wonders about the reverse procedure, here's a function to encode, too. I'm not exactly happy about the length of it, but I do think that breaking it down further to reduce the lines of code will just make it slower... Again, any improvements are welcome!
CREATE OR REPLACE FUNCTION "CEODO_FN_Base64Encode"
(
input_str varchar(8000)
)
RETURNS base64 nvarchar(4000)
LANGUAGE SQLSCRIPT
SQL SECURITY INVOKER
DETERMINISTIC
AS
BEGIN


declare i int;
declare binstring varchar(20);

binstring = '';
base64 = '';

FOR i IN 1..(LENGTH(:input_str)+1) DO

IF(:i <= LENGTH(:input_str)) THEN
binstring := binstring ||
CASE
ASCII(SUBSTRING(:input_str, i, 1))
WHEN 0 THEN '00000000'
WHEN 1 THEN '00000001'
WHEN 2 THEN '00000010'
WHEN 3 THEN '00000011'
WHEN 4 THEN '00000100'
WHEN 5 THEN '00000101'
WHEN 6 THEN '00000110'
WHEN 7 THEN '00000111'
WHEN 8 THEN '00001000'
WHEN 9 THEN '00001001'
WHEN 10 THEN '00001010'
WHEN 11 THEN '00001011'
WHEN 12 THEN '00001100'
WHEN 13 THEN '00001101'
WHEN 14 THEN '00001110'
WHEN 15 THEN '00001111'
WHEN 16 THEN '00010000'
WHEN 17 THEN '00010001'
WHEN 18 THEN '00010010'
WHEN 19 THEN '00010011'
WHEN 20 THEN '00010100'
WHEN 21 THEN '00010101'
WHEN 22 THEN '00010110'
WHEN 23 THEN '00010111'
WHEN 24 THEN '00011000'
WHEN 25 THEN '00011001'
WHEN 26 THEN '00011010'
WHEN 27 THEN '00011011'
WHEN 28 THEN '00011100'
WHEN 29 THEN '00011101'
WHEN 30 THEN '00011110'
WHEN 31 THEN '00011111'
WHEN 32 THEN '00100000'
WHEN 33 THEN '00100001'
WHEN 34 THEN '00100010'
WHEN 35 THEN '00100011'
WHEN 36 THEN '00100100'
WHEN 37 THEN '00100101'
WHEN 38 THEN '00100110'
WHEN 39 THEN '00100111'
WHEN 40 THEN '00101000'
WHEN 41 THEN '00101001'
WHEN 42 THEN '00101010'
WHEN 43 THEN '00101011'
WHEN 44 THEN '00101100'
WHEN 45 THEN '00101101'
WHEN 46 THEN '00101110'
WHEN 47 THEN '00101111'
WHEN 48 THEN '00110000'
WHEN 49 THEN '00110001'
WHEN 50 THEN '00110010'
WHEN 51 THEN '00110011'
WHEN 52 THEN '00110100'
WHEN 53 THEN '00110101'
WHEN 54 THEN '00110110'
WHEN 55 THEN '00110111'
WHEN 56 THEN '00111000'
WHEN 57 THEN '00111001'
WHEN 58 THEN '00111010'
WHEN 59 THEN '00111011'
WHEN 60 THEN '00111100'
WHEN 61 THEN '00111101'
WHEN 62 THEN '00111110'
WHEN 63 THEN '00111111'
WHEN 64 THEN '01000000'
WHEN 65 THEN '01000001'
WHEN 66 THEN '01000010'
WHEN 67 THEN '01000011'
WHEN 68 THEN '01000100'
WHEN 69 THEN '01000101'
WHEN 70 THEN '01000110'
WHEN 71 THEN '01000111'
WHEN 72 THEN '01001000'
WHEN 73 THEN '01001001'
WHEN 74 THEN '01001010'
WHEN 75 THEN '01001011'
WHEN 76 THEN '01001100'
WHEN 77 THEN '01001101'
WHEN 78 THEN '01001110'
WHEN 79 THEN '01001111'
WHEN 80 THEN '01010000'
WHEN 81 THEN '01010001'
WHEN 82 THEN '01010010'
WHEN 83 THEN '01010011'
WHEN 84 THEN '01010100'
WHEN 85 THEN '01010101'
WHEN 86 THEN '01010110'
WHEN 87 THEN '01010111'
WHEN 88 THEN '01011000'
WHEN 89 THEN '01011001'
WHEN 90 THEN '01011010'
WHEN 91 THEN '01011011'
WHEN 92 THEN '01011100'
WHEN 93 THEN '01011101'
WHEN 94 THEN '01011110'
WHEN 95 THEN '01011111'
WHEN 96 THEN '01100000'
WHEN 97 THEN '01100001'
WHEN 98 THEN '01100010'
WHEN 99 THEN '01100011'
WHEN 100 THEN '01100100'
WHEN 101 THEN '01100101'
WHEN 102 THEN '01100110'
WHEN 103 THEN '01100111'
WHEN 104 THEN '01101000'
WHEN 105 THEN '01101001'
WHEN 106 THEN '01101010'
WHEN 107 THEN '01101011'
WHEN 108 THEN '01101100'
WHEN 109 THEN '01101101'
WHEN 110 THEN '01101110'
WHEN 111 THEN '01101111'
WHEN 112 THEN '01110000'
WHEN 113 THEN '01110001'
WHEN 114 THEN '01110010'
WHEN 115 THEN '01110011'
WHEN 116 THEN '01110100'
WHEN 117 THEN '01110101'
WHEN 118 THEN '01110110'
WHEN 119 THEN '01110111'
WHEN 120 THEN '01111000'
WHEN 121 THEN '01111001'
WHEN 122 THEN '01111010'
WHEN 123 THEN '01111011'
WHEN 124 THEN '01111100'
WHEN 125 THEN '01111101'
WHEN 126 THEN '01111110'
WHEN 127 THEN '01111111'
WHEN 128 THEN '10000000'
WHEN 129 THEN '10000001'
WHEN 130 THEN '10000010'
WHEN 131 THEN '10000011'
WHEN 132 THEN '10000100'
WHEN 133 THEN '10000101'
WHEN 134 THEN '10000110'
WHEN 135 THEN '10000111'
WHEN 136 THEN '10001000'
WHEN 137 THEN '10001001'
WHEN 138 THEN '10001010'
WHEN 139 THEN '10001011'
WHEN 140 THEN '10001100'
WHEN 141 THEN '10001101'
WHEN 142 THEN '10001110'
WHEN 143 THEN '10001111'
WHEN 144 THEN '10010000'
WHEN 145 THEN '10010001'
WHEN 146 THEN '10010010'
WHEN 147 THEN '10010011'
WHEN 148 THEN '10010100'
WHEN 149 THEN '10010101'
WHEN 150 THEN '10010110'
WHEN 151 THEN '10010111'
WHEN 152 THEN '10011000'
WHEN 153 THEN '10011001'
WHEN 154 THEN '10011010'
WHEN 155 THEN '10011011'
WHEN 156 THEN '10011100'
WHEN 157 THEN '10011101'
WHEN 158 THEN '10011110'
WHEN 159 THEN '10011111'
WHEN 160 THEN '10100000'
WHEN 161 THEN '10100001'
WHEN 162 THEN '10100010'
WHEN 163 THEN '10100011'
WHEN 164 THEN '10100100'
WHEN 165 THEN '10100101'
WHEN 166 THEN '10100110'
WHEN 167 THEN '10100111'
WHEN 168 THEN '10101000'
WHEN 169 THEN '10101001'
WHEN 170 THEN '10101010'
WHEN 171 THEN '10101011'
WHEN 172 THEN '10101100'
WHEN 173 THEN '10101101'
WHEN 174 THEN '10101110'
WHEN 175 THEN '10101111'
WHEN 176 THEN '10110000'
WHEN 177 THEN '10110001'
WHEN 178 THEN '10110010'
WHEN 179 THEN '10110011'
WHEN 180 THEN '10110100'
WHEN 181 THEN '10110101'
WHEN 182 THEN '10110110'
WHEN 183 THEN '10110111'
WHEN 184 THEN '10111000'
WHEN 185 THEN '10111001'
WHEN 186 THEN '10111010'
WHEN 187 THEN '10111011'
WHEN 188 THEN '10111100'
WHEN 189 THEN '10111101'
WHEN 190 THEN '10111110'
WHEN 191 THEN '10111111'
WHEN 192 THEN '11000000'
WHEN 193 THEN '11000001'
WHEN 194 THEN '11000010'
WHEN 195 THEN '11000011'
WHEN 196 THEN '11000100'
WHEN 197 THEN '11000101'
WHEN 198 THEN '11000110'
WHEN 199 THEN '11000111'
WHEN 200 THEN '11001000'
WHEN 201 THEN '11001001'
WHEN 202 THEN '11001010'
WHEN 203 THEN '11001011'
WHEN 204 THEN '11001100'
WHEN 205 THEN '11001101'
WHEN 206 THEN '11001110'
WHEN 207 THEN '11001111'
WHEN 208 THEN '11010000'
WHEN 209 THEN '11010001'
WHEN 210 THEN '11010010'
WHEN 211 THEN '11010011'
WHEN 212 THEN '11010100'
WHEN 213 THEN '11010101'
WHEN 214 THEN '11010110'
WHEN 215 THEN '11010111'
WHEN 216 THEN '11011000'
WHEN 217 THEN '11011001'
WHEN 218 THEN '11011010'
WHEN 219 THEN '11011011'
WHEN 220 THEN '11011100'
WHEN 221 THEN '11011101'
WHEN 222 THEN '11011110'
WHEN 223 THEN '11011111'
WHEN 224 THEN '11100000'
WHEN 225 THEN '11100001'
WHEN 226 THEN '11100010'
WHEN 227 THEN '11100011'
WHEN 228 THEN '11100100'
WHEN 229 THEN '11100101'
WHEN 230 THEN '11100110'
WHEN 231 THEN '11100111'
WHEN 232 THEN '11101000'
WHEN 233 THEN '11101001'
WHEN 234 THEN '11101010'
WHEN 235 THEN '11101011'
WHEN 236 THEN '11101100'
WHEN 237 THEN '11101101'
WHEN 238 THEN '11101110'
WHEN 239 THEN '11101111'
WHEN 240 THEN '11110000'
WHEN 241 THEN '11110001'
WHEN 242 THEN '11110010'
WHEN 243 THEN '11110011'
WHEN 244 THEN '11110100'
WHEN 245 THEN '11110101'
WHEN 246 THEN '11110110'
WHEN 247 THEN '11110111'
WHEN 248 THEN '11111000'
WHEN 249 THEN '11111001'
WHEN 250 THEN '11111010'
WHEN 251 THEN '11111011'
WHEN 252 THEN '11111100'
WHEN 253 THEN '11111101'
WHEN 254 THEN '11111110'
WHEN 255 THEN '11111111'
ELSE '' END;
END IF;

WHILE(LENGTH(:binstring) >= 6 OR :i > LENGTH(:input_str)) DO

base64 := base64 ||
CASE LEFT(:binstring || '000000', 6)
WHEN '000000' THEN 'A'
WHEN '000001' THEN 'B'
WHEN '000010' THEN 'C'
WHEN '000011' THEN 'D'
WHEN '000100' THEN 'E'
WHEN '000101' THEN 'F'
WHEN '000110' THEN 'G'
WHEN '000111' THEN 'H'
WHEN '001000' THEN 'I'
WHEN '001001' THEN 'J'
WHEN '001010' THEN 'K'
WHEN '001011' THEN 'L'
WHEN '001100' THEN 'M'
WHEN '001101' THEN 'N'
WHEN '001110' THEN 'O'
WHEN '001111' THEN 'P'
WHEN '010000' THEN 'Q'
WHEN '010001' THEN 'R'
WHEN '010010' THEN 'S'
WHEN '010011' THEN 'T'
WHEN '010100' THEN 'U'
WHEN '010101' THEN 'V'
WHEN '010110' THEN 'W'
WHEN '010111' THEN 'X'
WHEN '011000' THEN 'Y'
WHEN '011001' THEN 'Z'
WHEN '011010' THEN 'a'
WHEN '011011' THEN 'b'
WHEN '011100' THEN 'c'
WHEN '011101' THEN 'd'
WHEN '011110' THEN 'e'
WHEN '011111' THEN 'f'
WHEN '100000' THEN 'g'
WHEN '100001' THEN 'h'
WHEN '100010' THEN 'i'
WHEN '100011' THEN 'j'
WHEN '100100' THEN 'k'
WHEN '100101' THEN 'l'
WHEN '100110' THEN 'm'
WHEN '100111' THEN 'n'
WHEN '101000' THEN 'o'
WHEN '101001' THEN 'p'
WHEN '101010' THEN 'q'
WHEN '101011' THEN 'r'
WHEN '101100' THEN 's'
WHEN '101101' THEN 't'
WHEN '101110' THEN 'u'
WHEN '101111' THEN 'v'
WHEN '110000' THEN 'w'
WHEN '110001' THEN 'x'
WHEN '110010' THEN 'y'
WHEN '110011' THEN 'z'
WHEN '110100' THEN '0'
WHEN '110101' THEN '1'
WHEN '110110' THEN '2'
WHEN '110111' THEN '3'
WHEN '111000' THEN '4'
WHEN '111001' THEN '5'
WHEN '111010' THEN '6'
WHEN '111011' THEN '7'
WHEN '111100' THEN '8'
WHEN '111101' THEN '9'
WHEN '111110' THEN '+'
WHEN '111111' THEN '/'
ELSE '' END;

IF (:i > LENGTH(:input_str)) THEN
BREAK;
END IF;

binstring := SUBSTRING(:binstring, 7);

END WHILE;

END FOR;

base64 := base64 ||
CASE
WHEN MOD(LENGTH(:base64), 4) = 0 THEN ''
ELSE LEFT('===', 4 - MOD(LENGTH(:base64), 4))
END;

END;

Best regards,

Joerg.
JoergAldinger
Active Contributor
0 Kudos
By the way, if you are interested in completely native functions, here is a link to the official improvement request: Provide Base64 decode/encode as native database function.

Thanks for voting!

Joerg.
Labels in this area