Innovating today, leading tomorrow

OpenSQL_Technical Guide
[OpenSQL] (Interface) GO – PGX

[OpenSQL] (Interface) GO – PGX

PGX 개요

PGX란?

pgx is a pure Go driver and toolkit for PostgreSQL.
The pgx driver is a low-level, high performance interface that exposes PostgreSQL-specific features such as LISTEN / NOTIFY and COPY. It also includes an adapter for the standard database/sql interface.
– pgx 공식 github –

순수하게 Go language만을 사용해 만든 PostgreSQL 드라이버 입니다.
COPY, LISTEN, NOTIFY 등 PoostgreSQL 특화 기능들을 지원하는 등 로우 레벨, 고성능을 지향하고 있는 드라이버이며, 표준 database/sql 인터페이스용 어댑터도 포함하고 있습니다.

database/sql란?

SQL 또는 SQL형태의 데이터베이스에 대해 제공되는 generic interface 입니다.
database/sql 패키지는 database/sql/driver 패키지와 같이 사용되어야 하며, driver 패키지는 여러 종류의 데이터베이스를 GO 언어를 통해 사용할 수 있도록 설계되었습니다.

pgx 이외에도 PostgreSQL에 연결 가능한 드라이버 목록은 아래의 링크를 통해 확인 하실 수 있습니다.

https://github.com/golang/go/wiki/SQLDrivers

여러 종류의 PostgreSQL용 드라이버가 있지만, PGX를 사용하는 이유는 다른 드라이버보다 빠르게 성장 및 관리가 되고 있으며, PostgreSQL 특화 기능들을 많이 지원하기 때문입니다.

지원 기능

  • Support for approximately 70 different PostgreSQL types
  • Automatic statement preparation and caching
  • Batch queries
  • Single-round trip query mode
  • Full TLS connection control
  • Binary format support for custom types (allows for much quicker encoding/decoding)
  • COPY protocol support for faster bulk data loads
  • Tracing and logging support
  • Connection pool with after-connect hook for arbitrary connection setup
  • LISTEN / NOTIFY
  • Conversion of PostgreSQL arrays to Go slice mappings for integers, floats, and strings
  • hstore support
  • json and jsonb support
  • Maps inet and cidr PostgreSQL types to netip.Addr and netip.Prefix
  • Large object support
  • NULL mapping to pointer to pointer
  • Supports database/sql.Scanner and database/sql/driver.Valuer interfaces for custom types
  • Notice response handling
  • Simulated nested transactions with savepoints

PGX 버전 호환성 확인

PGX가 공식적으로 지원하는 GO 버전은 최신 2개의 major 릴리즈 버전입니다. 작성일 기준 가장 최신의 GO 버전은 1.20 버전이므로, 1.19 이상 버전부터 지원됩니다.

PostgreSQL 버전은 최근 5년안에 릴리즈 된 모든 major 버전을 지원합니다.
작성일 기준 PostgreSQL 11 버전부터 지원합니다.

GO 버전1.19 이상
PostgreSQL 버전11.0 이상

PGX 다운로드

PGX는 go get 명령어를 이용하여, 모듈에 쉽게 추가할 수 있습니다.

go get github.com/jackc/pgx/v5

PGX 설치

Linux(CentOS7) 와 Windows 10 두 환경에서 설치를 해보도록 하겠습니다.

GO Language가 설치되어 있지 않다면, 아래의 링크를 참조하여 설치해주시기 바랍니다.
https://go.dev/doc/install

Linux (CentOS 7)에 설치

설치 시 필요한 패키지 목록

postgresql-14.2 기준

  • go 1.20.4 (1.19.0 이상 필요, 실습에는 최신 stable 버전인 1.20.4를 사용하도록 하겠습니다.)

실습 환경은 GO를 아래와 같이 설치하도록 하겠습니다.

GO 설치

1. GO Language 다운로드 Liunx 버전으로 다운로드 합니다.
https://go.dev/dl/

2. 설치
root 유저로 설치 합니다.

rm -rf /usr/local/go && tar -C /usr/local -xzf go1.20.4.linux-amd64.tar.gz

3. 실습을 진행할 유저의 환경변수 PATH에 GO를 추가합니다.

su – opensql
vi ~/.bash_profile

#아래 내용 추가
export PATH=$PATH:/usr/local/go/bin

#저장 후 현재 세션에도 적용시켜줍니다.
source ~/.bash_profile

