go-oci8のセットアップ手順（Linux）

日本語で解説された情報を見つけられなかったので書いてみました。
*\# Go言語をプロダクト投入するための後押しになるかも!? q@w@p* 

# go-oci8とは？

Go言語でOracle Databaseへアクセスするためのパッケージです。

* [mattn/go-oci8 ・ GitHub](https://github.com/mattn/go-oci8)

今回は`Red Hat Enterprise Linux`で動作を確認しました。

# 前提条件

* Go言語がインストールされていること。
* SQL*Plusクライアントがインストールされていること。
* Oracle Databseはインストールされていなくてもよい。

## バージョン確認

いずれも最新版ではありませんが、大丈夫でした。

```csh:Go
$ go version
go version go1.3 linux/amd64
```

```csh:SQL*Plus
$ sqlplus -v
SQL*Plus: Release 11.2.0.4.0 Production
```

# Instant Client

## Instant Clientのダウンロード

OracleのサイトからSQL*Plusのバージョンに合わせたInstant Clientをダウンロードします。

* [Instant Client Downloads](http://www.oracle.com/technetwork/database/features/instant-client/index-097480.html)
* [Instant Client Downloads for Linux x86-64](http://www.oracle.com/technetwork/topics/linuxx86-64soft-092277.html)

今回ダウンロードしたzipファイル

* instantclient-basic-linux.x64-11.2.0.4.0.zip
* instantclient-sdk-linux.x64-11.2.0.4.0.zip

SQL*Plusクライアント？

* instantclient-sqlplus-linux.x64-11.2.0.4.0.zip

## ダウンロードファイルの展開

root権限にて`/usr/local`へ展開。

```csh:
$ su
# unzip instantclient-basic-linux.x64-11.2.0.4.0.zip -d /usr/local
Archive:  instantclient-basic-linux.x64-11.2.0.4.0.zip
  inflating: instantclient_11_2/BASIC_README
  inflating: instantclient_11_2/adrci
  inflating: instantclient_11_2/genezi
  inflating: instantclient_11_2/libclntsh.so.11.1
  inflating: instantclient_11_2/libnnz11.so
  inflating: instantclient_11_2/libocci.so.11.1
  inflating: instantclient_11_2/libociei.so
  inflating: instantclient_11_2/libocijdbc11.so
  inflating: instantclient_11_2/ojdbc5.jar
  inflating: instantclient_11_2/ojdbc6.jar
  inflating: instantclient_11_2/uidrvci
  inflating: instantclient_11_2/xstreams.jar
# unzip instantclient-sdk-linux.x64-11.2.0.4.0.zip -d /usr/local
Archive:  instantclient-sdk-linux.x64-11.2.0.4.0.zip
   creating: instantclient_11_2/sdk/
   creating: instantclient_11_2/sdk/include/
  inflating: instantclient_11_2/sdk/include/occi.h
  inflating: instantclient_11_2/sdk/include/occiCommon.h
  inflating: instantclient_11_2/sdk/include/occiControl.h
  inflating: instantclient_11_2/sdk/include/occiData.h
  inflating: instantclient_11_2/sdk/include/occiObjects.h
  inflating: instantclient_11_2/sdk/include/occiAQ.h
  inflating: instantclient_11_2/sdk/include/oci.h
  inflating: instantclient_11_2/sdk/include/oci1.h
  inflating: instantclient_11_2/sdk/include/oci8dp.h
  inflating: instantclient_11_2/sdk/include/ociap.h
  inflating: instantclient_11_2/sdk/include/ociapr.h
  inflating: instantclient_11_2/sdk/include/ocidef.h
  inflating: instantclient_11_2/sdk/include/ocidem.h
  inflating: instantclient_11_2/sdk/include/ocidfn.h
  inflating: instantclient_11_2/sdk/include/ociextp.h
  inflating: instantclient_11_2/sdk/include/ocikpr.h
  inflating: instantclient_11_2/sdk/include/ocixmldb.h
  inflating: instantclient_11_2/sdk/include/ocixstream.h
  inflating: instantclient_11_2/sdk/include/odci.h
  inflating: instantclient_11_2/sdk/include/oratypes.h
  inflating: instantclient_11_2/sdk/include/ori.h
  inflating: instantclient_11_2/sdk/include/orid.h
  inflating: instantclient_11_2/sdk/include/orl.h
  inflating: instantclient_11_2/sdk/include/oro.h
  inflating: instantclient_11_2/sdk/include/ort.h
  inflating: instantclient_11_2/sdk/include/xa.h
  inflating: instantclient_11_2/sdk/include/nzt.h
  inflating: instantclient_11_2/sdk/include/nzerror.h
  inflating: instantclient_11_2/sdk/include/ldap.h
   creating: instantclient_11_2/sdk/demo/
  inflating: instantclient_11_2/sdk/demo/demo.mk
  inflating: instantclient_11_2/sdk/demo/cdemo81.c
  inflating: instantclient_11_2/sdk/demo/occidemo.sql
  inflating: instantclient_11_2/sdk/demo/occidemod.sql
  inflating: instantclient_11_2/sdk/demo/occidml.cpp
  inflating: instantclient_11_2/sdk/demo/occiobj.cpp
  inflating: instantclient_11_2/sdk/demo/occiobj.typ
  inflating: instantclient_11_2/sdk/SDK_README
 extracting: instantclient_11_2/sdk/ottclasses.zip
  inflating: instantclient_11_2/sdk/ott
```

## シンボリックリンクの作成

root権限にてシンボリックリック`libclntsh.so`を作成。

```csh:
$ su
# cd /usr/local/instantclient_11_2
# ln -s libclntsh.so.11.1 libclntsh.so
```

# pkg-config

## oci8.pcファイルの確認

以下のコマンドを実行して、何も表示されない場合はO.K.
`no`と表示された場合は、`oci8.pc`ファイルを作成。

```csh:
$ pkg-config --exists oci8 || echo no
```

### oci8.pcファイルの作成

root権限でファイルを作成。

```csh:
$ su
# vim /usr/lib/pkgconfig/oci8.pc
```

```vim:oci8.pc
prefix=/usr/local/instantclient_11_2/
libdir=${prefix}
includedir=${prefix}/sdk/include/

Name: oci8
Description: Oracle Instant Client
Version: 11.2
Libs: -L${libdir} -lclntsh
Libs.private:
Cflags: -I${includedir}
```

## 環境変数`PKG_CONFIG_PATH`の設定

`.bash_profile`ファイルに環境変数`PKG_CONFIG_PATH`を追加。

```csh:
$ cd
$ vim .bash_profile
```

```vim:.bash_profile
export PKG_CONFIG_PATH=/usr/lib/pkgconfig/
```

# go-oci8

## go-oci8の取得

`go get`にてダウンロード。

```csh:
$ cd $GOPATH/src
$ go get github.com/mattn/go-oci8
```

## カレントディレクトリーの移動

```csh:
$ cd $GOPATH/src/github.com/mattn/go-oci8/_example
```

## oracle.goの実行（1回目）

`NLS_LANG error`になりました。

```csh:
$ go run oracle.go
NLS_LANG error: should be Japanese_Japan.AL32UTF8, not Japanese_Japan.UTF8!Please specifiy connection parameter in GO_OCI8_CONNECT_STRING environment variable,
or as the first argument! (The format is user/name@host:port/sid)
exit status 1
```

### `NLS_LANG`エラーに対応

今回は`oracle.go`ファイルの13行目を修正することで対応しました。

```csh:
$ vim oracle.go
```

```vim:oracle.go（変更後）
13:  if !strings.HasSuffix(nlsLang, ".AL32UTF8") {
```

```vim:oracle.go（修正後）
13:  if !strings.HasSuffix(nlsLang, ".UTF8") {
```

## oracle.goの実行（2回目）

データベース接続パラメーターがない旨のメッセージが表示されました。

```vim:oracle.go
$ go run oracle.go
Please specifiy connection parameter in GO_OCI8_CONNECT_STRING environment variable,
or as the first argument! (The format is user/name@host:port/sid)
exit status 1
```

### データベース接続パラメーター

「環境変数への設定」と「実行時引数として指定」の２種類の方法があります。

* 環境変数`GO_OCI8_CONNECT_STRING`に設定する場合

```csh:
$ export GO_OCI8_CONNECT_STRING=scott/tiger@192.168.2.1:1521/ORAGOKU
```
* 実行時に引数で指定する場合

```csh:
$ go run oracle.go scott/tiger@192.168.2.1:1521/ORAGOKU
```
今回は「環境変数での設定」で対応しました。

## oracle.goの実行（3回目）

UTF-8文字列も正しく表示されることを確認できました！

```csh:
$ go run oracle.go
+3.140000e+000 foo
'Habitacion doble', '雙人房', 'двухместный номер'
```

# 開発資料

oracle.goなどのgo-oci8パッケージ配下のソースや以下のドキュメントなどをご参照下さい。

* [oci8 - GoDoc](https://godoc.org/github.com/mattn/go-oci8)
* [sql - The Go Programming Language](http://golang.org/pkg/database/sql/)

# 参考情報

## oracle.go実行時のエラー集

* `/usr/lib/pkgconfig`配下に`oci8.pc`ファイルがない場合
* 環境変数`PKG_CONFIG_PATH`が設定されていない場合

```csh:
$ go run oracle.go
# pkg-config --cflags oci8
Package oci8 was not found in the pkg-config search path.
Perhaps you should add the directory containing 'oci8.pc'
to the PKG_CONFIG_PATH environment variable
No package 'oci8' found
exit status 1
```

* シンボリックリンク`libclntsh.so`が作成していない場合

```csh:
$ go run oracle.go
# github.com/mattn/go-oci8
/usr/bin/ld: cannot find -lclntsh
collect2: ld はステータス 1 で終了しました
```

## .bash_profile（抜粋）

```vim:.bash_profile（抜粋）
export ORACLE_BASE=/opt/oracle
export ORACLE_HOME=${ORACLE_BASE}/product/11.2.0/db_1
export ORACLE_SID=ORAGOKU
PATH=${ORACLE_HOME}/bin:${PATH}
export LD_LIBRARY_PATH=${ORACLE_HOME}/lib:${LD_LIBRARY_PATH}
export NLS_LANG=japanese_japan.UTF8
# [start] for golang
export GOROOT=/usr/local/go
PATH=${PATH}:${GOROOT}/bin
# [ end ] for golang
# [start] for go-oci8
export PKG_CONFIG_PATH=/usr/lib/pkgconfig
# [ end ] for go-oci8
export PATH
```

## 参照サイト

* [linux下使用go-oci8 - 蝈蝈俊 - 博客园](http://www.cnblogs.com/ghj1976/p/3512555.html)

* [Centny/Articles/How build github.com:mattn:go-oci8.md at master ・ Centny/Centny ・ GitHub](https://github.com/Centny/Centny/blob/master/Articles/How%20build%20github.com:mattn:go-oci8.md)