• 다음 블로그 포스팅을 참고하여 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
  • 그리고 나서, MakeFileMODULE 필드에 base36을 입력해주면 된다.

참고 문헌

>> Home