4. 설치가 잘 되었는지 확인합니다.

$ go version

go version go1.20.4 linux/amd64

PGX 설치

1. PGX를 사용할 프로젝트를 생성해줍니다.

mkdir pgxTest
cd pgxTest

2.프로젝트에 사용할 GO 모듈을 초기화 합니다.

go mod init pgxTest

go: creating new go.mod: module pgxTest

3. PGX를 Go 모듈에 추가합니다.

go get github.com/jackc/pgx/v5

go: downloading github.com/jackc/pgx/v5 v5.3.1
go: downloading github.com/jackc/pgx v3.6.2+incompatible
go: downloading github.com/jackc/pgpassfile v1.0.0
go: downloading github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a
go: downloading golang.org/x/crypto v0.6.0
go: downloading golang.org/x/text v0.7.0
go: added github.com/jackc/pgpassfile v1.0.0
go: added github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a
go: added github.com/jackc/pgx/v5 v5.3.1
go: added golang.org/x/crypto v0.6.0
go: added golang.org/x/text v0.7.0

4. PGX가 잘 설치되었는지 확인합니다.
go.mod 파일을 확인하면, pgxTest 모듈에 어떤 패키지가 필요한지 정보가 나와있습니다.

cat go.mod

module pgxTest

go 1.20

require (
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
github.com/jackc/pgx/v5 v5.3.1 // indirect
golang.org/x/crypto v0.6.0 // indirect
golang.org/x/text v0.7.0 // indirect
)

Windows 10 (64-bit)에 설치

설치 시 필요한 패키지 목록

postgresql-14.2 기준

  • go 1.20.4 (1.19.0 이상 필요, 실습에는 최신 stable 버전인 1.20.4를 사용하도록 하겠습니다.)

실습 환경은 GO를 아래와 같이 설치하도록 하겠습니다.

GO 설치

1.GO Language 다운로드 Microsoft Windows 버전으로 다운로드 합니다.
https://go.dev/dl/

2. GO Language설치

3. 설치가 잘 되었는지 확인합니다.
윈도우 버전의 인스톨러에는 환경변수가 자동으로 잡혀있습니다.

# 시작 – 실행 – cmd

go version

go version go1.20.4 windows/amd64

PGX 설치

1.PGX를 사용할 프로젝트를 생성해줍니다.

# 시작 – 실행 – cmd를 실행하였으므로, 프로젝트 위치는 C:Users유저명 입니다.

mkdir pgxTest
cd pgxTest

2. 프로젝트에 사용할 GO 모듈을 초기화 합니다.

go mod init pgxTest

go: creating new go.mod: module pgxTest

3. PGX를 Go 모듈에 추가합니다.

go get github.com/jackc/pgx/v5

4. PGX가 잘 설치되었는지 확인합니다.
go.mod 파일의 내용을 확인하면, pgxTest 모듈에 어떤 패키지가 필요한지 정보가 나와있습니다.

type go.mod

module pgxTest

go 1.20

require (
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
github.com/jackc/pgx/v5 v5.3.1 // indirect
golang.org/x/crypto v0.6.0 // indirect
golang.org/x/text v0.7.0 // indirect
)

PGX 사용방법

PGX 사용방법 – Linux(CentOS 7)

사용방법 실습 환경
아래와 같은 환경에서 PGX를 사용 해보는 실습을 진행하겠습니다.

OSCentOS 7.9
PostgreSQL VersionPostgreSQL 14.2
Go VersionGO 1.20.4
PGX Version5.3.1

사용방법 실습 순서

1.실습에 필요한 테스트 코드 파일을 생성합니다.
설치에 사용했던 project를 이용하시거나, 새로운 프로젝트라면 go get을 이용해 프로젝트에 모듈로 PGX를 추가하셔야 합니다.

프로젝트에 테스트 코드가 담긴 pgxTest.go 파일을 생성 하겠습니다. connURL의 유저명, 패스워드, 호스트, 포트, 데이터베이스명을 변경해서
사용하시면 됩니다.

package main

import (
“context”
“fmt”
“os”

    "github.com/jackc/pgx/v5"

)

