MySQL SELECT with URL Decode

Viewed 47568

Is there a way to perform a MySQL query and have one of the columns in the output directly urldecode, rather than have PHP do it.

For example this table 'contacts' would contain,

------------------------------------
|name      |email                  |
------------------------------------
|John Smith|johnsmith%40hotmail.com|
------------------------------------
SELECT * FROM `contacts`

Would output,

John Smith | johnsmith%40@hotmail.com

Is there something along the lines of,

SELECT name, urldecode(email) FROM `contacts`

To output,

John Smith | johnsmith@hotmail.com

8 Answers

Inspired by Mistdemon's answer I were using the following function:

DELIMITER $$
DROP FUNCTION IF EXISTS `url_decode`$$
CREATE FUNCTION `url_decode`(str VARCHAR(255) CHARSET utf8) RETURNS VARCHAR(255) CHARSET utf8 DETERMINISTIC
BEGIN
    DECLARE X  INT;               
    SET X = 128;
    WHILE X  < 192 DO
        SET str = REPLACE(str, CONCAT('%C5%', HEX(X)), UNHEX(CONCAT('C5', HEX(X))));
        SET str = REPLACE(str, CONCAT('%C4%', HEX(X)), UNHEX(CONCAT('C4', HEX(X))));
        SET str = REPLACE(str, CONCAT('%C3%', HEX(X)), UNHEX(CONCAT('C3', HEX(X))));
        SET  X = X + 1;                           
    END WHILE;
    SET X = 32;
    WHILE X  < 127 DO
        SET str = REPLACE(str, CONCAT('%', HEX(X)), UNHEX(HEX(X)));
        SET  X = X + 1;                           
    END WHILE;
    RETURN REPLACE(str, '+', ' ');
END$$
DELIMITER ;
SELECT url_decode('/pl/tagi/mi%C5%82o%C5%9B%C4%87');

It is good if you know what characters you can expect. In the above code it converts only single bytes and 2-bytes characters from C3, C4 and C5 ranges. For more characters you need more REPLACE iterations.

If you need to decode all utf8 characters you can use the following function. It is faster than previous one, but potentially more bugy if you have incorrectly encoded strings.

DELIMITER $$
DROP FUNCTION IF EXISTS `url_decode`$$
CREATE FUNCTION `url_decode`(str VARCHAR(255) CHARSET utf8) RETURNS VARCHAR(255) DETERMINISTIC
BEGIN
    DECLARE end INT;
    DECLARE start INT;
    SET start = LOCATE('%', str);
    WHILE start > 0 DO
        SET end = start;
        WHILE SUBSTRING(str, end, 1) = '%' AND UPPER(SUBSTRING(str, end + 1, 1)) IN ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F') AND UPPER(SUBSTRING(str, end + 2, 1)) IN ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F') DO
            SET end = end + 3;
        END WHILE;
        IF start <> end THEN
            SET str = INSERT(str, start, end - start, UNHEX(REPLACE(SUBSTRING(str, start, end - start), '%', '')));
        END IF;
        SET start = LOCATE('%', str, start + 1);
    END WHILE;
    RETURN REPLACE(str, '+', ' ');
END$$
DELIMITER ;
SELECT url_decode('/bg/%D0%B8%D0%B3%D1%80%D0%B8%D1%82%D0%B5-%D0%BD%D0%B0-%D0%B3%D0%BB%D0%B0%D0%B4%D0%B0');

To expand on @fela's answer:

CREATE FUNCTION `url_decode`(str VARCHAR(255) CHARSET utf8) RETURNS VARCHAR(255) DETERMINISTIC
BEGIN
  DECLARE X  INT;
  SET X = 128;
  WHILE X  < 192 DO
    SET str = REPLACE(str, CONCAT('%C5%', HEX(X)), UNHEX(CONCAT('C5', HEX(X))));
    SET str = REPLACE(str, CONCAT('%C4%', HEX(X)), UNHEX(CONCAT('C4', HEX(X))));
    SET str = REPLACE(str, CONCAT('%C3%', HEX(X)), UNHEX(CONCAT('C3', HEX(X))));
    SET  X = X + 1;
  END WHILE;
  SET X = 32;
  WHILE X  < 127 DO
    SET str = REPLACE(str, CONCAT('%', HEX(X)), UNHEX(HEX(X)));
    SET  X = X + 1;
  END WHILE;
  SET X = 168; -- C2
  WHILE X  < 192 DO
    SET str = REPLACE(str, CONCAT('%', HEX(X)), UNHEX(CONCAT('C2', HEX(X))));
    SET  X = X + 1;
  END WHILE;
  SET X = 192; -- C3
  WHILE X  < 256 DO
    SET str = REPLACE(str, CONCAT('%', HEX(X)), UNHEX(CONCAT('C3', HEX(X-64))));
    SET  X = X + 1;
  END WHILE;
  SET X = 256; -- C4
  WHILE X  < 320 DO
    SET str = REPLACE(str, CONCAT('%', HEX(X)), UNHEX(CONCAT('C4', HEX(X-128))));
    SET  X = X + 1;
  END WHILE;
  SET X = 320; -- C5
  WHILE X  < 384 DO
    SET str = REPLACE(str, CONCAT('%', HEX(X)), UNHEX(CONCAT('C5', HEX(X-192))));
    SET  X = X + 1;
  END WHILE;
  RETURN REPLACE(str, '+', ' ');
END

See the new four while blocks -- These can decode non-standard C2, C3, C4 and C5 blocks. These blocks, that might have come from the use of escape, are HTML encodings instead of UTF encodings. @Mistdemon's answer also uses these encodings (at least C2 and C3) instead of more modern multi-byte UTF encodings (encodeURIComponent).

Related