- 다음 블로그 포스팅을 참고하여
POSTGRES
익스텐션을 만드는 과정을 실습해볼 것이다, 우선 소스코드를 다운로드 받고 디렉터리를 확인해보면 다음과 같다.
-
여기서
contrib
라고 하는 디렉터리가 바로, 익스텐션이 저장되어 있는 디렉터리이다. 소스코드에 포함된 많은 익스텐션을 확인 할 수 있다. -
여기서 우리는
base36
인코딩을 하는 익스텐션을 만들어볼 예정이다.
설정 파일 생성
- 우선 익스텐션을 만들려면 총 3가지의 파일이 필요하다. 첫번째는 익스텐션에 대한 정보를 나타내는
*.control
파일이다. 두 번째는 해당 익스텐션의 소스코드인*.sql
이다. 세 번째는 어떻게 빌드할지에 대한Makefile
이다. 첫번째로base36.control
파일부터 작성해보겠다.
# base36 extension
comment = 'base36 datatype'
default_version = '0.0.1'
relocatable = true
- base36 익스텐션에 대한 메타정보이다.
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
\echo Use "CREATE EXTENSION base36" to load this file. \quit
CREATE FUNCTION base36_encode(digits int)
RETURNS text
LANGUAGE plpgsql IMMUTABLE STRICT
AS $$
DECLARE
chars char[];
ret varchar;
val int;
BEGIN
chars := ARRAY[
'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','g','h',
'i','j','k','l','m','n','o','p','q','r','s','t', 'u','v','w','x','y','z'
];
val := digits;
ret := '';
WHILE val != 0 LOOP
ret := chars[(val % 36)+1] || ret;
val := val / 36;
END LOOP;
RETURN(ret);
END;
$$;
PL/pgsql
로 작성된 익스텐션이다.
EXTENSION = base36 # the extensions name
DATA = base36--0.0.1.sql # script files to install
# postgres build stuff
ifdef USE_PGXS
PG_CONFIG = pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs)
include $(PGXS)
else
subdir = contrib/base36
top_builddir = ../..
include $(top_builddir)/src/Makefile.global
include $(top_srcdir)/contrib/contrib-global.mk
endif
- 마지막으로
Makefile
이다. 빌드를 어떻게 할지를 나타낸다.
- 그리고 나서
sudo make install
을 해당 디렉터리에서 입력하면, 설치가 완료된다. 설치가 된다는 것은 사실postgres
가 설치된 파일의extension
디렉터리로*.source, *.sql
파일이 이동하는 것이기는 하다.
- 클라이언트에 접속해서
CREATE EXTENSION base36;
을 실행하면 익스텐션이 생성되었다고 나오며,SELECT base36_encode(123456789);
다음 쿼리문을 실행하면 성공적으로 인코딩이 이루어지는 것을 확인할 수 있다.
테스트 작성
-
sql
디렉터리를 만든 후에,base36_test.sql
파일에 익스텐션에서 만든 함수를 사용하는 쿼리를 적는다. 그리고 Makefile 파일로 이동해서, REGRESS 항목에 아까 폴더에 만든 테스트 파일을 입력하면 된다. -
그리고 나서,
sudo make install && sudo make installcheck
를 입력하면 자동으로result
디렉터리가 만들어지고, 쿼리의 실행결과가 저장된다. -
이 실행 결과를
expected
디렉터리에 만들고 나서, 다시 테스트를 실행하면 예상 결과에 맞다면 테스트가 통과하게 되고 예상 결과와 다르다면 테스트가 실패했다는 사실을 알려준다.
성능 높히기
- 익스텐션을 반복해서 많이 사용하면 성능이 좋지 못하다는 것을 확인할 수 있다. 따라서 이를
C
로 다시 작성해서 성능을 끌어올려볼 것이다.
#include "postgres.h"
#include "fmgr.h"
#include "utils/builtins.h"
PG_MODULE_MAGIC;
PG_FUNCTION_INFO_V1(base36_encode);
Datum
base36_encode(PG_FUNCTION_ARGS)
{
int32 arg = PG_GETARG_INT32(0);
char base36[36] = "0123456789abcdefghijklmnopqrstuvwxyz";
/* max 6 char + '\0' */
char *buffer = palloc(7 * sizeof(char));
unsigned int offset = (7 * sizeof(char));
buffer[--offset] = '\0';
do {
buffer[--offset] = base36[arg % 36];
} while (arg /= 36);
PG_RETURN_TEXT_P(cstring_to_text(&buffer[offset]));
}
base36.c
파일을 생성하고 나서, 위의 코드를 작성한다.
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
\echo Use "CREATE EXTENSION base36" to load this file. \quit
CREATE FUNCTION base36_encode(integer) RETURN text
AS '$libdir/base36'
LANGUAGE C IMMUTABLE STRICT;
*.sql
파일에 내용을 다음과 같이 입력한다.
EXTENSION = base36 # the extensions name
DATA = base36--0.0.1.sql # script files to install
REGRESS = base36_test # our test script file (without extension)
MODULE = base36
# postgres build stuff
ifdef USE_PGXS
PG_CONFIG = pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs)
include $(PGXS)
else
subdir = contrib/base36
top_builddir = ../..
include $(top_builddir)/src/Makefile.global
include $(top_srcdir)/contrib/contrib-global.mk
endif
- 그리고 나서,
MakeFile
에MODULE
필드에base36
을 입력해주면 된다.