func main() {
ctx := context.Background()

    connURL := "postgres://postgres:1234@222.121.72.226:15454/postgres"
    conn, err := pgx.Connect(ctx, connURL)
    if err != nil {
            fmt.Fprintf(os.Stderr, "Unable to connect to database: %vn", err)
            os.Exit(1)
    }
    defer conn.Close(ctx)

    rows, err := conn.Query(context.Background()," SELECT datname FROM pg_stat_database WHERE datname IS NOT NULL;")
    if err != nil {
            fmt.Fprintf(os.Stderr, "Query Execution failed: %vn", err)
            os.Exit(1)
    }
    defer rows.Close()

    fmt.Print("| ")
    for _, fd := range rows.FieldDescriptions() {
            fmt.Print(string(fd.Name)+" | ")
    }
    fmt.Println("")

    var rowSlice []string
    for rows.Next() {
var datname string
        err := rows.Scan(&datname)
        if err != nil {
            fmt.Fprintf(os.Stderr, "QueryRow failed: %vn", err)
            os.Exit(1)
        }
        rowSlice = append(rowSlice, datname)
    }

    for i := 1; i<len(rowSlice); i++{
            fmt.Println("| "+rowSlice[i]+" | ")
    }

}

2. 테스트 파일을 실행합니다.

go run pgxTest.go

go run pgxTest.go

아래와 같이 pg_stat_database 카탈로그에서 datname을 읽어온 결과가 출력됩니다.

| datname |
| template1 |
| template0 |
| test1 |
| test2 |

PostgreSQL과 호환되고, 속도가 빠른 데이터 타입을 사용하고 싶다면,
pgtype 패키지를 사용하시기 바랍니다.
pgx v5 버전은 내장되어 있습니다.

PGX 사용 방법 – Windows 10

사용방법 실습 환경

아래와 같은 환경에서 PGX를 사용 해보는 실습을 진행하겠습니다.

OSCentOS 7.9
PostgreSQL VersionPostgreSQL 14.2
Go VersionGO 1.20.4
PGX Version5.3.1

사용방법 실습 순서

1.실습에 필요한 테스트 코드 파일을 생성합니다. 설치에 사용했던 project를 이용하시거나, 새로운 프로젝트라면 go get을 이용해 프로젝트에 모
듈로 PGX를 추가하셔야 합니다.
프로젝트에 테스트 코드가 담긴 pgxTest.go 파일을 생성 하겠습니다. connURL의 유저명, 패스워드, 호스트, 포트, 데이터베이스명을 변경해서
사용하시면 됩니다.

package main

import (
“context”
“fmt”
“os”

    "github.com/jackc/pgx/v5"

)

func main() {
ctx := context.Background()

    connURL := "postgres://postgres:1234@222.121.72.226:15454/postgres"
    conn, err := pgx.Connect(ctx, connURL)
    if err != nil {
            fmt.Fprintf(os.Stderr, "Unable to connect to database: %vn", err)
            os.Exit(1)
    }
    defer conn.Close(ctx)

    rows, err := conn.Query(context.Background()," SELECT datname FROM pg_stat_database WHERE datname IS NOT NULL;")
    if err != nil {
            fmt.Fprintf(os.Stderr, "Query Execution failed: %vn", err)
            os.Exit(1)
    }
    defer rows.Close()

    fmt.Print("| ")
    for _, fd := range rows.FieldDescriptions() {
            fmt.Print(string(fd.Name)+" | ")
    }
    fmt.Println("")

    var rowSlice []string
    for rows.Next() {
var datname string
        err := rows.Scan(&datname)
        if err != nil {
            fmt.Fprintf(os.Stderr, "QueryRow failed: %vn", err)
            os.Exit(1)
        }
        rowSlice = append(rowSlice, datname)
    }

    for i := 1; i<len(rowSlice); i++{
            fmt.Println("| "+rowSlice[i]+" | ")
    }

}

2. 테스트 파일을 실행합니다.
go run pgxTest.go

go run pgxTest.go

아래와 같이 pg_stat_database 카탈로그에서 datname을 읽어온 결과가 출력됩니다.

| datname |
| template1 |
| template0 |
| test1 |
| test2 |

PostgreSQL과 호환되고, 속도가 빠른 데이터 타입을 사용하고 싶다면,pgtype 패키지를 사용하시기 바랍니다.
pgx v5 버전은 내장되어 있습니다.

PGX 사용 방법 – Windows 10

사용방법 실습 환경

아래와 같은 환경에서 PGX를 사용 해보는 실습을 진행하겠습니다.

OSWindows 10
PostgreSQL VersionPostgreSQL 14.7
Go Version1.20.4

