사용자 정의 함수는 C (또는 언어로 작성할 수 있습니다. C ++와 같은 C와 호환 될 수 있습니다). 그러한 기능은입니다 동적으로로드 가능한 객체 (공유라고도합니다 라이브러리) 및 주문형 서버에 의해로드됩니다. 역학 로딩 기능은 구별되는 것입니다"c 언어"함수"내부"함수 - 실제 코딩 컨벤션은 본질적으로 두 가지 모두 동일합니다. (따라서 표준 내부 기능 라이브러리는 풍부한 코딩 소스입니다. 사용자 정의 C 함수에 대한 예제.)
현재 두 개의 다른 통화 규칙이 c 기능. 최신"버전 1"전화 컨벤션은 A를 작성하여 표시됩니다.pg_function_info_v1 ()매크로 기능을 요청합니다. 아래 그림과 같이. 그러한 매크로의 부족은 구식을 나타냅니다 ("버전 0") 함수. 언어 지정된 이름함수 만들기isC두 경우 모두. 구식 기능 이식성 문제와 부족으로 인해 이제는 더 이상 사용되지 않습니다. 기능이지만 여전히 호환성을 위해 지원됩니다 이유.
처음으로 사용자 정의 기능이 처음입니다 로드 가능한 객체 파일은 세션에서 호출됩니다. 동적 로더 함수가 될 수 있도록 해당 객체 파일을 메모리에로드합니다. 라고 불리는. 그만큼함수 만들기a 따라서 사용자 정의 C 함수는 두 가지 조각을 지정해야합니다 기능에 대한 정보 :로드 가능한 객체의 이름 파일 및 특정 함수의 C 이름 (링크 기호) 해당 객체 파일 내에서 호출하십시오. C 이름이 명시 적으로없는 경우 그런 다음 지정된 다음 SQL 기능과 동일하다고 가정합니다. 이름.
다음 알고리즘은 공유 객체를 찾는 데 사용됩니다. 에 주어진 이름을 기준으로 파일생성 기능명령 :
이름이 절대 경로 인 경우 주어진 토토은 짐을 실은.
이름이 문자열로 시작하면$ libdir, 그 부분은로 대체됩니다.PostgreSQL패키지 라이브러리 빌드 타임에 결정된 디렉토리 이름
이름에 디렉토리 부분이없는 경우 토토 구성에 의해 지정된 경로에서 검색됩니다. 변하기 쉬운dynamic_library_path.
그렇지 않으면 파일이 경로에서 발견되지 않았습니다. 비 변제 디렉토리 부분), 동적 로더가 포함되어 있습니다 주어진대로 이름을 가져 가려고 할 것입니다. 실패하다. (현재 작업에 의존하는 것은 신뢰할 수 없습니다 예배 규칙서.)
이 시퀀스가 작동하지 않으면 플랫폼 별 공유 라이브러리 토토 이름 확장 (종종.so)는 주어진 이름과 이것에 추가됩니다 시퀀스가 다시 시도됩니다. 그것이 실패하면 부하가 있습니다 실패하다.
상대적으로 공유 라이브러리를 찾는 것이 좋습니다 에게$ libdir또는 동적을 통한 도서관 경로. 이것은 새로운 경우 버전 업그레이드를 단순화합니다 설치는 다른 위치에 있습니다. 실제 디렉토리 저것$ libdirstands를 찾을 수 있습니다 명령과 함께PG_CONFIG --pkglibdir.
사용자 IDPostgreSQL서버는 토토로의 경로를 가로 질러야합니다. 당신은로드하려고합니다. 토토 또는 더 높은 수준의 디렉토리 제작 읽을 수 없거나/또는 실행할 수 없음Postgres사용자는 일반적인 실수입니다.
어쨌든에 나와있는 토토 이름은함수 생성명령은 문자 그대로 기록됩니다 시스템이 카탈로그가되므로 토토을 다시로드 해야하는 경우 동일한 절차가 적용됩니다.
참고 : PostgreSQLC 함수를 자동으로 컴파일하지 않습니다. 대상 파일은 a에 참조되기 전에 컴파일해야합니다.함수 생성명령. 보다섹션 33.9.6추가 정보.
동적으로로드 된 객체 토토이 아니 었는지 확인 호환되지 않는 서버에로드PostgreSQL토토에 A가 포함되어 있는지 확인합니다"매직 블록"적절한 내용물. 이를 통해 서버는 명백한 것을 감지 할 수 있습니다 다른 전공에 대해 컴토토 된 코드와 같은 비 호환성 의 버전PostgreSQL. 마법 블록이 필요합니다PostgreSQL8.2. 마법 블록을 포함 시키려면 이것을 모듈 소스 파일의 하나 (그리고 하나만)로 작성하십시오. 헤더 포함 후fmgr.h:
#ifdef pg_module_magic PG_MODULE_MAGIC; #endif
the#ifdef테스트를 생략 할 수 있습니다 코드는 8.2 이전에 컴파일 할 필요가 없습니다.토토릴리스.
처음으로 사용 된 후 동적으로로드 객체 파일은 메모리에 유지됩니다. 같은 미래의 전화 해당 파일의 함수에 대한 세션은 심볼 테이블 조회의 작은 오버 헤드. 강제 a 예를 들어 객체 파일을 다시로드하고 예를 들어 다시 컴파일 한 후 새로운 세션을 시작하십시오.
선택적으로 동적으로로드 된 파일에 포함 할 수 있습니다
초기화 및 마무리 기능. 파일에 포함 된 경우
이름 함수_pg_init
, 그
파일을로드 후 즉시 기능이 호출됩니다. 그만큼
함수는 매개 변수를 수신하지 않으며 void를 반환해야합니다. 만약
파일은이라는 함수가 포함되어 있습니다._pg_fini
,이 함수는 호출됩니다
파일을 내리기 직전에. 마찬가지로 기능
매개 변수를받지 않으며 void를 반환해야합니다. 참고_pg_fini
만 호출됩니다
프로세스 종료 중에는 파일을 내릴 때.
(현재, 언로드는 비활성화되어 절대 발생하지 않을 것이지만
미래에 변할 수 있습니다.)
c-language functions를 작성하는 방법을 알아하려면 알아야합니다. 어떻게PostgreSQL내부 기본 데이터 유형 및 전달 방법을 나타내고 기능에서. 내부,PostgreSQL기본 유형을 a로 간주합니다."기억의 블로브". 사용자 정의 유형을 차례로 정의하는 함수는 길을 정의합니다. 저것PostgreSQL작동 할 수 있습니다 그것. 즉,PostgreSQL의지 디스크에서 데이터를 저장하고 검색하고 사용하십시오. 입력, 프로세스 및 출력에 대한 사용자 정의 함수 데이터.
기본 유형은 세 가지 내부 형식 중 하나를 가질 수 있습니다.
통과 별 가치, 고정 길이
참조로 통과, 고정 길이
참조별로 전달, 가변 길이
바이 값 유형은 길이가 1, 2 또는 4 바이트 일 수 있습니다 (또한 또한 8 바이트, ifsizeof (Datum)는 8입니다 기계). 당신은 당신의 유형을 정의하는 데주의해야합니다. 모든 아키텍처에서 크기 (바이트)가됩니다. 을 위한 예,Long유형은 위험합니다 일부 기계에서는 4 바이트이고 다른 기계의 8 바이트이기 때문에 반면int타입은 대부분의 유닉스에서 4 바이트입니다 기계. 의 합리적인 구현int4Unix 기계의 타입은 다음과 같습니다.
/ * 4-byte 정수, 가치에 따라 통과 */ typedef int int4;
반면에, 모든 크기의 고정 길이 유형이 회의 별 통과. 예를 들어 샘플이 있습니다 A 구현PostgreSQL유형 :
/ * 16 바이트 구조, 참조로 통과 */ typedef struct 더블 X, y; 가리키다;
전달할 때 그러한 유형에 대한 포인터 만 사용할 수 있습니다. 그리고PostgreSQL함수. 그러한 유형의 값을 반환하려면 권리를 할당하십시오. 를 가진 메모리의 양Palloc, 채우기 할당 된 메모리를하고 포인터를 반환합니다. (또한, 당신이 입력 중 하나와 동일한 값을 반환하고 싶습니다. 동일한 데이터 유형의 인수는 추가를 건너 뛸 수 있습니다Palloc그리고 포인터를 반환하십시오 입력 값.)
마지막으로 모든 가변 길이 유형도 지나쳐야합니다 참조. 모든 가변 길이 유형은 길이로 시작해야합니다 정확히 4 바이트의 필드 및 그 안에 저장 될 모든 데이터 유형은 그 다음에 메모리에 위치해야합니다. 길이 필드. 길이 필드에는 총 길이가 포함됩니다 구조, 즉 길이 필드의 크기가 포함됩니다. 그 자체.
경고 |
절대Pass-by-Reference 입력 값의 내용을 수정하십시오. 그렇게하면 온 디스크 데이터를 손상시킬 가능성이 높습니다. 주어진 포인터가 직접적으로 가리킬 수 있으므로 디스크 버퍼로. 이 규칙의 유일한 예외는입니다 설명PostgreSQL : 문서 : 8.2. |
예를 들어, 유형을 정의 할 수 있습니다텍스트다음과 같이 :
typedef struct int4 길이; 숯 데이터 [1]; 텍스트;
분명히 여기에 선언 된 데이터 필드는 충분히 길지 않습니다. 가능한 모든 줄을 잡고 있습니다. 선언하는 것은 불가능하기 때문에 의 가변 크기 구조C, 우리는에 대한 지식에 의존합니다.C컴토토러는 범위 점검되지 않습니다 배열 구역. 우리는 필요한 금액을 할당합니다 공간에 배열이 선언 된 것처럼 배열에 액세스하십시오. 올바른 길이. (이것은 당신이 읽을 수있는 일반적인 트릭입니다. C.)에 관한 많은 교과서에서
가변 길이 유형을 조작 할 때 조심해야합니다 올바른 양의 메모리를 할당하고 길이를 설정하려면 필드가 올바르게. 예를 들어, 우리가 40 바이트를 저장하고 싶다면 에이텍스트구조, 우리는 a를 사용할 수 있습니다 다음과 같은 코드 조각 :
#include "postgres.h" ... 숯 버퍼 [40]; / * 소스 데이터 */ ... 텍스트 *대상 = (텍스트 *) palloc (varhdrsz + 40); 대상- 길이 = varhdrsz + 40; memcpy (대상- 데이터, 버퍼, 40); ...
varhdrsz|sizeof (int4)이지만 좋은 스타일로 간주됩니다 매크로 사용varhdrsz가변 길이 유형에 대한 오버 헤드 크기.
표 33-1어떤 c 유형이 어떤 SQL 유형에 해당하는지 지정합니다. 내장 유형의 유형을 사용하는 c-language 함수 작성PostgreSQL. 그만큼"" 정의열은 헤더 토토을 제공합니다 유형 정의를 얻으려면 포함해야합니다. (실제 정의는 나열된 토토. 사용자가 정의 된 것을 고수하는 것이 좋습니다 인터페이스.) 항상 포함해야합니다postgres.h먼저 모든 소스 토토에서 어쨌든 필요한 많은 것들을 선언합니다.
표 33-1. 내장 SQL의 동등한 C 유형 유형
SQL 유형 | C 유형 | 정의 |
---|---|---|
Abstime | AbsoluteTime | utils/nabstime.h |
부울 | bool | postgres.h(아마도 컴토토러 내장) |
Box | Box* | utils/geo_decls.h |
BYTEA | BYTEA* | postgres.h |
"char" | char | (컴토토러 내장) |
캐릭터 | BPCHAR* | postgres.h |
CID | CommandId | postgres.h |
날짜 | dateadt | utils/date.h |
smallint (int2) | int2또는int16 | postgres.h |
int2vector | int2vector* | postgres.h |
Integer (int4) | int4또는int32 | postgres.h |
Real (float4) | float4* | Postgres.h |
이중 정밀 (float8) | float8* | postgres.h |
간격 | 간격* | utils/timestamp.h |
lseg | lseg* | utils/geo_decls.h |
이름 | 이름 | postgres.h |
OID | OID | postgres.h |
oidvector | oidvector* | postgres.h |
PATH | Path* | utils/geo_decls.h |
포인트 | 포인트* | utils/geo_decls.h |
Regproc | Regproc | postgres.h |
Reltime | RelativeTime | utils/nabstime.h |
텍스트 | 텍스트* | postgres.h |
TID | ItemPointer | Storage/itemptr.h |
시간 | Timeadt | utils/date.h |
시간대가있는 시간 | Timetzadt | utils/date.h |
타임 스탬프 | 타임 스탬프* | utils/timestamp.h |
TinterVal | TimeInterval | utils/nabstime.h |
Varchar | varchar* | postgres.h |
xid | TransactionId | postgres.h |
이제 우리는 가능한 모든 구조를 살펴 보았습니다. 기본 유형, 실제 기능의 몇 가지 예를 보여줄 수 있습니다.
우리는를 발표합니다."구식"컨벤션을 먼저 호출 -이 접근법은 지금 이루어졌지만 더 이상 사용되지 않으면 처음에 처리하는 것이 더 쉽습니다. 에서 버전 -0 메소드, C 함수의 인수 및 결과 정상적인 C 스타일로 방금 선언되지만 사용에주의를 기울입니다. 위와 같이 각 SQL 데이터 유형의 C 표현.
여기 몇 가지 예가 있습니다.
#include "postgres.h" #include <string.h / * 가치 별 */ int add_one (int arg) 반환 Arg + 1; / * 참조로 고정 길이 */ float8 * add_one_float8 (float8 *arg) float8 *result = (float8 *) palloc (sizeof (float8)); *결과 = *arg + 1.0; 반환 결과; 가리키다 * MakePoint (point *pointx, point *pointy) 지점 *new_point = (point *) palloc (sizeof (point)); new_point- x = pointx- x; new_point- y = pointy- y; New_Point를 반환합니다. / * 참조적으로 가변 길이 */ 텍스트 * 카피 텍스트 (텍스트 *t) /* * varsize는 바이트의 구조물의 총 크기입니다. */ 텍스트 *new_t = (텍스트 *) palloc (varsize (t)); varatt_sizep (new_t) = varsize (t); /* * Vardata는 구조물의 데이터 영역에 대한 포인터입니다. */ memcpy ((void *) vardata (new_t), / *대상 * / (void *) vardata (t), / *소스 * / varsize (t) - varhdrsz); / * 얼마나 많은 바이트 */ 뉴 _t를 반환합니다. 텍스트 * concat_text (text *arg1, text *arg2) int32 new_text_size = varsize (arg1) + varsize (arg2) - varhdrsz; 텍스트 *new_text = (텍스트 *) palloc (new_text_size); varatt_sizep (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다음과 같은 명령과 함께 :
함수 생성 add_one (정수) 정수를 반환합니다 처럼 '디렉토리/funcs ','add_one ' 언어 C 엄격한; - SQL 기능 이름 "add_one"의 과부하 참고 기능 Add_one (이중 정밀)을 작성하십시오. 이중 정밀도를 반환합니다 처럼 '디렉토리/funcs ','add_one_float8 ' 언어 C 엄격한; 함수 makepoint (점, 점)를 반환합니다 처럼 '디렉토리/funcs ','makepoint ' 언어 C 엄격한; 함수 CopyText (텍스트)를 작성합니다 텍스트를 반환합니다 처럼 '디렉토리/funcs ','CoppyText ' 언어 C 엄격한; CONCIT CONCAT_TEXT (텍스트, 텍스트) 텍스트를 반환합니다 처럼 '디렉토리/funcs ','concat_text ' 언어 C 엄격한;
여기,디렉토리공유 라이브러리 파일의 디렉토리 (예 :PostgreSQL튜토리얼 디렉토리, 여기에는이 섹션에 사용 된 예제에 대한 코드가 포함되어 있습니다). (더 나은 스타일은 그냥 사용하는 것입니다'funcs'inas조항, 추가 후디렉토리검색 경로로. 어느 쪽이든 사례, 우리는 공유에 대한 시스템 별 확장을 생략 할 수 있습니다. 도서관, 일반적으로.so또는.SL.)
함수를 다음과 같이 지정했음을 알 수 있습니다."엄격한", 시스템은해야한다는 것을 의미합니다 입력 값이 NULL 인 경우 자동으로 NULL 결과를 가정합니다. 이렇게함으로써, 우리는 기능 코드. 이것 없이는 널 값을 확인해야합니다 명시 적으로, 각각에 대한 널 포인터를 확인함으로써 통과 참조 주장. (패스 별 값 주장의 경우, 우리 확인 방법조차 없습니다!)
이 호출 규칙은 사용하기가 간단하지만 매우 휴대 성; 일부 아키텍처에는 문제가 있습니다 보다 작은 데이터 유형 전달int이 방법. 또한 간단한 방법은 없습니다 귀무 결과를 반환하거나 어떤 널 주장에 대처하기 위해 기능을 엄격하게 만드는 것 외에. 버전 -1 다음에 제시된 컨벤션은 이러한 반대 의견을 극복합니다.
버전 1 호출 컨벤션은 매크로에 의존합니다 통과 된 주장의 복잡성을 억제하고 결과. 버전 -1 기능의 C 선언은 다음과 같습니다 언제나
Datum funcname (pg_function_args)
또한 매크로 호출
pg_function_info_v1 (funcname);
동일한 소스 파일에 나타나야합니다. (전통적으로, 그것은입니다 함수 자체 직전에 작성되었습니다.)이 매크로 호출은 필요하지 않음내부-언어 기능, 이후PostgreSQL모든 내부 기능이 버전 -1을 사용한다고 가정합니다 협약. 그러나 동적으로로드되는 데 필요합니다 기능.
버전 -1 함수에서는 각 실제 인수가 가져옵니다
a 사용pg_getarg_xxx()
매크로에 해당합니다
인수의 데이터 유형 및 결과는 a를 사용하여 반환됩니다.pg_return_xxx()
반환 유형의 매크로.pg_getarg_xxx()
논쟁으로 취합니다
가져 오는 기능 인수 수, 여기서 계산
0에서 시작합니다.pg_return_xxx()
인수로 간주합니다
반품 할 실제 가치.
여기서 우리는 Version-1에 코딩 된 위와 동일한 함수를 보여줍니다. 스타일:
#include "postgres.h" #include <string.h #include "fmgr.h" / * 가치 별 */ pg_function_info_v1 (add_one); 자료 add_one (pg_function_args) int32 arg = pg_getarg_int32 (0); pg_return_int32 (arg + 1); / * 참조로 고정 길이 */ pg_function_info_v1 (add_one_float8); 자료 add_one_float8 (pg_function_args) /* float8의 매크로는 통과 참조 특성을 숨 깁니다. */ float8 arg = pg_getarg_float8 (0); pg_return_float8 (arg + 1.0); pg_function_info_v1 (makepoint); 자료 makepoint (pg_function_args) /* 여기서, 포인트의 추론 특성은 숨겨져 있지 않습니다. */ point *pointx = pg_getarg_point_p (0); point *pointy = pg_getarg_point_p (1); 지점 *new_point = (point *) palloc (sizeof (point)); new_point- x = pointx- x; new_point- y = pointy- y; pg_return_point_p (new_point); / * 참조적으로 가변 길이 */ pg_function_info_v1 (CopyText); 자료 CopyText (pg_function_args) 텍스트 *t = pg_getarg_text_p (0); /* * varsize는 바이트의 구조물의 총 크기입니다. */ 텍스트 *new_t = (텍스트 *) palloc (varsize (t)); varatt_sizep (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; 텍스트 *new_text = (텍스트 *) palloc (new_text_size); varatt_sizep (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);
the기능 생성명령은입니다 버전 -0 등가와 동일합니다.
언뜻보기에 버전 1 코딩 규칙이 나타날 수 있습니다
무의미한 모호함이되기 위해. 그러나 그들은 제안합니다
매크로가 불필요하게 숨길 수 있기 때문에 개선 횟수
세부 사항. 예를 들어 코딩에서add_one_float8
, 우리는 더 이상 알 필요가 없습니다
저것float8는 추천 유형입니다.
또 다른 예는getarg가변 길이 유형의 매크로는보다 효율적입니다
페치"토스트"(압축 또는
외부) 값.
버전 -1 기능의 큰 개선이 더 좋습니다
널 입력 및 결과 처리. 매크로PG_ARGISNULL (n)
함수를 테스트 할 수 있습니다
각 입력이 무효인지 여부. (물론, 이것을하는 것은 전용입니다
선언되지 않은 기능에 필요"엄격한".)와 마찬가지로pg_getarg_xxx()
매크로, 입력 인수
0에서 시작합니다. 하나는 자제해야합니다
실행pg_getarg_xxx()
하나가 확인할 때까지
논쟁은 무효가 아닙니다. 널 결과를 반환하려면 executepg_return_null ()
; 이것은 작동합니다
엄격한 기능과 기적 기능.
새로운 스타일 인터페이스에 제공된 다른 옵션은 2입니다
의 변형pg_getarg_xxx()
매크로. 이 중 첫 번째,pg_getarg_xxx_copy ()
, a
글을 쓰는 데 안전한 지정된 인수의 사본.
(일반 매크로는 때때로 값에 대한 포인터를 반환합니다.
물리적으로 테이블에 저장되어 있어야합니다.
에게. 사용 사용pg_getarg_xxx_copy ()
매크로는 a
쓰기 가능한 결과.) 두 번째 변형은로 구성됩니다.pg_getarg_xxx_slice ()
매크로
세 가지 주장. 첫 번째는 함수의 수입니다
인수 (위와 같이). 두 번째와 세 번째는 오프셋입니다
반환 할 세그먼트의 길이. 오프셋이 계산됩니다
0 및 음의 길이는 나머지가
가치를 반환합니다. 이 매크로는보다 효율적인 액세스를 제공합니다
저장소가있는 경우 큰 값의 일부로
유형"외부". (스토리지 유형
열의 열은를 사용하여 지정할 수 있습니다.ALTER
테이블TableNameAlter ColumnColname스토리지 설정StorageType. StorageType중 하나입니다일반, 외부,
확장또는Main.)
마지막으로 버전 -1 기능 호출 규칙이이를 만듭니다 설정 결과를 반환 할 수 있습니다 (섹션 33.9.10) 및 트리거 함수 구현 (토토 결과 : 문서 : 8.2 : 트리거) 및 절차 적 통화 처리기 (47 장). 버전 1 코드도 더 많습니다 버전 -0보다 휴대용 제한을 깨뜨리지 않기 때문입니다 C 표준의 기능 호출 프로토콜 자세한 내용은 보다src/backend/utils/fmgr/readmein 소스 분포.
보다 진보 된 주제로 돌아 가기 전에 에 대한 몇 가지 코딩 규칙에 대해 토론하십시오.PostgreSQLc-language functions. 그 동안 언어로 작성된 기능을로드 할 수 있습니다. C보다PostgreSQL,이 다른 이유는 일반적으로 (전혀 가능할 때) 어렵습니다. C ++, Fortran 또는 Pascal과 같은 언어는 종종 C와 동일한 통화 협약 인수와 반환 값이 같은 방식. 이러한 이유로, 우리는 당신의 c- 언어라고 가정 할 것입니다 기능은 실제로 C로 작성됩니다.
C 기능 작성 및 구축을위한 기본 규칙은 다음과 같습니다. 다음은 다음과 같습니다.
usePG_CONFIG -includedir-serverPostgreSQL서버 헤더 파일입니다 시스템에 설치 (또는 사용자가 켜짐).
코드를 컴토토하고 연결하여 동적으로로드PostgreSQL항상 특별해야합니다 깃발. 보다섹션 33.9.6특정 운영 체제.
a 정의하는 것을 잊지 마십시오."마법 차단하다"공유 라이브러리의 경우섹션 33.9.1.
메모리를 할당 할 때를 사용하십시오.토토기능Palloc
andpfree
해당 C 라이브러리 대신
기능Malloc
및무료
. 에 의해 할당 된 메모리Palloc
가 해방됩니다
각 트랜잭션이 끝날 때 자동으로 방지합니다
메모리 누출.
항상 구조물의 바이트를 항상 0memset
. 이것 없이는 그렇지 않습니다
해시 인덱스 또는 해시 조인을 지원하기가 어렵습니다.
데이터의 상당한 비트 만 선택해야합니다.
해시를 계산하는 구조. 모든 것을 초기화하더라도
구조의 필드, 정렬 패딩이있을 수 있습니다
쓰레기를 포함 할 수있는 (구조물의 구멍)
값.
대부분의 내부PostgreSQL유형은postgres.h관리자 인터페이스 (pg_function_args등)fmgr.h이므로 AT를 포함시켜야합니다 최소한이 두 토토. 휴대 할 수있는 이유로 가장 좋습니다 포함하다postgres.h 첫 번째시스템 또는 사용자 헤더 파일. 포함postgres.h포함elog.handpalloc.h당신을 위해.
객체 파일 내에 정의 된 기호 이름은 안됩니다 서로 충돌하거나에 정의 된 기호와 충돌PostgreSQL서버 실행 파일. 당신은 당신의 함수의 이름을 바꿔야합니다 이 효과에 오류 메시지가 표시되는 경우 변수
사용하기 전에PostgreSQL확장 기능이 작성되었습니다 C, 그들은 특별한 생산 방법으로 편집하고 연결되어야합니다. 서버에서 동적으로로드 할 수있는 파일. 장차 ~ 가 되는 정확한, A공유 도서관생성.
이 섹션에 포함 된 것 이상의 정보는 귀하에게 운영 체제의 문서를 읽어야합니다 특히 C 컴파일러의 수동 페이지,CC및 링크 편집기,LD. 또한PostgreSQL소스 코드에는 여러 가지가 포함되어 있습니다 의 작업 예제Contrib디렉토리. 이 예에 의존하면 의 가용성에 따라 모듈PostgreSQL소스 코드.
공유 라이브러리 생성은 일반적으로 연결과 유사합니다 실행 파일 : 먼저 소스 파일이 객체로 컴파일됩니다 파일, 객체 파일이 함께 연결됩니다. 대상 파일은로 만들어야합니다.위치 독립 코드 (PIC),개념적으로 그들이 그들이로드 할 때 메모리의 임의 위치 실행 파일. (실행 파일 용 객체 파일은 일반적으로입니다 그런 식으로 컴파일되지 않습니다.) 공유 라이브러리를 연결하라는 명령 링크와 구별하기위한 특수 플래그가 포함되어 있습니다 실행 파일 (적어도 이론적으로 - 일부 시스템에서는 실습 훨씬 추악합니다).
다음 예에서는 소스 코드가 파일에서foo.c그리고 우리는 a 공유 도서관foo.so. 그만큼 중간 객체 파일은입니다.foo.o49384_49500
생성 할 컴토토러 플래그PICis-fpic. 공유 라이브러리 생성 링커 플래그는입니다.-shared.
gcc -fpic -c foo.c ld -shared -o foo.so foo.o
버전 4.0에서 적용 가능BSD/OS.
생성 할 컴토토러 플래그PICis-fpic. 공유 라이브러리를 만들려면 컴토토러 플래그는입니다.-shared.
gcc -fpic -c foo.c gcc -shared -o foo.so foo.o
버전 3.0에서 적용 가능freebsd.
생성 할 시스템 컴토토러의 컴토토러 플래그PICis+z. 사용시GCCit-fpic. 공유 라이브러리의 링커 플래그 이다-B. 그래서
CC +Z -C foo.c
또는
gcc -fpic -c foo.c
and
ld -b -o foo.sl foo.o
hp-ux확대.SL공유 대부분의 다른 시스템과 달리 라이브러리.
PIC기본값입니다. 특수 컴토토러 옵션이 필요하지 않습니다. 링커 공유 라이브러리를 생산하는 옵션-shared.
CC -C FOO.C ld -shared -o foo.so foo.o
생성 할 컴토토러 플래그PICis-fpic. 어떤 상황에서는 일부 플랫폼에서-fpic-fpic작동하지 않습니다. GCC를 참조하십시오 자세한 내용은 설명서. 컴파일러 플래그를 작성합니다 공유 도서관은-shared. 에이 완전한 예는 다음과 같이 보입니다.
cc -fpic -c foo.c cc -shared -o foo.so foo.o
여기 예입니다. 개발자 도구가 있다고 가정합니다 설치.
CC -C foo.c CC -BUNDLE -FLAT_NAMESPACE- 정의 된 억제 -o foo.so foo.o
생성 할 컴토토러 플래그PICis-fpic. 을 위한ELF시스템, the 플래그를 가진 컴파일러-sharedIS 공유 라이브러리를 연결하는 데 사용됩니다. 더 오래된 비 엘프 시스템,ld -BsharableIS 사용된.
gcc -fpic -c foo.c gcc -shared -o foo.so foo.o
생성 할 컴토토러 플래그PICis-fpic. ld -Bsharable링크에 사용됩니다 공유 도서관.
gcc -fpic -c foo.c ld -bsharable -o foo.so foo.o
생성 할 컴토토러 플래그PICis-kpic썬 컴토토러와-fpicwithGCC. 공유 링크 라이브러리, 컴토토러 옵션은입니다.-g컴파일러 또는 대안으로-sharedwithGCC.
cc -kpic -c foo.c cc -g -o foo.so foo.o
또는
gcc -fpic -c foo.c gcc -g -o foo.so foo.o
PIC기본값입니다. 따라서 컴파일 명령은 일반적인 명령입니다.LD특수 옵션이있는 경우 사용됩니다 링크 :
CC -C FOO.C ld -shared -expect_unresolved '*'-o foo.so foo.o
동일한 절차가 GCC 대신 GCC와 함께 사용됩니다. 시스템 컴파일러; 특별한 옵션이 필요하지 않습니다.
생성 할 컴토토러 플래그PICis-K picSCO 컴토토러와-fpicwithGCC. 공유 링크 라이브러리, 컴토토러 옵션은입니다.-gSCO 컴토토러와-sharedwithGCC.
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) 할 수 있습니다 에서 생략기능 생성명령은 일반적으로 최선을 위해 생략해야합니다 이식성.
다시 참조섹션 33.9.1서버가 공유를 찾을 것으로 예상되는 위치에 대한 정보 도서관 토토.
배포에 대해 생각하고 있다면PostgreSQL확장 모듈, 설정 a 그들을위한 휴대용 빌드 시스템은 상당히 어려울 수 있습니다. 따라서PostgreSQL설치는 확장에 대한 빌드 인프라를 제공합니다. 라고 불리는PGXS확장 모듈은 이미 간단하게 구축 할 수 있습니다 설치된 서버. 이 인프라는 의도되지 않습니다 사용될 수있는 범용 빌드 시스템 프레임 워크가 되려면 모든 소프트웨어를 구축하여PostgreSQL; 그것은 단순히 공통을 자동화합니다 간단한 서버 확장 모듈에 대한 규칙을 작성하십시오. 자세한 내용 복잡한 패키지에는 자신의 빌드를 작성해야합니다 체계.
확장에 인프라를 사용하려면 작성해야합니다. 간단한 makefile. 그 makefile에서는 일부를 설정해야합니다 변수와 마지막으로 글로벌 포함PGXSmakefile. 다음은 다음과 같습니다 지명 된 확장 모듈 빌드ISBN_ISSN공유 라이브러리, SQL로 구성됩니다 스크립트 및 문서 텍스트 파일 :
modules = isbn_issn data_built = isbn_issn.sql 문서 = readme.isbn_issn pgxs : = $ (shell pg_config --pgxs) $ (pgxs) 포함
마지막 두 줄은 항상 동일해야합니다. 일찍 파일, 변수를 할당하거나 사용자 정의 추가make규칙.
다음 변수를 설정할 수 있습니다.
소스 파일에서 빌드 할 공유 개체 목록 같은 줄기로 (이 목록에 접미사를 포함하지 않음)
random files to into에 설치할prefix/share/contrib
random files to into에 설치할접두사/share/contrib먼저 건설해야
아래에 설치할 무작위 토토접두사/doc/contrib
스크립트 파일 (바이너리 아님)에 설치할접두사/bin
스크립트 파일 (바이너리 아님)에 설치할prefix/bin첫 번째 구축
회귀 테스트 사례 목록 (접미사없이) 아래에
또는이 두 가지 중 하나 :
빌드 할 바이너리 프로그램 (을 목록에 나란히OBJS)
빌드 할 공유 객체 (을 목록에서 목록OBJS)
다음도 설정할 수 있습니다 :
제거 할 추가 토토만들기 깨끗한
에 추가됩니다CPPFLAGS
에 추가됩니다프로그램링크 선
에 추가됩니다module_big링크 라인
이 makefile으로makefilein 확장을 보유하는 디렉토리. 그런 다음 할 수 있습니다만들기컴토토하고 나중에설치모듈을 설치하려면. 그만큼 Extension은 컴파일되어PostgreSQL해당 설치 첫 번째PG_CONFIG명령을 찾았습니다 당신의 길에서.
스크립트에 나열된 스크립트회귀변수는 모듈의 회귀 테스트에 사용됩니다. 좋다설치 확인기본PostgreSQL서버. 을 위한 이것은 작동하기 위해서는라는 서브 디렉토리가 필요합니다.SQL/Extension의 디렉토리에 있습니다 실행하려는 각 테스트 그룹에 대해 하나의 파일을 넣습니다. 그만큼 파일에는 확장이 있어야.SQL, 에 포함되어서는 안됩니다회귀makefile에 목록. 각 테스트마다 예상 결과가 포함 된 파일이 있어야합니다. 하위 디렉토리 이름예상/확대.out. 테스트는 다음과 같습니다 실행설치 확인결과 출력은 예상 파일과 비교됩니다. 그만큼 차이점은 파일에 기록됩니다regression.diffsindiff -기음형식. 누락 된 테스트를 실행하려고합니다. 예상 토토은로보고됩니다."문제", 모든 것이 예상되었는지 확인하십시오 토토.
팁 :예상을 만드는 가장 쉬운 방법 토토은 빈 토토을 만들고 신중하게 검사합니다 테스트 실행 후 결과 토토 (에서 찾을 수 있습니다.결과/디렉토리) 및 복사 그들에게예상/일치하는 경우 테스트에서 원하는 것.
복합 유형은 C와 같은 고정 레이아웃이 없습니다. 구조. 복합 유형의 인스턴스는 null을 포함 할 수 있습니다 전지. 또한 AN의 일부인 복합 유형 상속 계층 구조는 다른 필드와 다른 필드를 가질 수 있습니다 동일한 상속 계층의 구성원. 그러므로,PostgreSQL함수를 제공합니다 C에서 복합 유형의 필드에 액세스하기위한 인터페이스
쿼리에 응답하기 위해 함수를 작성하려고한다고 가정 해 봅시다
이름, C_overpaid (EMP, 1500)를 초과 지불로 선택하십시오 emp에서 여기서 name = 'bill'또는 name = 'sam';
Call Concentions 버전 0 사용c_overpaid
as :
#include "postgres.h" #include "executor/executor.h"/ * for getAttributeByName () */ 부 c_overpaid (HeptupleHeader t, / * 현재 행의 행 * / int32 한도) bool isnull; INT32 급여; Salary = DatumgetInt32 (getAttributeByName (t, "Salary", & isnull)); if (isnull) 거짓을 반환합니다. 반품 급여 한도;
버전 -1 코딩에서 위는 다음과 같습니다.
#include "postgres.h" #include "executor/executor.h"/ * for getAttributeByName () */ pg_function_info_v1 (c_overpaid); 자료 c_overpaid (pg_function_args) heptupleHeader t = pg_getarg_heaptupleHeader (0); int32 한계 = pg_getarg_int32 (1); bool isnull; 데이텀 급여; 급여 = getAttributeByName (t, "Salary", & isnull); if (isnull) pg_return_bool (false); /* 또는 널 급여에 대해 pg_return_null ()을 선호 할 수 있습니다. */ pg_return_bool (Datumgetint32 (Salary) 한도);
getAttributeByName
PostgreSQL시스템 기능
지정된 행에서 속성을 반환합니다. 세 가지가 있습니다
인수 : 유형의 주장HeappupleHeader이름, 이름으로 전달되었습니다
원하는 속성 및 반환 매개 변수의
속성이 null인지 여부.getAttributeByName
반환 aDatum적절한 데이터로 변환 할 수있는 값
적절한 사용으로 입력Datumgetxxx()
매크로. 귀무인이
깃발이 설정되어 있습니다. 시도하기 전에 항상 널 플래그를 확인하십시오
결과와 함께.
또한getAttributeBynum
66749_66825
다음 명령은 함수를 선언합니다C_OVERPAID
sql :
함수 만들기 c_overpaid (emp, integer) boolean을 반환합니다 처럼 '디렉토리/funcs ','c_overpaid ' 언어 C 엄격한;
우리가 사용한 통지엄격한우리는 입력 인수가 널.
c- 언어에서 행 또는 복합 유형 값을 반환하려면 기능, 매크로를 제공하는 특수 API를 사용할 수 있으며 구성 복합재의 복잡성의 대부분을 숨기는 기능 데이터 유형. 이 API를 사용하려면 소스 파일에는 다음을 포함해야합니다.
#include "funcapi.h"
복합 데이터 값을 구축 할 수있는 두 가지 방법이 있습니다.
(따라서 A"튜플") : 할 수 있습니다
Datum 값의 배열 또는 C의 배열에서 빌드하십시오.
입력 변환 기능으로 전달할 수있는 문자열
튜플의 열 데이터 유형. 두 경우 모두 먼저 필요합니다
a를 얻거나 구성하려면tupledesc튜플 구조에 대한 디스크립터. Datums와 함께 일할 때
당신은 통과합니다tupledesctoBlessTupledesc
그리고 전화heap_form_tuple
각 행마다.
C 줄로 작업 할 때를 통과합니다.tupledesctotupledescgetattinmetadata
그리고 전화BuildTupleFromCstrings
각각
열. 함수가 튜플 세트를 반환하는 경우
첫 번째 호출 중에 설정 단계를 모두 한 번 수행 할 수 있습니다.
기능.
설정을위한 여러 도우미 기능이 제공됩니다 필요한tupledesc. 권장 대부분의 기능 에서이 작업을 수행하는 방법은 복합 값을 반환하는 것입니다. 전화하려면
saperfuncclass get_call_result_type (functioncallinfo fcinfo, oid *resulttypeid, tupledesc *resulttupledesc)
같은 전달fcinfostruct 호출 기능 자체로 전달되었습니다. (물론 이것은 필요합니다 버전 1 전화 컨벤션을 사용한다는 것입니다.)resultTypeid|NULL또는 로컬 변수의 주소로 함수의 결과 유형 OID를받습니다.resultTupledesc지역의 주소 여야합니다tupledesc변수. 그것을 확인하십시오 결과는saptunc_composite; 그렇다면,resultTupledesc필요한 것tupledesc. (그렇다면 아니,의 줄을 따라 오류를보고 할 수 있습니다."기능 반환 레코드가 문맥에서 호출되었습니다 유형 레코드를 허용 할 수 없습니다 ".)
팁 :
get_call_result_type
해결할 수 있습니다 다형성 기능 결과의 실제 유형; 그렇습니다 스칼라 다형성 결과를 반환하는 기능에 유용하고, 복합재를 반환하는 기능뿐만 아니라. 그만큼resultTypeid출력은 주로 유용합니다 다형성 스칼라를 반환하는 기능.
참고 :
get_call_result_type
형제가 있습니다get_expr_result_type
예상 출력 유형을 해결하는 데 사용할 수 있습니다. 표현식 트리로 표시되는 함수 호출. 이것은 할 수 있습니다 결과 유형을 결정할 때 사용됩니다. 기능 자체 외부. 또한get_func_result_type
기능의 OID 만 사용할 수있는 경우 그러나 이것들 함수는 선언 된 기능을 다룰 수 없습니다. 반품레코드및get_func_result_type
해결할 수 없습니다 다형성 유형이므로 우선적으로 사용해야합니다get_call_result_type
.
획득하기위한 구식, 현재 배제 된 기능tupledescs are
tupledesc relationnamegetTupledesc (const char *relname)
atupledesc행의 경우 이름 지정된 관계의 유형 및
tupledesc typegetTupledesc (Oid typeoid, list *colaliases)
atupledesc기준 a OID를 입력하십시오. 이것은 A를 얻는 데 사용될 수 있습니다.tupledesc베이스 또는 복합 유형의 경우. 그것 반환하는 함수에 대해서는 작동하지 않습니다레코드그러나 해결할 수 없습니다 다형성 유형.
일단 당신이 atupledesc, 부르다
Tupledesc BlessTupledesc (tupledesc tupdesc)
Datums와 함께 일할 계획이라면
Attinmetadata *tupledescgetattinmetadata (tupledesc tupdesc)
C 문자열로 작업하려는 경우. 당신이 쓰는 경우 a 기능 반환 세트,이 결과를 저장할 수 있습니다. 의 함수FUNCCALLCONTEXT구조 - 사용tuple_desc또는Attinmeta필드
Datums에서 작업 할 때
heappuple heap_form_tuple (tupledesc tupdesc, datum *값, bool *isnull)
aHeappuple주어진 사용자 데이텀 형식의 데이터.
C 문자열로 작업 할 때 사용
Heatpuple buildtupleffflffflffffffflings (Attinmetadata *Attinmeta, char ** value)
aHeappuple주어진 사용자 C 문자열 형태의 데이터.값is C Strings의 배열, 리턴 행의 각 속성마다 하나씩. 각 C 문자열은 입력에 의해 예상되는 형식이어야합니다. 속성 데이터 유형의 함수. 널을 반환하기 위해 속성 중 하나에 대한 값, 해당 포인터 그만큼값배열을 설정해야합니다NULL. 이 기능은 있어야합니다 당신이 돌아 오는 각 행에 대해 다시 호출.
일단 기능에서 돌아 오기 위해 튜플을 만들면 it A로 변환해야합니다.Datum. 사용
HeappupleGetDatum (Heptuple Tuple)
변환Heappuplea 유효한 데이텀. 이것Datum반환 할 수 있습니다 단일 행 만 반환하려는 경우 직접 설정 퇴치에서 현재 반환 값으로 사용 기능.
다음 섹션에 예제가 나타납니다.
지원을 제공하는 특별한 API도 있습니다. C-Language 함수의 반환 세트 (다중 행). 에이 설정 퇴행 기능은 버전 -1 호출을 따라야합니다 규칙. 또한 소스 파일은 포함해야합니다.funcapi.h, 위와 같이.
세트 리턴 기능 (SRF) 각 항목마다 한 번 호출됩니다 보고. 그만큼SRF필수 그러므로 그것이하고있는 일을 기억하기에 충분한 상태를 절약하고 각 통화에서 다음 항목을 반환하십시오. 구조FUNCCALLCONTEXT제어를 돕기 위해 제공됩니다 이 과정. 함수 내에서fcinfo- flinfo- fn_extraa 포인터에 대한FUNCCALLCONTEXT전화.
typedef struct /* * 우리가 전에 전화를 한 횟수 * * call_cntr은 srf_firstcall_init ()에 의해 당신을 위해 0으로 초기화됩니다. * srf_return_next ()가 호출 될 때마다 당신을 위해 증분합니다. */ UINT32 CALL_CNTR; /* * 선택적 최대 통화 수 * * max_calls는 편의를 위해서만 여기에 있으며 선택 사항입니다. * 설정하지 않으면 언제 * 기능이 완료되었습니다. */ UINT32 MAX_CALLS; /* * 결과 슬롯에 대한 선택적 포인터 * * 이것은 더 이상 사용되지 않으며 거꾸로 호환성을 위해서만 존재합니다. * 더 이상 사용되지 않은 tupledescgetSlot ()를 사용하는 사용자 정의 SRF. */ tupletableslot *슬롯; /* * 기타 사용자 제공 컨텍스트 정보에 대한 선택적 포인터 * * user_fctx는 자신의 데이터에 대한 포인터로 사용하기위한 것입니다. * 기능의 호출 사이의 임의의 컨텍스트 정보. */ void *user_fctx; /* * 구조물 포함 속성 유형 입력 메타 데이터에 대한 선택적 포인터 * * Attinmeta는 튜플을 반환 할 때 사용합니다 (즉, 복합 데이터 유형) * 기본 데이터 유형을 반환 할 때 사용되지 않습니다. 필요합니다 * BuildTupleFromCstrings ()를 사용하여 반품을 작성하려는 경우 * 튜플. */ Attinmetadata *Attinmeta; /* * 여러 통화를 위해 살아야하는 구조에 사용되는 메모리 컨텍스트 * * multi_call_memory_ctx는 SRF_FIRSTCALL_INIT ()에 의해 설정되어 사용됩니다. * 청소용 srf_return_done ()에 의해. 가장 적절한 메모리입니다 * 여러 통화에서 재사용 할 메모리에 대한 컨텍스트 * SRF. */ MemoryContext multi_call_memory_ctx; /* * 튜플 설명을 포함하는 구조에 대한 선택적 포인터 * * tuple_desc는 튜플을 반환 할 때 사용합니다 (즉, 복합 데이터 유형) * 그리고 당신이 튜플을 만들려고하는 경우에만 필요합니다. * heap_form_tuple ()가 buildtuplefromcstrings ()를 사용하지 않고. 주목하십시오 * 여기에 저장된 Tupledesc 포인터는 보통 통과해야합니다. * FlessTupledesc () 먼저. */ tupledesc tuple_desc; funcCallContext;
anSRF몇 가지를 사용합니다 자동으로 조작하는 함수와 매크로FUNCCALLCONTEXT구조 (및 를 통해 찾을 것으로 예상fn_extra). 사용
SRF_IS_FIRSTCALL ()
첫 번째 기능이 호출되는지 확인하려면 또는 후속 시간. 첫 번째 통화 (전용)에서
SRF_FIRSTCALL_INIT ()
초기화FUNCCALLCONTEXT. 모든 기능 호출에서 첫 번째, 사용
srf_percall_setup ()
사용을 위해 올바르게 설정하려면FUNCCALLCONTEXT이전에 지우십시오 이전 패스에서 남은 반환 데이터.
함수가 반환 할 데이터가 있으면
srf_return_next (funcctx, result)
발신자에게 반환합니다. (결과유형이어야합니다Datum, 단일 위에서 설명한대로 준비한 값 또는 튜플.) 마지막으로, 언제 귀하의 기능은 데이터 반환 데이터를 완료했습니다. 사용
srf_return_done (funcctx)
정리하고 끝내려면SRF.
SRF는 일시적인 컨텍스트입니다
통화간에 지워집니다. 이것은 당신이 필요하지 않다는 것을 의미합니다
전화하려면pfree
사용 할당Palloc
; 그것은 할 것입니다
어쨌든 가십시오. 그러나 데이터를 할당하려면
전화를 가로 질러 살 수있는 구조, 당신은 그들을 어딘가에 두어야합니다.
또 다른. 에 의해 언급 된 메모리 컨텍스트multi_call_memory_ctx는 적합한 위치입니다
까지 생존 해야하는 모든 데이터의 경우SRF가 끝났습니다. 대부분의 경우
이것은 당신이로 전환해야한다는 것을 의미합니다.multi_call_memory_ctx일차 설정.
완전한 의사 코드 예제는 다음과 같습니다.
Datum my_set_returning_function (pg_function_args) funccallcontext *funcctx; 데이텀 결과; MemoryContext OldContext;필요에 따른 추가 선언if (srf_is_firstcall ()) 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, result); 또 다른 / * 여기서 우리는 반환 품목을 완료하고 청소하면됩니다 : */사용자 코드srf_return_done (funcctx);
간단한 완전한 예SRF복합 유형 모양을 반환합니다 좋다:
pg_function_info_v1 (retcomposite); 자료 retComposite (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)! = saperfunc_composite) Ereport (오류, (errcode (errcode_feature_not_supported), errmsg ( "컨텍스트에서 호출 된 기능 반환 레코드" "유형 레코드를 허용 할 수 없음")); /* * RAW에서 튜플을 생산하는 데 필요한 속성 메타 데이터 생성 * 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 ** 값; 핵심 튜플; 데이텀 결과; /* * 반환 된 튜플을 구축하기위한 값 배열 준비. * 이것은 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 (값 [1], 16, "%d", 2 * pg_getarg_int32 (1)); snprintf (값 [2], 16, "%d", 3 * pg_getarg_int32 (1)); / * 튜플 구축 */ 튜플 = buildTupleFromCstrings (AttinMeta, 값); / * 튜플을 데이텀으로 만듭니다 */ 결과 = HeptupleGetDatum (튜플); / * 정리 (정말로 필요하지 않습니다) */ pfree (값 [0]); pfree (값 [1]); pfree (값 [2]); pfree (값); srf_return_next (funcctx, 결과); else / * 더 이상 남지 않을 때하십시오 * / srf_return_done (funcctx);
SQL 에서이 함수를 선언하는 한 가지 방법은 다음과 같습니다.
유형 생성 __retcomposite as (F1 Integer, F2 Integer, F3 Integer); 기능 retcomposite 생성 또는 교체 (정수, 정수) __retcomposite를 설정합니다 처럼 'filename','retcomposite ' 언어 c 불변의 엄격한;
다른 방법은 매개 변수를 사용하는 것입니다 :
함수 retcomposite 생성 또는 교체 (정수, 정수, Out F1 Integer, Out F2 Integer, Out F3 Integer) Setof 레코드를 반환합니다 처럼 'filename','retcomposite ' 언어 c 불변의 엄격한;
이 방법에서 기능의 출력 유형이 있음을 알 수 있습니다. 공식적으로 익명입니다레코드타입.
디렉토리Contrib/TableFuncin 소스 분포에는 더 많은 세트 리턴 링의 예가 포함되어 있습니다 기능.
C- 언어 함수는 수락 및 반환으로 선언 될 수 있습니다
다형성 유형Anylement및AnyArray. 보다섹션
33.2.5다형성에 대한 자세한 설명
기능. 기능 인수 또는 반환 유형이 정의 된 경우
다형성 유형으로서 기능 저자는 알 수 없습니다
호출 할 데이터 유형을 전진 시키거나
반품. 에 제공된 두 가지 루틴이 있습니다.fmgr.h버전 -1 C 함수를 허용합니다
인수의 실제 데이터 유형과 유형을 발견하십시오.
돌아올 것으로 예상됩니다. 루틴은라고합니다.get_fn_expr_rettype (fmgrinfo *flinfo)andget_fn_expr_argtype (fmgrinfo *flinfo, int
Argnum). 결과 또는 인수 유형 OID를 반환합니다.invalidoid정보가없는 경우
사용 가능. 구조flinfois
일반적으로 액세스 됨fcinfo- flinfo. 매개 변수Argnum는 0에 근거합니다.get_call_result_type
대안get_fn_expr_rettype
.
예를 들어, 우리가 수락 할 함수를 작성하고 싶다고 가정합니다. 모든 유형의 단일 요소 및 1 차원 배열을 반환합니다. 그 유형의 :
pg_function_info_v1 (make_array); 자료 make_array (pg_function_args) ArrayType *결과; OID Element_Type = get_fn_expr_argtype (fcinfo- flinfo, 0); 데이텀 요소; bool isnull; int16 typlen; 부리 타자 발; 숯 타입자; int ndims; int dims [maxdim]; int lbs [maxdim]; if (! oidisvalid (element_type)) elog (오류, "입력의 데이터 유형을 결정할 수 없음"); / * 제공된 요소를 가져 오십시오. isnull = pg_argisnull (0); if (isnull) 요소 = (Datum) 0; 또 다른 요소 = pg_getarg_datum (0); / * 우리는 하나의 차원이 있습니다 */ ndims = 1; / * 및 하나의 요소 */ 희미한 [0] = 1; / * 그리고 하한은 1 */ lbs [0] = 1; / * 요소 유형에 대한 필수 정보 받기 */ get_typlenbyvalalign (element_type, & typlen, & typbyval, & typalign); / * 이제 배열을 빌드 */ result = construct_md_array (& Element, & IsNull, ndims, dims, lbs, element_type, typlen, typbyval, typalign); pg_return_arraytype_p (결과);
다음 명령은 함수를 선언합니다make_array
sql :
함수 생성 make_array (Anylement)는 anyArray를 반환합니다 처럼 '디렉토리/funcs ','make_array ' 언어 C 불변;
애드 인은 LWLOCKS 및 공유 할당을 예약 할 수 있습니다 서버 시작의 메모리. 애드 인의 공유 라이브러리는 있어야합니다 지정하여 사전로드shared_preload_libraries. 공유 메모리는 다음과 같이 호출하여 예약됩니다.
void requestAdDinshMemsPace (int size)
에서_pg_init
기능.
lwlocks는 다음과 같이 예약됩니다.
void requestAdDinlWlocks (int n)
From_PG_INIT
.
가능한 경주 조건을 피하려면 각 백엔드가 사용해야합니다
LWLOCKaddinshmeminitlock
공유 할당에 연결하고 초기화 할 때
여기에 표시된대로 메모리 :
정적 mystruct *ptr = null; if (! ptr) bool 발견; lwlockacquire (addinshmeminitlock, lw_excluction); ptr = shmeminitstruct ( "나의 구조물 이름", 크기, & 발견); if (! ptr) elog (오류, "공유 메모리에서"); if (! 찾았다) SHMEM 영역의 내용을 초기화합니다. 다음을 사용하여 요청 된 LWLOCKS를 획득하십시오. ptr- mylockid = lwlockassign (); lwlockrelease (addinshmeminitlock);