postgresql 내장 개발의addmonths 함수 실전
15138 단어 postgresql 내장 개발원본 코드 학습
pg 앞에서 실현된 Helloworld 입문은 사실상 하나의 함수를 실현한 것이지만 이 함수는 설명적 의미만 있고 함수 실현의 세부 사항도 상세하게 소개하지 않았다. 본고는postgresql 내부에서 어떻게 하나의 함수의 실현을 완성하는지 상세하게 소개하고자 한다.oracle에서addmonths 함수는 현재 시간에 근거하여 몇 개월을 증가하거나 줄일 수 있으며,postgresql에는 이런 함수가 없습니다.addmonths는 다음postgresql의 함수 증가 방법을 소개하는 예가 있다.C 언어에서 하나의 함수를 실현하는 것은 매우 간단하다. 함수 주체를 실현하기만 하면 된다. 다른 파일에서 사용하면include 헤더 파일에서 명성을 얻으면 된다. 이 두 단계는postgresql 핵에서도 자연히 있어야 하지만 동작을 추가하여 pg 에 등록해야 한다.proc 시스템 테이블에서 pgproc는postgresql의 함수의 시스템 표입니다.우선 함수를 실현한다. 시간과 관련된 함수이기 때문에 src/backend/utils/adt/date에 넣을 수 있다.c중,addmonths_date 및 addmonths_timestamp, 헤더 파일 src/include/utils/date.h 명성 증가, 코드는 다음과 같다.
Datum
add_months_date(PG_FUNCTION_ARGS)
{
DateADT date = PG_GETARG_DATEADT(0);
int added_mon = PG_GETARG_INT32(1);
struct pg_tm tt;
struct pg_tm * tm = &tt;
bool isLastDay = false;
int LastDay;
int year;
int mon;
int day;
DateADT result = 0;
/* check range */
if (DATE_NOT_FINITE(date))
{
PG_RETURN_DATEADT(date);
}
j2date((date + POSTGRES_EPOCH_JDATE), &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
year = tm->tm_year;
mon = tm->tm_mon;
day = tm->tm_mday;
isLastDay = (day == day_tab[isleap(year)][mon - 1]);
mon += added_mon;
if (mon > 12)
{
year += ((mon - 1) / 12);
mon = (((mon - 1) % 12) + 1);
}
else if (mon < 1)
{
year += ((mon / 12) - 1);
mon = ((mon % 12) + 12);
}
LastDay = day_tab[isleap(year)][mon - 1];
day = isLastDay ? LastDay : ((day > LastDay) ? LastDay : day);
if (!IS_VALID_JULIAN(year, mon, day))
{
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("date out of range")));
}
result = (DateADT)(date2j(year, mon, day) - POSTGRES_EPOCH_JDATE);
PG_RETURN_DATEADT(result);
}
Datum
add_months_timestamp(PG_FUNCTION_ARGS)
{
Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
int added_mon = PG_GETARG_INT32(1);
struct pg_tm tt;
struct pg_tm * tm = &tt;
bool isLastDay = FALSE;
int LastDay;
int year;
int mon;
int day;
int tz;
fsec_t fsec;
Timestamp result = 0;
if (TIMESTAMP_NOT_FINITE(timestamp))
{
PG_RETURN_TIMESTAMP(timestamp);
}
if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
{
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
}
year = tm->tm_year;
mon = tm->tm_mon;
day = tm->tm_mday;
isLastDay = (day == day_tab[isleap(year)][mon - 1]);
mon += added_mon;
if (mon > 12)
{
year += ((mon - 1) / 12);
mon = (((mon - 1) % 12) + 1);
}
else if (mon < 1)
{
year += ((mon / 12) - 1);
mon = ((mon % 12) + 12);
}
LastDay = day_tab[isleap(year)][mon - 1];
day = isLastDay ? LastDay : ((day > LastDay) ? LastDay : day);
tm->tm_year = year;
tm->tm_mon = mon;
tm->tm_mday = day;
if (tm2timestamp(tm, fsec, NULL, &result) != 0)
{
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
}
PG_RETURN_TIMESTAMP(result);
}
src/include/utils/date.h
extern Datum add_months_date(PG_FUNCTION_ARGS);
extern Datum add_months_timestamp(PG_FUNCTION_ARGS);
여기는 아니야ddmonths 함수 내부 논리가 깊고 관심 있는 것은oracle 이 함수의 표현을 연구할 수 있다. 대조적으로 함수체 실현을 완성한 데 중점을 두고 pg 에 다시 등록하기만 하면proc에서 새로운 증가 함수를 실현할 수 있습니다.어떻게 등록합니까?src/include/catalog/pgproc.h 새 코드는 다음과 같습니다.
DATA(insert OID = 9998 (add_months PGNSP PGUID 12 1 0 0 0 f f f f t f i f 2 0 1082 "1082 23" _null_ _null_ _null_ _null_ _null_ add_months_date _null_ _null_ _null_));
DATA(insert OID = 9997 (add_months PGNSP PGUID 12 1 0 0 0 f f f f t f i f 2 0 1114 "1114 23" _null_ _null_ _null_ _null_ _null_ add_months_timestamp _null_ _null_ _null_));
DATA(insert OID = 9996 (add_months PGNSP PGUID 14 1 0 0 0 f f f f t f i f 2 0 1114 "1184 23" _null_ _null_ _null_ _null_ _null_ "select add_months($1::timestamp,$2)" _null_ _null_ _null_));
OK, 추가해야 할 코드가 모두 완성되고, 컴파일되고, 설치되고, 라이브러리를 다시 초기화하고, 다음 테스트를 실행합니다.
postgres=# \d a
Table "public.a"
Column | Type | Modifiers
--------+-----------------------------+-----------
a | date |
b | timestamp without time zone |
postgres=# select *from a;
a | b
------------+----------------------------
2016-12-04 | 2016-12-04 22:17:28.447829
2016-02-28 | 2016-02-29 00:00:00
(2 rows)
postgres=# select a,add_months(a,3),b,add_months(b,4) from a;
a | add_months | b | add_months
------------+------------+----------------------------+----------------------------
2016-12-04 | 2017-03-04 | 2016-12-04 22:17:28.447829 | 2017-04-05 06:17:28.447829
2016-02-28 | 2016-05-28 | 2016-02-29 00:00:00 | 2016-06-30 08:00:00
(2 rows)
add_months의 기능이 정상적입니다. 이로써 내부 함수가 증가했습니다. 다음에 질문하는 방식으로 다음 가능한 의문들을 상세하게 소개하겠습니다.첫 번째 문제, 왜 두 개의 함수를 추가해야 하는지, 하나만add 이 아니다.months요?사실 모두 세 개가 늘었다.이 세 외부 호출은 모두addmonths 함수, 매개 변수에 따라 재부팅, pgproc.h 등록할 때 이 매개 변수를 설명합니다.(뒤에 상세한 설명이 있다) 두 번째 질문, 등록은 무슨 뜻입니까?템플릿 라이브러리에 기록을 삽입해서 라이브러리를 만들면 바로 있습니다.시스템 테이블에 대해 말하자면, 헤더 파일에 이 시스템 테이블에 대한 상세한 정의 설명이 있습니다. 이 헤더 파일 아래에 형식에 따라 기록을 미리 설정할 수 있습니다. 이 기록은 initdb에 있을 때 템플릿 라이브러리에 대응하는 시스템 테이블에 삽입됩니다.구체적으로 말하면, 이러한 미리 설정된 기록은 컴파일하는 과정에서perl 스크립트에postgres로 변환됩니다.bki에서 이 bki 파일은 디렉터리를 설치하는share 폴더에 있습니다. initdb에서 이 bki를 불러오고 하나의 ql 실행으로 해석하여 시스템 테이블을 만들고 초기 기록을 삽입하여 초기 정보를 준비합니다.관심 있는 분들은 initdb 모듈에서bootstraptemplate1 함수, 모듈을 초기화할 때 첫 번째는postgres를 불러오는 것입니다.bki 파일 번역 해석 실행.세 번째 문제, pgproc.h에 삽입된 기록은 어떤 의미입니까?첫 번째 행동 예로는 DATA(insert OID = 9998(add months PGNSP PGUID 12 1 0 0 f f f f t f i f 2 0 1082 "1082 23"null null null null null add months date null null null);
postgres=# select oid,typname from pg_type where oid in (1082,23,1114,1184) ;
oid | typname
------+-------------
23 | int4
1082 | date
1114 | timestamp
1184 | timestamptz
(4 rows)
nodeToString()
의 표현 방식에 따라).이것은 pronargdefaults 요소의 목록입니다. 마지막 N 개의 input 인자 (즉 마지막 N 개의 proargtypes 위치) 에 대응합니다.기본값이 있는 인자가 없으면 이 필드는 비어 있습니다 이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Mycat 연결 탱크 모형 원본 코드Physical DBNode는 Mycat 집단(Datanode)의 대응으로 하나의 연결 탱크 대상인 Physical DBPool을 인용하고 Physical DBPool에서 진정한 연결 탱크 대상인 Physical D...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.