12.2 SML#へのSQL式の導入
SQLのSELECT文はFROM節に記述されたテーブルの集合から 一つのテーブルを作成する式です. SQL言語は,ある特定のデータベースへの接続の下でSQL式を評価する機 能を提供しますが,これをデータベース接続を受け取りテーブルを返す関数式に 一般化すれば,関数型言語の型システムに統合することができます. テーブルはレコードの構造をしているため,多相レコードの型付けがほ ぼそのまま使用できます. しかし我々SML#チームの研究によって,このデータベースを受 け取る関数の型付けには,多相レコード以外にさらに型理論的な機構が必要であ ることが示されています[14]. そこで,データベース接続を受け取る関数には特別の文法を用意します. SML#では,前節のSQL式の例は,以下のような式で表現されます.
_sql db => select #P.name as name, #P.age as age
from #db.Persons as P
where #P.salary > 10000
_sql db => ...は,データベース接続を変数dbとして受 け取る問い合わせ関数であることを示しています. _sql式の中の>はデータベース問い合わせを実現する ライブラリモジュールSQLの中に定義されたSQLの値のための 大小比較プリミティブです. #P.NameはタプルPのNameフィールドの取り出し演算, #db.PersonsはデータベースdbからのPersonsテーブル取り 出し演算です. これらは,SML#式では#Name P#Persons dbと書か れるレコードからのフィールド取り出し式に相当します. _sql => 式では,SQLの文法に類似の構文を採用して います. この式に対して以下の型が推論されます.
val it = fn
: [’a#{Persons: ’b list},
’b#{age: ’c, name: ’e, salary: int},
’c::{int, intInf, word, char,...},
’d::{int, intInf, word, char,...},
’e::{int, intInf, word, char,...},
’f::{int, intInf, word, char,...},
’a SQL.conn -> {age: ’c, name: ’e} SQL.cursor]
この型は,’aの構造を持つデータベース接続の型 ’a connから{age: ’c, name: ’e}を列とする結果テーブルの型 への関数型です. ’aは,この問い合わせに必要なデータベース構造を表すレコード 多相型です. このようにSQL式は多相型を持つため,MLプログラミングの原理「式は 型が正しい限り自由に組み合わせることができる」に従って,第一級のデータ としてSML#の他の機能とともに自由にプログラムすることができます.