'utf8'에 해당하는 글 3건

ORACLE dump import

Daily/Prog 2021. 7. 22. 00:14

 

초보 오라클러가 오라클 데이터를 덤프받아 import 하며 간만에 크게 삽질한 과정을 적어본다. (난 도대체 언제까지 초보일껀가?) impdp 과정에서 오류나는 tablespace 열심히 만들고, 그 외에 유독 눈에 띄는 오류들이 있었다.

 

ora-12899: value too large for column actual x maximum n

 

아니 똑같은 스키마에 덤프 떠서 고대로 넣는데 먼 소린고... 

 

무시하다가 나중에 데이터를 확인했는데 같은 테이블에서도 어떤 컬럼은 한글이 깨지고 어떤 컬럼은 안깨지고... Mysql 에서도 테이블 별로 인코딩 설정은 가능하지만, 컬럼 별로 깨지고 안깨진다? 오라클 초보자로서는 당최 이해할 수가 없었는데 검색을 조금 해보니 알 것 같았다. KO16MSWIN949 의 2바이트짜리 한글들이 AL32UTF8 의 3바이트 한글로 넘어오면서 컬럼값이 넘친 것이니 인코딩 문제는 맞다. 아니 오라클 깔면 기본으로 UTF8 쓰게 되어 있는데 굳이 바꿔 가지고 이렇게들 피곤하게 할까잉...

 

오라클에서 인코딩 관련 설정 2개 / 언어 관련 설정 2개를 찾았다.

 

SELECT name, value$
FROM sys.props$
WHERE name IN ('NLS_LANGUAGE','NLS_TERRITORY','NLS_CHARACTERSET','NLS_NCHAR_CHARACTERSET');

or

SELECT * 
FROM NLS_DATABASE_PARAMETERS 
WHERE PARAMETER IN ('NLS_LANGUAGE','NLS_TERRITORY','NLS_CHARACTERSET','NLS_NCHAR_CHARACTERSET');

--NLS_LANGUAGE AMERICAN
--NLS_TERRITORY AMERICA
--NLS_CHARACTERSET AL32UTF8
--NLS_NCHAR_CHARACTERSET AL16UTF16

 

NLS_CHARACTERSET : char / varchar 데이터타입에서 사용하는 문자셋

NLS_VCHAR_CHARACTERSET  : nchar / nvarchar 데이터타입에서 사용하는 문자셋

 

 

역시 덤프 받아온 운영DB 와 NLS_CHARACTERSET 이 달랐고, varchar 의 한글만 문제가 발생한 것이다. KO16MSWIN949 로 인코딩 변경이 필요했다.

 

 

SQL> update props$ set value$='KO16MSWIN949' where name='NLS_CHARACTERSET';
SQL> commit;
SQL> shutdown immediate;
SQL> startup;

 

인터넷에서 대충 검색 해보고 뙇! 역시 천재라고 잠시 생각했지만, update 하면서 인코딩 값에 오타가 들어갔었는지 습관적으로 커밋은 했는데 startup 에 실패했다. 그 일순간의 오타로 오라클을 재설치까지 했다.ㅋㅋ nomount 하고 어쩌구 저쩌구 하면 가능하다고는 하는데, 난 모르겠고 빨리 재설치를 빨리 하는 것이 더 이득인 상황. 어짜피 이미 깨진 한글 다시 넣으려면 테이블들 다 확인해서 drop 을 하던 truncate 를 하던 해야 할 상황이었는데, 재설치가 빠르지... 라는 타협을 하고서는 ./deinstall ㅋㅋ 역시 뭔 프로그램이던 삭제는 참 빨라. $ORACLE_HOME 이랑 oradata 디렉토리도 비워주고 재설치 고고.

 

이번엔 미리 NLS_CHARACTERSET 인코딩 설정하고, profile 에 NLS_LANG 도 맞춰주고... impdp 뙇!

 

ORA-39006: internal error
ORA-39065: unexpected master process exception in DISPATCH
ORA-00600: internal error code, arguments: [kokle_lob2lob13:input mismatch], [1], [], [], [], [], [], []
ORA-39097: Data Pump job encountered unexpected error -600

 

아씨... 이럼 완전 나가린데...

 

한참 삽질 끝에 구글신이 도와주긴 했는데 이해는 안간다. NLS_CHARACTERSET 랑 DB internal 캐릭터셋이 따로 노는겨? 왜 둘다 바꿔줘야 하는겨? ㅡ.ㅡ 테스트 해보니 아래 방법이 NLS_CHARACTERSET 까지 확실하게 바뀌니, 아래 방법을 추천하는 걸로...

 

