🐘

GolangでPostgreSQL(その2)

2023/06/19に公開

はじめに

先日、Golang で PostgreSQL の各種データ型を扱った場合の評価を行いました。

https://zenn.dev/robon/articles/9d6ba760a74b89

今回は、日本語の識別子、データを扱った場合の評価を行います。

PostgreSQL

データベース

前回と同様、Amazon RDS 上に構築した PostgreSQL サーバを使用します。

テスト用のテーブル

対象とするデータ型

前回は、全てのデータ型を対象としましたが、今回は文字データを保持するものを対象とします。

名称 別名 説明
character varying [ (n) ] varchar [ (n) ] 可変長文字列
character [ (n) ] char [ (n) ] 固定長文字列
json JSONデータ
text 可変長文字列
xml XMLデータ

PostgreSQL は、潔いです。

テスト用のテーブル

ちょっとアレな感じの CREATE TABLE 文にします。

CREATE TABLE 日ほンゴ表 (
    列1 varchar(10),
    れつ2 character(10),
    レツ3 json,
    レツ4 text,
    Retsu5 xml,
    CONSTRAINT pk_日ほンゴ表 PRIMARY KEY(列1)
);

Golang

処理系とライブラリ

前回と同様、Golang は、1.18.6。github.com/lib/pq は、v1.10.9 を使用します。

アプリケーション

前回と同様ですが、Golang 側の識別子も日本語にしてみます。ただし、Golang の識別子の先頭文字は、パッケージ外への export の可否の識別に使われるため、先頭文字は英大文字にしておきます。
(こうしないと google/co-cmp/cmp で panic になります)

package main

import (
	"database/sql"
	"log"
	"os"
	"reflect"

	"github.com/google/go-cmp/cmp"
	"github.com/jmoiron/sqlx"
	_ "github.com/lib/pq"
)

// S日ほンゴ表 は、日本語テストテーブル
type S日ほンゴ表 struct {
	F列1     sql.NullString `db:"列1"`     // varchar(10)
	Fれつ2    sql.NullString `db:"れつ2"`    // character(10)
	Fレツ3    sql.NullString `db:"レツ3"`    // json
	Fレツ4    sql.NullString `db:"レツ4"`    // text
	FRetsu5 sql.NullString `db:"Retsu5"` // xml
}

// Key は、日本語テストテーブルのキー
type Key struct {
	Col01 string `db:"col1"`
}

func main() {
	dsn := os.Getenv("DSN")
	db, err := sqlx.Open("postgres", dsn)
	if err != nil {
		log.Printf("sql.Open error %s", err)
	}

	key := Key{"カヘン長文字列"}
	src := S日ほンゴ表{
		F列1:     sql.NullString{String: "カヘン長文字列", Valid: true},
		Fれつ2:    sql.NullString{String: "コテイ長文字列   ", Valid: true},
		Fレツ3:    sql.NullString{String: `{"日本語キー":"日本語文字列"}`, Valid: true},
		Fレツ4:    sql.NullString{String: "あぁアアガAa漢〇€㈱ー~―‐-", Valid: true},
		FRetsu5: sql.NullString{String: "<xml /><ルートノード></ルートノード>", Valid: true},
	}

	_, err = db.NamedExec(`
		INSERT INTO 日ほンゴ表 (
			列1, れつ2, レツ3, レツ4, Retsu5
		) VALUES (
			:列1, :れつ2, :レツ3, :レツ4, :Retsu5
		)`,
		src,
	)
	if err != nil {
		log.Printf("db.Exec error %s", err)
	}

	dst := S日ほンゴ表{}
	query, args, err := db.BindNamed(`
		SELECT 
			列1, れつ2, レツ3, レツ4, Retsu5
		FROM 日ほンゴ表 
		WHERE 列1 = :col1`,
		key,
	)
	if err != nil {
		log.Printf("db.BindNamed error %s", err)
	}
	err = db.QueryRowx(query,
		args...,
	).StructScan(
		&dst,
	)
	if err != nil {
		log.Printf("db.QueryRow error %s", err)
	}
	if !reflect.DeepEqual(src, dst) {
		// log.Printf("\nsrc = %#v\ndst = %#v\n", src, dst)
		diff := cmp.Diff(src, dst)
		if len(diff) > 0 {
			log.Print(diff)
		}
	}

	_, err = db.NamedExec(`
		DELETE FROM 日ほンゴ表
		WHERE 列1 = :col1`,
		key,
	)
	if err != nil {
		log.Printf("db.Exec error %s", err)
	}
}

sqlx の問題

今回の評価で明らかになったのですが、sqlx の Named Query は、マルチバイト Unicode 対応できていません。

このため、このプログラムを動かすには、sqlx を修正する必要があります。今回の修正は、sqlx には プルリク 済みです(が、休眠しているようなので、取り込まれないかもしれません)。

上記のソースコードに、このプルリクの修正を適用して動かすためには、以下のリポジトリを clone して、go.mod で replace する必要があります。

https://github.com/roboninc/sqlx

https://github.com/take0a/go-sqlx-sample/blob/master/go.mod

おわりに

今回の評価では、PostgreSQL 特有の日本語の問題は発見できませんでした。
(sqlx の修正を取り込んでもらえることを祈ります。)

GitHubで編集を提案
株式会社ROBONの技術ブログ

Discussion