ターミナル用データベースクライアント SQL-Bless のメンテを再開しています。
今までは、NYAGOS は Windows 7, 8, Server 2008R2 で動作させるため、ビルドは Go 1.20.14 で固定してきました。それとエコシステムが地続きということもあって、他のアプリも 1.20.14 にあわせてきました。1
が、ローカルで完結する NYAGOS はともかく、DB アプリはそろそろまずい気がしてきました。ということで、SQL-Bless は Go 1.20.14 縛りを解除して、最新 Go に切り替えることにします。
が、その前に Go 1.20.14 でビルドする「最後のバージョン」をリリースしておくべきでしょう。ということで、go1.20.14 get でビルドできるライブラリだけでもアップデートです。
> go1.20.14.exe get github.com/sijms/go-ora/v2@latest
go: upgraded github.com/sijms/go-ora/v2 v2.8.22 => v2.9.0
残念ながら go-ora 以外でエラーなくアップデートできたものはなし。そしてテスト:
> cd test
> pwsh test-oracle.ps1
; 中略
UPDATE TESTTBL
SET DT = :v1 , ST = :v2
WHERE TESTNO = :v3 AND DT = :v4 AND ST = :v5
(v1) time.Date(2015, time.June, 7, 20, 21, 22, 0, time.Local)
(v2) time.Date(2024, time.August, 9, 10, 11, 12, 787800000, time.Local)
(v3) 10
(v4) time.Date(2024, time.May, 25, 13, 45, 33, 0, time.Location(""))
(v5) time.Date(2024, time.July, 8, 17, 18, 19, 878700000, time.Location(""))
Apply this change? ("y":yes, "n":no, "a":all, "N":none) y
Starts a transaction
0 record(s) updated.
no data found
テーブルを編集して1件更新が走るはずが、スカってしまってテスト失敗。どうも、WHERE 句がマッチしなくなってしまったようです。
SET句で使われているバインド変数 v1 や v2 はユーザが編集した結果なので、SQL-Bless 側で生成した time.Time です。それゆえロケーションが time.Local になっています。一方、WHERE 句で使われている v4, v5 は DB から fetch してきた time.Time そのものです。これのロケーション名が空文字になっています。
そもそも Oracle の DATE 型や TIMESTAMP はタイムゾーン情報がないため、Go言語の time.Time 型へ読み込む場合ドライバー側でロケーション情報を補完する必要がありますが、どうやら、その動作が変わってしまったようです。観測範囲では、v2.8 系では time.Local に近い形で補完されていた一方、v2.9 系では空のロケーション情報となるケースが見られました。
レポジトリにも issue も出ていました。
今後の方針は次のようにしました。
- とりあえず、動かないと困るので、go-ora は一旦 v2.8 に固定2
→ SQL-Bless v0.27.6
- 恒久対応として、 DATE/TIMESTAMP型を照合する場合、文字列として日時情報を送り、SQL上の
TO_DATE 関数, TO_TIMESTAMP関数で DB 内で日時型へ戻すようにする
(なるべく ドライバーに time.Time を扱わせない)
→ #55, #57
しかし、データベースの日時型というのは、タイムゾーンを持たない「壁時計時刻」(wall-clock time) で扱っているものも多いため、この文字列で扱うという個別対応は、他の DB 対応にも展開した方がよいかもしれません。
なお、自分が go-ora を使っているのはPure Go 製の唯一の Oracle ドライバーパッケージだったためです(ドライバー一覧)。これが CGO 製だとC言語コンパイラが必要になって、他の OS 環境向けのビルド(クロスコンパイル)が面倒になってしまうんですよね。自分の選定はそういう事情があってのものであるため、そういうマルチ OS 対応が特に必要ないという方は他のドライバーパッケージを使うのも選択肢かもしれません。
追記
最新ソース版では次のように文字列ベースになっています
UPDATE TESTTBL
SET DT = TO_DATE(:v1,'YYYY-MM-DD HH24:MI:SS') , ST = TO_TIMESTAMP(:v2,'YYYY-MM-DD HH24:MI:SS.FF')
WHERE TESTNO = :v3 AND DT = TO_DATE(:v4,'YYYY-MM-DD HH24:MI:SS') AND ST = TO_TIMESTAMP(:v5,'YYYY-MM-DD HH24:MI:SS.FF')
(v1) "2015-06-07 20:21:22"
(v2) "2024-08-09 10:11:12.7878"
(v3) 10
(v4) "2024-05-25 13:45:33"
(v5) "2024-07-08 17:18:19.8787"
Apply this change? ("y":yes, "n":no, "a":all, "N":none) y
Starts a transaction
1 record(s) updated.