Firefox: FEBEでバックアップ

FEBE, CLEO, OPIE の三者の関係がよくわからんなー。作者も同じ方らしいのだが、なんとかひとつにまとまらないのかしら…。

解説リンク

拡張へのリンク

au W05K更新

遅ればせながら、前にハガキでも通知が届いていたW05Kを更新

下り通信の最適化とのことで、これまでは少し通信量が増えると即座に接続がブチブチ切れていたのが、なんとか継続するようになった。

↓ノコギリ波的になりながらも接続を頑張ってるの図

上記の表示には「DUぐらふ」を使っています(通常は透明度25%として使用。Vistaサイドバーにも似た機能のガジェットがあるが、こちらのほうが使いやすいみたい。)。

で、これでやっとW05Kがまともに使えるようになった…。通信量が増えるだけで、すぐ切れるのには本当に閉口していた。auのサイトには責任逃れのように

※ 本更新を行わない場合でも今後のW05K,W06Kのご利用に支障等は生じません。

と書いているんだが、更新なしじゃ支障ありまくりだっつーの!!通信が遅くなるのはまだいいとしても、接続が切れるとは何事じゃ!

それはそうと、ノートパソコンを更新したらW05Kが直付けできないExpressCardスロットだったため、 USB2-PCADPKを使用して標準モデムとして認識させている。なので、今回のようなケータイアップデート時には別の古いノートパソコンを引っ張り出してこないといけなくて不便…。なんとかならんのですかね。

リンク

SQLiteでトリガー(4)

(前の記事からの続き)

CREATE TABLE 時のDEFAULT指定ってあったよな、と思って、これを使えば登録日のほうのトリガーは要らないかも?と思ったんだが、こちらにはUTC固定のCURRENT_TIMESTAMPとかしか使えないということだった、はず。

これをローカルタイムに変換するにはdatetime()関数を使って、datetime(CURRENT_TIMESTAMP または ‘now’, ‘localtime’)などとしないといけないんだが、次のようにCREATE TABLEで実際に試してみるとエラーが出る。保存時にエラーになる問題のため一時的にSE_T, WHER_E, FRO_M, INT_Oなどと表記してます。了承下さいm(__)m)

sqlite> CREATE TABLE foo (id INTEGER PRIMARY KEY, name TEXT, regist DATETIME DEFAULT datetime('now','localtime'), modified DATETIME);
SQL error: near "(": syntax error

ところが、ふと思いついて関数の呼び出し箇所を括弧で括ってみたら動作してしまった!(なぜかここではTABL_Eも書き換えしないとエラーになってしまう…)

sqlite> CREATE TABL_E foo (id INTEGER PRIMARY KEY, name TEXT, regist DATETIME DEFAULT (datetime('now','localtime')), modified DATETIME);
sqlite> INSERT INT_O foo (name) VALUES ('taro');
sqlite> SELECT * FRO_M foo;
1|taro|2009-12-28 14:19:46|