사용방법 실습 순서

1.실습에 필요한 테스트 코드 파일을 생성합니다. 메모장을 이용해서 테스트 코드가 담긴 pgxTest.go 파일을 생성 하겠습니다.

package main

import (
“context”
“fmt”
“os”

    "github.com/jackc/pgx/v5"

)

func main() {
ctx := context.Background()

    connURL := "postgres://postgres:1234@222.121.72.226:15454/postgres"
    conn, err := pgx.Connect(ctx, connURL)
    if err != nil {
            fmt.Fprintf(os.Stderr, "Unable to connect to database: %vn", err)
            os.Exit(1)
    }
    defer conn.Close(ctx)

    rows, err := conn.Query(context.Background()," SELECT datname FROM pg_stat_database WHERE datname IS NOT NULL;")
    if err != nil {
            fmt.Fprintf(os.Stderr, "Query Execution failed: %vn", err)
            os.Exit(1)
    }
    defer rows.Close()

    fmt.Print("| ")
    for _, fd := range rows.FieldDescriptions() {
            fmt.Print(string(fd.Name)+" | ")
    }
    fmt.Println("")

    var rowSlice []string
    for rows.Next() {
var datname string
        err := rows.Scan(&datname)
        if err != nil {
            fmt.Fprintf(os.Stderr, "QueryRow failed: %vn", err)
            os.Exit(1)
        }
        rowSlice = append(rowSlice, datname)
    }

    for i := 1; i<len(rowSlice); i++{
            fmt.Println("| "+rowSlice[i]+" | ")
    }

}


2. 테스트 파일을 실행합니다.
cmd를 이용하여 CLI 환경에서 실행해보도록 하겠습니다.

cd pgxTest
go run pgxTest.go

아래와 같이 pg_stat_database 카탈로그에서 datname을 읽어온 결과가 출력됩니다.

| datname |
| template1 |
| template0 |
| test1 |
| test2 |

PostgreSQL과 호환되고, 속도가 빠른 데이터 타입을 사용하고 싶다면,
pgtype 패키지를 사용하시기 바랍니다.
pgx v5 버전은 내장되어 있습니다.

오류가 발생 한다면?

연결 오류

Unable to connect to database: failed to connect to host=192.168.200.151 user=postgres database=postgres: dial error (dial tcp 192.168.200.151:5432: connectex: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.) exit status 1

오류가 발생해요!

답변내용 :

PostgreSQL 서버에 접속이 불가능 한 상태입니다!

1. PostgreSQL 서버 기동 상태를 확인합니다.

  • PostgreSQL 데이터베이스 서버가 기동되어 있지 않다면 접속이 불가능합니다.
  • 기동이 되어 있다면 postgresql.conf와 postgresql.auto.conf의 listen_addresses 파라미터를 확인해주세요.

2. Host와 Port를 한번 더 확인 해주시기 바랍니다.

  • Host와 Port가 잘못 입력 되어서 입력 받은 접속 정보로 연결이 불가능 할 경우 위와 같은 메시지가 출력됩니다.

3. PostgreSQL 서버의 방화벽을 확인합니다.

  • 접속을 시도하는 서버가 PostgreSQL 서버의 방화벽에 막히지 않는지 방화벽 설정을 확인 해주시기 바랍니다.

Unable to connect to database: failed to connect to host=192.168.200.151 user=postgres database=postgres: server error (FATAL: no pg_hba.conf entry for host “192.168.200.135”, user “postgres”, database “postgres”, no encryption (SQLSTATE 28000)) exit status 1

오류가 발생해요!

답변내용

PostgreSQL의 pg_hba.conf에 연결 허용 설정이 되어있지 않아서 그렇습니다! pg_hba.conf에 접속 정보를 추가 해주세요! 아래는 TCP 연결을 통해 192.168.123.123 호스트로 부터 온 연결 요청에 대해서 모든 데이터베이스 및 모든 유저로 접속이 가능하고 패스워드는 입력하지 않아도 접속이 가능 하도록 설정하는 예시 입니다.

#TYPE DATABASE USER ADDRESS METHOD
host all all 192.168.123.123/32 trust

쿼리 오류

Query Execution failed: ERROR: column “oid” does not exist (SQLSTATE 42703) exit status 1

오류가 발생해요!

답변내용

