다국어 지원¶
다국어 지원(Globalization)은 다양한 언어와 지역에 적용될 수 있도록 하는 국제화(Internationalization)와 언어별 구성 요소를 추가하여 특정 지역의 언어나 문화에 맞추는 현지화(Localization)를 포함한다. CUBRID는 현지화를 쉽게 하기 위해 유럽과 아시아를 포함한 여러 언어들의 콜레이션(collation)을 지원한다.
문자 데이터 설정에 대한 전반적인 사항을 알고 싶다면 다국어 설정을 위한 고려 사항 를 참고한다.
문자셋, 콜레이션, 로캘이 무엇인지 알고 싶다면 다국어 개요 를 참고한다.
원하는 언어와 지역에 따른 로캘을 데이터베이스에 반영하고 싶으면 반드시 로캘을 먼저 설정한 후 데이터베이스를 생성해야만 한다. 이와 관련하여 로캘 설정 을 참고한다.
데이터베이스에 설정된 콜레이션 또는 문자셋을 변환하고 싶으면 해당 칼럼, 테이블, 표현식에 COLLATE 수정자 또는 CHARSET 수정자 를 지정하고, 문자열 상수에 COLLATE 수정자 또는 문자셋 소개자 를 지정한다. 이와 관련하여 콜레이션 을 참고한다.
문자열 관련 함수나 연산자는 문자셋과 콜레이션에 따라 다르게 동작할 수 있다. 이와 관련하여 문자셋과 콜레이션을 필요로 하는 연산 을 참고한다.
다국어 개요¶
문자 데이터¶
콜레이션을 적용할 수 있는 데이터의 타입은 VARCHAR, CHAR, ENUM 타입이다.
문자셋(charset, codeset)은 어떤 타입에 대해 문자가 저장되는 방식 또는 일련의 바이트가 하나의 문자를 구성하는 방식을 제어한다. CUBRID는 UTF-8, ISO-8859-1, EUC-KR 문자셋을 지원하며, UTF-8에 대해 코드포인트 10FFFF(4 바이트까지 인코딩됨)까지만 지원한다. 예를 들어, 문자 "Ç"는 코드셋 ISO-8859-1에서 1 바이트(C7)으로 인코딩되지만, UTF-8에서는 2 바이트(C3 87)로 인코딩된다. 반면, EUC-KR에서 이 문자는 사용할 수 없다.
콜레이션은 문자를 비교하는 방법을 결정한다. 사용자는 흔히 클레이션을 통해 대소문자를 구분하지 않거나 구분한다. 예를 들어 "ABC"와 "abc"는 대소문자 구분 무시(case insensitive) 콜레이션에서는 동일한 반면, 대소문자 구분(case sensitive) 콜레이션에서는 동일하지 않다. 또한 콜레이션에 따라 비교 결과가 "ABC" > "abc"가 되거나 "ABC" < "abc"가 될 수 있다.
콜레이션은 대소문자 비교 이상의 것을 의미한다. 콜레이션은 두 문자열 간에 관계를 결정하여 LIKE와 같은 문자열 매칭에 사용되거나 인덱스 스캔에서 영역을 계산하는데 사용된다.
CUBRID에서 콜레이션은 문자셋을 포함한다. 예를 들어, "utf8_en_ci"과 "iso88591_en_ci"은 대소문자를 구분하지 않는 비교이지만 다른 문자셋에서 동작한다. ASCII 범위에서 비교 결과는 비슷하지만 UTF-8 인코딩은 가변적인 바이트 수에 따라 동작해야 하기 때문에 "utf8_en_ci" 콜레이션에서 비교 수행 속도가 더 느리다.
- 'a' COLLATE iso88591_en_ci는 _iso88591'a' COLLATE iso88591_en_ci를 나타낸다.
- 'a' COLLATE utf8_en_ci는 _utf8'a' COLLATE utf8_en_ci를 나타낸다.
모든 문자 데이터 타입은 자릿수(precision)를 지원한다. 고정 길이 문자(CHAR)는 특별히 다루어져야 한다. CHAR 타입의 값은 자릿수를 채워서 저장된다. 예를 들어 "abc"를 CHAR(5) 칼럼에 저장하면, "abc "(2 개의 공백 문자가 패딩됨)를 저장하게 된다. 공백 문자(ASCII 32, Unicode 0020)는 대부분 문자에서 사용하는 패딩 문자이다. 하지만 EUC-KR 문자셋에서 패딩 문자는 두 개 바이트(A1 A1)로 저장된 하나의 문자로 구성된다.
관련 용어¶
문자셋(character set) : 기호를 인코딩(어떤 기호에 특정 번호를 부여)한 집합
콜레이션(collation) : 문자셋에서 문자를 비교하기 위한, 데이터 정렬을 위한 규칙의 집합
로캘(locale) : 사용자의 언어 및 국가에 따라 숫자 형식, 캘린더(월의 이름, 요일의 이름), 날짜/시간 형식, 콜레이션, 통화 등을 정의하는 인자들의 집합. 로캘은 언어에 대한 지역화(localization)를 정의한다. 로캘의 문자셋은 월의 이름 및 다른 데이터가 어떻게 인코딩되는지를 나타낸다. 로캘은 최소한 하나의 언어 식별자와 영역 식별자로 구성되어 있으며 language[_territory][.codeset]으로 표현한다. (예를 들어 UTF-8 인코딩을 쓰는 오스트레일리아 영어는 en_AU.utf8로 표기한다.)
유니코드 정규화(Unicode normalization) : 모양이 같은 여러 문자들이 있을 경우 기준에 따라 이를 하나로 통합하는 것. CUBRID는 입력 시에는 NFC(Normalization Form C) 형식(분해된 코드 코드포인트에서 결합된 코드포인트로 변환)을 사용하고, 출력 시에는 NFD(Normalization Form D) 형식(결합된 코드포인트에서 분해된 코드포인트로 변환)을 사용한다. 하지만, CUBRID는 예외적으로 규범적 등가(canonical equivalence) 규칙을 적용하지 않는다.
예를 들어, 일반적인 NFC 규칙에 따르면 규범적 등가 규칙을 적용하여 코드포인트 212A(캘빈 기호 K)는 코드포인트 4B(ASCII 코드 대문자 K)로 변환된다. CUBRID는 규범적 등가 규칙에 의한 변환을 수행하지 않도록 하여 정규화 알고리즘을 더 간단하고 빠르게 하였고, 따라서 역변환도 수행하지 않는다.
규범적 등가(canonical equivalence) : 시각적으로 구별이 불가능하고 텍스트 비교상 정확히 동일한 의미를 가지는 문자. 한 예로 'A'에 옹스트롬(Angstrom) 기호가 있는 'Å'가 있는데, 'Å'(유니코드 U+212B)와 라틴어 'A'(유니코드 U+00C5)는 모양이 같고 코드포인트가 다르지만 분해된 결과는 'A'와 U+030A로 같으므로 규범적 등가이다.
호환성 등가(compatibility equivalence) : 동일한 문자나 문자 시퀀스의 대체 표현 문자. 예로는 숫자 '2'(유니코드 U+0032)와 위첨자 '²'(유니코드 U+00B2)가 있는데, '²' 는 숫자 '2'의 다른 형태이긴 하지만 시각적으로 구별되고 의미도 다르기 때문에 규범적 등가에 해당되지 않는다. '2²'를 NFC로 정규화하면 규범적 등가를 사용하기 때문에 '2²'가 유지되지만, NFKC 방식에서는 '²'가 호환성 등가인 '2'로 분해된 후 결합되어 '22'로 바뀔 수 있다. CUBRID의 유니코드 정규화에서는 호환성 등가 규칙도 적용하지 않는다.
유니코드 정규화에 대한 설명은 유니코드 정규화 를 참고하며, 보다 자세한 내용은 http://unicode.org/reports/tr15/를 참고한다.
유니코드 정규화 관련 시스템 파라미터에서 기본으로 설정되는 값은 unicode_input_normalization=no이고 unicode_output_normalization=no이다. 이 파라미터에 대한 보다 자세한 설명은 구문/타입 관련 파라미터 를 참고한다.
로캘 속성¶
로캘은 다음과 같은 속성들로 정의된다.
- 문자셋(코드셋) : 여러 바이트를 하나의 문자로 해석하는 방법을 정의한다. 유니코드에서는 여러 개의 바이트가 하나의 코드포인트(codepoint)를 구성하는 것으로 해석된다.
- 콜레이션(collation) : LDML(UNICODE Locale Data Markup Language) 파일의 로캘 데이터에 여러 콜레이션을 지정할 수 있는데, 이 중에 마지막으로 명시된 것이 기본 콜레이션으로 사용된다.
- 알파벳(대소문자 규칙) : 하나의 로캘 데이터는 테이블 이름, 칼럼 이름과 같은 식별자용과 사용자 데이터용으로 최대 두 종류의 알파벳을 가질 수 있다.
- 캘린더 : 요일 이름, 월의 이름, 오전/오후(AM/PM) 표시
- 숫자 표기 : 자릿수 구분 기호, 소수점 기호, 통화 형식
- 텍스트 변환 데이터 : CSQL 콘솔 변환용 선택 사항
- 유니코드 정규화 데이터 : 모양이 같은 여러 문자들이 있을 경우 이를 기준에 따라 하나의 값으로 통합하는 정규화를 수행하여 변환된 데이터. 정규화 이후에는 로캘이 달라도 모양이 같은 문자는 같은 코드값을 가지며, 각 로캘은 이 정규화 기능을 활성화 또는 비활성화할 수 있다.
Note
일반적으로 한 로캘은 다양한 문자셋을 지원하지만, CUBRID 로캘은 영어와 한국어에 한해서만 ISO와 UTF-8 문자셋을 둘 다 지원한다. 그 외의 LDML 파일을 이용한 모든 사용자 정의 로캘은 UTF-8 문자셋만 지원한다.
콜레이션 속성¶
콜레이션(collation)은 문자열의 비교 및 정렬 규칙의 집합으로, CUBRID에서 콜레이션은 다음과 같은 속성(property)을 갖는다.
- 세기(strength) : 기본 비교 항목들(문자들)이 어떻게 다른지 나타내는 측정 기준이다. 이것은 선택도(selectivity)에 영향을 준다. LDML 파일에서 콜레이션의 세기는 네 가지 수준(level)으로 설정할 수 있다. 예를 들어, 대소문자 구분이 없는 콜레이션은 level = "secondary" (2) 또는 "primary" (1)로 설정해야 한다.
- 확장(expansion) 과 축약(contraction) 지원 여부
각각의 칼럼이 콜레이션을 가질 수 있기 때문에, LOWER()
, UPPER()
함수 등을 적용할 때 해당 콜레이션의 기본 언어에서 정의한 로캘의 대소문자 구분 규칙(casing rule)이 사용된다.
콜레이션 속성에 따라 일부 콜레이션에서 다음과 같은 특정 CUBRID 최적화가 동작하지 않을 수 있다.
- LIKE 구문 재작성: 같은 가중치(weight)에 여러 개의 다른 문자를 매핑하는 콜레이션, 예를 들어 대소문자 구분이 없는 콜레이션에서는 LIKE 구문이 재작성되지 않는다.
- 커버링 인덱스 스캔: 같은 가중치에 여러 개의 다른 문자를 매핑하는 콜레이션에서는 커버링 인덱스 스캔이 동작하지 않는다(커버링 인덱스 참고).
- prefix 인덱스: 확장이 있는 콜레이션을 사용한 칼럼에서는 prefix 인덱스를 생성할 수 없다.
이에 관한 보다 자세한 설명은 콜레이션 설정으로 인한 영향 을 참고하면 된다.
콜레이션 명명 규칙¶
콜레이션 이름은 다음 규칙을 따른다.
<charset>_<lang specific>_<desc1>_<desc2>_...
<charset>: 문자셋 이름. iso88591, utf8, euckr이 있다.
<lang specific>: 지역/언어를 나타내며, en, de, es, fr, it, ja, km, ko, tr, vi, zh가 있다. 특정 언어를 나타내지 않을 때는 "gen"으로 일반적인 정렬 규칙을 의미한다.
<desc1>_<desc2>_...: 대부분 LDML 콜레이션에만 적용되며 각각 다음의 의미를 갖는다.
ci: 대소문자 구분 안 함. LDML 파일에서 다음을 설정하면 적용된다: strength="secondary" caseLevel="off" caseFirst="off"
cs: 대소문자 구분. 기본적으로 모든 콜레이션은 대소문자를 구분한다. LDML 파일에서 다음을 설정하면 적용된다: strength="tertiary"
bin/binary: 정렬 순서가 코드포인트의 순서와 똑같음. 메모리의 바이트 순서를 비교하면 거의 같은 결과가 나오는데, 공백 문자와 EUC의 더블 바이트 패딩 문자는 "bin" 콜레이션에서 항상 0으로 정렬된다. LDML 파일에는 bin 콜레이션을 설정하는 방법이 없는데(bin 콜레이션은 이미 내장되어 있음), LDML 파일에서 다음을 설정하면 비슷하게 적용된다: strength="quaternary" 또는 strength="identical"
ai: 악센트 구분 안 함. 예를 들어, 'Á'는 'A'와 같은 순서이다. 이는 또한 대소문자를 구분하지 않는다. LDML 파일에서 다음을 설정하면 적용됨: strength="primary"
uca: UCA(Unicode Collation Algorithm) 기반 콜레이션을 의미함. 내장된 변형 콜레이션과 구별하기 위해서만 사용된다. 즉, 모든 LDML 콜레이션은 UCA를 기반으로 하지만 짧은 이름을 유지하기 위해 "_uca"가 생략되며, 예외적으로 'utf8_ko_cs_uca', 'utf8_tr_cs_uca' 이 두 개의 콜레이션만 내장된 'utf8_ko_cs', 'utf8_tr_cs' 콜레이션과 구별하기 위해 사용된다.
exp: 다른 콜레이션들이 문자 단위로 비교하는 것에 반해, 확장 은 전체 단어 매칭/비교 알고리즘을 사용한다. 이 콜레이션은 좀더 복잡한 알고리즘을 사용하므로 훨씬 느릴 수 있지만, 알파벳 정렬에 유용할 수 있다. LDML 파일에 다음이 명시되어야 한다: CUBRIDExpansions="use"
- ab: 역순 액센트(accent backwards). 특히 캐나다 프랑스어에만 적용되는데, UCA 2단계(액센트 가중치를 저장)는 문자열의 끝에서부터 시작 방향으로 비교된다. 이 콜레이션 설정은 오직 확장 이 활성화되는 경우에만 사용될 수 있다. "ab" 설정은 다음 정렬을 허용한다:
- 일반적인 액센트 순서: cote < coté < côte < côté
- 역방향 액센트 순서: cote < côte < coté < côté
- cbm: 축약 영역 매칭(contraction boundary match). 확장 과 축약 이 있는 콜레이션의 특별한 콜레이션이며, 매칭되는 문자열에서 축약 이 발견될 때 동작하는 방법을 설정한다.
콜레이션의 축약 을 "ch"로 정의했다고 가정하자. 그러면 일반적으로 "bac"라는 패턴은 문자열 "bachxxx"와는 매칭되지 않는다. 그러나 콜레이션이 "축약을 시작하는 문자 매칭"을 허용하도록 설정되면, 앞서 말한 문자열들은 매칭된다. 이러한 식으로 동작하는 콜레이션은 'utf8_ja_exp_cbm' 밖에 없는데, 일본어 정렬은 무수히 많은 축약 을 요구한다.
콜레이션 이름은 동적으로 생성되지 않는다. LDML에 정의되어 있으며, 콜레이션 설정을 반영해야 한다. 콜레이션 이름은 콜레이션의 내부적인 ID에 영향을 준다. CUBRID는 256 개의 콜레이션을 허용하며, 각 식별자들은 다음과 같이 등록된다.
- 0 - 31: 내장된(built-in) 콜레이션(이름과 식별자가 제품에 포함됨)
- 32 - 46: 언어 부분에 "gen"을 가지는 LDML 콜레이션
- 47 - 255: 나머지 LDML 콜레이션
CUBRID가 제공하는 모든 로캘을 데이터베이스에 포함하고 싶다면, 먼저 $CUBRID/conf 디렉터리의 cubrid_locales.all.txt 파일을 cubrid_locales.txt 파일로 복사한다. 그리고, make_locale 스크립트(확장자가 Linux는 .sh, Windows는 .bat)를 실행하면 된다. make_locale 스크립트에 대한 자세한 설명은 2단계: 로캘 컴파일하기 를 참고하면 된다. 기존의 데이터베이스에 새로 추가한 로캘 정보를 포함하고 싶다면 cubrid synccolldb <dbname>을 실행한다. 이에 대한 자세한 설명은 데이터베이스 콜레이션을 시스템 콜레이션에 동기화 를 참고하면 된다.
LDML 파일로 정의된 로캘을 모두 포함하는 경우 CUBRID는 다음의 콜레이션을 가진다.
콜레이션 | 대소문자 구분을 위한 로캘 | 문자 범위 |
---|---|---|
iso88591_bin | en_US - 영어 | ASCII + ISO88591 (C0-FE, except D7, F7) |
iso88591_en_cs | en_US - 영어 | ASCII + ISO88591 (C0-FE, except D7, F7) |
iso88591_en_ci | en_US - 영어 | ASCII + ISO88591 (C0-FE, except D7, F7) |
utf8_bin | en_US - 영어 | ASCII |
euckr_bin | ko_KR, en_US와 같음 - 영어 | ASCII |
utf8_en_cs | en_US - 영어 | ASCII |
utf8_en_ci | en_US - 영어 | ASCII |
utf8_tr_cs | tr_TR - 터키어 | 터키어 알파벳 |
utf8_ko_cs | ko_KR, en_US와 같음 - 영어 | ASCII |
utf8_gen | de_DE - 독일어, 독일어 규칙에 맞게 대소문자를 커스터마이징한 유니코드 | 0000-FFFF 범위의 모든 유니코드 코드포인트 |
utf8_gen_ai_ci | de_DE - 독일어, 독일어 규칙에 맞게 대소문자를 커스터마이징한 유니코드 | 0000-FFFF 범위의 모든 유니코드 코드포인트 |
utf8_gen_ci | de_DE - 독일어, 독일어 규칙에 맞게 대소문자를 커스터마이징한 유니코드 | 0000-FFFF 범위의 모든 유니코드 코드포인트 |
utf8_de_exp_ai_ci | de_DE - 독일어, 독일어 규칙에 맞게 대소문자를 커스터마이징한 유니코드 | 0000-FFFF 범위의 모든 유니코드 코드포인트 |
utf8_de_exp | de_DE - 독일어, 독일어 규칙에 맞게 대소문자를 커스터마이징한 유니코드 | 0000-FFFF 범위의 모든 유니코드 코드포인트 |
utf8_es_cs | es_ES - 스페인어, 일반적인 유니코드 대소문자 규칙과 동일 | 0000-FFFF 범위의 모든 유니코드 코드포인트 |
utf8_fr_exp_ab | fr_FR - 프랑스어, 일반적인 유니코드 대소문자 규칙과 동일 | 0000-FFFF 범위의 모든 유니코드 코드포인트 |
utf8_ja_exp | ja_JP - 일본어, 일반적인 유니코드 대소문자 규칙과 동일 | 0000-FFFF 범위의 모든 유니코드 코드포인트 |
utf8_ja_exp_cbm | ja_JP - 일본어, 일반적인 유니코드 대소문자 규칙과 동일 | 0000-FFFF 범위의 모든 유니코드 코드포인트 |
utf8_km_exp | km_KH - 캄보디아어, 일반적인 유니코드 대소문자 규칙과 동일 | 0000-FFFF 범위의 모든 유니코드 코드포인트 |
utf8_ko_cs_uca | ko_KR - 한국어, 일반적인 유니코드 대소문자 규칙과 동일 | 0000-FFFF 범위의 모든 유니코드 코드포인트 |
utf8_tr_cs_uca | tr_TR - 터키어, 터키어 규칙에 맞게 대소문자를 커스터마이징한 유니코드 | 0000-FFFF 범위의 모든 유니코드 코드포인트 |
utf8_vi_cs | vi_VN - 베트남어, 일반적인 유니코드 대소문자 규칙과 동일 | 0000-FFFF 범위의 모든 유니코드 코드포인트 |
위에서 iso88591_bin, iso88591_en_cs, iso88591_en_ci, utf8_bin, euckr_bin, utf8_en_cs, utf8_en_ci, utf8_tr_cs, utf8_ko_cs와 같은 9 개의 콜레이션은 CUBRID에 기본적으로 내장되어 있다.
로캘 저장 위치¶
CUBRID는 로캘 설정을 위해 여러 디렉터리와 파일들을 사용한다.
- $CUBRID/conf/cubrid_locales.txt 파일: 사용할 로캘 리스트를 포함하는 초기 설정 파일
- $CUBRID/conf/cubrid_locales.all.txt 파일: cubrid_locales.txt 와 같은 구조를 갖는 초기 설정 파일의 템플릿. 사용자가 직접 정의하지 않아도 되는 CUBRID가 현재 지원하는 CUBRID 로캘 버전의 전체 리스트를 포함한다.
- $CUBRID/locales/data 디렉터리: 로캘 데이터를 생성하는데 필요한 파일들을 포함한다.
- $CUBRID/locales/loclib 디렉터리: 로캘 데이터를 포함하는 공유 라이브러리 생성을 위한 C 언어로 작성된 locale_lib_common.h 헤더 파일과 빌드를 위한 makefile을 포함한다.
- $CUBRID/locales/data/ducet.txt 파일: 코드포인트, 축약과 확장 등과 같은 기본적인 범용 콜레이션 정보와 이들의 가중치 값을 표현하는 파일로, 이 정보들은 유니코드 콘소시엄에 의해 제정된 표준을 따른다. 자세한 사항은 http://unicode.org/reports/tr10/#Default_Unicode_Collation_Element_Table 을 참고한다.
- $CUBRID/locales/data/unicodedata.txt 파일: 대소문자 구별, 분해, 정규화 등 각각의 유니코드 코드 포인트를 포함하는 파일로, CUBRID는 대소문자 구분 규칙을 결정하기 위해 이 파일을 사용한다. 더 많은 정보는 http://www.ksu.ru/eng/departments/ktk/test/perl/lib/unicode/UCDFF301.html 을 참고한다.
- $CUBRID/locales/data/ldml 디렉터리: cubrid_<locale_name>.xml 형식의 이름을 지니는 XML 파일들을 포함한다. 각각의 XML 파일은 해당 언어에 대한 로캘 정보를 표현한다.
- $CUBRID/locales/data/codepages 디렉터리: 한 바이트 코드 페이지들을 위한 코드 페이지 콘솔 변환용 파일들(8859-1.txt, 8859-15.txt, 8859-9.txt)과 멀티 바이트 코드 페이지를 위한 코드 페이지 콘솔 변환용 파일들(CP1258.txt, CP923.txt, CP936.txt, CP949.txt)을 포함한다.
- $CUBRID/bin/make_locale.sh 파일 또는 %CUBRID%\bin\make_locale.bat 파일(Windows): 로캘 데이터를 표현하는 공유 라이브러리를 생성하기 위해 사용되는 스크립트 파일이다.
- $CUBRID/lib 디렉터리: 로캘 데이터를 표현하는 공유 라이브러리 파일이 저장된다.
로캘 설정¶
1단계: 로캘 선택¶
사용하려는 로캘을 $CUBRID/conf/cubrid_locales.txt 에 지정한다. 모두 선택하거나 부분만 선택할 수 있다.
CUBRID가 현재 지원하는 로캘은 en_US, de_DE, es_ES, fr_FR, it_IT, ja_JP, km_KH, ko_KR, tr_TR, vi_VN, zh_CN이며, 이 목록은 $CUBRID/conf/cubrid_locales.all.txt 에 작성되어 있다.
각 로캘 이름 및 언어, 사용 국가는 다음 표와 같다.
로캘 이름 | 언어 - 사용 국가 |
---|---|
en_US | 영어 - 미국 |
de_DE | 독일어 - 독일 |
es_ES | 스페인어 - 스페인 |
fr_FR | 프랑스어 - 프랑스 |
it_IT | 이태리어 - 이탈리아 |
ja_JP | 일본어 - 일본 |
km_KH | 크메르어 - 캄보디아 |
ko_KR | 한국어 - 대한민국 |
tr_TR | 터키어 - 터키 |
vi_VN | 베트남어 - 베트남 |
zh_CN | 중국어 - 중국 |
Note
지원하는 로캘들을 위한 LDML 파일들은 cubrid_<locale_name>.xml 파일로 명명되며, $CUBRID/locales/data/ldml 폴더에 저장된다. 지원하려는 로캘에 해당하는 LDML 파일이 $CUBRID/locales/data/ldml 디렉터리에 존재해야 한다. cubrid_locales.txt 에 로캘이 지정되지 않거나 cubrid_<locale_name>.xml 파일이 존재하지 않으면 해당 로캘을 사용할 수 없다.
로캘 라이브러리들은 $CUBRID/conf/cubrid_locales.txt 설정 파일에 의해 생성되는데, 이 파일은 원하는 로캘들의 언어 코드들을 포함하고 있다. 사용자가 정의하는 모든 로캘들은 UTF-8 문자셋으로만 생성된다. 또한 이 파일을 통해서 각 로캘 LDML 파일에 대한 파일 경로와 라이브러리들을 선택적으로 설정할 수 있다.
<lang_name> <LDML file> <lib file>
ko_KR /home/CUBRID/locales/data/ldml/cubrid_ko_KR.xml /home/CUBRID/lib/libcubrid_ko_KR.so
기본적으로 LDML 파일은 $CUBRID/locales/data/ldml 디렉터리에, 로캘 라이브러리들은 $CUBRID/lib 디렉터리에 존재한다. 이와 같이 LDML 파일과 로캘 라이브러리가 기본 위치에 존재한다면 <lang_name>만 작성해도 된다. LDML을 위한 파일 이름 형식은 cubrid_<lang_name>.ldml 이다. 라이브러리에 대한 파일 이름 형식은 Linux에서는 libcubrid_<lang_name>.so, Windows에서는 libcubrid_<lang_name>.dll 이다.
2단계: 로캘 컴파일하기¶
1단계에서 설명한 요구사항들이 충족되었다면 로캘 데이터를 컴파일할 수 있다.
CUBRID에 내장된 로캘을 사용한다면 사용자 로캘 라이브러리를 컴파일하지 않고 사용할 수 있으므로 2단계를 생략할 수 있으나, 내장된 로캘과 라이브러리 로캘에는 차이가 있다. 이와 관련하여 내장된 로캘과 라이브러리 로캘 을 참고한다.
로캘 데이터를 컴파일하려면 make_locale 스크립트(파일의 확장자는 Linux에선 .sh, Windows에선 .bat)를 사용한다. 이 스크립트는 $CUBRID/bin 디렉터리에 위치하며, 이 경로가 $PATH 환경 변수에 포함되어야 한다. 여기서 $CUBRID, $PATH 는 Linux의 환경 변수이며, Windows에서는 %CUBRID%, %PATH% 이다.
사용법은 make_locale.sh -h (Windows는 make_locale /h 이며, Visual C++ 2005, 2008 또는 2010 중 하나가 설치되어 있어야 한다.) 명령을 실행하면 출력되며, 사용 구문은 다음과 같다.
make_locale.sh [options] [locale]
options ::= [-t 32 | 64 ] [-m debug | release]
locale ::= [de_DE | es_ES | fr_FR | it_IT | ja_JP | km_KH | ko_KR | tr_TR | vi_VN | zh_CN]
- options
- -t : 32비트 또는 64비트 중 하나를 선택한다(기본값: 32).
- -m : release 또는 debug 중 하나를 선택한다. 일반적인 사용을 위해서는 release를 선택한다(기본값 : release). debug 모드는 로캘 라이브러리를 직접 작성하려는 개발자를 위해 제공한다.
- locale : 빌드할 라이브러리의 로캘 이름. locale 이 주어지지 않으면, 설정한 모든 로캘의 데이터를 포함하도록 빌드된다. 이 경우 $CUBRID/lib 디렉터리에 libcubrid_all_locales.so (Windows의 경우 .dll)라는 이름으로 라이브러리 파일이 저장된다.
여러 로캘에 대해서 사용자 정의 로캘 공유 라이브러리를 만들려면 다음 두 가지 방법 중 하나를 사용할 수 있다.
모든 로캘을 포함하는 하나의 라이브러리 생성: 다음과 같이 옵션을 지정하지 않고 실행한다.
make_locale.sh # Build and pack all locales (32/release)
하나의 로캘만을 포함하는 라이브러리를 여러 개 반복하여 생성: 다음과 같이 하나의 언어를 지정한다.
make_locale.sh -t 64 -m release ko_KR
이와 같은 두 가지 방법 중에서 첫 번째 방법을 사용하는 것을 권장한다. 공유 라이브러리를 생성하면 로캘들 간에 공유될 수 있는 데이터들이 중복되지 않기 때문에 메모리 사용량을 줄일 수 있다. 첫 번째 방식으로 지원하는 모든 로캘을 포함하도록 생성하면 약 15MB 정도 크기의 라이브러리가 생성되며, 두 번째 방식으로 생성할 경우에는 언어에 따라서 1MB에서 5MB 이상의 크기의 라이브러리가 생성된다. 또한 첫 번째 방식에서는 두 번째 방식을 사용했을 때에 서버 재시작 시점 등에 발생되는 런타임 오버헤드가 없기 때문에 런타임에도 유리하다.
Warning
제약 사항 및 규칙
- 일단 로캘 라이브러리가 생성된 후에는 $CUBRID/conf/cubrid_locales.txt 파일을 변경하면 안 된다. 다시 말해서, 이 파일에서 명시된 언어들의 순서를 포함하여 어떤 내용도 변경해서는 안 된다. 로캘이 컴파일되고 나면, 일반 콜레이션(generic collation)은 기본 로캘로 cubrid_locales.txt에 존재하는 첫번째 로캘을 사용한다. 따라서 순서를 바꾸면 해당 콜레이션(utf8_gen_*)에 대한 대소문자 변환 결과가 달라질 수 있다.
- $CUBRID/locales/data/*.txt 파일들은 변경되어서는 안 된다.
Note
make_locale.sh(.bat) 스크립트 수행 절차
make_locale.sh(.bat) 스크립트는 다음과 같은 작업을 수행한다.
- $CUBRID/locales/data/ducet.txt, $CUBRID/locales/data/unicodedata.txt, $CUBRID/locales/data/codepages/*.txt 와 같이 이미 설치된 공통 파일과 해당 언어의 .ldml 파일을 읽는다.
- 원본(raw) 데이터를 처리한 후 $CUBRID/locales/loclib/locale.c 임시 파일에 로캘 데이터를 포함하는 C 상수 값과 배열을 작성한다.
- .so (.dll) 파일을 빌드하기 위해 임시 파일인 locale.c 파일이 플랫폼 컴파일러에 전달된다. 이 단계는 장비가 C/C++ 컴파일러 및 링커를 가지고 있다고 가정한다. 현재 Windows 버전에서는 MS Visual Studio가, Linux 버전에서는 gcc 컴파일러가 사용된다.
- 임시 파일이 삭제된다.
3단계: 특정 로캘을 사용하기 위해 CUBRID 설정하기¶
여러 로캘을 정의할 수 있지만, CUBRID_CHARSET 환경 변수를 통해 오직 하나의 로캘을 기본 로캘로 지정할 수 있다. 언어에 따른 기본 캘린더(요일, 월, 오전/오후 표기 형식) 설정은 intl_date_lang 시스템 파라미터로 설정할 수 있다.
- CUBRID_CHARSET 환경 변수의 값은 <locale_name>[.utf8 | .iso88591]과 같이 설정한다. (예: tr_TR.utf8, en_US.iso88591, ko_KR.utf8)
- intl_date_lang 시스템 파라미터의 값은 <locale_name>과 같이 설정한다. <locale_name>으로 사용할 수 있는 값은 1단계: 로캘 선택 을 참고한다.
CUBRID_CHARSET 환경 변수는 제품 설치 초기에 en_US(문자셋은 ISO-8859-1)로 설정되어 있다.
Note
월, 요일, 오전/오후 표기 및 숫자 형식 설정
날짜/시간을 입출력하는 함수에서 각 로캘 이름에 따라 입출력하는 월, 요일, 오전/오후 표기 방법을 intl_date_lang 시스템 파라미터로 설정할 수 있다. 또한 문자열을 숫자로 또는 숫자를 문자열로 변환하는 함수에서 각 로캘에 따라 입출력하는 숫자의 문자열 형식은 intl_number_lang 시스템 파라미터로 설정할 수 있다.
내장된 로캘과 라이브러리 로캘¶
CUBRID에 내장된 로캘에 대해서는 사용자 로캘 라이브러리를 컴파일하지 않고 사용할 수 있으므로 2단계를 생략할 수 있으나, 내장된 로캘과 라이브러리 로캘에는 다음과 같은 차이가 있다.
- 내장된(built-in) 로캘(과 콜레이션)은 유니코드 데이터를 인식하지 못한다. 예를 들어, 내장된 로캘은 (Á, á) 간 대소문자 변환이 불가능하다. 반면 LDML 로캘(컴파일된 로캘)은 유니코드 코드포인트에 대한 데이터를 65535개까지 지원한다.
- 내장된 콜레이션은 ASCII 범위만 다루거나, utf8_tr_cs의 경우 ASCII와 터키어(turkish) 알파벳 글자만 다룬다. 따라서 내장된 UTF-8 로캘은 유니코드와 호환되지 않는 반면, LDML 로캘(컴파일된 로캘)은 유니코드와 호환된다.
CUBRID_CHARSET 환경 변수로 설정할 수 있는 내장 로캘은 다음과 같다.
- en_US.iso88591
- en_US.utf8
- ko_KR.utf8
- ko_KR.euckr
- ko_KR.iso88591: 월, 요일 표시 방법은 로마자 표기를 따른다(romanized).
- tr_TR.utf8
- tr_TR.iso88591: 월, 요일 표시 방법은 로마자 표기를 따른다(romanized).
만약 CUBRID_CHARSET 설정 시 문자셋(charset)이 명시되지 않으면 위 순서에서 앞에 있는 로캘의 문자셋으로 결정된다. 예를 들어, CUBRID_CHARSET 이 ko_KR로 설정되면 위의 목록에서 ko_KR 중 가장 먼저 나타나는 로캘인 ko_KR.utf8을 지정한 것과 같다. 위의 내장된 로캘을 제외한 나머지 언어의 로캘은 뒤에 반드시 .utf8 을 붙여야 한다. 예를 들어, 독일어의 경우 CUBRID_CHARSET 을 de_DE.utf8로 지정한다.
ko_KR.iso88591과 tr_TR.iso88591에서 월과 요일을 나타낼 때에는 로마자 표기를 따른다. 예를 들어, 한국어 "일요일"(영어로 Sunday)의 로마자 표기는 "Iryoil"이다. 이것은 ISO-8859-1 문자만 제공하기 위해서 요구되는 사항이다. 이에 관한 자세한 설명은 ISO-8859-1 문자셋에서 한국어와 터키어의 월, 요일 를 참고하면 된다.
ISO-8859-1 문자셋에서 한국어와 터키어의 월, 요일¶
문자셋이 UTF-8인 한국어나 터키어 또는 문자셋이 EUC-KR인 한국어에서 월, 요일, 오전/오후 표시는 각 국가에 맞게 인코딩된다. 그러나, ISO-8859-1 문자셋에서 한국어와 터키어의 월, 요일, 오전/오후 표시를 원래의 인코딩으로 사용하면 복잡한 표현식이 사용되는 경우 서버 프로세스에서 예기치 않은 행동이 발생할 수 있기 때문에, 로마자 표기(romanized)로 출력한다. CUBRID의 기본 문자셋은 ISO-8859-1이며, 한국어와 터키어의 경우 이 문자셋을 사용할 수 있다. 한국어와 터키어에서 각 요일, 월, 오전/오후는 로마자로 다음과 같이 출력한다.
요일
긴 / 짧은 형식 | 한국어 긴 / 짧은 형식 | 터키어 긴 / 짧은 형식 |
---|---|---|
Sunday / Sun | Iryoil / Il | Pazar / Pz |
Monday / Mon | Woryoil / Wol | Pazartesi / Pt |
Tuesday / Tue | Hwayoil / Hwa | Sali / Sa |
Wednesday / Wed | Suyoil / Su | Carsamba / Ca |
Thursday / Thu | Mogyoil / Mok | Persembe / Pe |
Friday / Fri | Geumyoil / Geum | Cuma / Cu |
Saturday / Sat | Toyoil / To | Cumartesi / Ct |
월
긴 / 짧은 형식 | 한국어 | 터키어 긴 / 짧은 형식 |
---|---|---|
January / Jan | 1wol | Ocak / Ock |
February / Feb | 2wol | Subat / Sbt |
March / Mar | 3wol | Mart / Mrt |
April / Apr | 4wol | Nisan / Nsn |
May / May | 5wol | Mayis / Mys |
June / Jun | 6wol | Haziran / Hzr |
July / Jul | 7wol | Temmuz / Tmz |
August / Aug | 8wol | Agustos / Ags |
September / Sep | 9wol | Eylul / Eyl |
October / Oct | 10wol | Ekim / Ekm |
November / Nov | 11wol | Kasim / Ksm |
December / Dec | 12wol | Aralik / Arl |
오전/오후
오전/오후 | 한국어 | 터키어 |
---|---|---|
AM | ojeon | AM |
PM | ohu | PM |
4단계: 선택한 로캘 설정으로 데이터베이스 생성하기¶
CUBRID_CHARSET 환경 변수를 설정하면 새로운 데이터베이스를 생성할 수 있다. cubrid createdb <db_name>을 실행하면, 해당 언어와 문자셋을 사용하는 데이터베이스가 생성된다. 일단 데이터베이스가 생성되면 해당 데이터베이스에 부여된 로캘 설정은 바꿀 수 없다. 문자셋과 로캘 이름은 db_root 라는 시스템 카탈로그 테이블에 저장되며, 생성 시점의 설정과 다른 설정을 사용하여 데이터베이스를 구동할 수 없다.
5단계(선택 사항): 로캘 파일의 수동 검증¶
로캘 라이브러리의 내용들을 dumplocale 유틸리티를 이용해서 사람이 읽을 수 있는 형태로 출력할 수 있다. 사용법은 cubrid dumplocale -h 로 출력할 수 있다.
cubrid dumplocale [options] [language-string]
options ::= -i|--input-file <shared_lib>
-d|--calendar
-n|--numeric
{-a |--alphabet=}{l|lower|u|upper|both}
-c|--codepoint-order
-w|--weight-order
{-s|--start-value} <starting_codepoint>
{-e|--end-value} <ending_codepoint>
-k
-z
language-string ::= de_DE | es_ES | fr_FR | it_IT | ja_JP | km_KH | ko_KR | tr_TR | vi_VN | zh_CN
- dumplocale: 로캘 라이브러리에 설정된 내용을 텍스트로 출력하는 명령이다.
- language-string: de_DE, es_ES, fr_FR, it_IT, ja_JP, km_KH, ko_KR, tr_TR, vi_VN, zh_CN 중 하나의 값. 로캘 공유 라이브러리를 덤프할 로캘 언어를 지정한다. language-string 이 생략되면 cubrid_locales.txt 파일에 명시된 모든 언어가 주어진다.
다음은 cubrid dumplocale 에 대한 [options]이다.
-
-i
,
--input-file
=FILE
¶ 로캘 공유 라이브러리 파일 이름을 지정하며, 경로를 포함한다.
-
-d
,
--calendar
¶
캘린더와 날짜/시간 정보를 추가로 덤프한다.
-
-n
,
--numeric
¶
숫자 정보를 덤프한다.
-
-a
,
--alphabet
=l | lower | u | upper | both
¶ 알파벳과 대소문자 구분 정보를 덤프한다.
-
--identifier-alphabet
=l | lower | u | upper
¶ 식별자에 대한 알파벳과 대소문자 구분 정보를 추가로 덤프한다.
-
-c
,
--codepoint-order
¶
코드포인트 값을 기반으로 정렬한 콜레이션 정보를 추가로 덤프한다. 출력되는 정보는 cp, char, weight, next-cp, char, weight이다.
-
-w
,
--weight-order
¶
가중치 값을 기반으로 정렬한 콜레이션 정보를 추가로 덤프한다. 출력되는 정보는 weight, cp, char이다.
-
-s
,
--start-value
=CODEPOINT
¶ 덤프 범위의 시작을 지정한다. -a , --identifier-alphabet , -c, -w 옵션들에 대한 시작 코드포인트이며, 기본값은 0이다.
-
-e
,
--end-value
=CODEPOINT
¶ 덤프 범위의 끝을 지정한다. -a, --identifier-alphabet, -c, -w 옵션들에 대한 끝 코드포인트이며, 기본값은 로캘 공유 라이브러리에서 읽은 최대값이다.
-
-k
,
--console-conversion
¶
콘솔 변환 데이터를 추가로 덤프한다.
-
-z
,
--normalization
¶
정규화 데이터를 추가로 덤프한다.
다음은 캘린더 정보, 숫자 표기 정보, 알파벳 및 대소문자 정보, 식별자에 대한 알파벳 및 대소문자 정보, 코드포인트 순서에 기반한 콜레이션의 정렬, 가중치에 기반한 콜레이션의 정렬, 데이터를 정규화하여 ko_KR 로캘의 내용을 ko_KR_dump.txt라는 파일에 덤프하는 예이다.
% cubrid dumplocale -d -n -a both -c -w -z ko_KR > ko_KR_dump.txt
여러 개의 옵션을 설정하면 출력되는 내용이 매우 많을 수 있으므로, 파일로 리다이렉션하여 저장할 것을 권장한다.
6단계: CUBRID 관련 프로세스 시작¶
모든 CUBRID 관련 프로세스는 같은 환경 설정을 통해 구동되어야 한다. CUBRID 서버, 브로커, CAS, CSQL 등은 CUBRID_CHARSET 환경 변수의 설정값이 모두 같아야 하며, 같은 버전의 로캘 바이너리 파일을 사용해야 한다. CUBRID HA, CUBRID SHARD 구성 시에도 마찬가지이다. 예를 들어, CUBRID HA 구성에서 마스터 서버, 슬레이브 서버와 레플리카 서버 등은 환경 설정이 모두 같아야 한다.
서버 프로세스와 CAS 프로세스에 의해 사용되는 로캘의 호환성 여부를 시스템이 자동으로 검사하지 않기 때문에, 두 프로세스 간에 LDML 파일들이 똑같다는 것을 보장해야 한다.
로캘 라이브러리 로딩은 CUBRID 구동의 첫 단계로서, 구동 시에 데이터베이스 구조를 초기화하기 위해 로캘 정보를 요구하는 서버, CAS, CSQL, createdb, copydb, unloaddb, loaddb 프로세스 등은 구동 시점에 로캘 라이브러리를 로딩한다.
로캘 라이브러리 로딩 절차는 다음과 같다.
- 라이브러리 경로가 제공되지 않으면 $CUBRID/lib/libcubrid_<lang_name>.so 파일의 로딩을 시도한다. 이 파일이 발견되지 않으면 하나의 파일 $CUBRID/lib/libcubrid_all_locales.so 에서 모든 로캘이 발견된다고 간주한다.
- 로캘 라이브러리가 발견되지 않거나 라이브러리를 로딩하는 동안 오류가 발생하면 CUBRID 프로세스 구동이 종료된다.
- 데이터베이스와 로캘 라이브러리 간 콜레이션 정보가 다르면 CUBRID 프로세스가 구동되지 않는다. 기존 데이터베이스에 로캘 라이브러리의 변경된 콜레이션을 포함하려면, 먼저 cubrid synccolldb 명령을 수행하여 데이터베이스 콜레이션을 로캘 라이브러리에 맞게 동기화한다. 다음으로, 스키마와 데이터를 원하는 콜레이션에 맞게 기존 데이터베이스에 업데이트해야 한다. 자세한 내용은 데이터베이스 콜레이션을 시스템 콜레이션에 동기화 를 참고한다.
데이터베이스 콜레이션을 시스템 콜레이션에 동기화¶
CUBRID가 정상적으로 동작하기 위해서는 시스템 콜레이션과 데이터베이스 콜레이션이 같아야 한다. 시스템 로캘은 내장된 로캘과 cubrid_locales.txt 파일을 통해(로캘 설정 참고) 생성한 라이브러리 로캘을 포함한 로캘을 의미하며, 시스템 로캘은 시스템 콜레이션 정보를 포함한다. 데이터베이스 콜레이션 정보는 _db_collation 시스템 카탈로그 테이블에 저장된다.
cubrid synccolldb 유틸리티는 데이터베이스 콜레이션이 시스템 콜레이션과 일치하는지 확인하고, 다를 경우 데이터베이스 콜레이션을 시스템 콜레이션에 동기화하는 유틸리티이다. 하지만, 이 유틸리티는 데이터베이스 서버에 저장된 데이터 자체를 변환하지 않음을 인지해야 한다.
이 유틸리티는 시스템 로캘이 변경된 이후 기존의 데이터베이스 콜레이션 정보를 변경해야 할 때 사용할 수 있다. 단, 사용자가 직접 수동으로 진행해야 하는 작업들이 있다.
동기화 이전에 다음과 같은 작업을 수행한다. cubrid synccolldb -c 명령을 수행하여 생성되는 cubrid_synccolldb_<database_name>.sql 파일을 CSQL을 통해 실행하면 된다.
- ALTER TABLE MODIFY 문을 사용하여 콜레이션을 수정한다.
- 콜레이션을 포함하는 뷰, 인덱스, 트리거, 분할(partition) 등을 모두 제거한다.
cubrid synccolldb 를 가지고 동기화를 수행한다. 그리고 아래 작업을 수행한다.
- 뷰, 인덱스, 트리거, 분할 등을 재생성한다.
- 새로운 콜레이션에 맞게 응용 프로그램의 질의문들을 업데이트한다.
이 유틸리티는 데이터베이스를 정지한 상태에서 수행해야 한다.
synccolldb 구문은 다음과 같다.
cubrid synccolldb [options] database_name
- cubrid: CUBRID 서비스 및 데이터베이스 관리를 위한 통합 유틸리티이다.
- synccolldb: 데이터베이스 콜레이션을 시스템 콜레이션(로캘 라이브러리의 내용과 $CUBRID/conf/cubrid_locales.txt 파일을 따름)으로 동기화하는 명령이다.
- database_name: 콜레이션 정보가 로캘 라이브러리의 콜레이션에 맞게 동기화될 데이터베이스의 이름이다.
[options]를 생략하면 시스템과 데이터베이스 간 콜레이션 차이를 출력하고, 동기화 이전에 삭제되어야 할 객체 질의문을 포함하는 cubrid_synccolldb_<database_name>.sql 파일을 생성한다.
다음은 cubrid synccolldb 에서 사용하는 [options]이다.
-
-c
,
--check-only
¶
데이터베이스의 콜레이션과 시스템의 콜레이션을 확인하여 불일치하는 콜레이션 정보를 출력한다.
-
-f
,
--force-only
¶
데이터베이스에 있는 콜레이션 정보를 시스템에서 설정한 콜레이션과 동일하게 업데이트할 때 업데이트 여부를 질문하지 않는다.
다음의 예는 시스템 콜레이션과 데이터베이스의 콜레이션이 서로 다를 때 어떻게 동작하는지를 보여준다.
먼저 ko_KR 로캘에 대한 로캘 라이브러리를 생성한다.
$ echo ko_KR > $CUBRID/conf/cubrid_locales.txt
$ make_locale.sh -t 64
다음으로 데이터베이스를 생성한다.
$ cubrid createdb xdb --db-volume-size=20m --log-volume-size=20m
스키마를 생성한다. 이때, 각 테이블에 원하는 콜레이션을 지정한다.
$ csql -S -u dba xdb -i in.sql
CREATE TABLE dept (depname STRING PRIMARY KEY) COLLATE utf8_ko_cs_uca;
CREATE TABLE emp (eid INT PRIMARY KEY, depname STRING, address STRING) COLLATE utf8_ko_cs_uca;
ALTER TABLE emp ADD CONSTRAINT FOREIGN KEY (depname) REFERENCES dept(depname);
시스템의 로캘 설정을 변경한다. cubrid_locales.txt에 아무런 값도 설정하지 않으면 데이터베이스에는 내장된 로캘만 존재하는 것으로 간주한다.
$ echo "" > $CUBRID/conf/cubrid_locales.txt
cubrid synccolldb -c 명령을 수행하여 시스템과 데이터베이스 간 콜레이션 차이를 확인한다.
$ cubrid synccolldb -c xdb
----------------------------------------
----------------------------------------
Collation 'utf8_ko_cs_uca' (Id: 133) not found in database or changed in new system configuration.
----------------------------------------
----------------------------------------
Collation 'utf8_gen_ci' (Id: 44) not found in database or changed in new system configuration.
----------------------------------------
----------------------------------------
Collation 'utf8_gen_ai_ci' (Id: 37) not found in database or changed in new system configuration.
----------------------------------------
----------------------------------------
Collation 'utf8_gen' (Id: 32) not found in database or changed in new system configuration.
----------------------------------------
----------------------------------------
There are 4 collations in database which are not configured or are changed compared to system collations.
Synchronization of system collation into database is required.
Run 'cubrid synccolldb -f xdb'
인덱스가 존재한다면 먼저 인덱스를 제거한 후 각 테이블의 콜레이션을 변환하고, 이후 인덱스 생성을 직접 수행해야 한다. 인덱스를 제거하고 테이블의 콜레이션을 변환하는 과정은 synccolldb에서 생성된 cubrid_synccolldb_xdb.sql 파일로 수행할 수 있다. 다음 예에서는 외래 키가 재생성해야 될 인덱스에 해당한다.
$ cat cubrid_synccolldb_xdb.sql
ALTER TABLE [dept] COLLATE utf8_bin;
ALTER TABLE [emp] COLLATE utf8_bin;
ALTER TABLE [emp] DROP FOREIGN KEY [fk_emp_depname];
ALTER TABLE [dept] MODIFY [depname] VARCHAR(1073741823) COLLATE utf8_bin;
ALTER TABLE [emp] MODIFY [address] VARCHAR(1073741823) COLLATE utf8_bin;
ALTER TABLE [emp] MODIFY [depname] VARCHAR(1073741823) COLLATE utf8_bin;
$ csql -S -u dba -i cubrid_synccolldb_xdb.sql xdb
시스템 콜레이션을 데이터베이스에 동기화하기 전에 위의 cubrid_synccolldb_xdb.sql 스크립트 파일을 실행하여 예전의 콜레이션들을 삭제해야 한다.
cubrid synccolldb 명령을 수행한다. 옵션을 생략하면 해당 명령을 수행할 것인지를 확인하는 메시지가 나타나며, -f 옵션을 주면 확인 과정 없이 데이터베이스와 시스템 간 콜레이션 동기화를 수행한다.
$ cubrid synccolldb xdb
Updating system collations may cause corruption of database. Continue (y/n) ?
Contents of '_db_collation' system table was updated with new system collations.
DROP된 외래 키를 다시 생성한다.
$ csql -S -u dba xdb
ALTER TABLE emp ADD CONSTRAINT FOREIGN KEY fk_emp_depname(depname) references dept(depname);
Note
CUBRID에서 콜레이션은 CUBRID 서버에 의해 숫자 ID로 인식되며, ID의 범위는 0부터 255까지이다. LDML 파일은 공유 라이브러리로 컴파일되는데, 콜레이션 ID와 콜레이션(이름, 속성)의 매핑 정보를 제공한다.
- 시스템 콜레이션은 CUBRID 서버와 CAS 모듈에 의해 로캘 라이브러리로부터 로딩되는 콜레이션이다.
- 데이터베이스 콜레이션은 _db_collation 시스템 테이블에 저장되는 콜레이션이다.
콜레이션 설정¶
콜레이션(collation)이란 문자열 비교 및 정렬 규칙의 집합이다. 콜레이션의 전형적인 예는 알파벳 순서의 정렬(alphabetization)이다.
테이블 생성 시에 칼럼의 문자셋과 콜레이션이 명시되지 않으면, 칼럼은 테이블의 문자셋과 콜레이션을 따른다. 문자셋과 콜레이션 설정은 기본적으로 클라이언트의 설정을 따른다. 표현식 결과가 문자열 데이터이면 표현식의 피연산자를 감안한 콜레이션 추론 과정을 통하여 문자셋과 콜레이션을 결정한다.
Note
CUBRID는 유럽과 아시아 언어를 포함한 여러 가지 언어들의 콜레이션을 지원한다. 이러한 언어들은 다른 알파벳들을 사용할 뿐만 아니라, 특정 언어들은 일부 문자셋에 대해 확장(expansion) 또는 축약(contraction) 정의를 필요로 한다. 이러한 사항들의 대부분은 The Unicode Consortium에 의해 유니코드 표준(2012년 현재 버전 6.1.0)으로 제정되어 있으며, 대부분의 언어가 요구하는 모든 문자 정보는 DUCET 파일(http://www.unicode.org/Public/UCA/latest/allkeys.txt)에 저장되어 있다.
이러한 DUCET에 표현된 대부분의 코드포인트는 0~FFFF 내의 범위에 포함되지만, 이 범위를 넘는 코드포인트도 존재한다. 하지만 CUBRID는 0~FFFF 내의 코드포인트만 사용하고, 나머지들은 무시한다(하위 부분만 사용하도록 설정할 수도 있다).
DUCET에 있는 각각의 코드포인트는 하나 또는 그 이상의 콜레이션 원소(element)를 가지고 있다. 하나의 콜레이션 원소는 네 개 숫자 값의 집합으로, 문자 비교의 네 가지 수준(level)을 가중치(weight)로 표현한다. 각각의 가중치 값은 0~FFFF의 범위를 가진다.
DUCET에서 한 문자는 하나의 라인으로 다음과 같이 표현된다.
< codepoint_or_multiple_codepoints > ; [.W1.W2.W3.W4][....].... # < readable text explanation of the symbol/character >
한국어 문자 기역은 다음과 같이 표현된다.
1100 ; [.313B.0020.0002.1100] # HANGUL CHOSEONG KIYEOK
위의 예에서 1100은 코드포인트, [.313B.0020.0002.1100]은 하나의 콜레이션 원소이며, 313B는 Level 1, 0020은 Level 2, 0002는 Level 3, 1100은 Level 4의 가중치이다.
언어의 기능적 속성으로 정의되는 확장 지원은 하나의 결합 문자를 그것을 만드는 한 쌍의 문자들로 해석하도록 지원한다는 것을 의미한다. 예를 들어, 한 문자 'æ' 을 두 개의 문자 'ae'와 같은 문자로 해석한다. DUCET에서 확장은 하나의 코드포인트나 축약에 대해 하나 이상의 콜레이션 원소들로 표현된다. 확장이 있는 콜레이션을 다루는 것은 두 개의 문자열을 비교할 때 콜레이션의 세기/수준까지 여러 번 비교하는 비용을 감수해야 하기 때문에, CUBRID는 기본적으로는 확장을 지원하지 않도록 설정되어 있다.
칼럼의 문자셋과 콜레이션¶
칼럼의 문자셋과 콜레이션은 문자열 데이터 타입(VARCHAR, CHAR)과 ENUM 타입에 적용된다. 기본적으로 모든 문자열 데이터 타입은 데이터베이스의 기본 문자셋과 콜레이션을 따르는데, 이를 변경하여 지정할 수 있는 방법을 제공한다.
문자셋¶
문자셋은 문자열 리터럴이나 따옴표 없는 식별자(identifier)로 명시될 수 있으며, 지원하는 문자셋은 다음과 같다.
- ISO-8859-1
- UTF-8 (문자당 최대 4 바이트 길이, 즉 0~0x10FFFF 범위 내의 코드포인트를 지원)
- EUC-KR (이 문자셋은 하위 호환을 위해서 존재할 뿐 사용을 권장하지 않는다.)
Note
CUBRID 9.0 이전 버전까지는 ISO-8859-1 문자셋이 설정되면 EUC-KR 문자들을 사용할 수 있도록 지원했지만, 이후 버전부터는 이를 지원하지 않는다. EUC-KR 문자들은 오직 EUC-KR 문자셋에서만 사용될 수 있다.
문자열 검사¶
기본적으로 모든 입력 데이터는 서버에서 CUBRID_CHARSET 환경 변수로 설정한 문자로 간주한다. 하지만 SET NAMES 문이나 문자셋 소개자(또는 COLLATE 문자열 수정자)가 CUBRID_CHARSET 환경 변수 설정보다 우선한다(테이블의 문자셋과 콜레이션 참고).
서버 문자셋이 UTF-8인데 UTF-8 바이트 순서(byte sequence)에 맞지 않는 데이터와 같이 무효한 데이터에 대해 문자열을 검사하지 않으면 정의되지 않은 동작을 보이거나 심지어 서버가 비정상 종료(crash)될 수 있다. 기본적으로는 문자열을 검사하지 않도록 설정되어 있다. 문자열을 검사하려면 intl_check_input_string 시스템 파라미터의 값을 yes로 설정한다(기본값: no). 하지만 유효한 데이터만 입력된다고 보장할 수 있다면, 문자열 검사는 하지 않는 것이 성능상 더 유리하다. intl_check_input_string 시스템 파라미터의 값이 yes인 경우, UTF-8과 EUC-KR 문자셋에 대해서만 유효한 데이터 인코딩인지 검사한다. ISO-8859-1 문자셋은 한 바이트 인코딩이므로 모든 바이트 값이 유효하기 때문에 검사하지 않는다.
문자셋 변환¶
콜레이션/문자셋 수정자(COLLATE / CHARSET) 또는 콜레이션 추론 과정에 의해서 문자셋 변환이 일어날 수 있는데, 이러한 문자셋 변환은 비가역적(irreversible)이다. 예를 들어, ISO-8859-1 문자셋을 UTF-8 문자셋으로 변환하는 경우, 발음 구별 기호(accent mark)가 있는 문자(e) 같은 일부 문자에서 손실이 발생할 수 있다. ISO-8859-1 문자셋에서 80~A0 바이트 범위의 문자는 UTF-8 문자셋에서 이에 해당하는 문자가 없으므로 '?'로 대체된다.
UTF-8 또는 EUC-KR 문자셋에서 ISO 문자셋으로의 변환은 간단한 데이터 스트림 재해석 과정으로, 대부분의 유니코드 문자는 ISO 문자에 대응되지 못한다. 00~7F 바이트 범위는 ISO와 UTF-8 문자셋에서 같은 문자로 인코딩되기 때문에 ASCII 문자는 문자셋 변환에 영향을 받지 않는다.
한 문자에서 다른 문자로 변환되는 규칙은 다음과 같다.
Source \ Destination | ISO-8859-1 | UTF-8 | EUC-KR |
---|---|---|---|
ISO-8859-1 | 변환 없음 | 바이트 변환. 바이트 크기가 증가되며 문자 길이는 같음 | 허용 안 함 |
UTF-8 | 바이트 재해석. 바이트 크기는 같으며 문자 길이는 증가 | 변환 없음 | 허용 안 함 |
EUC-KR | 바이트 재해석. 바이트 크기는 같으며 문자 길이는 증가 | 허용 안 함 | 변환 없음 |
콜레이션¶
콜레이션은 문자열 리터럴이나 따옴표 없는 식별자로 명시될 수 있다.
다음은 내장된(built-in) 콜레이션에 대한 db_collation 시스템 카탈로그 뷰의 질의 결과이다.
coll_id coll_name charset_name is_builtin has_expansions contractions uca_strength
================================================================================================
0 'iso88591_bin' 'iso88591' 'Yes' 'No' 0 'Not applicable'
1 'utf8_bin' 'utf8' 'Yes' 'No' 0 'Not applicable'
2 'iso88591_en_cs' 'iso88591' 'Yes' 'No' 0 'Not applicable'
3 'iso88591_en_ci' 'iso88591' 'Yes' 'No' 0 'Not applicable'
4 'utf8_en_cs' 'utf8' 'Yes' 'No' 0 'Not applicable'
5 'utf8_en_ci' 'utf8' 'Yes' 'No' 0 'Not applicable'
6 'utf8_tr_cs' 'utf8' 'Yes' 'No' 0 'Not applicable'
7 'utf8_ko_cs' 'utf8' 'Yes' 'No' 0 'Not applicable'
8 'euckr_bin' 'euckr' 'Yes' 'No' 0 'Not applicable'
내장된 콜레이션은 사용자 로캘 라이브러리의 추가 없이 사용 가능하며, 각 콜레이션은 관련 문자셋을 가지고 있기 때문에 문자셋과 콜레이션이 호환되도록 지정해야 한다.
COLLATE 수정자가 CHARSET 수정자 없이 명시되면, 콜레이션의 기본 문자셋이 설정된다. CHARSET 수정자가 COLLATE 수정자 없이 명시되면, 기본 콜레이션이 설정된다.
문자셋들에 대한 기본 콜레이션은 바이너리 콜레이션으로, 문자셋 및 이에 대응되는 바이너리 콜레이션은 다음과 같다.
- ISO-8859-1: iso88591_bin
- UTF-8: utf8_bin
- EUC-KR: euckr_bin
서로 다른 콜레이션(과 문자셋)을 가진 표현식 인자(피연산자)를 가질 때 어떤 콜레이션을 사용할지 결정하는 방법에 대해서는 콜레이션이 서로 다를 때 결정 방식 을 참고한다.
CHARSET과 COLLATE 수정자¶
기본 데이터베이스 콜레이션과 문자셋을 따르지 않고 콜레이션과 문자셋을 변경하여 지정할 수 있는 문자열 타입에 대한 수정자를 제공한다.
- CHARACTER_SET (또는 CHARSET) 수정자는 칼럼의 문자셋을 바꾼다.
- COLLATE 수정자는 칼럼의 콜레이션을 바꾼다.
<data_type> ::= <column_type> [<charset_modifier_clause>] [<collation_modifier_clause>]
<charset_modifier_clause> ::= {CHARACTER_SET | CHARSET} {<char_string_literal> | <identifier> }
<collation_modifier_clause> ::= COLLATE {<char_string_literal> | <identifier> }
다음은 VARCHAR 타입 칼럼의 문자셋을 UTF-8로 설정하는 예이다.
CREATE TABLE t1 (s1 VARCHAR (100) CHARSET utf8);
다음은 칼럼 s1의 이름을 c1으로 바꾸고, 해당 타입을 콜레이션이 utf8_en_cs인 CHAR(10) 으로 바꾸는 예이다. 문자셋은 해당 콜레이션에 대한 기본 문자셋인 UTF-8으로 지정된다.
ALTER TABLE t1 CHANGE s1 c1 CHAR(10) COLLATE utf8_en_cs;
다음은 c1 칼럼의 값을 콜레이션 iso88591_en_ci인 VARCHAR(5) 타입으로 바꿔 출력한다. 정렬 연산 또한 첫번째로 선택된 칼럼의 타입에 대한 콜레이션 iso88591_en_ci을 사용하여 수행된다.
SELECT CAST (c1 as VARCHAR(5) COLLATE 'iso88591_en_ci') FROM t1 ORDER BY 1;
다음은 위와 유사한 질의(같은 정렬)이지만, 출력되는 칼럼 결과가 원래의 값이다.
SELECT c1 FROM t1 ORDER BY CAST (c1 as VARCHAR(5) COLLATE iso88591_en_ci);
콜레이션이 서로 다를 때 결정 방식¶
CREATE TABLE t (s1 STRING COLLATE utf8_en_cs, s2 STRING COLLATE utf8_tr_cs);
-- insert values into both columns
SELECT s1, s2 FROM t WHERE s1 > s2;
위의 예에서 칼럼 s1과 s2 는 다른 콜레이션을 가지고 있고, s1과 s2 를 비교한다는 것은 테이블 t에 있는 레코드끼리 어떤 칼럼의 값이 "더 큰지" 결정할 수 있는 문자열을 비교한다는 것을 의미한다. 콜레이션 utf8_en_cs와 utf8_tr_cs는 서로 비교할 수 없으므로 이 경우에는 에러를 출력할 것이다.
표현식의 타입 결정 방법의 원칙이 콜레이션 결정 방법에도 마찬가지로 적용된다.
- 표현식의 모든 인자들을 고려하여 공통 콜레이션과 문자셋을 결정한다.
- 1.에서 결정된 공통 콜레이션(또는 문자셋)과 다른 인자들을 변환한다.
- 콜레이션을 변경하기 위해서
CAST()
연산자가 사용될 수 있다.
비교 표현식의 결과 콜레이션을 결정하기 위해 "콜레이션 변환도(collation coercibility)"를 사용한다. 이는 자신의 콜레이션이 얼마나 쉽게 상대 인자의 콜레이션으로 변환되기 쉬운가를 표현한 것으로, 표현식의 두 피연산자를 비교할 때 콜레이션 변환도가 크다는 것은 상대 인자의 콜레이션으로 쉽게 변환된다는 것을 의미한다. 즉, 높은 변환도를 지닌 인자는 더 낮은 변환도를 지닌 인자의 콜레이션으로 변환될 수 있다.
표현식의 인자들이 서로 다른 콜레이션을 가지면, 이들에 대한 공통 콜레이션은 각 인자들의 콜레이션과 변환도에 기반하여 결정된다.
- 높은 변환도를 가진 인자는 더 낮은 변환도를 가진 인자의 콜레이션으로 변환된다.
- 인자들의 콜레이션이 서로 다르고 변환도가 같은 경우에는 표현식의 콜레이션을 결정할 수 없고 에러가 리턴된다.
표현식 인자들의 변환도는 다음의 표와 같다.
콜레이션 변환도 | 표현식의 인자(피연산자) |
---|---|
0 | COLLATE 수정자를 지닌 피연산자 |
1 | 칼럼이 바이너리가 아닌(non-binary) 콜레이션을 가진 경우 |
2 | 칼럼이 ISO-8859-1 문자셋을 가진 경우를 제외하고 바이너리 콜레이션을 가진 경우 |
3 | 칼럼이 바이너리 콜레이션과 ISO-8859-1 문자셋(iso88591_bin)을 가진 경우 |
4 | SELECT 값, 표현식이 바이너리가 아닌 콜레이션을 가진 경우 |
5 | SELECT 값, 표현식이 ISO-8859-1 문자셋을 가진 경우를 제외하고 바이너리 콜레이션을 가진 경우 |
6 | SELECT 값, 표현식이 바이너리 콜레이션과 ISO-8859-1 문자셋(iso88591_bin)을 가진 경우 |
7 | 특수 함수들 (USER() , DATABASE() , SCHEMA() , VERSION() ) |
8 | 상수 문자열이 바이너리가 아닌(non-binary) 콜레이션을 가진 경우 |
9 | 상수 문자열이 ISO-8859-1 문자셋을 가진 경우를 제외하고 바이너리 콜레이션을 가진 경우 |
10 | 상수 문자열이 바이너리 콜레이션과 ISO-8859-1 문자셋(iso88591_bin)을 가진 경우 |
11 | 호스트 변수, 사용자 정의 변수 |
콜레이션이 서로 다른 두 개의 인자가 하나의 콜레이션으로 변환되는 경우를 살펴보면 다음과 같다.
원하는 콜레이션을 지정하여 변환
앞의 예제에서 실행에 실패한 SELECT 문은 다음 질의문처럼 한 칼럼에 CAST 연산자로 콜레이션을 지정하여 두 피연산자를 같은 콜레이션을 갖도록 하면 성공적으로 수행된다.
SELECT s1, s2 FROM t WHERE s1 > CAST (s2 AS STRING COLLATE utf8_en_cs);
또는 s2를 바이너리 콜레이션으로 CAST 하면, s1의 콜레이션으로 변환도 5로 "완전히 변환 가능"하다.
SELECT s1, s2 FROM t WHERE s1 > CAST (s2 AS STRING COLLATE utf8_bin);
다음과 같은 질의문에서 두 번째 피연산자 "CAST (s2 AS STRING COLLATE utf8_tr_cs)"는 서브 표현식이고, 서브 표현식은 칼럼(s1)보다 더 높은 변환도를 가지기 때문에, "CAST (s2 AS STRING COLLATE utf8_tr_cs)"는 s1의 콜레이션으로 변환된다.
SELECT s1, s2 FROM t WHERE s1 > CAST (s2 AS STRING COLLATE utf8_tr_cs);
어떤 표현식이든 표현식은 칼럼보다 높은 변환도를 갖는다.
SELECT s1, s2 FROM t WHERE s1 > CONCAT (s2, '');
상수와 칼럼의 콜레이션 변환
다음의 경우 칼럼 s1의 콜레이션을 사용하여 비교가 수행된다.
SELECT s1, s2 FROM t WHERE s1 > 'abc';
칼럼이 바이너리 콜레이션으로 생성되는 경우
CREATE TABLE t2 (s1 STRING COLLATE utf8_en_cs, s2 STRING COLLATE utf8_bin); SELECT s1, s2 FROM t WHERE s1 > s2;
위 경우 s2 칼럼의 변환도는 5(바이너리 콜레이션)로 s1 칼럼의 콜레이션으로 "완전히 변환 가능"하여 utf8_en_cs 콜레이션으로 변환된다.
CREATE TABLE t2 (s1 STRING COLLATE utf8_en_cs, s2 STRING COLLATE iso88591_bin); SELECT s1, s2 FROM t WHERE s1 > s2;
위 경우에도 마찬가지로 콜레이션으로 utf8_en_cs가 사용되는데, s2 칼럼이 ISO 문자셋이므로 UTF-8로 변환하는 오버헤드가 발생한다는 차이가 있다. 실제 문자셋 변환은 ISO를 UTF-8로 변환할 때만 발생한다.
다음 질의문에서 문자셋 변환은 발생하지 않고 s2 칼럼의 UTF-8의 바이트 데이터는 간단하게 ISO-8859-1 문자셋으로 재해석되며, iso88591_en_cs 콜레이션을 사용하여 문자 비교만 수행된다.
CREATE TABLE t2 (s1 STRING COLLATE iso88591_en_cs, s2 STRING COLLATE utf8_bin); SELECT s1, s2 FROM t WHERE s1 > s2;
서브 표현식과 칼럼의 콜레이션 변환
CREATE TABLE t ( s1 STRING COLLATE utf8_en_cs, s2 STRING COLLATE utf8_tr_cs ); SELECT s1, s2 FROM t WHERE s1 > s2 + 'abc';
위 경우 두 번째 피연산자는 표현식이기 때문에 s1의 콜레이션이 사용된다.
다음 예제는 서로 다른 콜레이션을 지닌 s2와 s3에 대해 '+' 연산을 수행하려고 하기 때문에 에러가 발생한다.
CREATE TABLE t ( s1 STRING COLLATE utf8_en_cs, s2 STRING COLLATE utf8_tr_cs, s3 STRING COLLATE utf8_en_ci ); SELECT s1, s2 FROM t WHERE s1 > s2 + s3;
다음 예제에서는 s2와 s3가 같은 콜레이션이므로 '+' 표현식이 utf8_tr_cs이 되고, s1은 칼럼이므로 표현식보다 낮은 변환도를 갖기 때문에 비교 연산은 utf8_en_cs 콜레이션을 사용해서 수행된다.
CREATE TABLE t ( s1 STRING COLLATE utf8_en_cs, s2 STRING COLLATE utf8_tr_cs, s3 STRING COLLATE utf8_tr_cs ); SELECT s1, s2 FROM t WHERE s1 > s2 + s3;
테이블의 문자셋과 콜레이션¶
테이블 생성 구문에 문자셋과 콜레이션을 지정할 수 있다.
CREATE TABLE table_name ( column_list ) [CHARSET charset_name] [COLLATE collation_name]
칼럼의 문자셋과 콜레이션이 생략되면, 테이블의 문자셋과 콜레이션이 사용된다. 테이블의 문자셋과 콜레이션이 생략되면, 시스템의 문자셋과 콜레이션이 사용된다.
다음은 테이블에 콜레이션을 지정하는 예이다.
CREATE TABLE tbl (i1 INTEGER, s STRING) CHARSET utf8 COLLATE utf8_en_cs;
문자열 리터럴의 문자셋과 콜레이션¶
문자열 리터럴(string literal)의 문자셋과 콜레이션은 다음과 같은 우선 순위에 따라 정해진다.
- 문자셋 소개자 또는 문자열의 COLLATE 수정자
- SET NAMES 문으로 명시한 문자셋과 콜레이션
- 시스템 문자셋과 콜레이션(문자셋과 CUBRID_CHARSET 환경 변수에 의해 설정된 기본 콜레이션)
SET NAMES 문¶
SET NAMES 문은 기본 클라이언트 문자셋과 콜레이션 값을 변경하여, 이를 실행한 클라이언트에서 이후에 실행하는 모든 문장은 지정한 문자셋과 콜레이션을 가지게 된다. 구문은 다음과 같다.
SET NAMES [charset_name] [COLLATE collation_name]
- charset_name : 유효한 문자셋 이름은 iso88591, utf8 그리고 euckr이다.
- collation_name : 콜레이션 지정은 생략할 수 있으며, 모든 가능한 콜레이션이 설정될 수 있다. 콜레이션과 문자셋은 호환되어야 하며, 그렇지 않으면 오류가 발생한다. 사용 가능한 콜레이션 이름은 db_collation 카탈로그 뷰를 검색하여 확인할 수 있다. (칼럼의 문자셋과 콜레이션 참고)
다음은 기본 문자셋과 콜레이션을 가진 문자열 상수를 생성한다.
SELECT 'a';
다음은 utf8 문자셋과 utf8_bin 콜레이션을 가진 문자열 상수를 생성한다. 참고로 기본 콜레이션은 해당 문자셋의 바이너리 콜레이션이다.
SET NAMES utf8;
SELECT 'a';
문자셋 소개자¶
상수 문자열 앞에는 문자셋 소개자(introducer)가 올 수 있고, 뒤에는 COLLATE 수정자(modifier)가 올 수 있는데, 문자셋 소개자는 언더바(_)로 시작하는 문자셋 이름으로 상수 문자열 앞에 올 수 있다. 문자열에 대해 문자셋 소개자와 COLLATE 수정자를 지정하는 구문은 다음과 같다.
[charset_introducer]'constant-string' [COLLATE collation_name]
- charset_introducer : 언더바(_)를 앞에 붙인 문자셋 이름으로 생략할 수 있다. _utf8, _iso88591, _euckr 중 하나를 입력할 수 있다.
- constant-string : 상수 문자열 값이다.
- collation_name : 시스템에서 사용 가능한 콜레이션 이름으로 생략할 수 있다.
상수 문자열의 기본 문자셋과 콜레이션은 현재의 데이터베이스 연결을 기준으로 정해지며, 가장 마지막에 수행한 SET NAMES 문 또는 기본값으로 설정된다. 문자셋 소개자 또는 COLLATE 수정자를 생략했을 때는 다음과 같이 동작한다.
- 문자셋 소개자를 지정하고 COLLATE 수정자를 생략하면, 해당 문자셋의 기본 콜레이션(바이너리 콜레이션)이 설정된다.
- 문자셋 소개자를 생략하고 COLLATE 수정자를 지정하면, 문자셋은 콜레이션에 따라 설정된다.
다음은 문자셋 소개자와 COLLATE 수정자를 지정하는 예제이다.
SELECT 'cubrid';
SELECT _utf8'cubrid';
SELECT _utf8'cubrid' COLLATE utf8_en_cs;
다음 예에서는 utf8 문자셋과 utf8_en_cs 콜레이션을 가지는 문자열 상수를 생성한다. SELECT 문의 COLLATE 수정자가 SET NAMES 문에서 지정한 콜레이션을 오버라이드한다.
SET NAMES utf8 COLLATE utf8_en_ci;
SELECT 'a' COLLATE utf8_en_cs;
표현식의 문자셋과 콜레이션¶
표현식 결과의 문자셋과 콜레이션은 표현식의 인자들로부터 추론된다. 콜레이션 추론 과정은 콜레이션 변환도(coercibility)에 기반하며 이에 관한 자세한 내용은 콜레이션이 서로 다를 때 결정 방식을 참고한다.
모든 문자열 매칭 함수(LIKE, REPLACE, INSTR, POSITION, LOCATE, SUBSTRING_INDEX, FIND_IN_SET 등)와 비교 연산자들(<, >, = 등)에서 콜레이션이 고려된다.
시스템 데이터의 문자셋과 콜레이션¶
시스템 문자셋은 CUBRID_CHARSET 환경 변수에서 가져온다. 시스템의 콜레이션은 항상 시스템 문자셋의 바이너리 콜레이션(<charset>_bin)이다. CUBRID는 iso88591, euckr, utf8 3 개의 문자셋을 지원하며, 따라서 기본적으로 3 개의 시스템 콜레이션을 지원한다.
CUBRID_CHARSET의 영향¶
CUBRID_CHARSET의 로캘 부분은 다음에 영향을 끼친다.
- 식별자(identifier)와 대소문자 규칙에서 지원되는 문자(이를 "알파벳"이라고 지칭함)
- 날짜-문자열 변환 함수들에 대한 기본 로캘
- 숫자-문자열 변환 함수들에 대한 기본 로캘
- CSQL에서 콘솔 변환
식별자의 대소문자 구분¶
CUBRID에서 식별자는 대소문자 구분을 하지 않는다. 테이블 칼럼, 사용자 정의 변수, 트리거, 저장 프로시저들의 이름은 소문자로, 사용자 이름 및 그룹 이름은 대문자로 저장된다.
내장된 문자셋인 ISO-8859-1은 255 개의 문자만을 포함하므로 전체 문자들이 EUC-KR 문자셋에서는 ASCII 호환 문자들만이 대소문자 변환의 대상이 된다.
UTF-8 문자셋에 해당하는 로캘은 내장된 로캘(en_US.utf8, tr_TR.utf8, ko_KR.utf8)과 LDML 로캘과 같은 두 종류가 있다.
내장된 로캘은 특정 문자(en_US.utf8과 ko_KR.utf8에서는 ASCII 문자, tr_TR.utf8에서는 ASCII 문자와 터키어의 글리프(glyphs) [1])만 구현한 것이다. 즉, 최대 4 바이트까지 인코딩된 모든 UTF-8 문자는 식별자로 받아들여지기는 하지만, 이 중 대부분의 문자들은 일반적인 유니코드 문자로 처리되어 대소문자 변환이 이뤄지지 않는다는 것을 뜻한다. 예를 들어, 테이블 이름에서 È(유니코드 코드포인트 00C8)는 허용되지만, 그것을 포함하는 식별자는 소문자 "è"로 변환되어 표현되지 않는다.
CREATE TABLE ÈABC;
따라서, 위의 질의 수행 시 테이블 이름은 _db_class 시스템 테이블에 "Èabc"라는 이름으로 저장된다.
LDML 로캘(내장된 로캘은 LDML 로캘에 의해 오버라이드됨)은 지원하는 유니코드 문자셋을 코드포인트 FFFF까지 확장하므로 식별자에 대해 확장된 알파벳의 대소문자 변환이 가능하다. 예를 들어, CUBRID_CHARSET이 es_ES.utf8이고 해당 로캘 라이브러리가 로딩되면, 위의 CREATE TABLE 문은 "èabc"라는 이름을 가진 테이블을 생성한다.
앞서 설명한 바와 같이 대소문자 규칙과 지원되는 문자들로 "알파벳"(LDML 파일에 "alphabet" 태그로 정의됨)이 구성되며, tr_TR과 de_DE와 같은 일부 로캘들은 특별한 대소문자 규칙을 가진다. 터키어에서 lower ('I') = 'ı'(점없는 소문자 i)이고, upper ('i') = 'İ'(점있는 대문자 I)이다. 독일어에서 upper ('ß') = 'SS'(두 개의 대문자 S)이다.
이런 특수한 규칙을 갖는 로캘들은 식별자가 대문자 또는 소문자로 변환 저장되면서 발생할 수 있는 문제를 피하기 위해 시스템 데이터(식별자)를 위한 "알파벳"과 사용자 데이터를 위한 "알파벳" 두 개를 가진다. 즉, 사용자 데이터에 적용되는 "알파벳"은 위에서 설명한 특별한 규칙을 포함하는 반면, 시스템 데이터(식별자)를 위한 "알파벳"은 특별한 규칙을 포함하지 않는다. 예를 들어 터키어에서 그룹 이름 "public"에 대해 사용자 데이터에 적용되는 "알파벳"을 적용하면 "PUBLİC"이 되어 결국 의도했던 "PUBLIC"과는 다른 값이 되는 문제가 발생한다.
또한, 시스템 데이터를 위한 "알파벳"은 서로 다른 로캘을 가진 데이터베이스 간에 호환성 제공을 위해서도 필요하다. 이로 인해 서로 다른 로캘 사이에 데이터베이스의 스키마와 데이터를 언로드-로드하는 것이 가능해진다.
문자열 리터럴의 입출력¶
문자열 리터럴 데이터는 CUBRID에 다양한 방법으로 입력된다.
- C API interface (CCI)
- 언어 의존적인 인터페이스. JDBC, Perl 드라이버 등
- CSQL - 콘솔 또는 파일로부터 입력
드라이버를 통해 문자 데이터를 받을 때, CUBRID는 이 문자들의 문자셋을 인지할 수 없다. 문자열 리터럴(따옴표로 감싼 문자)에 해당하는 모든 텍스트 데이터는 있는 그대로(raw data) 다루어진다. 문자셋 메타 정보는 응용 클라이언트에 의해 제공되어야 한다. 클라이언트는 SET NAMES 문 이나 문자셋 소개자 를 통해 문자셋 정보를 제공할 수 있다.
CSQL을 위한 텍스트 변환¶
CSQL 콘솔 인터페이스에서는 텍스트 변환 동작이 일어날 수 있다. 대부분의 로캘들에는 콘솔에서 ASCII 문자가 아닌 문자를 쉽게 쓸 수 있도록 해주는 문자셋이 별도로 존재한다. 예를 들어 로캘 tr_TR.utf8에 대한 LDML 파일에는 다음 라인이 포함되어 있다.
<consoleconversion type="ISO88599" windows_codepage="28599" linux_charset="iso88599,ISO_8859-9,ISO8859-9,ISO-8859-9" />
사용자가 이와 같이 콘솔의 문자셋을 설정하면(예: Windows에서 chcp 28599, Linux에서 export LANG=tr_TR.iso88599), 모든 입력이 ISO-8859-9 문자셋으로 인코딩된다고 가정하고 모든 데이터를 UTF-8로 변환한다. 또한 결과를 출력할 때는 반대로 UTF-8을 ISO-8859-9로 변환한다. Linux에서는 이러한 변환을 피하기 위해 UTF-8 콘솔(예: export LANG=tr_TR.utf8)을 직접 사용할 것을 권장한다.
LDML 로캘 파일에서 이 XML 태그 설정은 반드시 요구되지는 않으며 선택 사항이다. 예를 들어, 로캘 km_KH.utf8은 관련 코드 페이지가 없다.
다음은 프랑스어 설정 및 프랑스어 문자 입력을 위한 설정 예이다.
프랑스어 설정을 하려면 먼저 CUBRID_CHARSET=fr_FR.utf8을 설정하고, cubrid_locales.txt 파일에 fr_FR을 설정하며, 로캘을 컴파일(로캘 설정 참고)해야 한다.
Linux에서는 다음과 같이 설정한다.
- 콘솔이 UTF-8을 입력받을 수 있도록 설정한다. LANG=fr_FR.utf8 또는 en_US.utf8로 설정한다. 이 설정은 프랑스어 문자 뿐만 아니라 모든 UTF-8 문자를 입력받을 수 있게 한다.
- 또는 콘솔이 ISO-8859-15를 입력받을 수 있도록 설정한다. LANG=fr_FR.iso885915로 설정한다. LDML 파일의 <consoleconversion> 태그에서 linux_charset="iso885915"로 설정한다. 이와 같이 설정하면 ISO-8859-15 문자만을 입력받아 CSQL에 의해 UTF-8로 변환될 것이다.
Windows에서는 다음과 같이 설정한다.
- Windows 코드페이지를 28605로 변환한다(chcp 28605). LDML <consoleconversion> 태그에서 set windows_codepage="28605"로 설정한다. 코드페이지 28605는 ISO-8859-15 문자셋에 해당한다.
입력 시 콘솔 변환 프로세스는 SQL 문장을 포함한 모든 입력에 대해 변환이 필요한 문자 데이터들을 변환한다. 결과 출력과 에러 메시지 출력 시에 CSQL은 모든 텍스트를 변환하지 않고 역시 변환이 필요한 문자들만 변환한다. 예를 들어, 숫자 텍스트들은 모두 ASCII 문자이므로 이를 출력할 때는 콘솔 변환 작업이 발생하지 않는다.
유니코드 정규화¶
글리프(glyph [1] , 문자 기호)는 유니코드 문자를 사용해서 다양한 방법으로 사용된다. 대부분 분해(decomposed)된 형태와 결합(composed form)된 형태로 사용된다. 예를 들어, 글리프 'Ä'는 단일 코드포인트 00C4로 결합된 형태로 쓰이는데, UTF-8에서 "C3 84"와 같이 2 바이트로 표현된다. 완전히 분해된 형태에서 2 개의 코드 포인트 0041('A')과 0308(COMBINING DIAERESIS)로 쓰여지며, UTF-8에서 "41 CC 88"과 같이 3 바이트로 표현된다. 대부분의 텍스트 편집기는 두 가지 형식을 모두 다룰 수 있어서, 두 가지 형식의 인코딩은 같은 글리프 'Ä'로 나타날 것이다. 내부적으로 CUBRID는 "완전히 결합된" 텍스트만을 처리할 수 있다.
"완전히 분해된" 텍스트로 작업하는 클라이언트에 대해 CUBRID는 "완전히 결합된" 텍스트로 변환하고 돌려줄 때는 "완전히 분해된" 텍스트로 변환하도록 설정될 수 있다. 정규화는 로캘에 대한 기능이 아니며, 따라서 로캘에 의존하지 않는다.
시스템 파라미터 unicode_input_normalization 는 결합 여부를 설정하며, 시스템 파라미터 unicode_output_normalization 는 분해 여부를 설정한다. 보다 자세한 내용은 unicode_input_normalization 을 참고한다.
응용 클라이언트가 분해된 유니코드만을 다룰 수 있는 경우에는 unicode_input_normalization 과 unicode_output_normalization 을 모두 yes로 설정하는 경우를 사용해야 하고, 분해된 형태와 결합된 형태를 모두 다룰 수 있는 경우에는 unicode_input_normalization = yes 와 unicode_output_normalization = no 로 설정하여 사용할 수 있다.
콜레이션의 축약과 확장¶
콜레이션의 구축을 위해 축약(contraction)과 확장(expansion)을 지원하며, 축약과 확장은 UTF-8 문자셋 콜레이션에서만 가능하다. 이러한 축약과 확장은 LDML 파일의 콜레이션 설정에서 정의할 수 있는데, 이들의 사용은 로캘 데이터(공유 라이브러리)의 크기와 서버의 성능 모두에 영향을 준다.
축약¶
축약은 둘 또는 그 이상의 코드포인트로 이루어진 일련의 문자들을 하나의 문자로 간주하여 정렬할 수 있도록 해주는 일련의 시퀀스들로 구성된다. 예를 들어, 전통적인 스페인어 정렬 순서에서 "ch"는 하나의 문자로 간주된다. "ch"로 시작하는 모든 단어들은 "c"로 시작하는 모든 단어들 뒤에 정렬되지만, "d"로 시작하는 단어보다 앞에 위치한다. 축약의 다른 예는 체코어의 "ch"인데 "h" 뒤에 정렬되며, 크로아티아어와 세르비아어의 라틴 문자에서 "lj"와 "nj"는 각각 "l"과 "n" 뒤에 정렬된다. 축약에 대한 추가 정보는 http://userguide.icu-project.org/collation/concepts를 참고한다. http://www.unicode.org/Public/UCA/latest/allkeys.txt의 DUCET에도 축약에 대해 일부가 정의되어 있다.
확장이 있는 콜레이션과 확장이 없는 콜레이션 모두에 대해 축약을 지원한다. 콜레이션을 정의하는 <setting> 태그에서 DUCETContractions="ignore/use" 와 TailoringContractions="ignore/use" 두 개의 LDML 파라미터를 통해서 설정할 수 있다. DUCETContractions 파라미터는 DUCET 파일에 있는 축약을 콜레이션에 로딩할 것인지를 결정하며, TailoringContractions 파라미터는 LDML 파일의 규칙에 의해 정의된 축약을 사용할 것인지를 결정한다.
확장¶
확장은 하나의 콜레이션 원소보다 많은 원소들을 가진 코드포인트(문자)들을 참조한다. 확장을 사용하면 아래에 서술된 바와 같이 콜레이션의 동작이 근본적으로 변경된다. LDML 파일의 CUBRIDExpansions="use" 파라미터 설정을 통해 확장을 사용할 수 있다.
확장이 없는 콜레이션
확장이 없는 콜레이션에서 각 코드포인트는 개별적으로 처리된다. 콜레이션의 세기에 기반하여 문자들이 완전히 정렬될 수도 있고 그렇지 않을 수도 있다. 콜레이션 알고리즘은 각 수준들의 집합의 가중치를 비교하여 해당 코드포인트의 가중치를 나타내는 하나의 값을 생성하며, 이를 기반으로 코드포인트들을 정렬한다. 확장이 없는 콜레이션에서 두 문자열 비교는 이와 같이 계산된 가중치로 각각의 코드포인트를 차례로 비교하게 된다.
확장이 있는 콜레이션
확장이 있는 콜레이션에서 일부 결합 문자(코드포인트)들은 다른 문자들로 구성된 순서 있는 리스트(ordered list)로 해석된다. 예를 들어, 'æ'는 'ae', 'ä'는 'ae' 또는 'aa'와 같이 해석된다. DUCET에서 'æ'의 콜레이션 원소 리스트는 'a'와 'e'의 순서로 두 콜레이션 원소 리스트들을 연결(concatenation)한 것이 된다. 코드포인트에 대해 특정한 순서를 부여하는 것은 불가능하며, 각 문자(코드포인트)들의 새로운 가중치를 계산하는 것도 불가능하다.
확장이 있는 콜레이션에서 문자열 비교는 두 개의 코드포인트/축약에 대해 콜레이션 원소들을 연결(concatenation)한 후에, 각 단계별로 두 리스트의 가중치를 비교하는 것이다.
예제 1
다음의 예제는 콜레이션 설정에 따라 문자열 비교가 다른 결과를 가져올 수 있다는 것을 보여준다.
다음의 DUCET 파일 일부는 아래 예에서 사용할 코드포인트들이다.
0041 ; [.15A3.0020.0008.0041] # LATIN CAPITAL LETTER A 0052 ; [.1770.0020.0008.0052] # LATIN CAPITAL LETTER R 0061 ; [.15A3.0020.0002.0061] # LATIN SMALL LETTER A 0072 ; [.1770.0020.0002.0072] # LATIN SMALL LETTER R 00C4 ; [.15A3.0020.0008.0041][.0000.0047.0002.0308] # LATIN CAPITAL LETTER A WITH DIAERESIS; 00E4 ; [.15A3.0020.0002.0061][.0000.0047.0002.0308] # LATIN SMALL LETTER A WITH DIAERESIS;콜레이션을 위해 세 가지 설정 타입으로 표현된다.
- 첫 번째 세기(primary strength), 대소문자 구분 없음 (단계 1)
- 두 번째 세기(secondary strength), 대소문자 구분 없음 (단계 1, 2)
- 세 번째 세기(tertiary strength), 대문자 우선 (단계 1, 2, 3)
지금부터 확장이 있는 콜레이션과 확장이 없는 콜레이션을 가지고 문자열 ''Ar''과 ''Är''의 정렬을 살펴볼 것이다.
확장이 없는 콜레이션
확장이 없을 때 각 코드포인트는 하나의 가중치 값을 부여받는다. A, Ä, R과 해당 소문자 코드포인트에 대한 가중치를 위에서 언급된 알고리즘을 기반으로 한 이 문자들에 대한 코드포인트의 순서는 다음과 같다.
- 첫 번째 세기: A = Ä < R = r
- 두 번째 세기: A < Ä < R = r
- 세 번째 세기: A < Ä < R < r
각 코드포인트에 대해 계산된 가중치가 있기 때문에 문자열들의 정렬 순서는 쉽게 결정된다.
- 첫 번째 세기: "Ar" = "Är"
- 두 번째 세기: "Ar" < "Är"
- 세 번째 세기: "Ar" < "Är"
확장이 있는 콜레이션
확장이 있는 콜레이션이면 정렬 순서가 바뀐다. DUCET에 기반한 콜레이션 원소들의 연결된 리스트들은 다음과 같다.
Ar [.15A3.0020.0008.0041][.1770.0020.0002.0072] Är [.15A3.0020.0008.0041][.0000.0047.0002.0308][.1770.0020.0002.0072]수준 1의 첫 번째 과정에서 가중치 0x15A3과 0x15A3이 비교된다. 두 번째 과정에서 가중치 0x0000은 비교가 생략되고, 0x1770과 0x1770이 비교된다. 여기까지 문자열이 동일하므로 수준 2 가중치로 계속 비교하게 되는데, 첫 번째 과정에서 0x0020을 0x0020과 비교하고 두 번째 과정에서 0x0020을 0x0047과 비교하여 "Ar" < "Är"이라는 결과를 생성한다. 이 예제를 통해 확장이 있는 콜레이션을 사용할 때 어떻게 문자열 비교가 수행되는지 살펴보았다.
이제 콜레이션 설정을 독일어 콜레이션으로 변경하여 같은 문자열에 대해 다른 순서로 정렬되는 과정을 살펴보자. 독일어에서 "Ä"는 문자 그룹 "AE"로 해석된다. 이 예에 해당하는 코드포인트와 콜레이션 원소들은 다음과 같다.
0041 ; [.15A3.0020.0008.0041] # LATIN CAPITAL LETTER A 0045 ; [.15FF.0020.0008.0045] # LATIN CAPITAL LETTER E 0072 ; [.1770.0020.0002.0072] # LATIN SMALL LETTER R 00C4 ; [.15A3.0020.0008.0041][.15FF.0020.0008.0045] # LATIN CAPITAL LETTER A WITH DIAERESIS; EXPANSION문자열 "Ar"과 "Är"을 비교할 때 확장이 있는 콜레이션을 사용하면, 두 문자열에 있는 문자들의 콜레이션 원소 리스트를 결합한 후 비교하는 과정이 포함된다.
Ar [.15A3.0020.0008.0041][.1770.0020.0002.0072] Är [.15A3.0020.0008.0041][.15FF.0020.0008.0045][.1770.0020.0002.0072]첫 번째 과정에서 수준 1의 가중치 0x15A3과 0x15A3를 비교한다. 그리고나서 0x1770과 0x15FF를 비교하여 "Ar" > "Är"이라는 결과가 나오는데, 이는 앞의 예제와는 전혀 다른 결과이다.
예제 2
캐나다 프랑스어의 확장이 있는 콜레이션(utf8_fr_exp_ab)에서는 액센트 문자를 뒤쪽에서 앞쪽 방향으로 비교하여 정렬한다.
- 일반적인 액센트 순서: cote < coté < côte < côté
- 역순 액센트 순서: cote < côte < coté < côté
문자셋과 콜레이션을 필요로 하는 연산¶
문자셋
문자셋 정보는 문자열 데이터를 사용하는 연산자와 함수들에게 필요한 정보이다. 하지만 예외적으로,
OCTET_LENGTH()
함수와BIT_LENGTH()
함수는 바이트와 비트 값을 반환하기 위해 문자셋 정보가 불필요하다. 그러나, 다른 문자셋으로 저장된 같은 글리프(glyph, 문자 기호)에 대해 이 함수들을 수행하면 다른 값을 반환한다.CREATE TABLE t (s_iso STRING CHARSET iso88591, s_utf8 STRING CHARSET utf8); SET NAMES iso88591; INSERT INTO t VALUES ('È','È'); -- the first returnes 1, while the second does 2 SELECT OCTET_LENGTH (s_iso), OCTET_LENGTH (s_utf8) FROM t;위의 예는 콘솔(또는 응용 클라이언트)에서 iso88591 문자셋으로 질의를 입력해야 한다.
콜레이션
콜레이션은
STRCMP()
,POSITION()
, LIKE 조건, <, =, > 등 두 문자열 간의 비교 또는 매칭을 수반하는 연산자와 함수에서 필요하다. 또한 ORDER BY, GROUP BY 및 집계 함수(MIN()
,MAX()
,GROUP_CONCAT()
) 등에서도 콜레이션이 필요하다.콜레이션은 또한
UPPER()
,LOWER()
함수에서도 고려되는데, 다음과 같이 동작한다.
- 각 콜레이션은 부모에 해당하는 기본 로캘이 있다.
- UPPER와 LOWER 함수는 콜레이션의 기본 로캘을 사용하여 수행된다.
대부분의 콜레이션에서 기본 로캘은 명확하다(콜레이션 이름에 포함됨).
- utf8_tr_cs → tr_TR.utf8
- iso88591_en_ci → en_US (ISO-8859-1 문자셋)
바이너리 콜레이션은 다음의 기본 로캘을 가지고 있다.
- iso88591_bin → en_US (ISO-8859-1 문자셋)
- utf8_bin (en_US.utf8 - 내장된 로캘 - ASCII 문자만 다룬다)
- euckr_bin (ko_KR.euckr - 내장된 로캘 - ASCII 문자만 다룬다)
LDML에서 정의한 일반적인(generic) 콜레이션들이 있는데, 이 콜레이션들은 $CUBRID/conf/cubrid_locales.txt 파일에서 먼저 나타나는 로캘을 기본 로캘로 가진다. 최초 설치 시 가장 처음에 나타나는 로캘은 de_DE(독일어)이므로, de_DE가 일반적인 콜레이션의 기본 로캘이 된다.
문자셋 변환
CUBRID가 지원하는 3 가지 문자셋에 대한 변환 규칙은 다음과 같다.
euckr과 utf8 간의 상호 변환은 허용되지 않는다.
iso88591에서 utf8로의 변환 - 바이트 변환
iso88591에서 euckr로 변환 - 허용되지 않는다. (일부 문자가 EUC-KR로 인코딩될 수 없음)
utf8과 euckr에서 iso88591로 변환 - 바이트 재해석; 변환될 값이 무제한의 자릿수(precision)를 가지는 타입이면, 저장 공간의 크기는 같지만 자릿수는 증가한다.
Note
문자셋 변환 시 9.0 버전에서 어떤 값이 정해진 자릿수를 지닌 타입이면 자릿수는 유지되고 데이터가 절삭되었다. 9.1 버전부터는 자릿수를 확장하고 데이터를 유지한다.
콜레이션 설정으로 인한 영향¶
LIKE 조건 최적화
LIKE 조건은 문자열 데이터 간의 패턴을 비교하여 문자열이 패턴과 매칭되면 TRUE 를 리턴한다. 확장이 없는 콜레이션을 사용할 때에는 각 코드포인트는 가중치를 나타내는 하나의 정수 값을 갖는데, 이 가중치 값은 콜레이션 설정(세기, 대소문자 구분 등)에 기반하여 계산된다.
문자들은 항상 하나의 개체(entity)로 간주될 수 있기 때문에, LIKE 조건을 사용한 패턴으로 문자열을 매칭하려는 시도는 문자열이 어떤 범위 내에서 발견될 수 있는지 확인하는 것과 같다고 볼 수 있다. 예를 들어, "s LIKE 'abc%'"는 칼럼 s의 값은 문자열 "abc"로 시작해야 한다는 것을 의미하므로, "s LIKE 'abc%'"와 같은 절을 수행하기 위해 먼저 칼럼 s의 문자열에 대한 제한 범위로 구문을 재작성한다. 확장이 없는 콜레이션에서 이는 s가 "abc"보다 크거나 같지만 뒤따르는 문자열보다 작다는 의미이다. 예를 들어, 영어의 알파벳 기준으로 'abc'에 뒤따르는 문자열은 'abd'이므로 아래와 같이 변환할 수 있다.
s LIKE 'abc%' → s ≥ 'abc' AND s < 'abd' (if using strictly the English aphabet)이와 같이 LIKE 조건의 패턴은 간단한 비교 조건으로 대체될 수 있는데, 확장이 있는 콜레이션의 경우는 다르게 동작한다. 확장이 있는 콜레이션을 사용할 때 문자열을 비교하는 것은 각 코드포인트나 확장에 대해 각 수준(level)별로 콜레이션 원소의 결합된 리스트들을 비교하는 것을 뜻한다. 확장이 있는 콜레이션에서 문자열 비교에 대한 자세한 내용은 확장 을 참고하면 된다.
확장이 있는 콜레이션에 대해서 위의 예와 같이 LIKE 조건을 일반 비교 조건으로 변환하면 비교가 잘못될 수 있다. 정확한 질의 결과를 보장하기 위하여 확장이 있는 콜레이션의 경우에는 LIKE 조건 재작성 방법이 아래의 예와 같이 다르게 동작한다. 즉, 범위 조건으로 변경하고 확장 있는 콜레이션에서 잘못 추가될 수 있는 데이터들을 배제시키기 위해 주어진 LIKE 조건이 필터로 추가된다.
s LIKE 'abc%' → s ≥ 'abc' AND s < 'abd' and s LIKE 'abc%' (if using strictly the English aphabet)
prefix 인덱스와 콜레이션 확장
확장이 있는 콜레이션을 가진 칼럼에는 prefix 인덱스를 생성할 수 없다.
CREATE TABLE t1 (s1 VARCHAR (200) COLLATE utf8_ja_exp); CREATE INDEX idx_t_s1 on t (s1 (5)); ERROR: before ' ; ' Prefix index is not allowed on attribute 's' (has collation with expansions).
커버링 인덱스
커버링 인덱스 스캔은 실제 레코드를 액세스하지 않고 인덱스에 있는 값만을 사용해서 질의를 처리하는 질의 최적화 기법으로, 이에 대한 자세한 내용은 커버링 인덱스 를 참고한다.
대소문자 구분이 없는 콜레이션에서 'abc'와 'ABC' 두 개의 문자열을 인덱스에 저장한다고 가정할 때 인덱스의 키 값으로 이 중 하나만이 저장된다. 이와 같이 하나의 콜레이션에서 서로 다른 두 개 이상의 문자열이 하나의 키 값을 가지게 되면, 정확한 질의 결과를 만들어낼 수 없게 된다. 결국 수준 4(quarternary) 보다 작은 세기(strength)의 모든 UTF-8 콜레이션에서 커버링 인덱스에 의한 질의 최적화는 적용되지 않는다.
이러한 세기 수준은 LDML에서 콜레이션 정의를 위한 <strength> 태그의 strength="tertiary/quarternary"에 의해 제어될 수 있다. 확장이 있는 콜레이션의 세기 값을 최대 값으로 설정하는 것은 주의깊게 고려되어야 하는데, 네 번째 세기 수준은 공유 라이브러리 크기와 메모리 요구량이 커질 뿐만 아니라 문자열 비교 시간을 증가시키기 때문이다.
콜레이션과 관련된 자세한 내용은 콜레이션 설정을 참고한다.
각 콜레이션에 대한 기능 요약
콜레이션 LIKE 문을 범위로 재작성 이후 조건 유지 커버링 인덱스 허용 prefix 인덱스 허용 iso88591_bin No Yes Yes iso88591_en_cs No Yes Yes iso88591_en_ci Yes No Yes utf8_bin No Yes Yes euckr_bin No Yes Yes utf8_en_cs No Yes Yes utf8_en_ci Yes No Yes utf8_tr_cs No Yes Yes utf8_ko_cs No Yes Yes utf8_gen No Yes Yes utf8_gen_ai_ci Yes No Yes utf8_gen_ci Yes No Yes utf8_de_exp_ai_ci Yes No No utf8_de_exp Yes No No utf8_es_cs No Yes Yes utf8_fr_exp_ab Yes No No utf8_ja_exp Yes No No utf8_ja_exp_cbm Yes No No utf8_km_exp Yes No No utf8_ko_cs_uca No Yes Yes utf8_tr_cs_uca No Yes Yes utf8_vi_cs No Yes Yes
콜레이션 정보 보기¶
콜레이션 정보를 보려면 CHARSET()
, COLLATION()
및 COERCIBILITY()
정보 함수를 사용한다.
데이터베이스 콜레이션 정보는 db_collation 시스템 뷰 또는 SHOW COLLATION을 통해 확인할 수 있다.
다국어 설정을 위한 고려 사항¶
데이터베이스 설계자는 데이터베이스 구조를 설계할 때 문자 데이터의 속성을 고려해야 한다. 다음은 문자 데이터 설정 시에 알아야 할 사항들을 요약한 것이다.
CUBRID_CHARSET¶
- 기본적으로 CUBRID_CHARSET=en_US를 사용한다. 이 설정이 가장 좋은 성능을 낸다.
- UTF-8 로캘의 사용은 CHAR 타입에 대해 추가적인 저장 공간을 필요로 한다. 고정 길이 문자 타입(CHAR)의 경우 4배까지 늘어나며, EUC-KR의 경우 3배까지 늘어난다.
- 사용자 문자열 리터럴이 시스템과 다른 문자셋과 콜레이션을 가진다면, 질의문은 문자셋과 콜레이션을 설정하기 위해 더 길어질 것이다.
- ASCII 문자가 아닌 문자를 사용자 식별자로 사용하려면 .utf8 로캘을 사용한다.
- UTF-8 문자셋으로 CUBRID_CHARSET을 설정하면, LDML 로캘을 사용하는 것이 좋다. LDML 로캘이 식별자에 포함된 유니코드 문자의 대소문자 변환을 보장한다.
- 로캘 설정은 문자열 변환 함수에도 영향을 준다. 가장 빈번하게 변환이 이루어지는 로캘을 선택하는 것이 좋다.
- CUBRID_CHARSET 설정 시 문자열 상수, 사용자 테이블 칼럼의 문자셋과 콜레이션에 대해 고민하지 않아도 된다. 질의문에서
CAST()
연산자를 사용하여 런타임에 바꿀 수 있으며, "ALTER ... CHANGE" 문을 통해 영구히 바꿀 수 있다.
CHAR와 VARCHAR¶
- 일반적으로 데이터의 크기 변화가 심할 때는 VARCHAR를 사용한다.
- CHAR 타입은 고정 길이 타입이므로, 영문만 저장하는 경우에도 UTF-8은 4 bytes의 저장 공간을, EUC-KR은 3 bytes의 저장 공간을 필요로 한다.
- 칼럼의 자릿수(precision)는 문자(글리프, 문자 기호)의 개수이다.
- 자릿수를 정한 이후에, 대부분의 사용 시나리오에 따라 문자셋과 콜레이션이 설정되어야 한다.
문자셋 선택¶
- 텍스트가 ASCII가 아닌 문자를 포함하고 있더라도 응용 프로그램이 문자 개수 세기, 문자열 치환 등의 문자열 조작이 필요한 경우에 utf8이나 euckr 문자셋을 사용한다.
- CHAR 타입의 저장 공간을 고려해야 한다.
- CHAR와 VARCHAR 타입에서 INSERT/UPDATE 시 오버헤드가 있다. 각 행에서 문자열의 문자 개수(precision)를 세는 것은 ISO가 아닌 문자셋에서 더 많은 수행 시간을 필요로 한다.
- 질의문 내의 표현식의 문자셋은
CAST()
연산자를 사용하여 변환할 수 있다.
콜레이션 선택¶
- 콜레이션 의존적인 동작(문자열 검색, 정렬, 비교, 대소문자화)이 수행되지 않는다면, 해당 문자셋의 바이너리 콜레이션을 사용한다.
- 표현식의 원래 문자셋과 새로운 콜레이션 사이에서 문자셋이 변경되지 않는다면 콜레이션은
CAST()
연산자, COLLATE 수정자를 사용하여 쉽게 오버라이드할 수 있다. - 콜레이션은 문자열의 대소문자 구분 규칙을 제어한다.
- 확장이 있는 콜레이션은 더 느리지만 더 유연하며 전체 단어 정렬을 수행한다.
정규화¶
- 응용 클라이언트가 CUBRID에 분해된 형태의 텍스트 데이터를 보낸다면, unicode_input_normalization = yes로 설정하여 CUBRID가 재구성하여 결합된 형태로 다룰 수 있도록 한다.
- 응용 클라이언트가 분해된 형태만 다룰 수 있다면, unicode_output_normalization = yes로 설정하여 CUBRID가 항상 분해된 형식으로 텍스트 데이터를 보내도록 한다.
- 응용 클라이언트가 모든 형식을 알고 있다면, unicode_output_normalization = no인 상태로 둔다.
CAST vs COLLATE¶
CAST()
연산자는 COLLATE 수정자 보다 더 많은 실행 비용이 든다.- COLLATE 수정자 는 질의 실행 과정에서 실행 연산이 추가되지 않기 때문에, COLLATE 수정자 를 사용하는 것이
CAST()
연산자를 사용하는 것보다 실행 속도가 더 빠르다. - COLLATE 수정자 는 문자셋이 바뀌지 않을 때만 사용될 수 있다.
주의 사항¶
- 문자셋은 데이터베이스 인스턴스마다 같다고 가정한다. UTF-8 문자셋으로 구동된 데이터베이스 인스턴스에 JDBC, CCI 드라이버를 통해 응용 프로그램으로부터 직접 UTF-8 문자를 입력하는 것이 가능하다. ISO 문자셋을 사용하는 경우에는 입력되는 모든 문자열이 ISO 문자로 여겨지며 UTF-8 문자셋으로 변환된다. ASCII 문자들은 ISO와 UTF-8 문자셋과 모두 호환되기 때문에 변환되지 않는다.
- 호스트 변수의 지연 바인딩이 있는 경우에 질의 실행 계획 출력 시에 콜레이션이 출력되지 않는다.
- 기본 다국어 영역인 0000~FFFF 범위의 유니코드 코드포인트만 정규화된다.
- 숫자 구분자로 특정 문자(예를 들어, 공백 문자)를 사용할 수 없다. 일부 로캘에서는 공백 문자를 숫자 구분자로 활용하기도 하는데, 이는 허용되지 않는다.
- 사용자 정의 변수는 시스템 콜레이션과 다른 콜레이션으로 설정할 수 없다. 예를 들어, 시스템 콜레이션이 iso88591일 때 "set @v1='a' collate utf8_en_cs;"과 같은 구문을 사용할 수 없다.
Footnotes
[1] | (1, 2) 글리프(glyph): 글자 하나의 모양에 대한 기본 단위로 문자의 모양이나 형태를 나타내는 그래픽 부호. 글리프는 눈에 보이는 모양을 지정하는 것으로서 하나의 글자에 대해 여러 개의 글리프가 존재할 수 있다. |