MySQL Function not running properly on server - mysql

I have a function that works on my local MySQL database but does not return the same value on the public server. I am not sure why. I am using UTF-8.
The parameter is an integer (Keyval). The idea is to take Keyval: 216 and convert it to '‚‚„ƒˆ', where they are characters: 130,130,132,131,136 thru: MakeAltAbbr(216)
UPDATE `cc_team` SET `AltTMAbbr`= MakeAltAbbr(TeamKey) WHERE TeamKey = 216;
On localhost it creates some special characters, on the server it is 'blank'.
BEGIN
DECLARE cc CHAR(5);
DECLARE str CHAR(5);
DECLARE x INT default 0;
DECLARE y INT default 0;
SET str = '';
SET x = 1;
SET cc = LPAD(Keyval,5,'0');
SET y = LENGTH(cc);
WHILE x <= y DO
SET str = CONCAT(str,CHAR(SUBSTRING(cc,x,1) + 130));
SET x = x + 1;
END WHILE;
RETURN str;
END

Related

MySQL search array without PHP

I want to search an array in MySQL without PHP but all the examples I found were with PHP. Here is my procedure:
BEGIN
DECLARE indx INT default 0;
DECLARE y INT default 0;
UPDATE radios SET geoblocking_enabled = in_enabledgeoblocking WHERE id = in_radioid;
DELETE FROM geoblocking WHERE assigned_radioid = in_radioid;
SELECT JSON_EXTRACT(in_geoblockingjson ,'$.countries');
SET indx = JSON_LENGTH(JSON_EXTRACT(in_geoblockingjson ,'$.countries'));
REPEAT
INSERT INTO geoblocking (country, countryindex) VALUES (JSON_EXTRACT(in_geoblockingjson, CONCAT("$[", indx, "].countries")), JSON_EXTRACT(in_geoblockingjson, CONCAT("$[", indx, "].countryindexes")));
SET y = y + 1;
UNTIL y = indx
END REPEAT;
END
For some reason it inserts the data but with NULL values.. here is what I used for my example request:

Bitwise operating issue

I'm trying to rebuild a function for generating GUIDs used by the game Arma 3 in a MySQL function. There are some examples in various languages over here: https://gist.github.com/Fank/11127158
Basicially this is what I tried so far:
CREATE DEFINER=`root`#`localhost` FUNCTION `generateGUID`(playerid varchar(17)) RETURNS varchar(32) CHARSET latin1
BEGIN
DECLARE temp bigint;
DECLARE i int;
SET i = 0;
SET temp = 0;
WHILE i < 8 DO
SET temp = temp + CHAR(playerid & 0xFF);
SET playerid = playerid >> 8;
SET i = i + 1;
END WHILE;
RETURN MD5("BE" + temp);
END
What I understood so far orientating at the php example:
First of all we have the steamid given as a varchar.
Afterwards we are iterating 8 times and adding the char of the bitwise addition of the playerid and the value of 0xFF. Then we are performing a 8 bitwise right shift on the playerid.
Afterwards the string "BE" is added the temp result and a md5 is generated of this and returned.
However I'm facing the issue that this function always returns 0. I tried many things so far, like using a blob instead of an int for the temp var.
Edit: After the hint to use CONCAT instead of the + operator the result is still not matching with the guid calculators out there.
The code looks now like this:
CREATE DEFINER=`root`#`localhost` FUNCTION `generateGUID`(playerid varchar(17)) RETURNS varchar(32) CHARSET latin1
BEGIN
DECLARE temp bigint;
DECLARE i int;
SET i = 0;
SET temp = "";
WHILE i < 8 DO
SET temp = CONCAT(temp, CHAR(playerid & 0xFF));
SET playerid = playerid >> 8;
SET i = i + 1;
END WHILE;
RETURN MD5(CONCAT("BE", temp));
END
However, using the playerid 76561197996545192 the function returns 2a0f7ebed67e04afaf7ea032e1ed22e3 instead of cd97cc68c1038b485b081ba2aa3ea6fa which should be the expected output.
This works for me:
DROP FUNCTION IF EXISTS `generateGUID`;
DELIMITER //
CREATE DEFINER=`root`#`localhost` FUNCTION `generateGUID`(`playerid` BIGINT UNSIGNED) RETURNS varchar(32) CHARSET latin1
DETERMINISTIC
BEGIN
DECLARE temp text CHARSET ascii;
DECLARE i int;
SET i = 0;
SET temp = "";
WHILE i < 8 DO
SET temp = CONCAT(temp, CHAR(playerid & 0xFF));
SET playerid = playerid >> 8;
SET i = i + 1;
END WHILE;
RETURN MD5(CONCAT("BE", temp));
END//
DELIMITER ;
http://sqlfiddle.com/#!9/6cc709/1

Convert CAP_FIRST Function from MySQL to PostgreSQL

