| PostgreSQL 9.1.24 문서 | ||||
|---|---|---|---|---|
| PostgreSQL : 문서 : 9.1 : 토토 핫 기능 | 위로 | 35장. 연장SQL | 다음 | |
토토 캔자 정의 함수는 C(또는 다음 언어를 토토 캔하는 언어)로 작성될 수 있습니다. C++ 등 C와 호환되도록 만들 수 있습니다. 그러한 기능은 동적으로 로드 가능한 객체(공유라고도 함)로 컴파일됩니다. 라이브러리)이며 요청 시 서버에 의해 로드됩니다. 역동적인 로딩 기능이 차별화됩니다."C 언어"함수"내부"함수 — 실제 코딩 규칙은 본질적으로 둘 다 동일합니다. (따라서, 표준 내부 함수 라이브러리는 풍부한 코딩 소스입니다. 토토 캔자 정의 C 함수의 예)
현재 C에는 두 가지 다른 호출 규칙이 토토 캔됩니다. 기능. 최신"버전 1"호출 규칙은 다음을 작성하여 표시됩니다.PG_FUNCTION_INFO_V1()함수에 대한 매크로 호출, 아래 그림과 같이. 이러한 매크로가 없으면 이전 스타일을 나타냅니다. ("버전 0") 함수입니다. 언어 에 지정된 이름함수 생성isC두 경우 모두. 이전 스타일의 함수 이제 이식성 문제와 부족으로 인해 더 이상 토토 캔되지 않습니다. 기능이 있지만 호환성을 위해 여전히 지원됩니다. 이유.
특정 항목에서 처음으로 토토 캔자 정의 함수가 로드 가능한 객체 파일은 세션에서 호출되며 동적 로더는 함수가 실행될 수 있도록 해당 객체 파일을 메모리에 로드합니다. 전화했다.함수 생성에 대한 따라서 토토 캔자 정의 C 함수는 다음 두 부분을 지정해야 합니다. 함수에 대한 정보: 로드 가능한 객체의 이름 파일 및 특정 함수의 C 이름(링크 기호) 해당 개체 파일 내에서 호출하십시오. C 이름이 명시적으로 지정되지 않은 경우 지정된 경우 SQL 함수와 동일한 것으로 간주됩니다. 이름.
다음 알고리즘은 공유 객체를 찾는 데 토토 캔됩니다 파일은에 지정된 이름을 기반으로 합니다.만들기 기능명령:
이름이 절대 경로인 경우, 주어진 파일은 로드되었습니다.
이름이 문자열로 시작하는 경우$libdir, 해당 부분은로 대체됩니다.PostgreSQL패키지 라이브러리 빌드 시 결정되는 디렉터리 이름입니다.
이름에 디렉토리 부분이 포함되어 있지 않으면 파일 구성에 지정된 경로에서 검색됩니다. 변수dynamic_library_path.
그렇지 않으면(파일이 경로에서 발견되지 않았거나 절대 디렉토리가 아닌 부분을 포함함), 동적 로더 주어진 이름을 토토 캔하려고 시도할 것입니다. 실패하다. (현재 작업에 의존하는 것은 신뢰할 수 없습니다. 디렉토리.)
이 순서가 작동하지 않으면 플랫폼별 공유 라이브러리 파일 이름 확장자(종종).so)가 지정된 이름에 추가되며 이는 시퀀스가 다시 시도됩니다. 이것도 실패하면 로드는 실패하다.
공유 라이브러리를 상대적으로 찾는 것이 좋습니다. 에$libdir또는 동적을 통해 도서관 길. 새로운 버전이 있는 경우 버전 업그레이드가 단순화됩니다. 설치 위치가 다릅니다. 실제 디렉토리 그$libdir'는 찾을 수 있음을 의미합니다. 명령을 토토 캔하여 종료pg_config --pkglibdir.
토토 캔자 ID는PostgreSQL서버는 파일 경로를 통과할 수 있어야 실행됩니다. 로드하려고 합니다. 파일이나 상위 디렉토리 만들기 다음에서 읽을 수 없거나 실행할 수 없습니다.포스트그레스토토 캔자는 흔히 저지르는 실수입니다.
어쨌든, 다음에 주어진 파일 이름은함수 생성명령은 문자 그대로 다음과 같이 기록됩니다. 시스템 카탈로그이므로 파일을 다시 로드해야 하는 경우 동일한 절차가 적용됩니다.
참고: PostgreSQLC 함수를 자동으로 컴파일하지 않습니다. 개체 파일은 a에서 참조되기 전에 컴파일되어야 합니다.함수 생성명령. 참조섹션 35.9.6용 추가 정보.
동적으로 로드된 개체 파일이 호환되지 않는 서버에 로드되었습니다.PostgreSQL파일에 다음이 포함되어 있는지 확인합니다."마법 블록"적절한 내용. 이를 통해 서버는 명백한 것을 감지할 수 있습니다. 다른 전공을 위해 컴파일된 코드와 같은 비호환성 버전PostgreSQL. 마법 현재 블록이 필요합니다.PostgreSQL8.2. 매직 블록을 포함하려면, 모듈 소스 파일 중 하나(그리고 하나만)에 이것을 작성합니다. 헤더를 포함시킨 후fmgr.h:
#ifdef PG_MODULE_MAGIC PG_MODULE_MAGIC; #endif
그#ifdef다음의 경우 테스트를 생략할 수 있습니다. 코드는 8.2 이전 버전에 대해 컴파일할 필요가 없습니다.PostgreSQL출시.
처음 토토 캔된 후에는 동적으로 로드됩니다. 객체 파일은 메모리에 유지됩니다. 동일한 미래의 호출 해당 파일의 함수에 대한 세션은 심볼 테이블 조회의 작은 오버헤드. 강제로 실행해야 하는 경우 예를 들어 다시 컴파일한 후 개체 파일을 다시 로드합니다. 새로운 세션을 시작하세요.
선택적으로 동적으로 로드된 파일에는 다음이 포함될 수 있습니다.
초기화 및 종료 기능. 파일에 포함된 경우
라는 함수_PG_init, 그거
함수는 파일을 로드한 후 즉시 호출됩니다. 는
함수는 매개변수를 받지 않으며 void를 반환해야 합니다. 만약
파일에는라는 함수가 포함되어 있습니다._PG_fini, 해당 함수가 호출됩니다.
파일을 언로드하기 직전. 마찬가지로, 함수
매개변수를 받지 않으며 void를 반환해야 합니다. 참고하세요_PG_fini호출만 됩니다
프로세스가 종료되는 동안이 아니라 파일을 언로드하는 동안입니다.
(현재 언로드는 비활성화되어 있으며 절대 발생하지 않지만,
향후 변경될 수 있습니다.)
C 언어 함수를 작성하는 방법을 알려면 다음 사항을 알아야 합니다. 어떻게PostgreSQL내부적으로 기본 데이터 유형과 해당 유형이 전달될 수 있는 방법을 나타냅니다. 기능에서. 내부적으로는,PostgreSQL기본 유형을 다음과 같이 간주합니다."기억 덩어리". 토토 캔자 정의 유형에 대해 정의하는 함수는 차례로 다음과 같은 방식을 정의합니다. 그포스트그레SQL작동 가능 그것. 즉,포스트그레SQL할 것이다 디스크에서만 데이터를 저장 및 검색하고 입력, 처리, 출력을 위한 토토 캔자 정의 함수 데이터.
기본 유형은 세 가지 내부 형식 중 하나를 가질 수 있습니다:
값 전달, 고정 길이
참조로 전달, 고정 길이
참조로 전달, 가변 길이
값 기준 유형은 길이가 1, 2 또는 4바이트만 될 수 있습니다(또한 8바이트인 경우크기(데이텀)당신의 숫자는 8입니다 기계). 다음과 같이 유형을 정의할 때 주의해야 합니다. 모든 아키텍처에서 동일한 크기(바이트 단위)입니다. 에 대한 예를 들어,긴유형은 위험합니다 일부 시스템에서는 4바이트이고 다른 시스템에서는 8바이트이기 때문에 반면int유형은 대부분의 Unix에서 4바이트입니다. 기계. 의 합리적인 구현int4Unix 시스템의 유형은 다음과 같습니다:
/* 4바이트 정수, 값으로 전달됨 */ typedef int int4;
반면에, 어떤 크기의 고정 길이 유형도 가능합니다. 참조로 전달되었습니다. 예를 들어, 여기 샘플이 있습니다 a의 구현PostgreSQL유형:
/* 참조로 전달된 16바이트 구조 */
typedef 구조체
이중 x, y;
가리키다;
해당 유형에 대한 포인터만 전달할 때 토토 캔할 수 있습니다. 그리고 밖으로PostgreSQL함수. 이러한 유형의 값을 반환하려면 권한을 할당하십시오. 메모리 양팔록, 입력 할당된 메모리를 반환하고 이에 대한 포인터를 반환합니다. (또한 만약 당신이 입력 중 하나와 동일한 값을 반환하고 싶습니다. 동일한 데이터 유형의 인수인 경우 추가 항목을 건너뛸 수 있습니다.팔록그리고 포인터를 다음으로 반환하면 됩니다. 입력 값입니다.)
마지막으로 모든 가변 길이 유형도 다음을 통해 전달되어야 합니다. 참조. 모든 가변 길이 유형은 길이로 시작해야 합니다. 정확히 4바이트의 필드와 그 안에 저장될 모든 데이터 유형은 해당 유형 바로 뒤에 있는 메모리에 위치해야 합니다. 길이 필드. 길이 필드에는 전체 길이가 포함됩니다. 즉, 길이 필드의 크기를 포함합니다. 그 자체.
또 다른 중요한 점은 어떤 곳도 떠나지 않는 것입니다. 데이터 유형 값 내의 초기화되지 않은 비트; 예를 들어 정렬 패딩 바이트를 0으로 만드십시오. 구조체에 존재합니다. 이것이 없으면 논리적으로 동등하다. 데이터 유형의 상수는 다음과 같은 방식으로 동일하지 않은 것으로 보일 수 있습니다. 플래너, 비효율적(비록 틀린 것은 아님)으로 이어짐 계획.
| 경고 |
|
절대로참조별 입력 값의 내용을 수정합니다. 그렇게 하면 디스크에 있는 데이터가 손상될 가능성이 높습니다. 주어진 포인터가 직접 가리킬 수 있기 때문에 디스크 버퍼에 넣습니다. 이 규칙의 유일한 예외는 다음과 같습니다. 에서 설명함PostgreSQL : 문서 : 9.1. |
예를 들어, 유형을 정의할 수 있습니다.텍스트다음과 같습니다:
typedef 구조체
int4 길이;
문자 데이터[1];
텍스트;
분명히 여기에 선언된 데이터 필드는 충분히 길지 않습니다. 가능한 모든 문자열을 보유합니다. 신고가 불가능하기 때문에 가변 크기 구조C, 우리는 다음과 같은 지식에 의존합니다.C컴파일러가 범위 검사를 하지 않습니다 배열 첨자. 필요한 만큼만 할당해 드립니다. 공간을 확보한 다음 마치 선언된 것처럼 배열에 액세스합니다. 올바른 길이. (이것은 일반적인 트릭입니다. C에 관한 많은 교과서에서.)
가변 길이 유형을 조작할 때 주의해야 합니다. 올바른 양의 메모리를 할당하고 길이를 설정하려면 필드를 올바르게 지정하세요. 예를 들어 40바이트를 저장하고 싶다면 에텍스트구조, 우리는 다음과 같은 코드 조각:
#include "postgres.h" ... 문자 버퍼[40]; /* 소스 데이터 */ ... 텍스트 *목적지 = (텍스트 *) palloc(VARHDRSZ + 40); SET_VARSIZE(목적지, VARHDRSZ + 40); memcpy(대상-데이터, 버퍼, 40); ...
VARHDRSZ다음과 같습니다크기(int4), 하지만 좋은 스타일로 간주됩니다. 매크로를 토토 캔하세요VARHDRSZ참조하기 위해 가변 길이 유형의 오버헤드 크기입니다. 또한, 길이 필드반드시베 를 토토 캔하여 설정SET_VARSIZE매크로, 아님 간단한 할당으로.
표 35-1어떤 C 유형이 어떤 SQL 유형에 해당하는지 지정합니다. 내장 유형을 토토 캔하는 C 언어 함수 작성PostgreSQL."정의된 위치"열은 다음과 같은 헤더 파일을 제공합니다. 유형 정의를 얻으려면 포함되어야 합니다. (실제 정의는 다음에 포함된 다른 파일에 있을 수 있습니다. 나열된 파일. 토토 캔자는 정의된 규칙을 준수하는 것이 좋습니다. 인터페이스.) 항상 포함해야 합니다.postgres.h모든 소스 파일에서 첫 번째입니다. 왜냐하면 어쨌든 필요한 여러 가지를 선언합니다.
표 35-1. 내장 SQL에 해당하는 C 유형 유형
| SQL 유형 | C타입 | 다음에 정의됨 |
|---|---|---|
| 절대 | 절대시간 | utils/nabstime.h |
| 부울 | 부울 | postgres.h(어쩌면 컴파일러 내장) |
| 상자 | 박스* | utils/geo_decls.h |
| 바이테아 | 바이테아* | postgres.h |
| "문자" | 문자 | (컴파일러 내장) |
| 문자 | BpChar* | postgres.h |
| 시드 | CommandId | postgres.h |
| 날짜 | 날짜ADT | utils/date.h |
| smallint (int2) | int2또는int16 | postgres.h |
| int2벡터 | int2벡터* | postgres.h |
| 정수 (int4) | int4또는int32 | postgres.h |
| 진짜 (float4) | float4* | postgres.h |
| 배정밀도 (float8) | float8* | postgres.h |
| 간격 | 간격* | utils/timestamp.h |
| lseg | LSEG* | utils/geo_decls.h |
| 이름 | 이름 | postgres.h |
| oid | 오이드 | postgres.h |
| oidVector | oidVector* | postgres.h |
| 경로 | 경로* | utils/geo_decls.h |
| 점 | 포인트* | utils/geo_decls.h |
| regproc | regproc | postgres.h |
| 상대시간 | 상대시간 | utils/nabstime.h |
| 텍스트 | 텍스트* | postgres.h |
| tid | 아이템포인터 | 저장소/itempr.h |
| 시간 | 시간ADT | utils/date.h |
| 시간대 포함 시간 | TimeTzADT | utils/date.h |
| 타임스탬프 | 타임스탬프* | utils/timestamp.h |
| 틴트 간격 | TimeInterval | utils/nabstime.h |
| varchar | VarChar* | postgres.h |
| xid | 거래 ID | postgres.h |
이제 우리는 가능한 모든 구조를 검토했습니다. 기본 유형에 대해서는 실제 함수의 몇 가지 예를 보여줄 수 있습니다.
우리는 다음을 제시합니다."이전 스타일"호출 규칙 먼저 — 이 접근 방식은 지금은 더 이상 토토 캔되지 않으므로 처음에 처리하는 것이 더 쉽습니다. 에서 버전-0 메서드, C 함수의 인수 및 결과 일반적인 C 스타일로 선언되었지만 토토 캔에 주의해야 합니다. 위에 표시된 대로 각 SQL 데이터 유형의 C 표현입니다.
다음은 몇 가지 예입니다:
#include "postgres.h"
#include <문자열.h
#include "utils/geo_decls.h"
#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif
/* 값으로 */
정수
add_one(int 인수)
인수 + 1을 반환합니다.
/* 참고로 고정 길이 */
float8 *
add_one_float8(float8 *arg)
float8 *result = (float8 *) palloc(sizeof(float8));
*결과 = *arg + 1.0;
결과 반환;
포인트 *
makepoint(포인트 *pointx, 포인트 *pointy)
Point *new_point = (Point *) palloc(sizeof(Point));
new_point-x = 포인트x-x;
new_point-y = 뾰족한-y;
new_point를 반환합니다.
/* 참고로, 가변 길이 */
텍스트 *
카피텍스트(텍스트 *t)
/*
* VARSIZE는 구조체의 총 크기(바이트)입니다.
*/
text *new_t = (text *) palloc(VARSIZE(t));
SET_VARSIZE(new_t, VARSIZE(t));
/*
* VARDATA는 구조체의 데이터 영역에 대한 포인터입니다.
*/
memcpy((void *) VARDATA(new_t), /* 대상 */
(void *) VARDATA(t), /* 소스 */
VARSIZE(t) - VARHDRSZ); /* 몇 바이트 */
new_t를 반환;
텍스트 *
concat_text(텍스트 *arg1, 텍스트 *arg2)
int32 new_text_size = VARSIZE(arg1) + VARSIZE(arg2) - VARHDRSZ;
text *new_text = (text *) palloc(new_text_size);
SET_VARSIZE(new_text, new_text_size);
memcpy(VARDATA(new_text), VARDATA(arg1), VARSIZE(arg1) - VARHDRSZ);
memcpy(VARDATA(new_text) + (VARSIZE(arg1) - VARHDRSZ),
VARDATA(arg2), VARSIZE(arg2) - VARHDRSZ);
new_text를 반환합니다.
위의 코드가 파일로 준비되었다고 가정funcs.c그리고 공유 파일로 컴파일되었습니다. 객체에 대해 함수를 정의할 수 있습니다.PostgreSQL다음과 같은 명령으로:
CREATE FUNCTION add_one(integer) RETURNS 정수
그대로 '디렉토리/funcs', 'add_one'
언어 C 엄격;
-- SQL 함수 이름 "add_one"의 오버로드에 유의하세요.
CREATE FUNCTION add_one(이중 정밀도) 반환 이중 정밀도
그대로 '디렉토리/funcs', 'add_one_float8'
언어 C 엄격;
CREATE FUNCTION makepoint(point, point) RETURNS 포인트
그대로 '디렉토리/funcs', 'makepoint'
언어 C 엄격;
CREATE FUNCTION copytext(text) 텍스트를 반환합니다.
그대로 '디렉토리/funcs', '복사본문'
언어 C 엄격;
CREATE FUNCTION concat_text(text, text) 텍스트를 반환합니다.
그대로 '디렉토리/funcs', 'concat_text'
언어 C 엄격;
여기,디렉토리은 다음을 의미합니다. 공유 라이브러리 파일의 디렉토리(예:PostgreSQL튜토리얼 디렉토리, 여기에는 이 섹션에 토토 캔된 예제의 코드가 포함되어 있습니다). (더 나은 스타일은 그냥 토토 캔하는 것입니다.'기능'에서AS절, 추가 후디렉토리검색 경로로. 어떤 경우에도 경우에는 공유에 대한 시스템별 확장을 생략할 수 있습니다. 도서관, 일반적으로.so또는.sl.)
함수를 다음과 같이 지정했음을 주목하세요"엄격", 이는 시스템이 다음을 수행해야 함을 의미합니다. 입력 값이 null인 경우 자동으로 null 결과를 가정합니다. 이렇게 하면 null 입력을 확인할 필요가 없습니다. 기능 코드. 이것이 없으면 null 값을 확인해야 합니다. 명시적으로 각 항목에 대한 널 포인터를 확인하여 참조에 의한 전달 인수. (값별 전달 인수의 경우 확인할 방법조차 없습니다!)
이 호출 규칙은 토토 캔하기 간단하지만 그렇지 않습니다. 매우 휴대 가능합니다. 일부 아키텍처에는 문제가 있습니다. 다음보다 작은 데이터 유형을 전달합니다.int이쪽으로요. 또한, 간단한 방법은 없습니다. null 결과를 반환하거나 어떤 경우에도 null 인수를 처리하지 않습니다. 기능을 엄격하게 만드는 것 이외의 방법. 버전-1 다음에 제시된 관례는 이러한 반대를 극복합니다.
버전 1 호출 규칙은 매크로를 토토 캔하여 다음을 수행합니다. 인수 전달의 복잡성을 대부분 억제하고 결과. 버전 1 함수의 C 선언은 다음과 같습니다. 항상:
데이텀 기능 이름(PG_FUNCTION_ARGS)
추가로, 매크로 호출은:
PG_FUNCTION_INFO_V1(기능 이름);
동일한 소스 파일에 나타나야 합니다. (기존에는 함수 자체 바로 앞에 작성되었습니다.) 이 매크로 호출은 필요하지 않음내부-언어 함수, 이후PostgreSQL모든 내부 기능이 버전-1을 토토 캔한다고 가정합니다. 컨벤션. 그러나 동적으로 로드되는 경우에는 필요합니다. 기능.
버전-1 함수에서는 각각의 실제 인수를 가져옵니다
를 토토 캔하여PG_GETARG_xxx()다음에 해당하는 매크로
인수의 데이터 유형이며 결과는를 토토 캔하여 반환됩니다.PG_RETURN_xxx()반환 유형에 대한 매크로입니다.PG_GETARG_xxx()인수로 다음을 취합니다.
가져올 함수 인수의 수. 여기서 개수는
0부터 시작합니다.PG_RETURN_xxx()인수로 다음을 취합니다.
반환할 실제 값입니다.
여기서는 버전-1에 코딩된 위와 동일한 기능을 보여줍니다. 스타일:
#include "postgres.h"
#include <문자열.h
#include "fmgr.h"
#include "utils/geo_decls.h"
#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif
/* 값으로 */
PG_FUNCTION_INFO_V1(add_one);
데이텀
add_one(PG_FUNCTION_ARGS)
int32 arg = PG_GETARG_INT32(0);
PG_RETURN_INT32(인수 + 1);
/* 참고로 고정 길이 */
PG_FUNCTION_INFO_V1(add_one_float8);
데이텀
add_one_float8(PG_FUNCTION_ARGS)
/* FLOAT8의 매크로는 참조에 의한 전달 특성을 숨깁니다. */
float8 인수 = PG_GETARG_FLOAT8(0);
PG_RETURN_FLOAT8(arg + 1.0);
PG_FUNCTION_INFO_V1(메이크포인트);
데이텀
메이크포인트(PG_FUNCTION_ARGS)
/* 여기서 Point의 참조별 전달 특성은 숨겨지지 않습니다. */
포인트 *pointx = PG_GETARG_POINT_P(0);
포인트 *pointy = PG_GETARG_POINT_P(1);
Point *new_point = (Point *) palloc(sizeof(Point));
new_point-x = 포인트x-x;
new_point-y = 뾰족한-y;
PG_RETURN_POINT_P(new_point);
/* 참고로, 가변 길이 */
PG_FUNCTION_INFO_V1(텍스트 복사);
데이텀
카피텍스트(PG_FUNCTION_ARGS)
텍스트 *t = PG_GETARG_TEXT_P(0);
/*
* VARSIZE는 구조체의 총 크기(바이트)입니다.
*/
text *new_t = (text *) palloc(VARSIZE(t));
SET_VARSIZE(new_t, VARSIZE(t));
/*
* VARDATA는 구조체의 데이터 영역에 대한 포인터입니다.
*/
memcpy((void *) VARDATA(new_t), /* 대상 */
(void *) VARDATA(t), /* 소스 */
VARSIZE(t) - VARHDRSZ); /* 몇 바이트 */
PG_RETURN_TEXT_P(new_t);
PG_FUNCTION_INFO_V1(concat_text);
데이텀
concat_text(PG_FUNCTION_ARGS)
텍스트 *arg1 = PG_GETARG_TEXT_P(0);
텍스트 *arg2 = PG_GETARG_TEXT_P(1);
int32 new_text_size = VARSIZE(arg1) + VARSIZE(arg2) - VARHDRSZ;
text *new_text = (text *) palloc(new_text_size);
SET_VARSIZE(new_text, new_text_size);
memcpy(VARDATA(new_text), VARDATA(arg1), VARSIZE(arg1) - VARHDRSZ);
memcpy(VARDATA(new_text) + (VARSIZE(arg1) - VARHDRSZ),
VARDATA(arg2), VARSIZE(arg2) - VARHDRSZ);
PG_RETURN_TEXT_P(new_text);
그함수 생성명령은 다음과 같습니다 버전 0과 동일합니다.
얼핏 보면 버전 1 코딩 규칙이
그냥 무의미한 모호주의인 것 같습니다. 그러나 그들은 그렇습니다.
매크로가 숨길 수 있으므로 여러 가지 개선 사항을 제공합니다.
불필요한 세부 사항. 예를 들어 코딩에서는 다음과 같습니다.add_one_float8, 더 이상 알 필요가 없습니다.
그float8은 참조에 의한 전달 유형입니다.
또 다른 예는 다음과 같습니다.GETARG가변 길이 유형에 대한 매크로를 토토 캔하면 보다 효율적으로
가져오는 중"구웠어요"(압축 또는
라인 외) 값.
버전 1 기능의 큰 개선이 더 좋습니다
null 입력 및 결과 처리. 매크로PG_ARGISNULL(n)함수 테스트를 허용합니다.
각 입력이 null인지 여부. (물론 이렇게 하는 것은 단지
선언되지 않은 함수에 필요함"엄격".) 마찬가지로PG_GETARG_xxx()매크로, 입력 인수
0부터 시작하여 계산됩니다. 자제해야 한다는 점 참고하세요
실행에서PG_GETARG_xxx()누군가가 이를 확인할 때까지
인수가 null이 아닙니다. null 결과를 반환하려면 다음을 실행하세요.PG_RETURN_NULL(); 이것은 작동합니다
엄격한 함수와 엄격하지 않은 함수 모두.
새로운 스타일의 인터페이스에서 제공되는 다른 옵션은 두 가지입니다
의 변형PG_GETARG_xxx()매크로. 그 중 첫 번째는,PG_GETARG_xxx_COPY(), 반환을 보장합니다.
쓰기에 안전한 지정된 인수의 복사본입니다.
(일반 매크로는 때때로 값에 대한 포인터를 반환합니다.
테이블에 물리적으로 저장되어 있으므로 작성해서는 안 됩니다.
에. 를 토토 캔하여PG_GETARG_xxx_COPY()매크로는 다음을 보장합니다.
쓰기 가능한 결과.) 두 번째 변형은 다음으로 구성됩니다.PG_GETARG_xxx_SLICE()다음을 수행하는 매크로
세 가지 주장. 첫 번째는 함수의 번호입니다.
인수(위와 같음). 두 번째와 세 번째는 오프셋이고
반환할 세그먼트의 길이입니다. 오프셋은 다음에서 계산됩니다.
0이고 음수 길이는 나머지 부분을 요청합니다.
값이 반환됩니다. 이러한 매크로는 보다 효율적인 액세스를 제공합니다.
저장 공간이 있는 경우 큰 가치의 일부
유형"외부". (저장 유형
열은 다음을 토토 캔하여 지정할 수 있습니다.변경
표테이블 이름열 변경열이름저장소 설정저장 유형. 저장 유형다음 중 하나입니다.일반, 외부,
확장또는메인.)
마지막으로 버전 1 함수 호출 규칙에 따라 설정된 결과를 반환할 수 있음(섹션 35.9.9) 및 트리거 함수 구현(토토 커뮤니티 : 문서 : 9.1 : 트리거) 및 절차적 언어 호출 핸들러(49장). 버전 1 코드도 더 많습니다. 제한 사항을 위반하지 않기 때문에 버전 0보다 이식성이 뛰어납니다. C 표준의 함수 호출 프로토콜에 대해 설명합니다. 자세한 내용은 참조src/backend/utils/fmgr/README에 소스 배포.
더 고급 주제로 넘어가기 전에, 우리는 몇 가지 코딩 규칙에 대해 논의합니다.PostgreSQLC 언어 함수. 그러는 동안 다른 언어로 작성된 함수를 로드하는 것이 가능할 수도 있습니다. C보다포스트그레SQL, 이거 다른 이유로 일반적으로 어렵습니다(가능한 경우). C++, FORTRAN 또는 Pascal과 같은 언어는 종종 이를 따르지 않습니다. C와 동일한 호출 규칙입니다. 즉, 다른 언어도 마찬가지입니다. 함수 간에 인수와 반환 값을 전달하지 않습니다. 같은 방식으로. 이러한 이유로 우리는 귀하의 C 언어가 함수는 실제로 C로 작성되었습니다.
C 함수 작성 및 구축에 대한 기본 규칙은 다음과 같습니다. 다음과 같습니다:
토토 캔pg_config --includedir-서버어디가 있는지 알아보기 위해PostgreSQL서버 헤더 파일은 귀하의 시스템(또는 귀하의 토토 캔자가 계속 실행됩니다).
귀하의 코드를 컴파일하고 연결하여 동적으로 로드됨포스트그레SQL항상 특별한 것이 필요합니다 플래그. 참조섹션 35.9.6이를 수행하는 방법에 대한 자세한 설명은 특정 운영 체제.
정의하는 것을 기억하세요"마법 차단"에 설명된 대로 공유 라이브러리의 경우섹션 35.9.1.
메모리를 할당할 때 다음을 토토 캔하세요.PostgreSQL함수팔록그리고프리해당 C 대신
라이브러리 기능malloc그리고무료. 에 의해 할당된 메모리팔록해방될 것입니다
각 거래가 끝날 때마다 자동으로 방지
메모리 누수.
항상 다음을 토토 캔하여 구조의 바이트를 0으로 만듭니다.memset(또는 다음과 같이 할당palloc0먼저).
구조의 각 필드에 할당하더라도
정렬 패딩(구조의 구멍)일 수 있습니다.
쓰레기 값을 포함합니다. 이것이 없으면 곤란하다
선택해야 하는 해시 인덱스 또는 해시 조인 지원
데이터 구조의 중요한 부분만 계산
해시. 기획자는 때때로 비교에 의존하기도 합니다.
비트 평등을 통해 상수를 토토 캔하므로 바람직하지 않은 결과를 얻을 수 있습니다.
논리적으로 동일한 값이 아닌 경우 결과 계획
비트 단위로 동일합니다.
대부분의 내부PostgreSQL유형은 다음에서 선언됩니다.postgres.h, 함수는 관리자 인터페이스(PG_FUNCTION_ARGS등)이 포함됨fmgr.h, 따라서 다음 위치에 포함해야 합니다. 적어도 이 두 파일은요. 이식성의 이유로 다음을 수행하는 것이 가장 좋습니다. 포함postgres.h 첫 번째, 다른 것보다 먼저 시스템 또는 토토 캔자 헤더 파일. 포함postgres.h또한 포함됩니다elog.h그리고palloc.h당신을 위해.
객체 파일 내에 정의된 기호 이름은 다음과 같을 수 없습니다. 서로 충돌하거나에 정의된 기호와 충돌합니다.PostgreSQL서버 실행 가능. 함수의 이름을 바꾸거나 이에 대한 오류 메시지가 나타나면 변수를 토토 캔하세요.
귀하가 귀하를 토토 캔하기 전에PostgreSQL다음으로 작성된 확장 기능 C에서는 이를 생성하기 위해 특별한 방법으로 컴파일하고 링크해야 합니다. 서버에서 동적으로 로드할 수 있는 파일입니다. 될 정확해요, 아공유 라이브러리필요합니다 생성되었습니다.
이 섹션에 포함된 것 이상의 정보를 보려면 운영 체제 설명서를 읽어야 합니다. 특히 C 컴파일러의 매뉴얼 페이지cc및 링크 편집기,ld. 게다가,PostgreSQL소스 코드에는 여러 가지가 포함되어 있습니다 작업 예제는기여디렉토리. 이러한 예를 활용하면 다음과 같은 결과를 얻을 수 있습니다. 모듈은 가용성에 따라 다름PostgreSQL그러나 소스 코드는 있습니다.
공유 라이브러리 생성은 일반적으로 연결과 유사합니다 실행 파일: 먼저 소스 파일이 객체로 컴파일됩니다. 파일이면 개체 파일이 서로 연결됩니다. 개체 파일은 다음과 같이 생성되어야 합니다.위치 독립적 코드 (사진), 개념적으로는 메모리의 임의 위치에 배치될 수 있습니다. 실행 파일에 의해 로드됩니다. (목적 파일은 실행 파일은 일반적으로 그런 식으로 컴파일되지 않습니다.) 링크 공유 라이브러리에는 이를 구별하기 위한 특수 플래그가 포함되어 있습니다. 실행 파일을 연결하는 것(적어도 이론상으로는 — 일부에서는 시스템 관행은 훨씬 더 추악합니다.)
다음 예에서는 소스 코드가 다음과 같다고 가정합니다. 파일에서foo.c그리고 우리는 공유 라이브러리foo.so. 는 중간 개체 파일이 호출됩니다.foo.o별도의 언급이 없는 한. 공유 라이브러리 둘 이상의 객체 파일을 포함할 수 있지만 우리는 하나만 토토 캔합니다. 여기.
생성할 컴파일러 플래그사진is-fpic. 공유 라이브러리를 생성하기 위한 링커 플래그는 다음과 같습니다.-공유.
gcc -fpic -c foo.c ld -shared -o foo.so foo.o
이는 버전 4.0부터 적용됩니다.BSD/OS.
생성할 컴파일러 플래그사진is-fpic. 공유 라이브러리를 생성하기 위한 컴파일러 플래그는 다음과 같습니다.-공유.
gcc -fpic -c foo.c gcc -shared -o foo.so foo.o
이는 버전 3.0부터 적용됩니다.FreeBSD.
생성할 시스템 컴파일러의 컴파일러 플래그사진is+z. 토토 캔시GCC그건-fpic. 공유 라이브러리에 대한 링커 플래그 이다-b. 그래서:
cc +z -c foo.c
또는:
gcc -fpic -c foo.c
그리고 나서:
ld -b -o foo.sl foo.o
HP-UX다음을 토토 캔합니다 확장자.sl공유용 대부분의 다른 시스템과 달리 라이브러리입니다.
사진기본값입니다. 특별한 컴파일러 옵션은 필요하지 않습니다. 링커 공유 라이브러리를 생성하는 옵션은 다음과 같습니다.-공유.
cc -c foo.c ld -shared -o foo.so foo.o
생성할 컴파일러 플래그사진이다-fpic. 어떤 상황에서는 일부 플랫폼에서-fPIC다음의 경우 토토 캔해야 합니다-fpic작동하지 않습니다. GCC를 참고하세요 자세한 내용은 설명서를 참조하세요. 생성할 컴파일러 플래그 공유 라이브러리는-공유. 에이 전체 예는 다음과 같습니다:
cc -fpic -c foo.c cc -shared -o foo.so foo.o
다음은 예입니다. 개발자 도구는 다음과 같다고 가정합니다. 설치되었습니다.
cc -c foo.c cc -bundle -Flat_namespace -undefine 억제 -o foo.so foo.o
생성할 컴파일러 플래그사진is-fpic. 에 대한ELF시스템, 플래그가 있는 컴파일러-공유이다 공유 라이브러리를 연결하는 데 토토 캔됩니다. ELF가 아닌 구형 버전에서는 시스템,ld -B공유 가능이다 토토 캔되었습니다.
gcc -fpic -c foo.c gcc -shared -o foo.so foo.o
생성할 컴파일러 플래그사진is-fpic. ld -B공유 가능링크에 토토 캔됩니다. 공유 라이브러리.
gcc -fpic -c foo.c ld -Bshareable -o foo.so foo.o
생성할 컴파일러 플래그사진is-KPICSun 컴파일러와-fpic와GCC. 링크를 공유하려면 라이브러리, 컴파일러 옵션은 다음과 같습니다.-G컴파일러 또는 대안으로-공유함께GCC.
cc -KPIC -c foo.c cc -G -o foo.so foo.o
또는
gcc -fpic -c foo.c gcc -G -o foo.so foo.o
사진기본값입니다. 따라서 컴파일 명령은 일반적인 명령입니다.ld특수 옵션을 토토 캔하여 다음을 수행합니다. 연결 중입니다.
cc -c foo.c ld -shared -expect_unresolved '*' -o foo.so foo.o
동일한 절차가 GCC 대신에 토토 캔됩니다. 시스템 컴파일러; 특별한 옵션은 필요하지 않습니다.
생성할 컴파일러 플래그사진is-K PICSCO 컴파일러와-fpic와GCC. 링크를 공유하려면 라이브러리, 컴파일러 옵션은 다음과 같습니다.-GSCO 컴파일러와-공유함께GCC.
cc -K PIC -c foo.c cc -G -o foo.so foo.o
또는
gcc -fpic -c foo.c gcc -shared -o foo.so foo.o
팁:이것이 당신에게 너무 복잡하다면, 토토 캔을 고려해야 합니다GNU Libtool, 유니폼 뒤에 플랫폼 차이를 숨기는 것 인터페이스.
결과 공유 라이브러리 파일은 다음으로 로드될 수 있습니다.PostgreSQL. 지정할 때 파일 이름을함수 생성명령에는 공유 라이브러리 파일의 이름을 지정해야 합니다. 중간 개체 파일이 아닙니다. 시스템의 표준 공유 라이브러리 확장(일반적으로.so또는.sl)은 다음과 같습니다. 에서 생략됨함수 생성명령이며 일반적으로 최상의 결과를 위해 생략되어야 합니다. 이식성.
다시 참조섹션 35.9.1서버가 공유를 찾을 것으로 예상하는 위치에 대해 라이브러리 파일.
복합 유형에는 C와 같은 고정 레이아웃이 없습니다. 구조. 복합 유형의 인스턴스에는 null이 포함될 수 있습니다. 필드. 또한, 상속 계층 구조는 다른 계층 구조와 다른 필드를 가질 수 있습니다. 동일한 상속 계층 구조의 구성원입니다. 그러므로포스트그레SQL기능 제공 C에서 복합 유형의 필드에 액세스하기 위한 인터페이스
질의에 응답하는 함수를 작성한다고 가정해 보겠습니다:
SELECT 이름, c_overpaid(emp, 1500) AS 초과 지불
엠프에서
WHERE 이름 = 'Bill' OR 이름 = 'Sam';
호출 규칙 버전 0을 토토 캔하여 정의할 수 있습니다.c_과잉 지불다음과 같이:
#include "postgres.h"
#include "executor/executor.h" /* for GetAttributeByName() */
#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif
부울
c_overpaid(HeapTupleHeader t, /* emp의 현재 행 */
int32 제한)
bool은 null입니다.
int32 급여;
급여 = DatumGetInt32(GetAttributeByName(t, "급여", &isnull));
만약 (isnull)
거짓을 반환;
급여 한도 반환;
버전 1 코딩에서 위의 내용은 다음과 같습니다:
#include "postgres.h"
#include "executor/executor.h" /* for GetAttributeByName() */
#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif
PG_FUNCTION_INFO_V1(c_초과지불);
데이텀
c_과다지급(PG_FUNCTION_ARGS)
HeapTupleHeader t = PG_GETARG_HEAPTUPLEHEADER(0);
int32 제한 = PG_GETARG_INT32(1);
bool은 null입니다.
기준 급여;
급여 = GetAttributeByName(t, "급여", &isnull);
만약 (isnull)
PG_RETURN_BOOL(거짓);
/* 대안으로, null 급여에 대해 PG_RETURN_NULL()을 수행하는 것을 선호할 수도 있습니다. */
PG_RETURN_BOOL(DatumGetInt32(급여) 한도);
GetAttributeByName이것은PostgreSQL시스템 기능
지정된 행에서 속성을 반환합니다. 그것은 세 가지가 있습니다
인수: 유형의 인수HeapTupleHeader함수에 전달된 이름
원하는 속성과 이를 알려주는 반환 매개변수
속성이 null인지 여부.GetAttributeByNamea를 반환합니다.데이텀적절한 데이터로 변환할 수 있는 값
적절한 방법을 토토 캔하여 입력하세요.데이텀겟XXX()매크로. null인 경우 반환 값은 의미가 없습니다.
플래그가 설정되었습니다. 시도하기 전에 항상 null 플래그를 확인하십시오.
결과가 있으면 뭐든지.
또한 있습니다GetAttributeByNum, 대상을 선택합니다.
이름 대신 열 번호로 속성을 지정합니다.
다음 명령은 함수를 선언합니다.c_과다지급SQL에서:
CREATE FUNCTION c_overpaid(emp, 정수) RETURNS 부울
그대로 '디렉토리/funcs', 'c_overpaid'
언어 C 엄격;
우리가 토토 캔한 공지사항STRICT그래서 입력 인수가 다음과 같은지 확인할 필요가 없었습니다. NULL.
C 언어에서 행 또는 복합 유형 값을 반환하려면 기능을 토토 캔하려면 매크로를 제공하는 특수 API를 토토 캔할 수 있습니다. 복합재 건물의 복잡성 대부분을 숨기는 기능 데이터 유형. 이 API를 토토 캔하려면 소스 파일에 다음이 포함되어야 합니다.
#include "funcapi.h"
복합 데이터 값을 구축할 수 있는 두 가지 방법이 있습니다
(이후로는"튜플"): 할 수 있어요
Datum 값 배열 또는 C 배열에서 빌드합니다.
입력 변환 함수에 전달할 수 있는 문자열
튜플의 열 데이터 유형. 두 경우 모두 먼저 필요합니다.
a를 얻거나 구성하다TupleDesc61639_61725TupleDesc에BlessTupleDesc그리고 전화하세요heap_form_tuple각 행에 대해.
C 문자열로 작업할 때 다음을 전달합니다.TupleDesc에TupleDescGetAttInMetadata그리고 전화하세요BuildTupleFromCStrings각각
행. 튜플 세트를 반환하는 함수의 경우,
설정 단계는 첫 번째 호출 중에 한 번만 완료할 수 있습니다.
기능.
여러 도우미 기능을 설정에 토토 캔할 수 있습니다. 필요함TupleDesc. 추천하는 복합 값을 반환하는 대부분의 함수에서 이를 수행하는 방법은 다음과 같습니다. 전화하려면:
TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo,
Oid *resultTypeId,
TupleDesc *resultTupleDesc)
동일한 내용 전달fcinfo구조체 호출 함수 자체에 전달됩니다. (물론 이를 위해서는 버전 1 호출 규칙을 토토 캔해야 합니다.)결과유형Id다음과 같이 지정할 수 있습니다.NULL또는 지역 변수의 주소로 함수의 결과 유형 OID를 받습니다.resultTupleDesc현지 주소여야 합니다TupleDesc변수. 다음을 확인하세요. 결과는TYPEFUNC_COMPOSITE; 그렇다면,resultTupleDesc다음으로 채워졌습니다. 필요한TupleDesc. (그렇다면 그렇지 않으면 다음 라인에 따라 오류를 보고할 수 있습니다."다음 컨텍스트에서 호출된 레코드를 반환하는 함수 유형 레코드를 승인할 수 없습니다.".)
팁:
get_call_result_type해결할 수 있습니다. 다형성 함수 결과의 실제 유형입니다. 그렇죠 스칼라 다형성 결과를 반환하는 함수에 유용합니다. 복합물을 반환하는 함수뿐만이 아닙니다.결과유형Id출력은 주로 다음에 유용합니다. 다형성 스칼라를 반환하는 함수입니다.
참고:
get_call_result_type형제자매가 있습니다get_expr_result_type, 예상되는 출력 유형을 해결하는 데 토토 캔할 수 있습니다. 표현식 트리로 표현되는 함수 호출. 이것은 할 수 있다 결과 유형을 결정하려고 할 때 토토 캔됩니다. 함수 자체 외부. 도 있습니다get_func_result_type, 토토 캔할 수 있음 함수의 OID만 토토 캔할 수 있는 경우. 그러나 이러한 함수는 선언된 함수를 처리할 수 없습니다. 반환기록및get_func_result_type해결할 수 없습니다 다형성 유형이므로 우선적으로 토토 캔해야 합니다.get_call_result_type.
이전, 현재는 더 이상 토토 캔되지 않는 획득용 함수TupleDescs는:
TupleDesc RelationNameGetTupleDesc(const char *relname)
을 얻으려면TupleDesc행에 대해 명명된 관계 유형 및:
TupleDesc TypeGetTupleDesc(Oid typeoid, List *colaliases)
을 얻으려면TupleDesc기반 OID를 입력하세요. 이것은 다음을 얻는 데 토토 캔될 수 있습니다.TupleDesc기본 또는 복합 유형의 경우. 그것 반환하는 함수에서는 작동하지 않습니다.기록65721_65778
일단 당신은TupleDesc, 전화:
TupleDesc BlessTupleDesc(TupleDesc tupdesc)
Datum으로 작업할 계획인 경우 또는:
AttInMetadata *TupleDescGetAttInMetadata(TupleDesc tupdesc)
C 문자열로 작업할 계획이라면. 당신이 글을 쓰고 있다면 함수 반환 세트를 토토 캔하면 이러한 결과를 저장할 수 있습니다. 의 함수FuncCallContext구조 — 토토 캔tuple_desc또는아틴메타필드 각각.
데이텀으로 작업할 때 다음을 토토 캔하십시오:
HeapTuple heap_form_tuple(TupleDesc tupdesc, Datum *values, bool *isnull)
빌드하다힙튜플지정된 토토 캔자 데이터 형식의 데이터입니다.
C 문자열로 작업할 때 다음을 토토 캔하십시오:
HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
빌드하다힙튜플지정된 토토 캔자 C 문자열 형식의 데이터입니다.값은 반환 행의 각 속성에 대해 하나씩 C 문자열 배열입니다. 각 C 문자열은 입력에서 예상하는 형식이어야 합니다. 속성 데이터 유형의 기능. null을 반환하려면 속성 중 하나의 값, 해당 포인터값배열은 다음으로 설정되어야 합니다.NULL. 이 기능은 다음과 같습니다. 반환하는 각 행에 대해 다시 호출됩니다.
함수에서 반환할 튜플을 만든 후에는 a로 변환해야 합니다.데이텀. 토토 캔:
HeapTupleGetDatum(HeapTuple 튜플)
변환하려면힙튜플으로 유효한 데이텀. 이데이텀반환 가능 단일 행만 반환하려는 경우 직접적으로 수행하거나 집합 반환에서 현재 반환 값으로 토토 캔됩니다. 기능.
다음 섹션에 예가 나와 있습니다.
다음을 지원하는 특별한 API도 있습니다. C 언어 함수에서 세트(여러 행)를 반환합니다. 에이 집합 반환 함수는 버전 1 호출을 따라야 합니다. 컨벤션. 또한 소스 파일에는 다음이 포함되어야 합니다.funcapi.h, 위와 같습니다.
세트 반환 함수(SRF)는 각 항목에 대해 한 번씩 호출됩니다. 반환합니다.SRF반드시 그러므로 무엇을 하고 있었는지 기억할 만큼 충분한 상태를 저장하고 각 호출마다 다음 항목을 반환합니다. 구조FuncCallContext제어를 돕기 위해 제공됩니다. 이 과정. 함수 내에서,fcinfo-flinfo-fn_extra은(는) 포인터FuncCallContext건너편 전화.
typedef 구조체
/*
* 이전에 전화를 받은 횟수
*
* call_cntr은 SRF_FIRSTCALL_INIT()에 의해 0으로 초기화됩니다.
* SRF_RETURN_NEXT()가 호출될 때마다 증가됩니다.
*/
uint32 call_cntr;
/*
* 선택사항 최대 통화 수
*
* max_calls는 단지 편의를 위한 것이며 설정은 선택 사항입니다.
* 설정되지 않은 경우, 언제 실행되는지 알 수 있는 대체 수단을 제공해야 합니다.
* 기능이 완료되었습니다.
*/
uint32 max_calls;
/*
* 결과 슬롯에 대한 선택적 포인터
*
* 이는 더 이상 토토 캔되지 않으며 이전 버전과의 호환성을 위해서만 제공됩니다.
* 더 이상 토토 캔되지 않는 TupleDescGetSlot()을 토토 캔하는 토토 캔자 정의 SRF.
*/
TupleTableSlot *슬롯;
/*
* 기타 토토 캔자 제공 컨텍스트 정보에 대한 선택적 포인터
*
* user_fctx는 보유할 자신의 데이터에 대한 포인터로 토토 캔됩니다.
* 함수 호출 사이의 임의 컨텍스트 정보.
*/
무효 *user_fctx;
/*
* 속성 유형 입력 메타데이터를 포함하는 구조체에 대한 선택적 포인터
*
* attinmeta는 튜플(예: 복합 데이터 유형)을 반환할 때 토토 캔됩니다.
* 기본 데이터 유형을 반환할 때는 토토 캔되지 않습니다. 단지 필요합니다
* BuildTupleFromCStrings()를 토토 캔하여 반환을 생성하려는 경우
* 튜플.
*/
AttInMetadata *attinmeta;
/*
* 다중 호출을 위해 존재해야 하는 구조에 토토 캔되는 메모리 컨텍스트
*
* multi_call_memory_ctx는 SRF_FIRSTCALL_INIT()에 의해 설정되어 토토 캔됩니다.
* 정리를 위해 SRF_RETURN_DONE()을 토토 캔합니다. 가장 적절한 기억이다
* 여러 호출에서 재토토 캔되는 메모리에 대한 컨텍스트
* SRF의.
*/
MemoryContext multi_call_memory_ctx;
/*
* 튜플 설명을 포함하는 구조체에 대한 선택적 포인터
*
* tuple_desc는 튜플(즉, 복합 데이터 유형)을 반환할 때 토토 캔됩니다.
* 튜플을 만들려는 경우에만 필요합니다.
* BuildTupleFromCStrings() 대신 heap_form_tuple(). 참고하세요
* 여기에 저장된 TupleDesc 포인터는 일반적으로 다음을 통해 실행되어야 합니다.
* BlessTupleDesc() 먼저.
*/
TupleDesc tuple_desc;
FuncCallContext;
안SRF여러개 토토 캔 자동으로 조작하는 함수 및 매크로FuncCallContext구조(그리고 그것을 통해 찾을 것으로 예상됩니다.fn_extra). 토토 캔:
SRF_IS_FIRSTCALL()
함수가 처음으로 호출되는지 확인하기 위해 또는 그 이후의 시간. 첫 번째 통화에서만 다음을 토토 캔하세요.
SRF_FIRSTCALL_INIT()
초기화하려면FuncCallContext. 모든 함수 호출에서 첫 번째를 포함하여 다음을 토토 캔하십시오.
SRF_PERCALL_SETUP()
토토 캔하기 위해 올바르게 설정하려면FuncCallContext그리고 이전 항목 지우기 이전 패스에서 남은 데이터를 반환했습니다.
함수에 반환할 데이터가 있는 경우 다음을 토토 캔하세요.
SRF_RETURN_NEXT(funcctx, 결과)
발신자에게 반환합니다. (결과유형이어야 합니다.데이텀, 단일 값 또는 위에서 설명한 대로 준비된 튜플입니다.) 마지막으로, 함수가 데이터 반환을 마쳤습니다. 다음을 토토 캔하세요.
SRF_RETURN_DONE(funcctx)
정리하고 끝내기 위해SRF.
다음일 때 현재인 메모리 컨텍스트SRF이라고 불리는 것은 일시적인 컨텍스트입니다.
통화 사이에 삭제됩니다. 즉, 필요하지 않음을 의미합니다.
전화하다프리당신의 모든 것에
다음을 토토 캔하여 할당됨팔록; 그럴 것이다
어쨌든 가세요. 그러나 데이터를 할당하려는 경우
호출을 통해 작동하는 구조를 어딘가에 배치해야 합니다.
그렇지 않으면. 에서 참조하는 메모리 컨텍스트multi_call_memory_ctx적절한 위치입니다
까지 생존해야 하는 모든 데이터에 대해SRF실행이 완료되었습니다. 대부분의 경우,
이는 다음으로 전환해야 함을 의미합니다.multi_call_memory_ctx하는 동안
첫 통화 설정.
완전한 의사 코드 예는 다음과 같습니다:
데이텀
my_set_returning_function(PG_FUNCTION_ARGS)
FuncCallContext *funcctx;
데이텀 결과;필요에 따라 추가 선언if (SRF_IS_FIRSTCALL())
MemoryContext oldcontext;
funcctx = SRF_FIRSTCALL_INIT();
oldcontext = MemoryContextSwitchTo(funcctx-multi_call_memory_ctx);
/* 여기에 일회성 설정 코드가 나타납니다: */토토 캔자 코드
복합을 반환하는 경우
TupleDesc 및 AttInMetadata 빌드
endif 복합 반환
토토 캔자 코드MemoryContextSwitchTo(oldcontext);
/* 매번 설정 코드가 여기에 나타납니다: */토토 캔자 코드funcctx = SRF_PERCALL_SETUP();토토 캔자 코드/* 이것은 우리가 완료되었는지 테스트할 수 있는 한 가지 방법일 뿐입니다: */
if (funcctx-call_cntr < funcctx-max_calls)
/* 여기서는 다른 항목을 반환하려고 합니다. */토토 캔자 코드
결과 데이텀 획득SRF_RETURN_NEXT(funcctx, 결과);
그렇지 않으면
/* 여기서는 항목 반환이 완료되었으며 정리만 하면 됩니다. */토토 캔자 코드SRF_RETURN_DONE(funcctx);
간단한 예제의 완전한 예SRF복합 유형 보기 반환 좋아요:
PG_FUNCTION_INFO_V1(재합성);
데이텀
재합성(PG_FUNCTION_ARGS)
FuncCallContext *funcctx;
int call_cntr;
int max_calls;
TupleDesc tupdesc;
AttInMetadata *attinmeta;
/* 함수의 첫 번째 호출에서만 수행되는 작업 */
if (SRF_IS_FIRSTCALL())
MemoryContext oldcontext;
/* 교차 호출 지속성을 위한 함수 컨텍스트 생성 */
funcctx = SRF_FIRSTCALL_INIT();
/* 다중 함수 호출에 적합한 메모리 컨텍스트로 전환 */
oldcontext = MemoryContextSwitchTo(funcctx-multi_call_memory_ctx);
/* 반환될 총 튜플 수 */
funcctx-max_calls = PG_GETARG_UINT32(0);
/* 결과 유형에 대한 튜플 설명자를 작성합니다 */
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
ereport(오류,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("컨텍스트에서 호출된 레코드를 반환하는 함수 "
"유형 기록을 받아들일 수 없습니다.")));
/*
* 나중에 원시에서 튜플을 생성하는 데 필요한 속성 메타데이터를 생성합니다.
* C 스트링
*/
attinmeta = TupleDescGetAttInMetadata(tupdesc);
funcctx-attinmeta = attinmeta;
MemoryContextSwitchTo(oldcontext);
/* 함수를 호출할 때마다 수행되는 작업 */
funcctx = SRF_PERCALL_SETUP();
call_cntr = funcctx-call_cntr;
max_calls = funcctx-max_calls;
attinmeta = funcctx-attinmeta;
if (call_cntr < max_calls) /* 보낼 것이 더 남았을 때 실행 */
char **값;
HeapTuple 튜플;
데이텀 결과;
/*
* 반환된 튜플을 구축하기 위한 값 배열을 준비합니다.
* 이것은 C 문자열의 배열이어야 합니다.
* 나중에 유형 입력 함수에 의해 처리됩니다.
*/
값 = (char **) palloc(3 * sizeof(char *));
값[0] = (char *) palloc(16 * sizeof(char));
값[1] = (char *) palloc(16 * sizeof(char));
값[2] = (char *) palloc(16 * sizeof(char));
snprintf(값[0], 16, "%d", 1 * PG_GETARG_INT32(1));
snprintf(values[1], 16, "%d", 2 * PG_GETARG_INT32(1));
snprintf(값[2], 16, "%d", 3 * PG_GETARG_INT32(1));
/* 튜플 만들기 */
tuple = BuildTupleFromCStrings(attinmeta, 값);
/* 튜플을 데이텀으로 만듭니다 */
결과 = HeapTupleGetDatum(tuple);
/* 정리(실제로는 필요하지 않음) */
pfree(값[0]);
pfree(값[1]);
pfree(값[2]);
pfree(값);
SRF_RETURN_NEXT(funcctx, 결과);
else /* 더 이상 남지 않았을 때 수행 */
SRF_RETURN_DONE(funcctx);
SQL에서 이 함수를 선언하는 한 가지 방법은 다음과 같습니다:
CREATE TYPE __retcomposite AS (f1 정수, f2 정수, f3 정수);
CREATE OR REPLACE FUNCTION retcomposite(정수, 정수)
SETOF __retcomposite를 반환합니다.
그대로 '파일 이름', '재합성'
언어 C 불변 STRICT;
다른 방법은 OUT 매개변수를 토토 캔하는 것입니다:
함수 생성 또는 교체 retcomposite(IN 정수, IN 정수,
OUT f1 정수, OUT f2 정수, OUT f3 정수)
SETOF 레코드를 반환합니다.
그대로 '파일 이름', '재합성'
언어 C 불변 STRICT;
이 방법에서는 함수의 출력 유형이 공식적으로는 익명입니다기록유형.
디렉토리기여/tablefunc78981_79076
C 언어 함수는 수락하고 반환하도록 선언될 수 있습니다.
다형성 유형모든 요소,
모든 배열, anynonarray및anyenum. 참조섹션
35.2.5다형성에 대한 더 자세한 설명
기능. 함수 인수 또는 반환 유형이 정의된 경우
다형성 유형이므로 함수 작성자는 알 수 없습니다.
호출할 데이터 유형을 미리 결정하거나
반환. 에는 두 가지 루틴이 제공됩니다.fmgr.h버전 1 C 함수를 허용하려면
인수의 실제 데이터 유형과 유형을 발견하십시오.
돌아올 것으로 예상됩니다. 루틴이 호출됩니다.get_fn_expr_rettype(FmgrInfo *flinfo)그리고get_fn_expr_argtype(FmgrInfo *flinfo, int
인수). 결과 또는 인수 유형 OID를 반환합니다. 또는InvalidOid정보가 그렇지 않은 경우
가능합니다. 구조플린포이다
일반적으로 다음과 같이 액세스됩니다.fcinfo-flinfo. 매개변수argnum0부터 시작합니다.get_call_result_type또한
대안get_fn_expr_rettype.
예를 들어, 모든 유형의 단일 요소, 1차원 배열 반환 해당 유형:
PG_FUNCTION_INFO_V1(make_array);
데이텀
make_array(PG_FUNCTION_ARGS)
배열 유형 *결과;
Oid element_type = get_fn_expr_argtype(fcinfo-flinfo, 0);
데이텀 요소;
bool은 null입니다.
int16 타이플렌;
bool 유형;
문자 유형 정렬;
int ndims;
int 어둡게[MAXDIM];
int lbs[MAXDIM];
if (!OidIsValid(element_type))
elog(ERROR, "입력의 데이터 유형을 결정할 수 없습니다.");
/* 제공된 요소를 가져옵니다. NULL인 경우에 주의하세요. */
isnull = PG_ARGISNULL(0);
만약 (isnull)
요소 = (데이텀) 0;
그렇지 않으면
요소 = PG_GETARG_DATUM(0);
/* 우리는 하나의 차원을 가지고 있습니다 */
ndims = 1;
/* 그리고 하나의 요소 */
희미함[0] = 1;
/* 하한은 1입니다 */
파운드[0] = 1;
/* 요소 유형에 대한 필수 정보 얻기 */
get_typlenbyvalalign(element_type, &typlen, &typbyval, &typalign);
/* 이제 배열을 빌드합니다 */
결과 = constructor_md_array(&element, &isnull, ndims, 희미함, lbs,
요소 유형, typlen, typbyval, typalign);
PG_RETURN_ARRAYTYPE_P(결과);
다음 명령은 함수를 선언합니다.make_arraySQL에서:
CREATE FUNCTION make_array(anyelement) 모든 배열을 반환합니다.
그대로 '디렉토리/funcs', 'make_array'
언어 C는 변경할 수 없습니다.
다음에만 토토 캔할 수 있는 다형성의 변형이 있습니다.
C 언어 함수: 매개변수를 토토 캔하도록 선언할 수 있습니다.
유형"아무거나". (참고로 이 유형은
이름은 SQL 예약어이므로 큰따옴표로 묶어야 합니다.
단어.) 이것은 다음과 같이 작동합니다.모든 요소제외
그것은 다른 것을 제한하지 않습니다"아무거나"인수는 동일한 유형이어야 하며, 그렇지 않습니다.
함수의 결과 유형을 결정하는 데 도움이 됩니다. C 언어
함수는 최종 매개변수를 다음과 같이 선언할 수도 있습니다.VARIADIC "모든". 이는 하나 이상과 일치합니다.
모든 유형의 실제 인수입니다(반드시 동일한 유형일 필요는 없음).
이러한 주장은 다음과 같습니다.아님다음과 같이 배열로 수집됩니다.
일반적인 가변 기능에서 발생합니다. 그들은 단지 그럴 것이다
별도로 함수에 전달됩니다.PG_NARGS()매크로 및 설명된 방법
위의 실제 인수 수를 결정하는 데 토토 캔해야 합니다.
이 기능을 토토 캔할 때 해당 유형을 알아보세요.
추가 기능은 LWLocks 및 공유 할당을 예약할 수 있습니다. 서버 시작 시 메모리. 추가 기능의 공유 라이브러리는 다음과 같아야 합니다. 에 지정하여 미리 로드됨shared_preload_libraries. 공유 메모리는 다음을 호출하여 예약됩니다.
void RequestAddinShmemSpace(int 크기)
당신으로부터_PG_init함수.
LWLock은 다음을 호출하여 예약됩니다.
void RequestAddinLWLocks(int n)
from_PG_init.
가능한 경쟁 조건을 방지하려면 각 백엔드는 다음을 토토 캔해야 합니다.
LWLockAddinShmemInitLock공유 할당에 연결하고 초기화할 때
메모리는 여기에 표시된 대로입니다.
정적 mystruct *ptr = NULL;
만약 (!ptr)
부울이 발견되었습니다.
LWLockAcquire(AddinShmemInitLock, LW_EXCLUSIVE);
ptr = ShmemInitStruct("내 구조체 이름", 크기, &found);
만약 (!발견)
shmem 영역의 내용을 초기화합니다.
다음을 토토 캔하여 요청된 LWLock을 획득합니다.
ptr-mylockid = LWLockAssign();
LWLockRelease(AddinShmemInitLock);
비록포스트그레SQL백엔드는 C로 작성되었습니다. 확장 기능을 C로 작성할 수 있습니다. 다음 지침을 따르는 경우 C++:
백엔드에서 액세스하는 모든 기능은 C를 제공해야 합니다. 백엔드에 대한 인터페이스; 그런 다음 이러한 C 함수는 다음을 호출할 수 있습니다. C++ 함수. 예를 들어,외부 ㄷ85458_85631
적절한 할당 해제 방법을 토토 캔하여 메모리를 확보하십시오.
예를 들어 대부분의 백엔드 메모리는 다음을 토토 캔하여 할당됩니다.팔록(), 그러니 토토 캔하세요pfree()해제합니다. C++ 토토 캔삭제그런 경우에는
실패하다.
예외가 C 코드로 전파되는 것을 방지합니다(토토 캔
모두의 최상위 수준에 있는 포괄적인 블록외부 C함수). 이것도 꼭 필요하다
C++ 코드가 명시적으로 예외를 발생시키지 않는 경우
메모리 부족과 같은 이벤트로 인해 여전히 오류가 발생할 수 있기 때문입니다.
예외. 모든 예외를 포착하고 적절하게 처리해야 합니다.
오류가 C 인터페이스로 다시 전달되었습니다. 가능하다면 컴파일하세요.
C++와-fno-예외에
예외를 완전히 제거합니다. 그러한 경우에는 반드시
C++ 코드에서 오류가 있는지 확인하세요. NULL인지 확인
에 의해 반환됨신규().
C++ 코드에서 백엔드 함수를 호출하는 경우 다음을 확인하세요.
C++ 호출 스택에는 기존의 일반 데이터 구조만 포함되어 있습니다.
(POD). 이것은 필요하다
백엔드 오류로 인해 먼 거리가 생성되기 때문입니다.longjmp()제대로 풀리지 않는
POD가 아닌 객체가 포함된 C++ 호출 스택.
요약하자면 C++ 코드를 벽 뒤에 배치하는 것이 가장 좋습니다.외부 C다음과 인터페이스하는 함수 백엔드, 예외, 메모리 및 호출 스택 방지 누출.