SQL> shutdown immediate;
SQL> startup mount;
SQL> alter system enable restricted session;
SQL> alter system set job_queue_processes=0;
SQL> alter database open;
SQL> alter database character set internal_use KO16MSWIN949;
SQL> shutdown immediate;
SQL> startup;

 

alter database character set internal_use <- 요기가 포인트!

 

아무튼 긴~ 삽질끝에 덤프질 해결~


WRITTEN BY
손가락귀신
정신 못차리면, 벌 받는다.

,

예제에서 텍스트 파일을 binary 로 읽길래, 잠시 파일 처리에 대해 살펴봤다.

파이썬에서 텍스트 파일을 읽을 때(open) 사용하는 옵션 중 text(rt:default) 모드와 binary(rb) 모드가 있다.


말 그대로,

- text 모드는 텍스트 파일 객체로 읽어오는 것이고,

- binary 모드는 텍스트 파일을 바이너리 객체로 인코딩하여 읽어오는 것이다.

ㅋㅋ...;;;


두 모드에 대해 조금더 알아보면...


Text mode

- 이 모드로 파일을 open 하면 io.IObase 클래스를 상속받은 텍스트 파일 객체(io.TextIOWrapper)를 생성한다.

- 정해진 인코딩(encoding)으로 디코딩(decoding)이 발생하며 파일의 내용은 문자열 str 로 반환된다.

- 텍스트 인코딩을 지정하지 않을시 플랫폼의 기본 인코딩을 따른다.

- text 파일이 아닌 파일(binary=non-text)을 이 모드로 열면 글자가 깨져보여 내용을 알아볼 수 없다.


Binary mode

- 이 모드로 파일을 open 하면 io.IObase 클래스를 상속받은 바이너리 파일 객체(io.BufferedReader)를 생성한다.

- 디코딩 없이 파일의 내용은 1바이트 크기의 배열인 bytes 객체로 반환된다.

- binary 파일이 아닌 text 파일의 경우 bytes 객체로 인코딩하는 과정을 거친다.

- text 파일을 포함한 모든 binary 파일을 처리할 수 있다.

- text mode 에 비해 디스크 및 메모리가 적게 소모되며 속도가 빠르다.



예를 들어,


한글 ㅋㅋ
abc    1    def
오예
cs


위 내용처럼 한글과 영문 등이 혼합된 utf-8 로 인코딩된 파일을 binary 모드로 불러온다면


lines = open("file.txt""rb")
= 0
for line in lines:
    #line = line.decode('utf-8').strip()
    i = i + 1
    print(line)
cs


b'\xed\x95\x9c\xea\xb8\x80 \xe3\x85\x8b\xe3\x85\x8b\r\n'
b'abc\t1\tdef\r\n'
b'\xec\x98\xa4\xec\x98\x88'
cs


위 결과처럼 파이썬에서는 b로 시작하는 작은/큰따옴표 형태를 bytes 객체라고 한다. 위에서도 아스키 문자와 이스케이프 시퀀스(탭, 개행 등)를 제외하고는 binary 형태로 출력된 것을 볼 수 있다. 이 상태에서 주석을 해제하면 다시 utf-8 로 디코딩 된 문자열로 내용을 확인할 수 있다.


근데 왜 예제에서는 텍스트 파일을 바이너리 모드로 읽어왔을까...


모르겠다...ㅎㅎ; 텍스트 문서를 읽을 때 어떤 모드를 사용해도 별 문제는 없는 것 같다. 다만 어떤 모드를 사용하든 문서에 한글 등이 포함되어 있다면 인코딩을 알고 있어야 한다. 한글 Windows 의 경우 EUC-KR 을 확장한 CP949 를 사용할 것이며, 요즘은 ANSI 와의 하위호환성이 보장된 UTF-8 를 주로 사용한다.(다국어를 모두 사용할 수 있음) 편의를 위해 만들어 놨으니 text 파일은 text 모드로 binary 파일은 binary 로 처리하면 되지 않을까 싶다...




WRITTEN BY
손가락귀신
정신 못차리면, 벌 받는다.

,

Insert Emoji

Database/Mysql 2017. 2. 21. 22:52

웹서비스를 구축할 때 데이터베이스는 주로 utf-8 을 사용해 왔다.

