Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 11162] ファイルの概要

このコミットは、Go言語の実験的なSQLパッケージ (exp/sql) において、time.Time 型のサポートを追加するものです。これにより、データベースとの間で日付や時刻のデータをGoの標準的なtime.Time型として直接やり取りできるようになります。具体的には、driverパッケージ内の型変換ロジックが更新され、time.Time型がパラメータとして渡されたり、スキャンされたりする際の処理が適切に行われるようになります。また、関連するテストファイルも更新され、time.Time型の変換とデータベース操作が正しく機能することを確認しています。

コミット

commit bf734d62d8210b3030757522c3e9ff581457daa4
Author: Brad Fitzpatrick <bradfitz@golang.org>
Date:   Fri Jan 13 15:45:05 2012 -0800

    exp/sql: add time.Time support
    
    Fixes #2694
    
    R=golang-dev, r
    CC=golang-dev
    https://golang.org/cl/5541057

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/bf734d62d8210b3030757522c3e9ff581457daa4

元コミット内容

exp/sql: add time.Time support

Fixes #2694

R=golang-dev, r
CC=golang-dev
https://golang.org/cl/5541057

変更の背景

この変更の背景には、Go言語の実験的なSQLパッケージが、データベースとの間で日付や時刻のデータを扱う際に、標準のtime.Time型を直接サポートしていなかったという問題があります。Issue #2694("exp/sql: add time.Time support")がこの機能追加の必要性を示しており、開発者がデータベースから取得した日付/時刻データを手動で変換したり、逆にGoのtime.Time型をデータベースに保存する際に不便を感じていたことが推測されます。このコミットは、このような手動変換の必要性をなくし、より自然でGoらしいデータベース操作を可能にすることを目的としています。

前提知識の解説

このコミットを理解するためには、以下のGo言語およびデータベース関連の基本的な知識が必要です。

  • Go言語のexp/sqlパッケージ: これはGoの標準ライブラリの一部として提供されているdatabase/sqlパッケージの実験的な前身、または関連するパッケージです。データベースとのインタラクション(接続、クエリの実行、結果の取得など)のための汎用的なインターフェースを提供します。
  • Go言語のtime.Time: Go言語で日付と時刻を扱うための標準的な型です。特定の時点を表現し、タイムゾーン情報なども保持できます。
  • SQLデータベースのデータ型: 多くのリレーショナルデータベースには、日付 (DATE)、時刻 (TIME)、日時 (DATETIME, TIMESTAMP) などの専用のデータ型が存在します。これらの型は、データベースシステムによって内部的な表現が異なります。
  • データベースドライバ: database/sqlパッケージは、特定のデータベースシステム(例: MySQL, PostgreSQL, SQLiteなど)と通信するための具体的な実装である「ドライバ」を介して動作します。ドライバは、Goのデータ型とデータベースのデータ型間の変換を担当します。
  • driver.Valuedriver.Scannerインターフェース: database/sqlパッケージでは、Goのカスタム型がデータベースとの間で値をやり取りできるように、driver.Value(Goの型からデータベースの型への変換)とdriver.Scanner(データベースの型からGoの型への変換)というインターフェースが定義されています。これらのインターフェースを実装することで、Goの任意の型をデータベースの列にマッピングできます。
  • 型変換 (Type Conversion): プログラミングにおいて、あるデータ型から別のデータ型へ値を変換するプロセスです。データベース操作においては、Goの型とデータベースの型の間で適切な変換が行われることが重要です。

技術的詳細

このコミットの技術的な核心は、exp/sqlパッケージの内部でtime.Time型を認識し、適切に処理するための型変換ロジックを拡張することにあります。

  1. driver/types.goの変更:

    • IsParameterSubsetType関数とIsScanSubsetType関数が更新され、time.Time型がパラメータとして渡せる型(IsParameterSubsetType)およびデータベースからスキャンできる型(IsScanSubsetType)のリストに追加されました。これにより、time.Time型の値がデータベースドライバに渡されたり、ドライバから返されたりする際に、これらの関数がtime.Time型を有効な型として認識するようになります。
    • 具体的には、switch v.(type)文のcasetime.Timeが追加されています。
  2. driver/driver.goの変更:

    • Valueインターフェースのドキュメントコメントにtime.Timeが追加され、time.Time型がdriver.Valueとしてサポートされることが明示されました。これは、Goのtime.Time型の値がデータベースドライバに渡される際に、driver.Valueインターフェースを満たす必要があることを示唆しています。
  3. テストファイルの更新:

    • convert_test.go: time.Time型の変換テストケースが追加されました。conversionTest構造体にwanttimeフィールドが追加され、TestConversions関数内でtime.Time型の値が正しく変換されるかどうかが検証されています。convertAssign関数がtime.Time型を処理できるように拡張されたことを示唆しています。
    • types_test.go: DefaultParameterConvertertime.Time型を正しく処理できることを確認するテストケースが追加されました。
    • fakedb_test.go: テスト用の偽のデータベース実装において、time.Time型がサポートされるようにcheckSubsetTypes関数が更新されました。また、converterForType関数に"datetime"型が追加され、DefaultParameterConverterが使用されるように設定されました。これは、データベースのDATETIME型がGoのtime.Time型にマッピングされることを示しています。
    • sql_test.go: 実際のSQL操作を模倣したテストにおいて、time.Time型を含むカラムを持つテーブルの作成、データの挿入、およびクエリによる取得がテストされています。CREATE文にbdate=datetimeが追加され、INSERT文でtime.Time型の値が渡されています。QueryRowScanを使ってtime.Time型の値が正しく取得できるかどうかが検証されています。