A couple of years ago, I found this CAP_FIRST function for MySQL:
CREATE FUNCTION CAP_FIRST (input VARCHAR(255))
RETURNS VARCHAR(255)
DETERMINISTIC
BEGIN
DECLARE len INT;
DECLARE i INT;
SET len = CHAR_LENGTH(input);
SET input = LOWER(input);
SET i = 0;
WHILE (i < len) DO
IF (MID(input,i,1) = ' ' OR MID(input,i,1) = '-' OR i = 0) THEN
IF (i < len) THEN
SET input = CONCAT(
LEFT(input,i),
UPPER(MID(input,i + 1,1)),
RIGHT(input,len - i - 1)
);
END IF;
END IF;
SET i = i + 1;
END WHILE;
RETURN input;
END;
I have used this function extensively to convert people's names to proper capitalization for reports, like so:
UPDATE DataImport
SET FirstName = CAP_FIRST(FirstName);
UPDATE DataImport
SET LastName = CAP_FIRST(LastName);
Now I am migrating to PostgreSQL, and need this same functionality there. Do I need to convert this function to PostgreSQL, or is there a better way to get the same results? If I do need to convert, can someone help me?
It turns out that PostgreSQL has a builtin function initcap() that does this for me like so:
UPDATE DataImport
SET FirstName = initcap(FirstName);
UPDATE DataImport
SET LastName = initcap(LastName);

Hi, How to Use for loops in my sql , to print concat() column values of two Tables?

CREATE procedure mydbase.while_example2()
wholeblock:BEGIN
declare str VARCHAR(255) default '';
declare x1 int default 0;
declare x STRING default NULL;
declare y STRING default NULL;
SET x = SELECT*FROM stems;
SET y = SELECT*FROM suffixs;
WHILE x1 <= 5 DO
SET str = CONCAT(str,x,'y');
SET x1 = x1 + 1;
END WHILE;
select str;
END//
mysql> call while_example2();//
You can use group_concat to concat different columns if i get your requirement correctly.
http://www.mysqltutorial.org/mysql-group_concat/

base64 encode in MySQL

