MW211 EXIT

devlog
PostgreSQL/regexp_replace()の最短一致
2013年06月14日
「regexp_replace()」では基本最長一致で置換される。
「.*」や「.+」の場合、最短一致にするには末尾に「?」を付ければいいようだ。

例えば、LF改行で特定の行を置換するにはこんな感じとなる。
┌──────────────────────────────────────┐
│UPDATE 表 SET 列 = regexp_replace(列,                                       │
│                                  '見出:.*?' || chr(10),                   │
│                                  '見出:'    || chr(10));                  │
└──────────────────────────────────────┘

例えば、CRLF改行の場合はこう。
┌──────────────────────────────────────┐
│UPDATE 表 SET 列 = regexp_replace(列,                                       │
│                                  '見出:.*?' || chr(13) || chr(10),        │
│                                  '見出:'    || chr(13) || chr(10));       │
└──────────────────────────────────────┘
分類:PostgreSQL
PostgreSQL/勤怠管理(2)
2013年06月13日
テストデータを使って別のアプローチで勤務時間を計算してみよう。

まずは前回同様、「09:00~18:00」勤務で「12:00~13:00」休憩の場合。
┌──────────────────────────────────────┐
│WITH "test"("start",                                                        │
│            "end"  ) AS (                                                   │
│         VALUES('09:00'::time,                                              │
│                '18:00'::time)                                              │
│     )                                                                      │
│SELECT trunc((extract(EPOCH FROM '12:00'::time - "start"::time)             │
│            + extract(EPOCH FROM "end"         - '13:00'::time)) / 60)      │
│    FROM "test";                                                            │
└──────────────────────────────────────┘
続いて、さらに「18:00~18:30」の休憩をはさんで「18:30~21:30」が平常残業、
「21:30~22:00」の休憩をはさんで「22:00~24:00」が深夜残業の場合。
以下のように時間帯マスタを駆使して計算が可能だ。
┌──────────────────────────────────────┐
│WITH "t"("s",                                                               │
│         "e"  ) AS (                                                        │
│         VALUES('09:30'::time,                                              │
│                '22:30'::time)                                              │
│     ),                                                                     │
│     "r"("s1",                                                              │
│         "e1"  ,                                                            │
│         "s2",                                                              │
│         "e2",                                                              │
│         "s3",                                                              │
│         "e3"  ,                                                            │
│         "s4",                                                              │
│         "e4"  ) AS (                                                       │
│         VALUES('09:00'::time,                                              │
│                '12:00'::time,                                              │
│                '13:00'::time,                                              │
│                '18:00'::time,                                              │
│                '18:30'::time,                                              │
│                '21:30'::time,                                              │
│                '22:00'::time,                                              │
│                '23:00'::time)                                              │
│     )                                                                      │
│SELECT CASE WHEN "t1" > 0 THEN "t1" ELSE 0 END AS "平常",                   │
│       CASE WHEN "t2" > 0 THEN "t2" ELSE 0 END AS "残業",                   │
│       CASE WHEN "t3" > 0 THEN "t3" ELSE 0 END AS "深夜",                   │
│       "t0" - "t1"                             AS "欠勤"                    │
│  FROM (                                                                    │
│    SELECT trunc((extract(EPOCH FROM "e1" - "s1")                           │
│                + extract(EPOCH FROM "e2" - "s2")) / 60) AS "t1",           │
│           trunc((extract(EPOCH FROM "e3" - "s3")) / 60) AS "t2",           │
│           trunc((extract(EPOCH FROM "e4" - "s4")) / 60) AS "t3",           │
│           "t0"                                                             │
│      FROM (                                                                │
│        SELECT CASE WHEN t.s < r.s1 THEN r.s1 ELSE t.s END AS "s1",         │
│               CASE WHEN t.e > r.e1 THEN r.e1 ELSE t.e END AS "e1",         │
│               CASE WHEN t.s < r.s2 THEN r.s2 ELSE t.s END AS "s2",         │
│               CASE WHEN t.e > r.e2 THEN r.e2 ELSE t.e END AS "e2",         │
│               CASE WHEN t.s < r.s3 THEN r.s3 ELSE t.s END AS "s3",         │
│               CASE WHEN t.e > r.e3 THEN r.e3 ELSE t.e END AS "e3",         │
│               CASE WHEN t.s < r.s4 THEN r.s4 ELSE t.s END AS "s4",         │
│               CASE WHEN t.e > r.e4 THEN r.e4 ELSE t.e END AS "e4",         │
│               trunc((extract(EPOCH FROM "e1" - "s1")                       │
│                    + extract(EPOCH FROM "e2" - "s2")) / 60) AS "t0"        │
│            FROM t,r                                                        │
│      ) AS "z1"                                                             │
│  ) AS "z2"                                                                 │
└──────────────────────────────────────┘
ただし、翌朝深夜残業が…。「time」型は「25:00」とかいう概念がない…。
分類:PostgreSQL
PostgreSQL/勤怠管理(1)
2013年06月12日
例えば「09:00」に出社し、「18:00」に退社した日の労働時間を
分単位で求めたいとする。
で、だいたい「12:00~13:00」はお昼休みで1時間休憩だったりして
8時間(480分)労働だったりするわけだ。
これをSQL文で求めるとこんな感じになる。
┌──────────────────────────────────────┐
│SELECT trunc((extract(EPOCH FROM '18:00'::time - '09:00'::time)             │
│            - extract(EPOCH FROM '13:00'::time - '12:00'::time)) / 60);     │
└──────────────────────────────────────┘
中身を説明すると…。
「time」型はタイムスタンプとは違って時間のみを管理する便利な型だ。
で、これをそのまま減算することにより、経過時間が取得できる
その経過時間は「interval」型という特殊な型なので、
これを分に換算する訳だが、「extract(EPOCH FROM …」で秒にしか換算できない
よってここからは自力で、60秒で割って「trunc()」で
端数を切り捨てるってことをしている。
でこれを、「総勤務時間-休憩時間」で差し引きすると労働時間が求まるって寸法だ。

実際に倣って差し引きを分単位で行いたいって場合なら、
おのおので一旦分換算するというのもある。
┌──────────────────────────────────────┐
│SELECT trunc((extract(EPOCH FROM '18:00'::time - '09:00'::time)) / 60)      │
│     - trunc((extract(EPOCH FROM '13:00'::time - '12:00'::time)) / 60);     │
└──────────────────────────────────────┘

お昼休みは特に時間帯は決まっていなくて
とにかく1時間休める(混んでない時に飯にいける)って場合であれば
経過時間をそのまま使えばよい
┌──────────────────────────────────────┐
│SELECT trunc((extract(EPOCH FROM '18:00'::time - '09:00'::time)             │
│            - extract(EPOCH FROM '01:00'::time                )) / 60);     │
└──────────────────────────────────────┘

ということで、これがわかれば、今ベタで書いている時間の部分を
「time」型のデータに置き換えて(なんなら文字型データをキャストしてもよいが)
労働時間の計算が自由自在にできてしまいそうだ。
分類:PostgreSQL
PostgreSQL/正規表現で置換
2013年06月10日
特定の接頭辞を置換する例は以下のような感じとなる。
┌──────────────────────────────────────┐
│UPDATE 表 SET 列 = regexp_replace(列,'^接頭辞','');                         │
└──────────────────────────────────────┘
分類:PostgreSQL
PostgreSQL/2038年対応
2013年06月09日
┌──────────────────────────────────────┐
│SELECT current_timestamp;                                                   │
└──────────────────────────────────────┘
の代替。
┌──────────────────────────────────────┐
│SELECT CASE                                                                 │
│         WHEN current_timestamp < '2001-01-01 00:00:00' THEN                │
│           current_timestamp + '49710 days' + '23295 seconds'               │
│         ELSE                                                               │
│           current_timestamp                                                │
│       END AS "now";                                                        │
└──────────────────────────────────────┘
viewにしてでもお使いください。

って、いいのかい?

「'49710 days' + '23295 seconds'」の根拠がわからん。
実地試験で一番近い値はこれだった。

ついでに、
┌──────────────────────────────────────┐
│SELECT current_date;                                                        │
└──────────────────────────────────────┘
の代替
┌──────────────────────────────────────┐
│SELECT CASE                                                                 │
│         WHEN current_timestamp < '2001-01-01 00:00:00' THEN                │
│           CAST(current_timestamp + '49710 days' + '23295 seconds' AS DATE) │
│         ELSE                                                               │
│           CAST(current_timestamp AS DATE)                                  │
│       END AS "date";                                                       │
└──────────────────────────────────────┘
分類:PostgreSQL
C言語/fcntl()による排他制御・実例
2013年06月08日
読込系処理で共有ロックをかける場合の処理の流れ
┌──────────────────────────────────────┐
│int           fd;                                                           │
│struct flock  ファイルロック構造体;                                         │
├──────────────────────────────────────┤
│fd = open(ファイル名,                                                       │
│          O_RDONLY,                                // 読込専用でオープンする│
│          0444);                                                            │
│if (fd == -1) {                                                             │
│    オープン失敗;                                                           │
│    exit(EXIT_FAILURE);                                                     │
│}                                                                           │
├──────────────────────────────────────┤
│ファイルロック構造体.l_type   = F_RDLCK;                       // 共有ロック│
│ファイルロック構造体.l_whence = SEEK_SET;                                   │
│ファイルロック構造体.l_start  = 0;                                          │
│ファイルロック構造体.l_len    = 16;                                         │
│戻り値 = fcntl(fd,                                                          │
│               F_SETLK,                                    // ロックをかける│
│               &ファイルロック構造体);                                      │
│if (戻り値 == -1) {                                                         │
│    他でロック中を検出;                                                     │
│}                                                                           │
├──────────────────────────────────────┤
│読込処理など                                                                │
├──────────────────────────────────────┤
│close(fd);                                             // アンロックも兼ねる│
└──────────────────────────────────────┘
・ファイル先頭から16バイト分の領域についてロックを行う
────────────────────────────────────────
書込系処理で排他ロックをかける場合の処理の流れ
┌──────────────────────────────────────┐
│int           fd;                                                           │
│struct flock  ファイルロック構造体;                                         │
├──────────────────────────────────────┤
│fd = open(ファイル名,                                                       │
│          O_RDWR,                                  // 読書両用でオープンする│
│          0666);                                                            │
│if (fd == -1) {                                                             │
│    オープン失敗;                                                           │
│    exit(EXIT_FAILURE);                                                     │
│}                                                                           │
├──────────────────────────────────────┤
│ファイルロック構造体.l_type   = F_WRLCK;                       // 排他ロック│
│ファイルロック構造体.l_whence = SEEK_SET;                                   │
│ファイルロック構造体.l_start  = 0;                                          │
│ファイルロック構造体.l_len    = 16;                                         │
│戻り値 = fcntl(fd,                                                          │
│               F_SETLK,                                    // ロックをかける│
│               &ファイルロック構造体);                                      │
│if (戻り値 == -1) {                                                         │
│    他でロック中を検出;                                                     │
│}                                                                           │
├──────────────────────────────────────┤
│書込処理など                                                                │
├──────────────────────────────────────┤
│close(fd);                                             // アンロックも兼ねる│
└──────────────────────────────────────┘
・ファイル先頭から16バイト分の領域についてロックを行う
分類:C/C++
C言語/fcntl()による排他制御・基礎知識
2013年06月07日
まず、「fcntl()」を排他制御機構として使用する場合の書式は以下のような感じ。
┌──────────────────────────────────────┐
│int fcntl(fd,                                                               │
│          コマンド,                                                         │
│          *ファイルロック構造体);                                           │
└──────────────────────────────────────┘
なお、「fcntl()」はファイル制御関数なのでロック以外にも使い道がいろいろとある。
その場合には「コマンド」の部分が変わってくる。

コマンドの種別は以下の通り(排他制御機構として使用する場合のコマンドとなる)。
┌──────────────────────────────────────┐
│・F_GETLK   …ロック参照                                                    │
│・F_SETLK   …ロック設定断念                                                │
│・F_SETLKW  …ロック設定待機                                                │
└──────────────────────────────────────┘
他がロック中の場合、「F_SETLK」はエラーとしてすぐ断念するが、
「F_SETLKW」はロックが解除されるまで待つという違いがある。

ファイルロック構造体の中身を抽出すると以下のような感じ。
┌──────────────────────────────────────┐
│struct flock{                                                               │
│    short  l_type;    // ロック種類を指定する                               │
│    short  l_whence;  // ロック領域(基準位置)                               │
│    off_t  l_start;   // ロック領域(開始位置)                               │
│    off_t  l_len;     // ロック領域(長さ)                                   │
│    pid_t  l_pid;     // ロック主                                           │
│};                                                                          │
└──────────────────────────────────────┘

「l_type」に指定するロック種類は以下の通り。
┌──────────────────────────────────────┐
│・F_RDLCK  …共有ロック                                                     │
│・F_WLCLK  …排他ロック                                                     │
│・F_UNLCK  …アンロック(非ロック中)                                         │
└──────────────────────────────────────┘

「l_whence」に指定するロック領域の基準位置は以下の通り。
┌──────────────────────────────────────┐
│・SEEK_SET  …ファイル先頭                                                  │
│・SEEK_CUR  …現在位置                                                      │
│・SEEK_END  …ファイル末尾                                                  │
└──────────────────────────────────────┘
これは「fseek()」のやつと同じだ。

「l_start」は「l_whence」で指定した基準位置からの相対位置(もちろん負数も可)。
「l_len」は「l_start」からの長さ。
これらを指定することにより、ファイルの一部分をロック領域として指定できる。

「l_pid」にはロック中のプロセスID(つまりロック主)が設定されるので、
これがある場合にはその人が排他中というわけだ。
分類:C/C++
C言語/fcntl()による排他制御・注意
2013年06月06日
fcntl()による排他制御の場合、同一ファイルであれば
ファイルディスクリプタ(fd)が違っても、「close()」するだけで
全てについてアンロックされてしまう。
┌───────────────────────┐
│              ┌──┐            ┌────┐│
│            ┌┤fd1 │←(ロック)─┤fcntl() ││
│┌────┐│└──┘            └────┘│
││ファイル├┤    ↑(アンロック)              │
│└────┘│┌──┐            ┌────┐│
│            └┤fd2 │←─────┤close() ││
│              └──┘            └────┘│
└───────────────────────┘
上記の場合は、「fd1」を扱っている人がいつのまにか
アンロックされているって状況になりうるみたい。
注意が必要だ。
分類:C/C++
controlの省略形
2013年06月05日
「control」の省略形って、コントロールキーだと「ctrl」なのに、
ファイルコントロールの「fcntl()」関数だと「cntl」なんだね。

紛らわしい。
分類:注意
Windows/zip圧縮パスワード
2013年06月04日
WindowsXP以前であればzip圧縮を行ったファイルにパスワードをかけることができた。
しかし、WindowsVista以降からこの機能はなくなってしまった。

但し、圧縮時のパスワード設定機能がなくなっただけで、
解凍時のパスワード入力機能は残っているみたい。

よって、圧縮ツールを使ってパスワード付き圧縮ファイルを作れば
他の環境でも(たいていは)解凍できるはず。

圧縮ツールは「LhaPlus」とかがおすすめ。
分類:Windows
前へ 1 2 3 次へ