수행한 쿼리에서 oid 컬럼을 SELECT 하려고 하지만, FROM절의 대상 테이블 또는 서브쿼리에 oid 컬럼이 존재하지 않습니다.

해결 방안 1. 조회하려고 하는 테이블에 해당 컬럼이 존재하는지 확인합니다.

  • 아래의 쿼리에서 WHERE절의 테이블명만 변경해서 조회 하시거나, psql 클라이언트의 d 명령어를 이용하는 방법이 있습니다.
    `d 테이블명

SELECT a.attname,
pg_catalog.format_type(a.atttypid, a.atttypmod),
(SELECT pg_catalog.pg_get_expr(d.adbin, d.adrelid, true)
FROM pg_catalog.pg_attrdef d
WHERE d.adrelid = a.attrelid AND d.adnum = a.attnum AND a.atthasdef),
a.attnotnull,
(SELECT c.collname FROM pg_catalog.pg_collation c, pg_catalog.pg_type t
WHERE c.oid = a.attcollation AND t.oid = a.atttypid AND a.attcollation <> t.typcollation) AS attcollation,
a.attidentity,
a.attgenerated,
a.attstorage,
a.attcompression AS attcompression,
CASE WHEN a.attstattarget=-1 THEN NULL ELSE a.attstattarget END AS attstattarget,
pg_catalog.col_description(a.attrelid, a.attnum)
FROM pg_catalog.pg_attribute a LEFT OUTER JOIN pg_catalog.pg_class c on a.attrelid=c.oid
WHERE a.attnum > 0 AND NOT a.attisdropped AND c.relname=’테이블명’
ORDER BY a.attnum;

QueryRow failed: can’t scan into dest[0]: cannot scan NULL into *string exit status 1

오류가 발생해요!

답변내용

쿼리를 수행한 결과 값이 NULL이라서 그렇습니다.
전체가 NULL일 수도 있고, 특정 ROW만 NULL일 수 있어서 데이터를 확인 하시거나, NULL에 대한 에러 처리가 필요합니다.

PGX 에 대한 더욱 자세한 정보는 아래의 github 또는 go package 정보를 확인 해주시기 바랍니다!
https://github.com/jackc/pgx
https://pkg.go.dev/github.com/jackc/pgx

지금까지 ‘(Interface) GO – PGX’에 관해 알아보았습니다

‘PostgreSQL의 (Interface) Ruby – pg’를 바로 이어서 확인해보세요!


광고성 정보 수신

개인정보 수집, 활용 목적 및 기간

(주)티맥스티베로의 개인정보 수집 및 이용 목적은 다음과 같습니다.
내용을 자세히 읽어보신 후 동의 여부를 결정해 주시기 바랍니다.

  • 수집 목적: 티맥스티베로 뉴스레터 발송 및 고객 관리
  • 수집 항목: 성함, 회사명, 회사 이메일, 연락처, 부서명, 직급, 산업, 담당업무, 관계사 여부, 방문 경로
  • 보유 및 이용 기간: 동의 철회 시까지

※ 위 개인정보 수집 및 이용에 대한 동의를 거부할 권리가 있습니다.
※ 필수 수집 항목에 대한 동의를 거부하는 경우 뉴스레터 구독이 제한될 수 있습니다.

개인정보의 처리 위탁 정보
  • 업체명: 스티비 주식회사
  • 위탁 업무 목적 및 범위: 광고가 포함된 뉴스레터 발송 및 수신자 관리
 

개인정보 수집 및 이용

개인정보 수집, 활용 목적 및 기간

(주)티맥스티베로의 개인정보 수집 및 이용 목적은 다음과 같습니다. 내용을 자세히 읽어보신 후 동의 여부를 결정해 주시기 바랍니다.

  • 수집 목적: 티맥스티베로 뉴스레터 발송 및 고객 관리
  • 수집 항목: 성함, 회사명, 회사 이메일, 연락처, 부서명, 직급, 산업, 담당업무, 관계사 여부, 방문 경로
  • 보유 및 이용 기간: 동의 철회 시까지

※ 위 개인정보 수집 및 이용에 대한 동의를 거부할 권리가 있습니다.
※ 필수 수집 항목에 대한 동의를 거부하는 경우 뉴스레터 구독이 제한될 수 있습니다.

개인정보의 처리 위탁 정보

  • 업체명: 스티비 주식회사
  • 위탁 업무 목적 및 범위: 광고가 포함된 뉴스레터 발송 및 수신자 관리
  •