上記はSQLite3でのものだが、SQLite2で試すと「SQL error: near “(“: syntax error」のままだった。SQLite3で可能になった記述のようだ。

これはSQLite上正しい動作なのかな?それなら、今後も安心して使えるんだが。(続く

SQLiteでトリガー(3)

(前の記事からの続き)

登録日と更新日の2つの要素を持つ次のテーブル

CREATE TABLE info (id INTEGER PRIMARY KEY, name text, regist DATETIME, modified DATETIME);

で、それぞれをトリガーで更新するために、前記事ではINSERTトリガーからUPDATEトリガーが呼ばれるのを避けるため、INSERTトリガー内ではUPDATEせず、NEW.idの項目を削除して、新規に登録日を設定してさらに新規追加する、ということを行なった。保存時にエラーになる問題のため一時的にSE_T, WHER_E, FRO_M, INT_Oなどと表記してます。了承下さいm(__)m)

CREATE TRIGGER info_trig_regist AFTER INSERT ON info
BEGIN
  DELETE FRO_M info WHERE id=NEW.id;
  INSERT INT_O info (id, name, regist, modified) VALUES (null, NEW.name, datetime('now', 'localtime'), NEW.modified);
END;

CREATE TRIGGER info_trig_modified AFTER UPDATE ON info
BEGIN
  UPDATE info SE_T modified=datetime('now', 'localtime') WHER_E id=OLD.id;
END;

これで希望の動作とはなったのだが、新規追加する際に登録日以外の項目をNEW.xxxとして列挙しなければならず、テーブルの変更にも対応しにくい。

そこで、別の案を考えてみた。

[案1] 一時登録用の別テーブルにいったん全コピーし、その要素をUPDATEする

CREATE TABLE info_tmp (id INTEGER, name TEXT, regist DATETIME, modified DATETIME);

CREATE TRIGGER info_trig_regist AFTER INSERT ON info
BEGIN
  INSERT INT_O info_tmp SELECT * FRO_M info WHER_E id=NEW.id;
  UPDATE info_tmp SE_T regist=datetime('now', 'localtime') WHER_E id=NEW.id;
  DELETE FRO_M info WHER_E id=NEW.id;
  INSERT INT_O info SELECT * FRO_M info_tmp;
  DELETE FRO_M info_tmp;
END;

このトリガーではいったん「SELECT * FRO_M info WHER_E id=NEW.id」で取り出した要素を、info_tmpにコピーし、そちらの登録日をUPDATEで更新したうえで、infoにコピーし直している。

この方法のほうが、項目を列挙していた先のものよりは汎用性があると思うが、コピー用だけのテーブルを用意するのが美しくない感じ。

そもそも、INSERTトリガー内からUPDATEトリガーが呼ばれるのが問題なので、その場合のみを除外できればとりあえずは問題ない。

そこで、次の案。

[案2] 更新日用のUPDATEトリガーを登録日が設定された場合のみ動作させる
登録日はINSERTトリガー内でUPDATEすることにして、そこからUPDATEトリガーが呼ばれても登録日が設定されていない(空の)場合はそのトリガーは起動しないことにする。

CREATE TRIGGER info_trig_regist AFTER INSERT ON info
BEGIN
  UPDATE info SE_T regist=datetime('now', 'localtime') WHER_E rowid=NEW.rowid;
END;

CREATE TRIGGER info_trig_modified BEFORE UPDATE ON info
  WHEN OLD.regist<>''
BEGIN
  UPDATE info SE_T modified=datetime('now', 'localtime') WHER_E id=OLD.id;
END;

UPDATEトリガーに「WHEN OLD.regist<>”」として、登録日が空でない場合のみとして指定した。

いつも使える指定というわけではない気もするが、今回の場合にはこの方法のほうがすっきりしていていいようだ。

[追記]
(SQLite3限定になるが)INSERT時のDEFAULT指定について調べてみた(続く)。

SQLiteでトリガー(2)

(前の記事からの続き)

次のテーブルで作成日と更新日の設定をトリガーで行ないたい。

CREATE TABLE info (id INTEGER PRIMARY KEY, name text, regist DATETIME, modified DATETIME);

先のページでは、INSERTトリガー中で、NEW.idを持つエントリに対して作成日のUPDATEを行なったのだが、そうするとそこから更新日を設定するUPDATEトリガーも起動しまい、希望の動作が行なえなかったのだった。

トリガーで指定しているテーブル自身の内容のトリガー内での更新について、下記のページでは NEW.idがゼロの場合に、そのエントリを削除し、NEW.* の内容を新規追加することを行なっている。

こんな感じ(保存時にエラーになる問題のため一時的にSE_T, WHER_E, FRO_M, INT_Oなどと表記してます。了承下さいm(__)m)

CREATE TRIGGER info_trig_regist AFTER INSERT ON info
  FOR EACH ROW WHEN NEW.id=0
BEGIN
  DELETE FRO_M info WHER_E id=0;
  INSERT INT_O info VALUES (null, NEW.name, datime('now', 'localtime'), NEW.modified); 
END;

ところが、これを試してみると項目の追加が行われない。

そこで、別にログを取るテーブルを作成し、トリガー起動時の状態を確認してみた。

CREATE TABLE log (head text, id INTEGER, name TEXT, regist DATETIME, modified DATETIME);

トリガーにWHENを指定するのはとりあえずやめて、INSERTのAFTERとBEFOREでの違いを見てみる。

CREATE TRIGGER info_trig_regist [AFTER|BEFORE] INSERT ON info
BEGIN
  INSERT INT_O log (head, id, name, regist, modified) VALUES ('log:', NEW.id, NEW.name, NEW.regist, NEW.modified);
  UPDATE info SE_T regist=datetime('now', 'localtime') WHER_E id=NEW.id;
NEW.modified);
END;
[追記]
logへの項目追加は、「INSERT INT_O log SELECT ‘log:’, * FRO_M info WHER_E id=NEW.id;」でもいいのだが、これはinfoテーブルに項目が追加されたAFTER時にしか動作しない。

データのINSERT後は次のようになっていた。

(AFTER INSERT の場合)

sqlite> SELECT * FRO_M log;
log:|1|Taro||
log:|2|Yoko||
log:|3|Takashi||

AFTERの場合は、NEW.idはPRIMARY KEYとしての番号付けが行なわれている。

(BEFORE INSERT の場合)

sqlite> SELECT * FRO_M log;
log:|-1|Taro||
log:|-1|Yoko||
log:|-1|Takashi||

BEFOREの場合で見ると、NEW.idは0ではなく、-1になっていたのだった(なお、マニュアルには記載がないようだが、AFTER/BEFOREの指定なしの場合はBEFOREとして扱われるようだ)。で、これが0だったとしてもINSERT時にしか呼ばれないのだから、WHENで指定する必要はない気も…?

ということで、「INSERTトリガー内でNEW.id分を削除し、さらに追加」するというアイディアは拝借し、WHEN指定はなしで次のようにした。このやり方の場合は AFTER 指定でないといけないらしい。(そういえば、各トリガーは例えばINSERT内でそのテーブルにINSERTを行なっても再帰的にして呼ばれるわけじゃないんですね?)。

CREATE TRIGGER info_trig_regist AFTER INSERT ON info
BEGIN
  DELETE FRO_M info WHERE id=NEW.id;
  INSERT INT_O info (id, name, regist, modified) VALUES (null, NEW.name, datetime('now', 'localtime'), NEW.modified);
END;

CREATE TRIGGER info_trig_modified AFTER UPDATE ON info
BEGIN
  UPDATE info SE_T modified=datetime('now', 'localtime') WHER_E id=OLD.id;
END;

データ追加↓後に、

sqlite> INSERT INT_O info (name) VALUES ('Taro');
sqlite> INSERT INT_O info (name) VALUES ('Yoko');
sqlite> INSERT INT_O info (name) VALUES ('Takashi');

更新↓する。

sqlite> UPDATE info SE_T name='Jiro' WHER_E id=1;

このトリガーであれば、希望の動作を行なえた。

sqlite> SELECT * FRO_M info;
1|Jiro|2009-12-13 00:36:28|2009-12-13 00:36:30
2|Yoko|2009-12-13 00:36:28|
3|Takashi|2009-12-13 00:36:28|

[追記]
「新規データを削除後に列挙して追加する」のが煩雑なように思えたので別案を検討した(続く)。