설명에 따라PostgreSQL : 문서 : 13 : 37.2. PostgreSQL 롤 토토 시스템, 포스트그레SQL새로운 데이터 유형을 지원하도록 확장될 수 있습니다. 이 섹션에서는 새로운 기본 유형을 정의하는 방법을 설명합니다. 이는 기본 유형 아래에 정의된 데이터 유형입니다.SQL언어. 새로운 기본 토토 꽁 머니을 생성하려면 저수준 언어(보통 C)로 해당 토토 꽁 머니에 대해 작동하는 함수를 구현해야 합니다.
이 섹션의 예는 다음에서 찾을 수 있습니다.복잡한.sql그리고복잡한.c에서src/튜토리얼소스 배포 디렉토리. 참조README예제 실행에 대한 지침은 해당 디렉토리에 있는 파일입니다.
사용자 정의 유형에는 항상 입력 및 출력 기능이 있어야 합니다. 이러한 함수는 유형이 문자열에 표시되는 방식(사용자가 입력하고 사용자에게 출력하는 경우)과 유형이 메모리에서 구성되는 방식을 결정합니다. 입력 함수는 null로 끝나는 문자열을 인수로 사용하고 해당 유형의 내부(메모리 내) 표현을 반환합니다. 출력 함수는 유형의 내부 표현을 인수로 사용하고 null로 끝나는 문자열을 반환합니다. 유형을 단순히 저장하는 것 이상으로 더 많은 작업을 수행하려면 해당 유형에 대해 원하는 모든 작업을 구현하는 추가 함수를 제공해야 합니다.
토토 꽁 머니을 정의하고 싶다고 가정복잡한복소수를 나타냅니다. 메모리에서 복소수를 표현하는 자연스러운 방법은 다음 C 구조입니다.
typedef 구조체 복합체
더블엑스;
이중 y;
복잡한;
우리는 이것을 참조에 의한 전달 토토 꽁 머니으로 만들어야 할 것입니다. 왜냐하면 그것은 단일에 들어가기에는 너무 크기 때문입니다.데이텀값.
유형의 외부 문자열 표현으로 우리는 다음 형식의 문자열을 선택합니다.(x,y).
입력 및 출력 함수는 일반적으로 작성하기 어렵지 않습니다. 특히 출력 함수는 더욱 그렇습니다. 그러나 토토 꽁 머니의 외부 문자열 표현을 정의할 때는 결국 해당 표현에 대한 완전하고 강력한 구문 분석기를 입력 함수로 작성해야 한다는 점을 기억하십시오. 예를 들어:
PG_FUNCTION_INFO_V1(콤플렉스인);
데이텀
complex_in(PG_FUNCTION_ARGS)
char *str = PG_GETARG_CSTRING(0);
더블 엑스,
와이;
복잡한 *결과;
if (sscanf(str, " ( %lf , %lf )", &x, &y) != 2)
ereport(오류,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("%s 유형에 대한 입력 구문이 잘못되었습니다: \"%s\"",
"복잡한", str))));
결과 = (복소수 *) palloc(sizeof(복소수));
결과-x = x;
결과-y = y;
PG_RETURN_POINTER(결과);
출력 기능은 간단하게 다음과 같습니다:
PG_FUNCTION_INFO_V1(complex_out);
데이텀
complex_out(PG_FUNCTION_ARGS)
복잡한 *복잡한 = (복잡한 *) PG_GETARG_POINTER(0);
문자 *결과;
결과 = psprintf("(%g,%g)", 복합체-x, 복합체-y);
PG_RETURN_CSTRING(결과);
입력 및 출력 기능이 서로 반대가 되도록 주의해야 합니다. 그렇지 않으면 데이터를 파일에 덤프한 다음 다시 읽어야 할 때 심각한 문제가 발생하게 됩니다. 이는 부동 소수점 숫자와 관련된 경우 특히 일반적인 문제입니다.
선택적으로 사용자 정의 토토 꽁 머니은 바이너리 입력 및 출력 루틴을 제공할 수 있습니다. 바이너리 I/O는 일반적으로 텍스트 I/O보다 빠르지만 이식성이 떨어집니다. 텍스트 I/O와 마찬가지로 외부 바이너리 표현이 무엇인지 정확하게 정의하는 것은 사용자의 몫입니다. 대부분의 내장 데이터 토토 꽁 머니은 기계 독립적인 이진 표현을 제공하려고 합니다. 에 대한복잡한, 토토 꽁 머니에 대한 바이너리 I/O 변환기를 피기백하겠습니다.float8:
PG_FUNCTION_INFO_V1(complex_recv);
데이텀
complex_recv(PG_FUNCTION_ARGS)
StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
복잡한 *결과;
결과 = (복소수 *) palloc(sizeof(복소수));
결과-x = pq_getmsgfloat8(buf);
결과-y = pq_getmsgfloat8(buf);
PG_RETURN_POINTER(결과);
PG_FUNCTION_INFO_V1(complex_send);
데이텀
complex_send(PG_FUNCTION_ARGS)
복잡한 *복잡한 = (복잡한 *) PG_GETARG_POINTER(0);
StringInfoData buf;
pq_begintypsend(&buf);
pq_sendfloat8(&buf, complex-x);
pq_sendfloat8(&buf, complex-y);
PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
I/O 함수를 작성하고 이를 공유 라이브러리로 컴파일한 후에는 다음을 정의할 수 있습니다.복잡한SQL을 입력하세요. 먼저 이를 쉘 유형으로 선언합니다.
CREATE TYPE 콤플렉스;
이것은 I/O 기능을 정의하는 동안 토토 꽁 머니을 참조할 수 있는 자리 표시자 역할을 합니다. 이제 I/O 함수를 정의할 수 있습니다.
CREATE FUNCTION complex_in(cstring)
반품 콤플렉스
그대로 '파일 이름'
언어 C 불변 STRICT;
CREATE FUNCTION complex_out(복잡한)
반환 cstring
그대로 '파일 이름'
언어 C 불변 STRICT;
CREATE FUNCTION complex_recv(내부)
반품 콤플렉스
그대로 '파일 이름'
언어 C 불변 STRICT;
CREATE FUNCTION complex_send(복잡한)
반환 bytea
그대로 '파일 이름'
언어 C 불변 STRICT;
마지막으로 데이터 토토 꽁 머니의 전체 정의를 제공할 수 있습니다.
CREATE TYPE 콤플렉스( 내부 길이 = 16, 입력 = complex_in, 출력 = complex_out, 수신 = complex_recv, 보내기 = complex_send, 정렬 = 이중 );
새 기본 토토 꽁 머니을 정의할 때,PostgreSQL자동으로 해당 유형의 배열을 지원합니다. 배열 유형은 일반적으로 밑줄 문자()가 포함된 기본 유형과 이름이 동일합니다._)이 앞에 붙습니다.
데이터 유형이 존재하면 데이터 유형에 유용한 작업을 제공하기 위해 추가 함수를 선언할 수 있습니다. 그런 다음 함수 위에 연산자를 정의할 수 있으며, 필요한 경우 데이터 유형의 인덱싱을 지원하기 위해 연산자 클래스를 만들 수 있습니다. 이러한 추가 레이어에 대해서는 다음 섹션에서 설명합니다.
데이터 유형의 내부 표현이 가변 길이인 경우 내부 표현은 가변 길이 데이터의 표준 레이아웃을 따라야 합니다. 처음 4바이트는 다음과 같아야 합니다.문자[4]직접 액세스할 수 없는 필드(관습적으로 명명됨vl_len_). 다음을 사용해야 합니다.SET_VARSIZE()이 필드에 데이텀의 전체 크기(길이 필드 자체 포함)를 저장하는 매크로 및VARSIZE()그것을 검색합니다. (플랫폼에 따라 길이 필드가 인코딩될 수 있기 때문에 이러한 매크로가 존재합니다.)
자세한 내용은 다음 설명을 참조하세요.토토 꽁 머니 생성명령.
데이터 토토 꽁 머니 값의 크기(내부 형식)가 다른 경우 일반적으로 데이터 토토 꽁 머니을 만드는 것이 바람직합니다.토스트-가능(참조섹션 69.2). 값이 항상 너무 작아 외부에서 압축하거나 저장할 수 없는 경우에도 이 작업을 수행해야 합니다. 왜냐하면토스트헤더 오버헤드를 줄여 작은 데이터의 공간도 절약할 수 있습니다.
지원하기 위해토스트저장, 데이터 유형에서 작동하는 C 함수는 다음을 사용하여 전달되는 토스트된 값을 압축 해제할 때 항상 주의해야 합니다.PG_DETOAST_DATUM. (이 세부 사항은 토토 꽁 머니별 정의에 따라 관례적으로 숨겨져 있습니다.GETARG_DATATYPE_P매크로.) 그런 다음, 다음을 실행할 때토토 꽁 머니 생성명령, 내부 길이를 다음과 같이 지정변수다음 이외의 적절한 저장 옵션을 선택하세요.일반.
데이터 정렬이 중요하지 않은 경우(특정 함수에 대해서만 또는 데이터 유형이 바이트 정렬을 지정하기 때문에) 다음의 일부 오버헤드를 피할 수 있습니다.PG_DETOAST_DATUM. 당신은 사용할 수 있습니다PG_DETOAST_DATUM_PACKED대신(관례적으로 다음을 정의하여 숨겨짐GETARG_DATATYPE_PP매크로) 및 매크로 사용VARSIZE_ANY_EXHDR그리고VARDATA_ANY잠재적으로 압축된 데이텀에 액세스합니다. 다시 말하지만, 이러한 매크로에 의해 반환된 데이터는 데이터 유형 정의가 정렬을 지정하더라도 정렬되지 않습니다. 정렬이 중요하다면 정기적으로 진행해야 합니다.PG_DETOAST_DATUM인터페이스.
이전 코드가 자주 선언됨vl_len_으로int32필드 대신문자[4]. 구조체 정의에 최소한int32정렬. 그러나 정렬되지 않은 데이텀을 사용할 때 이러한 구조체 정의를 사용하는 것은 위험합니다. 컴파일러는 데이터가 실제로 정렬되었다고 가정하는 라이센스로 받아들여 정렬에 엄격한 아키텍처의 코어 덤프로 이어질 수 있습니다.
다음에 의해 활성화되는 또 다른 기능토스트지원은 다음을 가질 수 있는 가능성입니다확장디스크에 저장된 형식보다 작업하기 더 편리한 메모리 내 데이터 표현입니다. 일반 또는“평면”varlena 저장 형식은 궁극적으로 단지 바이트 덩어리입니다. 예를 들어 메모리의 다른 위치로 복사될 수 있으므로 포인터를 포함할 수 없습니다. 복잡한 데이터 유형의 경우 플랫 형식을 사용하면 작업 비용이 상당히 많이 들 수 있으므로포스트그레SQL방법을 제공합니다“확장”플랫 형식을 계산에 더 적합한 표현으로 변환한 다음 해당 형식을 데이터 유형의 함수 간에 메모리 내에서 전달합니다.
확장된 저장소를 사용하려면 데이터 유형은 다음에 제공된 규칙을 따르는 확장된 형식을 정의해야 합니다.src/include/utils/expandeddatum.h, 함수를 제공합니다“확장”평탄한 varlena 값을 확장된 형식으로 변환하고“평탄화”확장된 형식은 다시 일반 varlena 표현으로 돌아갑니다. 그런 다음 데이터 유형에 대한 모든 C 함수가 수신 즉시 하나를 다른 표현으로 변환하여 둘 중 하나의 표현을 허용할 수 있는지 확인하십시오. 표준이 있기 때문에 데이터 유형에 대한 모든 기존 함수를 한 번에 수정할 필요는 없습니다.PG_DETOAST_DATUM매크로는 확장된 입력을 일반 플랫 형식으로 변환하도록 정의됩니다. 따라서 flat varlena 형식으로 작동하는 기존 기능은 약간 비효율적이지만 확장된 입력으로 계속 작동합니다. 더 나은 성능이 중요하지 않는 한 변환할 필요가 없습니다.
확장된 표현으로 작업하는 방법을 아는 C 함수는 일반적으로 확장된 형식만 처리할 수 있는 함수와 확장되거나 평면적인 varlena 입력을 처리할 수 있는 함수의 두 가지 범주로 분류됩니다. 전자는 작성하기 쉽지만 전체적으로 효율성이 떨어질 수 있습니다. 단일 함수에서 사용하기 위해 단순 입력을 확장 형식으로 변환하는 것은 확장 형식에서 작업하여 절약하는 것보다 비용이 더 많이 들 수 있기 때문입니다. 확장된 형식만 처리해야 하는 경우 일반 입력을 확장된 형식으로 변환하는 것은 인수 가져오기 매크로 내부에 숨겨질 수 있으므로 함수는 기존 varlena 입력으로 작업하는 것보다 더 복잡해 보이지 않습니다. 두 가지 유형의 입력을 모두 처리하려면 외부, 짧은 헤더 및 압축된 varlena 입력을 제거하지만 확장 입력은 제거하지 않는 인수 가져오기 함수를 작성하세요. 이러한 함수는 플랫 varlena 형식과 확장 형식의 결합에 대한 포인터를 반환하는 것으로 정의할 수 있습니다. 발신자는 다음을 사용할 수 있습니다.VARATT_IS_EXPANDED_HEADER()매크로가 수신한 형식을 결정합니다.
그토스트인프라는 일반 varlena 값을 확장된 값과 구별할 수 있을 뿐만 아니라 다음도 구별합니다.“읽기-쓰기”그리고“읽기 전용”확장된 값에 대한 포인터. 확장된 값만 검사하거나 안전하고 의미상 보이지 않는 방식으로만 변경하는 C 함수는 어떤 유형의 포인터를 받는지 신경 쓸 필요가 없습니다. 입력 값의 수정된 버전을 생성하는 C 함수는 읽기-쓰기 포인터를 받으면 확장된 입력 값을 내부에서 수정할 수 있지만 읽기 전용 포인터를 받으면 입력을 수정해서는 안 됩니다. 이 경우 먼저 값을 복사하여 수정할 새 값을 생성해야 합니다. 새로운 확장된 값을 생성한 C 함수는 항상 해당 값에 대한 읽기/쓰기 포인터를 반환해야 합니다. 또한 읽기-쓰기 확장 값을 내부에서 수정하는 C 함수는 도중에 실패할 경우 값을 정상 상태로 유지하도록 주의해야 합니다.
확장된 값을 사용한 작업의 예는 특히 표준 배열 인프라를 참조하십시오.src/backend/utils/adt/array_expanded.c.
문서에 올바르지 않은 내용이 있으면 일치하지 않습니다. 특정 기능에 대한 경험이 있거나 추가 설명이 필요한 경우 이용해주세요이 양식문서 문제를 보고합니다.