레이블이 unhex인 게시물을 표시합니다. 모든 게시물 표시
레이블이 unhex인 게시물을 표시합니다. 모든 게시물 표시

2016년 7월 6일 수요일

MySQL에서 URL Decoding 하는 SQL Stored Procedure.

MySQL에서 URL Decoding 하는 SQL Stored Procedure.

데이터 입력을 encode된걸 넣어서 - 게다가 중간중간 깨진데이터들이나 URL일부가 그대로 들어가있는 경우도 있었고 (물론 매우 소수 일부가 그러했다.)아무튼 그런 이유로 어쩔 수 없이 검증하는 쿼리가 필요했다. (등떠밀려 만듦ㅎ)

아래는 최초 적용한 함수이다.
근데.. 이게 영 이상하게 동작한다. 실패작이다.
(그냥 된다카길래 가져다 썼는데 이거 원;)

  1. DELIMITER $$  
  2.   
  3. DROP FUNCTION IF EXISTS `url_decode` $$  
  4. CREATE DEFINER=`root`@`%` FUNCTION `url_decode`(original_text TEXT) RETURNS TEXT CHARSET utf8  
  5. BEGIN  
  6.     DECLARE new_text TEXT DEFAULT NULL;  
  7.     DECLARE pointer INT DEFAULT 1;  
  8.     DECLARE end_pointer INT DEFAULT 1;  
  9.     DECLARE encoded_text TEXT DEFAULT NULL;  
  10.     DECLARE result_text TEXT DEFAULT NULL;
  11.     DECLARE EXIT HANDLER FOR SQLEXCEPTION
  12.     BEGIN
  13.         return NULL;
  14.     END;

  15.     SET new_text = REPLACE(original_text,'+',' ');  
  16.     SET new_text = REPLACE(new_text,'%0A','\r\n');  
  17.    
  18.     SET pointer = LOCATE("%", new_text);  
  19.     while pointer <> 0 && pointer < (CHAR_LENGTH(new_text) - 2) DO  
  20.         SET end_pointer = pointer + 3;  
  21.         while MID(new_text, end_pointer, 1) = "%" DO  
  22.             SET end_pointer = end_pointer+3;  
  23.         END while;  
  24.    
  25.         SET encoded_text = MID(new_text, pointer, end_pointer - pointer);  
  26.         SET result_text = CONVERT(UNHEX(REPLACE(encoded_text, "%""")) USING utf8);  
  27.         SET new_text = REPLACE(new_text, encoded_text, result_text);  
  28.         SET pointer = LOCATE("%", new_text, pointer + CHAR_LENGTH(result_text));  
  29.     END while;  
  30.    
  31.     return new_text;  
  32.   
  33. END $$  
  34.   
  35. DELIMITER ;


그래서 다른 것을 찾아보았다.
그래서 아래와 같은 함수를 발견하게되었고 이번엔 꼼꼼하게 소스를 다 훝어보았다.
먼저 소스보다 훨씬 더 가독성이 좋았고 편리하게 작성되어있어 수정도 편했다.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
DROP FUNCTION IF EXISTS urldecode;

DELIMITER |

CREATE FUNCTION urldecode (s VARCHAR(4096)) RETURNS VARCHAR(4096)
DETERMINISTIC 
CONTAINS SQL 
BEGIN
       DECLARE c VARCHAR(4096) DEFAULT '';
       DECLARE pointer INT DEFAULT 1;
       DECLARE s2 VARCHAR(4096) DEFAULT '';
       DECLARE h3 VARCHAR(4096) DEFAULT '';
       DECLARE CONTINUE handler FOR 1366
       BEGIN
       END;

       IF ISNULL(s) THEN
          RETURN NULL;
       ELSE
       SET s2 = '';
       WHILE pointer <= LENGTH(s) DO
          SET c = SUBSTR(s,pointer,1);
          IF c = '+' THEN
             SET h3 = '20';
          ELSEIF c = '%' AND pointer + 2 <= LENGTH(s) THEN
                   SET h3 = UPPER(SUBSTR(s,pointer+1,2));
                   SET pointer = pointer + 2;
          ELSE
                   SET h3 = HEX(c);
          END IF;
          SET s2 = CONCAT(s2,h3);
          SET pointer = pointer + 1;
       END while;
       END IF;
       RETURN UNHEX(s2);
END;

|

DELIMITER ;

헌데, 이넘도 문제가 있다.

encode data가 깨진 경우, 마지막 RETURN UNHEX(s2); 에서 1366 오류가 난다.
이해가 가지 않는다; ㅠㅠ;;;;;;;;;;;;;;;;

일단 작업에 방해가 되면 안되니, 위 소스처럼
DECLARE CONTINUE handler FOR 1366
BEGIN
END;
로서 땜빵.

문제의 진짜 이유를 찾기 위해 테스트해 보았다.

결국, 수십여분 삽질끝에.. 이상한것을 발견했다. 이유는 모른다. 

RETURN UNHEX(s2); #1366 ERROR 발생
위 부분을 
RETURN s2;

위와 같이 UNHEX 배제 후 함수 호출부분에서 UNHEX하니 

SELECT urldecode('%ED%81%AC%EBCsn%3D3%7Chk%3Dbbcac20f524e408ffbd748bce750e921a2aca717'); #1366 ERROR 발생 

SELECT UNHEX(urldecode('%ED%81%AC%EBCsn%3D3%7Chk%3Dbbcac20f524e408ffbd748bce750e921a2aca717'));


결과가 나왔다. 응?! 왜지?!
return되기직전에 unhex를 사용하면 안되고 반환반고나서 unhex를 쓰면된다?!

SQL 잘하는 사람한테 물어봐야할라나..?

아는사람은 좀 알려주세요~~~~ ㅠㅠ