これらの変更により、exp/sqlパッケージはtime.Time型をネイティブに扱い、開発者が日付/時刻データをより簡単にデータベースとやり取りできるようになります。

コアとなるコードの変更箇所

このコミットにおけるコアとなるコードの変更箇所は、主に以下のファイルに集中しています。

  • src/pkg/exp/sql/driver/types.go:

    • IsParameterSubsetType関数とIsScanSubsetType関数において、time.Time型がサポートされる型リストに追加されました。
      // IsParameterSubsetType
      // ...
      //   time.Time
      // ...
      func IsParameterSubsetType(v interface{}) bool {
          if IsScanSubsetType(v) {
              return true
          }
          switch v.(type) {
          case int64, float64, []byte, bool, time.Time: // time.Time が追加
              return true
          }
          return false
      }
      
      // IsScanSubsetType
      // ...
      //   time.Time
      // ...
      func IsScanSubsetType(v interface{}) bool {
          if v == nil {
              return true
          }
          switch v.(type) {
          case int64, float64, []byte, bool, time.Time: // time.Time が追加
              return true
          }
          return false
      }
      
  • src/pkg/exp/sql/driver/driver.go:

    • Valueインターフェースのコメントにtime.Timeが追加され、サポートされる型として明示されました。
      // Value is a value that drivers must be able to handle.
      // It is a subset of the Go built-in types, plus []byte.
      //
      // The following types are supported:
      //   int64
      //   float64
      //   bool
      //   nil
      //   []byte
      //   string   [*] everywhere except from Rows.Next.
      //   time.Time // 追加
      //
      package driver
      

これらの変更は、exp/sqlパッケージがtime.Time型をデータベースとの間でやり取りする際の基本的な型チェックと変換ロジックを確立するものです。

コアとなるコードの解説

src/pkg/exp/sql/driver/types.goにおけるIsParameterSubsetTypeIsScanSubsetTypeの変更は、exp/sqlパッケージの型システムにおいてtime.Time型が「認識される」ようにするためのものです。

  • IsParameterSubsetType: この関数は、Goの特定の型がデータベースクエリのパラメータとして安全に渡せるかどうかを判断します。time.Timeがこのリストに追加されたことで、db.Execdb.Queryなどの関数にtime.Time型の値を直接渡せるようになります。ドライバは、このtime.Time値をデータベースが理解できる形式(例: タイムスタンプ文字列や数値)に変換する責任を負います。

  • IsScanSubsetType: この関数は、データベースから読み取られた値がGoの特定の型に安全にスキャンできるかどうかを判断します。time.Timeがこのリストに追加されたことで、rows.Scanrow.Scanなどの関数を使って、データベースのDATETIMEDATETIMETIMESTAMPなどの列の値をGoの*time.Time変数に直接読み込むことができるようになります。ドライバは、データベースの値をGoのtime.Time型に変換する責任を負います。

src/pkg/exp/sql/driver/driver.goにおけるValueインターフェースのコメント更新は、time.Time型がdriver.Valueインターフェースを実装している、または実装すべきであることを示唆しています。driver.Valueインターフェースは、Goの型がデータベースドライバに渡される際に、どのような形式で渡されるべきかを定義します。time.Timeがこのリストに含まれることで、ドライバはtime.Time型の値を適切に処理し、データベースに送信できるようになります。

これらの変更は、exp/sqlパッケージがtime.Time型を「ファーストクラスの市民」として扱い、開発者が日付/時刻データを扱う際の利便性と型安全性を向上させるための基盤となります。

関連リンク

参考にした情報源リンク