#ああ、regexp-replaceがdisplayで文字列化をやってくれるんだった。
#confファイルで評価するなら、いっそのこと各置換パラメータ (room-name等) をparameterとして定義しちゃって、confファイル自体をloadさせればいいかも。そしたらトップレベル式も評価されるし。includeは既にloadでサポートされてる (非公式だけど)。
#dbd.mysql は insert の場合に dbi-execute が mysql_insert_id を返すとうれしいかもしれない。
#select以外の場合の戻り値ってあんまりちゃんと考えてないんだよね。dbiに見せるならバックエンドに依存しない値が望ましいけど、もともと使ってないものならバックエンド毎に意味を持たせるってのはありかもしれない。
#そうですね。insert なら insert_id、update なら updateされた行を知りたいってのは良くあることだと思うので本当は dbi がそういうインターフェースを持つのが良さそうな気もします。
#update された行ではなくて、「update された行数」の間違い。
#dbiのレイヤではいろんなバックエンドに対応できなくちゃならなくて、insert_idとかupdate行数が定義できないバックエンドもあるから、dbi公式仕様は最大公約数的にならざるを得ない。
#アプリ毎に、「バックエンドはmysqlだとわかってるからinsert_idが取れるはず」などと判断して使うのはokだろう。
#Perl の場合だと http://search.cpan.org/~timb/DBI/DBI.pm を見ると last_insert_id というのがありますね。どこまでが最大公約数と判断するかは難しいなあ。 #例えば (dbi-do conn "insert ...") => id なんて場合には、dbdのほうでinsertとselect last_insert_id() ...の二つがクエリされる感じですか?
#そういう実装になると思います。mysql の場合は dbd.mysql が mysql_insert_id を呼ぶことで last_insert_id を取得する感じだと思います。
#(どうもです。Chaton改造版、機能よさそうなのあったらどうぞ持っていってください。
#"insert ..."だけしたつもりが"insert ..."と"select last_insert_id () ..."の二つがクエリされてた、ってなると個人的には怖い感じがします。dbdの一個上の層でそういうの作るなら良いと思いますが(個人的には)。
#s/dbdの一個上/dbiの一個上/
#dbiに渡すDSNのオプションでどっちも選べるようにするとか。DSNのオプションの解釈はdbdに任されてるし。insert_idみたいな非標準機能を使うアプリは当然DSNオプションも使い方に合わせて書けるし。
#ところでlast_insert_idを別コールで取る場合、複数スレッドがdbにアクセスしてたらどうなるんだろう。
#insert と select last_insert_id の間にほかの人が insert するとずれません?
#MySQL
#MySQLの場合、コネクション毎にlast_insert_idの値は個別管理されているはずです。同一コネクションの中でINSERT/SELECTを一気に行えば、last_insert_idはずれないはずです。
#last_insert_idの値を生成するAUTO_INCREMENTカラムの扱いは、RDBMSによって異なってくるので、異なるRDBへの移行が起こりうる場合は慎重に扱う必要があります。個人的にはdbiは現状のまま、last_insert_idを扱うラッパーを上からかけて、さらにその上から抽象化するのがいいと思っていたのですが、そうすると同じような抽象化レイヤーが二重になってしまうのかな?
#私自身は、以前はAUTO_INCREMENTカラムをレコードIDにするコードを書いていましたが、最近ではUUIDでレコードを識別するようにしています。UUIDの一意性がどこまで信用できるのかはまだ不安なのですが、IBMのページに大丈夫ってあったようなので、とりあえず信用しています。
#ちなみにuuidgenのコードは次のとおりです。
#(define (uuidgen)
(let* ((process (run-process '("uuidgen" "-t") :output :pipe))
(line (read-line (process-output process))))
(process-wait process)
line))
#UNIXコマンドをそのまま使っているだけです。
#Perl の DBI のように last_insert_id という項目自体は dbi にあり、値の意味は下のレイヤーによって異なるというアプローチが現実的な気がします。異なる RDB への移行の場合はそのあたりをチェックする責任はプログラマにあると。
#私自身は、dbiにはlast_insert_id取得を含めて欲しくないなあ、というのが正直なところです。実際問題としてAUTO_INCREMENTカラムがなければ意味がないし、INSERTの時に自動的にSELECTかけられるのもちょっと・・・。もしlast_insert_id取得をオプションにするという場合でも、呼び出し時のオプションが増えるのは好ましくありません。それにAUTO_INCREMENTカラムを使う手法って、No-SQLの利用ノウハウがRDBサイドにフィードバックされることで、だんだん少なくなっていくのではないかなあ、という気もするんですよ。(根拠はないんですが)
#前言一部撤回。オプションは増えてもいいです。使わなければいいんだ。last_insert_id取得をオプションで実装、というのはアリですね。
#last_insert_id は実際便利ですよね。last っていうと「最後」っていう感じがするけど、自分が最後に insert した行、っていう意味ですよね。
#もう SQL は 5 年以上触ってないですが、そろそろまた仕事で使うかもしれないので、いろいろ思い出さなきゃ。
#>Pettal管理人さん、本題とは関係ないけど、外部コマンド起動して出力を取るのは (process-output->string '(uuidgen "-t")) でいけますよ。
#ありがとうございます。圧倒的にシンプルですね。リファクタリングしなくちゃ。
#リファレンスを改めて確認。なんだ、こんないいFunctionを見落としてたなんて。「できた!」と思うとすぐコーディングしちゃう、悪い癖。
#sf.netへのアタックの影響で、sf.netのCVSサービスがいずれフェードアウトするっぽい。いくつか古いプロジェクトはまだCVSのままだったがこの機会に移行するかなあ。 https://sourceforge.net/blog/sourceforge-attack-full-report/ #リビングの床がらむ太の「ぴたごらそうち」で埋め尽くされつつある。あれはどこにいったんだ、と思って探すと装置の一部になってること多し。時々物理法則に反する動きをさせようとして「もうなんでうごかないの!」と泣いて怒っている。自然の法則は厳しいものなのだよ。そうやって身に刻め。
#Gaucheのdbiって使ったことないのですが、RDBの抽象化レイヤーって必要なんでしょうか? (ちょっと極端)
#昔、Javaのアプリで複数種類のRDBに対応するようなアプリを作ったことがあるのですが、RDBごとにSQLの構文も違いますし、トランザクションやロックの考え方も異なるため、insertやselectといった単位でなく、もうちょっと大きな単位で抽象化(いわゆるビジネスロジックみたいなもの)して、各RDBごとの処理を実装することになったことがあります。
#RDB の抽象化は2つの理由で必要かなと思います。
#で、性能のチューニングとか始めると個々のRDBに特化した機能をつかうはめになるので、あんまり抽象化されるとかえって使いにくかったような。
#(1)いわゆるDBDを書く人たちが I/F ばらばらなものを書いてしまうのを防ぐ(プログラマが困る)
#(2) もうひとつは最大公約数だけしか使わないという大半の人たちが楽できる
#koguro さんのようなケースでは確かに不要だというのは賛成です。
#結局チューニング等でごにょごにょすることがありますよね。
#最近ではデータの取得は大きな単位での抽象化(repository)もよく見かけますね。Java の世界では特にそうかも。
#うーん、そもそも「どんなRDBでも動くアプリを作りたい」という要望ってそんなにあるんでしょうか?
#はっきり言ってないです。
#そうではなくて
#極端な話、今だったらMySQL固定(PostgreSQLでもいいけど)じゃだめですか?
#このアプリは MySQL、もう一つのアプリは PostgreSQL という場合に似たような書き方ができるのがうれしいのではないかと。
#それだったら、「APIの指針」を決めとくレベルでいいんじゃないかなと思うのですが。
#プログラマがdb毎に違うapiを覚えなくちゃならない負担を減らすっていう意味はありますね。
#あ、かぶった。
#MySQL 固定で良いというのは賛成です。なので Mosh でも MySQL の dbd しかありません。
#APIが似ていればよくて、一致させる必要はないような気がします。
#そこは微妙なラインですね>一致させる必要はない
#そうかな? dbiみたいな形になってれば共通構造が抽象化できるチャンスは増えると思いますが
#うーん、「共通構造」って具体的にどんなものを指していますか?
#たとえSQL本体がDB毎にチューニングしたものであっても、「何か
#「何かSQL投げて、結果をこう料理する」というような部分は共通だったりするとか。どちらかというとアプリを書く人よりは、ミドルウェアを書く人の発想ですが。
#>「何かSQL投げて、結果をこう料理する」
#まさに今そんなコードを書いています。
#その場合、SQLとDSNを外から与えてもらえれば、中はdbiでだいたい書けるってことはあるんじゃないかと。
#あと、いずれチューニングでDB毎にコードが分岐するとしても、とりあえず動くフレームワークを先に作っておけるってのはメリットじゃないかと。
#うーん、実際に以前業務アプリのミドルウェアを書いていたのですが、RDB毎にトランザクションやロックの考え方が変わるので、先にRDBを決定しないと設計が難しかったりしました。なので、RDBを決めないうちにプログラムを書いてうれしいかなと思ったりしています。
#koguro さんのお仕事の問題領域がやや特殊なのかもしれません。自分はもう少しカジュアルなものをイメージしています。
#RDBの使い方は千差万別で、気軽な永続ストレージとして使う場合と、がっつり使う場合とで違ってくるでしょう。koguroさんの使い方が特殊だとは思いませんが。
#ああそうですね。特殊というのは間違い。
#いわゆるSI的なお仕事が多かったんですが、だいたい最後には「Oracle直接触らせろ」みたいな感じになってました。
#まあ、dbiがいらないというのは極端ですが、例えば「MySQLのdbdのレイヤーでは、MySQLのC API+Scheme風にアレンジしたAPIを提供する」「dbiではdbdで提供するもののサブセット(最大公約数的な物)を提供する」というふうにして、個々のRDBに特化した機能を使いたい場合dbdを直接触れるようにするのがいいのかな、と思います。
#たとえばJavaだとJDBCというライブラリがあるのでコネクションなどが抽象化できるわけですが。(たとえばテスト用にはPostgreSQLを使って本番用はOracle、とか)
#ありますねー>「Oracle直接触らせろ」
#今でもそうなってますよ>dbiは最大公約数、dbdはDB-specific
#DB-specificというのは、dbd.mysqlなら mysql-なんちゃら という形でlibmysqlに対応するapiが見えるということです。
#今のところ必要最小限の機能しか見せてないってのはありますが。精神としてはdbdで見せられるだけ見せる。
#dbmインタフェースも同じですね。dbm-なんちゃら は最大公約数、dbm.gdbmなんかでは gdbm-なんちゃら でspecificなルーチンが叩ける。
#精神なそうかなと思っていたのですが、ソース見たらMySQL C APIを全部公開していないみたいだったので。
#最初に思ったのは、last_index_idみたいな機能ってdbiじゃなくてdbdのレイヤでサポートすればいいんじゃないかな、と。
#プログラマが個々のRDBを気にかける必要があるなら、それはdbiでなくdbdの領分かなと思います。
#単に怠惰なだけです>C APIが全部公開されてないの
#怠惰は重要な美徳です :-)
#特定のRDBだけのものならdbd、というのはそのとおりだと思います。ただまあ、dbiにはお手軽インタフェースって役割もあって、そういうお手軽な使い方でlast_index_idが帰ってくるとコードがうんと短くなるっていうなら、まあサポートするのもありかなと。
#もちろんオプションで。
#うーん、それならPettal管理人さんがやっていたように、「UUID生成してからinsert」の方が汎用的でいいんじゃないかなと思います。少なくともOracleだとlast_index_idの実装は面倒です。
#それならそれでも。私自身はlast_index_id使ったことないので判断できませんです。
#UUID パターンは行の順序を別カラムで管理しないといけないのが若干面倒かも。
#う、そもそもRDBを使うときに「行の順序」なんてものがinherentにあるという概念がない。
#どこまで厳密にするかですが、「とりあえず一意っぽいIDをinsertしてみる」「一意制約違反ならIDをつくり直してもう一回やりなおす」というのはどうでしょう?
#ありですねー。
#それは正しい理解です。RT : shiro: う、そもそもRDBを使うときに「行の順序」なんてものがinherentにあるという概念がない。
#んー、dbi/dbdがデータベースのスキーマに干渉するんですか?
#order by id とすると楽なのですよ(何
#いや、dbiを使う人がそういうスキーマを作るってことで、dbiが勝手にidをつけるってわけじゃないです。ですよね?>all
#はい。dbi の外側の話ですね。
#そのイメージです。
#なるほど。
#あれ、ちょっと目を離していた間にずいぶん盛り上がっていますね。とりあえず一言。ID(レコードの一意性)とORDER(順序)は切り離しておいた方がいいと思いますよ。両者は本質的に違う意味を持っているから。一意性は絶対的ですが、順序性は相対的です。私ならIDはUUIDにしておいて、順序性が必要であればそのためのカラムを用意します。でもAUTO_INCREMENTですむのであれば、Timestampの方が汎用性が高いです。
#UUID生成してからINSERTっていう方法は、(1)クエリーの回数を減らせるのでコストが低い、(2)一意性をアプリケーション側でコントロールできるので融通が利く、というメリットがあります。その点はKoguroさんの意見に賛成です。
#私がAUTO_INCREMENTの利用をあきらめたのは、MySQLとPostgreSQLではデータ型が違うし、Oracleでは扱いが厄介、という点に躊躇したからという理由があります。
#でも個々のRDBMSで仕様がカナリ違うからといって、すべてRDBMSに直アクセスというのはもったいない話で、可能であれば「最大公約数」的な機能をdbiで提供していただいて、その上で各RDBMSに特化した機能を実装した方が、プログラマーとしては融通が利くのかなあ、という気持ちがあります。そういう意味で「dbiはいまのままでOKなんですよね。
#koguroさんの「RDBを決めないうちにプログラムを書いてうれしいかなと思ったりしています」というのは、実感としてよくわかります。私もDB2、Sybase、Oracle、MysqlとRDBを渡り歩いて(なんていうと格好いいですけど、とりあえず使ってみて)、共通項はあるにしても「なんでこんな肝心なところが違うの?」と思ったことが多々ありました。でもこの20年間の流れをみていると、進化のスピードは 言語<アプリケーション<データストア<ハードウェア という気がするんですよね(またまた根拠はない)。そうであれば今の段階でRDBMSがある程度多様化するのは必然なのかもしれません。実際ひとつのアプリケーションが複数のデータストアを乗り換えて生き残っていくっていうケースはけっこうあります。そうすると、やはり「このコードで他のデータストアに移行できるか」って、気になります。ハードウェアの乗り換えを意識する人は多いと思うんだけど、その次はデータストアの乗り換えを意識した方がいいのかもしれない。そういう意味で最大公約数的な抽象化を行うdbiの存在は偉大だと思ってます。
#分野ごとに特性が違うのかもしれませんが、今まで私はあんまり他のデータストアに切り替えるといった例は見たことなかったです。
#データベースって変えにくくて、上のプログラムが変わってもデータベースはそのままというのが多かったような。
#データベースが切り替わるのはシステム全体を新しく作り替えるとき、っていうのはよくありました。
#業務に特化したアプリケーションだと、ここ15年はOracleだけでもいけそうですね。でも商用アプリとか、ネットサービスではけっこう乗り換えてますよ。FacebookやTwitterもそうですし。Googleは自分で作っちゃっているから中が見えませんけど、おそらく結構変えているのではないかと推測しています。Subversionも複数のデータストアに対応していたと思いますが、これも途中から選択肢を増やしたのではないかな?
#そうそう、以前まで業務アプリがメインだったんです。
#利用者の多いネットサービスでは、スケーラビリティを確保するため、これからHadoopとかCassandraとか、No-SQLへの移行が結構進むと思います。この流れは企業内ITにも影響しているみたいで、某オラクルの人がとある雑誌社の人達に「君たちがHadoopだなんだって、騒ぐから」みたいなことを聞いたことがあります。
#しまった、s/某オラクル/某IT企業/・・・いまさらおそいか。
#うーん、おっしゃることはごもっともなのですが、No-SQLまで含めちゃうと dbi の抽象化では追いつかないような。
#企業内の業務アプリではRDB決め打ちが当たり前だと思います。一部のIBM派を除けば、大企業ならOracle、予算が少ない企業か部門独自ならSQL Server、一部のBIならSybaseですよね。ネットサービス系とはかなり違うような気がします。
#そう、No-SQLまで含めると、dbiの抽象化では追いつかないのですよ。そこでもう1つ上のレベルで抽象化するか、違う手を打つ必要がある。私はとりあえず、MySQLの上でNo-SQLを擬似的に扱うことにしたので、dbiの上に抽象化レイヤーを作っています。
#でも私自身も業務系でいまNo-SQLをメインで使うのは現実的ではないと思うので、これはあくまでもネットサービス系(ロジックは単純だけどスケールが見えない)のケースだと考えていただいた方がいいと思います。
#えーと、誤解を避けるために蛇足を付け加えますが、dbiにはNo-SQLを意識した機能が必要だとは「全く」思っていません。現状のまま、SQLを適切に発行できる機能があれば、それで十分です。prepare/execがきちんと分かれているだけでも、ありがたいことなんです。
#(小さい声で)だれかThrift対応ライブラリ作ってくれないかなあ、という他力本願的な希望はありますが。(あくまで小声で)