I want to select a blob col from one table, base64 encode it and insert it into another tables. Is there any way to do this without round tripping the data out of the DB and through my app?
I was looking for the same thing and I've just seen that MySQL 5.6 has a couple of new string functions supporting this functionality: TO_BASE64 and FROM_BASE64.
Functions from http://wi-fizzle.com/downloads/base64.sql contain some error when in encoded string are 32-byte (space), ex BASE64_ENCODE(CONCAT(CHAR(15), CHAR(32))). Here is corrected function
DELIMITER $$
USE `YOUR DATABASE`$$
DROP TABLE IF EXISTS core_base64_data$$
CREATE TABLE core_base64_data (c CHAR(1) BINARY, val TINYINT)$$
INSERT INTO core_base64_data VALUES
('A',0), ('B',1), ('C',2), ('D',3), ('E',4), ('F',5), ('G',6), ('H',7), ('I',8), ('J',9),
('K',10), ('L',11), ('M',12), ('N',13), ('O',14), ('P',15), ('Q',16), ('R',17), ('S',18), ('T',19),
('U',20), ('V',21), ('W',22), ('X',23), ('Y',24), ('Z',25), ('a',26), ('b',27), ('c',28), ('d',29),
('e',30), ('f',31), ('g',32), ('h',33), ('i',34), ('j',35), ('k',36), ('l',37), ('m',38), ('n',39),
('o',40), ('p',41), ('q',42), ('r',43), ('s',44), ('t',45), ('u',46), ('v',47), ('w',48), ('x',49),
('y',50), ('z',51), ('0',52), ('1',53), ('2',54), ('3',55), ('4',56), ('5',57), ('6',58), ('7',59),
('8',60), ('9',61), ('+',62), ('/',63), ('=',0) $$
DROP FUNCTION IF EXISTS `BASE64_ENCODE`$$
CREATE DEFINER=`YOUR DATABASE`#`%` FUNCTION `BASE64_ENCODE`(input BLOB) RETURNS BLOB
DETERMINISTIC
SQL SECURITY INVOKER
BEGIN
DECLARE ret BLOB DEFAULT '';
DECLARE done TINYINT DEFAULT 0;
IF input IS NULL THEN
RETURN NULL;
END IF;
each_block:
WHILE NOT done DO BEGIN
DECLARE accum_value BIGINT UNSIGNED DEFAULT 0;
DECLARE in_count TINYINT DEFAULT 0;
DECLARE out_count TINYINT;
each_input_char:
WHILE in_count < 3 DO BEGIN
DECLARE first_char BLOB(1);
IF LENGTH(input) = 0 THEN
SET done = 1;
SET accum_value = accum_value << (8 * (3 - in_count));
LEAVE each_input_char;
END IF;
SET first_char = SUBSTRING(input,1,1);
SET input = SUBSTRING(input,2);
SET accum_value = (accum_value << 8) + ASCII(first_char);
SET in_count = in_count + 1;
END; END WHILE;
-- We've now accumulated 24 bits; deaccumulate into base64 characters
-- We have to work from the left, so use the third byte position and shift left
CASE
WHEN in_count = 3 THEN SET out_count = 4;
WHEN in_count = 2 THEN SET out_count = 3;
WHEN in_count = 1 THEN SET out_count = 2;
ELSE RETURN ret;
END CASE;
WHILE out_count > 0 DO BEGIN
BEGIN
DECLARE out_char CHAR(1);
DECLARE base64_getval CURSOR FOR SELECT c FROM core_base64_data WHERE val = (accum_value >> 18);
OPEN base64_getval;
FETCH base64_getval INTO out_char;
CLOSE base64_getval;
SET ret = CONCAT(ret,out_char);
SET out_count = out_count - 1;
SET accum_value = accum_value << 6 & 0xffffff;
END;
END; END WHILE;
CASE
WHEN in_count = 2 THEN SET ret = CONCAT(ret,'=');
WHEN in_count = 1 THEN SET ret = CONCAT(ret,'==');
ELSE BEGIN END;
END CASE;
END; END WHILE;
RETURN ret;
END$$
DELIMITER ;
SELECT `id`,`name`, TO_BASE64(content) FROM `db`.`upload`
this will convert the blob value from content column to base64 string.
Then you can do with this string whatever you want even insert it into another table
Looks like no, though it was requested, and there’s a UDF for it.
Edit: Or there’s… this. Ugh.
For those interested, these are the only alternatives so far:
1) Using these Functions:
http://wi-fizzle.com/downloads/base64.sql
2) If you already have the sys_eval UDF, (Linux) you can do this:
sys_eval(CONCAT("echo '",myField,"' | base64"));
The first method is known to be slow. The problem with the second one, is that the encoding is actually happening "outside" MySQL, which can have encoding problems (besides the security risks that you are adding with sys_* functions).
Unfortunately there is no UDF compiled version (which should be faster) nor a native support in MySQL (Posgresql supports it!).
It seems that the MySQL development team are not interested in implement it as this function already exists in other languages, which seems pretty silly to me.
Yet another custom implementation that doesn't require support table:
drop function if exists base64_encode;
create function base64_encode(_data blob)
returns text
begin
declare _alphabet char(64) default 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
declare _lim int unsigned default length(_data);
declare _i int unsigned default 0;
declare _chk3 char(6) default '';
declare _chk3int int default 0;
declare _enc text default '';
while _i < _lim do
set _chk3 = rpad(hex(binary substr(_data, _i + 1, 3)), 6, '0');
set _chk3int = conv(_chk3, 16, 10);
set _enc = concat(
_enc
, substr(_alphabet, ((_chk3int >> 18) & 63) + 1, 1)
, if (_lim-_i > 0, substr(_alphabet, ((_chk3int >> 12) & 63) + 1, 1), '=')
, if (_lim-_i > 1, substr(_alphabet, ((_chk3int >> 6) & 63) + 1, 1), '=')
, if (_lim-_i > 2, substr(_alphabet, ((_chk3int >> 0) & 63) + 1, 1), '=')
);
set _i = _i + 3;
end while;
return _enc;
end;
drop function if exists base64_decode;
create function base64_decode(_enc text)
returns blob
begin
declare _alphabet char(64) default 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
declare _lim int unsigned default 0;
declare _i int unsigned default 0;
declare _chr1byte tinyint default 0;
declare _chk4int int default 0;
declare _chk4int_bits tinyint default 0;
declare _dec blob default '';
declare _rem tinyint default 0;
set _enc = trim(_enc);
set _rem = if(right(_enc, 3) = '===', 3, if(right(_enc, 2) = '==', 2, if(right(_enc, 1) = '=', 1, 0)));
set _lim = length(_enc) - _rem;
while _i < _lim
do
set _chr1byte = locate(substr(_enc, _i + 1, 1), binary _alphabet) - 1;
if (_chr1byte > -1)
then
set _chk4int = (_chk4int << 6) | _chr1byte;
set _chk4int_bits = _chk4int_bits + 6;
if (_chk4int_bits = 24 or _i = _lim-1)
then
if (_i = _lim-1 and _chk4int_bits != 24)
then
set _chk4int = _chk4int << 0;
end if;
set _dec = concat(
_dec
, char((_chk4int >> (_chk4int_bits - 8)) & 0xff)
, if(_chk4int_bits > 8, char((_chk4int >> (_chk4int_bits - 16)) & 0xff), '\0')
, if(_chk4int_bits > 16, char((_chk4int >> (_chk4int_bits - 24)) & 0xff), '\0')
);
set _chk4int = 0;
set _chk4int_bits = 0;
end if;
end if;
set _i = _i + 1;
end while;
return substr(_dec, 1, length(_dec) - _rem);
end;
Gist
You should convert charset after decoding: convert(base64_decode(base64_encode('ёлка')) using utf8)
If you need this for < 5.6, I tripped across this UDF which seems to work fine:
https://github.com/y-ken/mysql-udf-base64
create table encrypt(username varchar(20),password varbinary(200))
insert into encrypt values('raju',aes_encrypt('kumar','key'))
select *,cast(aes_decrypt(password,'key') as char(40)) from encrypt where username='raju';