요즘은 웹과 모바일 앱을 동시에 사용하다 보니, 입력란에 모바일 이모지들을 함부로(?) 입력하는 유저들 덕분에 앱이 종료되거나 오류가 발생하는 일이 생긴다.

이것은 모바일 내장 이모지들이 4byte 문자열이고, DB collation 이 3byte 집합인 UTF8 을 사용하기 때문이다.

그로 인해 아래와 흡사한 오류들을 마주할 수 있다.


### Error updating database.  

Cause: java.sql.SQLException: Incorrect string value: '\xF0\x9F\x98\x83 \xF0...' for column 'comment' at row 1



해결 방법은 어렵지 않다. DB 옵션의 character_set / collation 과 테이블을 UTF8 에서 UTF8MB4 로 변경하면 된다.

Mysql 에서는 2010년 MYSQL 5.5.3 버전에 4byte 집합인 utf8mb4 charset 을 추가하였다.

기존 utf8 시스템을 utf8mb4 로 바꾸어도 값의 손실은 없으며, DB 용량이 조금 늘어날 것이다.


난 아래의 순서대로 기존 UTF8 코드를 UTF8MB4 로 변경했다.

(환경 : java / RDS mysql)



1. JDBC


connect.url=jdbc:mysql://db_domains.rds.amazonaws.com:3306/test?useUnicode=true&characterEncoding=utf8
cs


소스에서 DB 연결에 jdbc characterEncoding 을 지정하는데 이것을 utf8 에서 utf8mb4 로 바꾸면 되는줄 알았지만 MySQL Connector/J 문서에 보면 utf8mb4 는 지원하지 않는다.

그냥 characterEncoding 파라미터를 삭제해 버리면 DB 의 기본 인코딩대로 작동한다. 이거 수정하고 그냥 배포!

요고 안하면 조~기 맨 위에 오류가 발생한다.



2. Parameter Groups


RDS mysql 의 Parameter Groups 은 my.ini 파일과 같다. 각종 옵션들을 수정할 수 있다. 여기서 인코딩을 전부 바꿔준다.

(참고로 character_set_server 만 바꿔주고, 나머지는 default 로 내비둬도 utf8mb4 적용되었음.)



3. Table Column


이모지를 저장할 테이블의 컬럼들을 utf8mb4 로 수정한다.

table 전체를 바꿔도 무방하지만 난 이모지가 저장될 컬럼에만 utf8mb4 를 적용했다.


ALTER TABLE `oops4u`.`article` 
CHANGE COLUMN `title` `title` VARCHAR(255CHARACTER SET 'utf8mb4' NOT NULL COMMENT '제목 ' ,
CHANGE COLUMN `content` `content` VARCHAR(255CHARACTER SET 'utf8mb4' NOT NULL COMMENT '내용' ;
...
cs



4. DB reboot


Parameter groups 의 인코딩 관련한 옵션들은 바로 적용이 되지 않는다. 재부팅이 필요하다.

Parameter groups 가 적용되지 않으면 테이블 collation 변경 덕분에 오류 없이 데이터는 들어오지만 이모지 대신 ??? 문자로 도배될 것이다.

재부팅하고 자알~ 되는지 확인한다.



위 이미지는 ios 에서 입력한 이모지를 android 와 web 에서 확인한 것이다.

http://getemoji.com/ 의 이모지 리스트처럼 웹에서 ㅁ형태로 깨져보이는 이모지도 꽤 있지만 뭐...

그건 내 힘으로 해결할 수 있는건 아닌듯 하고...




유의사항


Mysql 에서 한 컬럼의 최대 key 사이즈는 767 byte 이다.

그래서 index 가 문자열일 경우 utf8 에서는 255 까지 지정이 가능했다 (767 / 3 byte = 255...)

만약 utf8mb4 로 변경한 컬럼이 문자열 index 로 사용되고 있다면, 그 컬럼의 자료형은 varchar(191) 로 수정되어야 한다. (767 / 4 byte = 191...)

그렇지 않으면 아마도 이런 오류를 만나게 될 것이다.


ERROR 1071 (42000): Specified key was too long; max key length is 767 bytes


혹은 innodb_large_prefix=1 로 시스템 변수를 설정하면 key 길이가 3072 byte 까지 확장되므로 위 오류를 막을 수 있다.




WRITTEN BY
손가락귀신
정신 못차리면, 벌 받는다.

,