source: branches/version-2_12-dev/data/class/SC_Query.php @ 21651

Revision 21651, 36.1 KB checked in by Seasoft, 12 years ago (diff)

#1666 (create_table_*.sql 間の差異を減らす)

  • インストーラから SC_DB_DBFactory_Ex#initObjQuery が呼ばれていない不具合を回避。
  • インストーラから誤ったDB用の SC_DB_DBFactory_Ex#initObjQuery が呼ばれる不具合を修正。

#1613 (typo修正・ソース整形・ソースコメントの改善)

  • Property svn:eol-style set to LF
  • Property svn:keywords set to Id
  • Property svn:mime-type set to text/x-httpd-php; charset=UTF-8
Line 
1<?php
2/*
3 * This file is part of EC-CUBE
4 *
5 * Copyright(c) 2000-2011 LOCKON CO.,LTD. All Rights Reserved.
6 *
7 * http://www.lockon.co.jp/
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22 */
23
24/**
25 * SQLの構築・実行を行う
26 *
27 * TODO エラーハンドリング, ロギング方法を見直す
28 *
29 * @author LOCKON CO.,LTD.
30 * @version $Id$
31 */
32class SC_Query {
33
34    var $option = '';
35    var $where = '';
36    var $arrWhereVal = array();
37    var $conn;
38    var $groupby = '';
39    var $order = '';
40    var $force_run = false;
41
42    /**
43     * コンストラクタ.
44     *
45     * @param string $dsn データソース名
46     * @param boolean $force_run エラーが発生しても処理を続行する場合 true
47     * @param boolean $new 新規に接続を行うかどうか
48     */
49    function SC_Query($dsn = '', $force_run = false, $new = false) {
50
51        if ($dsn == '') {
52            $dsn = DEFAULT_DSN;
53        }
54
55        // Debugモード指定
56        // 常時ONにするとメモリが解放されない。
57        // 連続クエリ実行時に問題が生じる。
58        if (DEBUG_MODE) {
59            $options['debug'] = PEAR_DB_DEBUG;
60        } else {
61            $options['debug'] = 0;
62        }
63
64        // 持続的接続オプション
65        $options['persistent'] = PEAR_DB_PERSISTENT;
66
67        // バッファリング trueにするとメモリが解放されない。
68        // 連続クエリ実行時に問題が生じる。
69        $options['result_buffering'] = false;
70
71        if ($new) {
72            $this->conn = MDB2::connect($dsn, $options);
73        } else {
74            $this->conn = MDB2::singleton($dsn, $options);
75        }
76        if (!PEAR::isError($this->conn)) {
77            $this->conn->setCharset('utf8');
78            $this->conn->setFetchMode(MDB2_FETCHMODE_ASSOC);
79        }
80
81        // XXX 上書きインストール時にDBを変更するケースを想定し第1引数を与えている。
82        $this->dbFactory = SC_DB_DBFactory_Ex::getInstance($this->conn->dsn['phptype']);
83        $this->dbFactory->initObjQuery($this);
84
85        $this->force_run = $force_run;
86    }
87
88    /**
89     * シングルトンの SC_Query インスタンスを取得する.
90     *
91     * @param string $dsn データソース名
92     * @param boolean $force_run エラーが発生しても処理を続行する場合 true
93     * @param boolean $new 新規に接続を行うかどうか
94     * @return SC_Query シングルトンの SC_Query インスタンス
95     */
96    function getSingletonInstance($dsn = '', $force_run = false, $new = false) {
97        if (!isset($GLOBALS['_SC_Query_instance'])
98            || is_null($GLOBALS['_SC_Query_instance'])) {
99            $GLOBALS['_SC_Query_instance'] =& new SC_Query_Ex($dsn, $force_run, $new);
100        }
101        $GLOBALS['_SC_Query_instance']->where = '';
102        $GLOBALS['_SC_Query_instance']->arrWhereVal = array();
103        $GLOBALS['_SC_Query_instance']->order = '';
104        $GLOBALS['_SC_Query_instance']->groupby = '';
105        $GLOBALS['_SC_Query_instance']->option = '';
106        return $GLOBALS['_SC_Query_instance'];
107    }
108
109    /**
110     * エラー判定を行う.
111     *
112     * @deprecated PEAR::isError() を使用して下さい
113     * @return boolean
114     */
115    function isError() {
116        if (PEAR::isError($this->conn)) {
117            return true;
118        }
119        return false;
120    }
121
122    /**
123     * COUNT文を実行する.
124     *
125     * @param string $table テーブル名
126     * @param string $where where句
127     * @param array $arrWhereVal プレースホルダ
128     * @return integer 件数
129     */
130    function count($table, $where = '', $arrWhereVal = array()) {
131        return $this->get('COUNT(*)', $table, $where, $arrWhereVal);
132    }
133
134    /**
135     * EXISTS文を実行する.
136     *
137     * @param string $table テーブル名
138     * @param string $where where句
139     * @param array $arrWhereVal プレースホルダ
140     * @return boolean 有無
141     */
142    function exists($table, $where = '', $arrWhereVal = array()) {
143        $sql_inner = $this->getSql('*', $table, $where, $arrWhereVal);
144        $sql = "SELECT CASE WHEN EXISTS($sql_inner) THEN 1 ELSE 0 END";
145        $res = $this->getOne($sql, $arrWhereVal);
146        return (bool)$res;
147    }
148
149    /**
150     * SELECT文を実行する.
151     *
152     * @param string $col カラム名. 複数カラムの場合はカンマ区切りで書く
153     * @param string $table テーブル名
154     * @param string $where WHERE句
155     * @param array $arrWhereVal プレースホルダ
156     * @param integer $fetchmode 使用するフェッチモード。デフォルトは MDB2_FETCHMODE_ASSOC。
157     * @return array|null
158     */
159    function select($col, $table, $where = '', $arrWhereVal = array(), $fetchmode = MDB2_FETCHMODE_ASSOC) {
160        $sqlse = $this->getSql($col, $table, $where, $arrWhereVal);
161        return $this->getAll($sqlse, $arrWhereVal, $fetchmode);
162    }
163
164    /**
165     * 直前に実行されたSQL文を取得する.
166     *
167     * @param boolean $disp trueの場合、画面出力を行う.
168     * @return string SQL文
169     */
170    function getLastQuery($disp = true) {
171        $sql = $this->conn->last_query;
172        if ($disp) {
173            echo $sql . ";<br />\n";
174        }
175        return $sql;
176    }
177
178    /**
179     * トランザクションをコミットする.
180     *
181     * @return MDB2_OK 成功した場合は MDB2_OK;
182     *         失敗した場合は PEAR::Error オブジェクト
183     */
184    function commit() {
185        return $this->conn->commit();
186    }
187
188    /**
189     * トランザクションを開始する.
190     *
191     * @return MDB2_OK 成功した場合は MDB2_OK;
192     *         失敗した場合は PEAR::Error オブジェクト
193     */
194    function begin() {
195        return $this->conn->beginTransaction();
196    }
197
198    /**
199     * トランザクションをロールバックする.
200     *
201     * @return MDB2_OK 成功した場合は MDB2_OK;
202     *         失敗した場合は PEAR::Error オブジェクト
203     */
204    function rollback() {
205        return $this->conn->rollback();
206    }
207
208    /**
209     * トランザクションが開始されているかチェックする.
210     *
211     * @return boolean トランザクションが開始されている場合 true
212     */
213    function inTransaction() {
214        return $this->conn->inTransaction();
215    }
216
217    /**
218     * 更新系の SQL を実行する.
219     *
220     * この関数は SC_Query::query() のエイリアスです.
221     *
222     * FIXME MDB2::exec() の実装であるべき
223     */
224    function exec($str, $arrVal = array()) {
225        return $this->query($str, $arrVal);
226    }
227
228    /**
229     * クエリを実行し、結果行毎にコールバック関数を適用する
230     *
231     * @param callback $function コールバック先
232     * @param string $sql SQL クエリ
233     * @param array $arrVal プリペアドステートメントの実行時に使用される配列。配列の要素数は、クエリ内のプレースホルダの数と同じでなければなりません。
234     * @param integer $fetchmode 使用するフェッチモード。デフォルトは DB_FETCHMODE_ASSOC。
235     * @return boolean 結果
236     */
237    function doCallbackAll($cbFunc, $sql, $arrVal = array(), $fetchmode = MDB2_FETCHMODE_ASSOC) {
238
239        $sql = $this->dbFactory->sfChangeMySQL($sql);
240
241        $sth =& $this->prepare($sql);
242        if (PEAR::isError($sth) && $this->force_run) {
243            return;
244        }
245
246        $affected =& $this->execute($sth, $arrVal);
247        if (PEAR::isError($affected) && $this->force_run) {
248            return;
249        }
250
251        while ($data = $affected->fetchRow($fetchmode)) {
252            $result = call_user_func($cbFunc, $data);
253            if ($result === false) {
254                break;
255            }
256        }
257        $sth->free();
258        return $result;
259    }
260
261    /**
262     * クエリを実行し、全ての行を返す
263     *
264     * @param string $sql SQL クエリ
265     * @param array $arrVal プリペアドステートメントの実行時に使用される配列。配列の要素数は、クエリ内のプレースホルダの数と同じでなければなりません。
266     * @param integer $fetchmode 使用するフェッチモード。デフォルトは DB_FETCHMODE_ASSOC。
267     * @return array データを含む2次元配列。失敗した場合に 0 または DB_Error オブジェクトを返します。
268     */
269    function getAll($sql, $arrVal = array(), $fetchmode = MDB2_FETCHMODE_ASSOC) {
270
271        $sql = $this->dbFactory->sfChangeMySQL($sql);
272
273        $sth =& $this->prepare($sql);
274        if (PEAR::isError($sth) && $this->force_run) {
275            return;
276        }
277
278        $affected =& $this->execute($sth, $arrVal);
279        if (PEAR::isError($affected) && $this->force_run) {
280            return;
281        }
282
283        // MySQL での不具合対応のため、一旦変数に退避
284        $arrRet = $affected->fetchAll($fetchmode);
285
286        // PREPAREの解放
287        $sth->free();
288
289        return $arrRet;
290    }
291
292    /**
293     * 構築した SELECT 文を取得する.
294     *
295     * クラス変数から WHERE 句を組み立てる場合、$arrWhereVal を経由してプレースホルダもクラス変数のもので上書きする。
296     * @param string $col SELECT 文に含めるカラム名
297     * @param string $table SELECT 文に含めるテーブル名
298     * @param string $where SELECT 文に含める WHERE 句
299     * @param mixed $arrWhereVal プレースホルダ(参照)
300     * @return string 構築済みの SELECT 文
301     */
302    function getSql($col, $table, $where = '', &$arrWhereVal = null) {
303        $sqlse = "SELECT $col FROM $table";
304
305        // 引数の$whereを優先する。
306        if (strlen($where) >= 1) {
307            $sqlse .= " WHERE $where";
308        } elseif (strlen($this->where) >= 1) {
309            $sqlse .= ' WHERE ' . $this->where;
310            // 実行時と同じくキャストしてから評価する (空文字を要素1の配列と評価させる意図)
311            $arrWhereValForEval = (array)$arrWhereVal;
312            if (empty($arrWhereValForEval)) {
313                $arrWhereVal = $this->arrWhereVal;
314            }
315        }
316
317        $sqlse .= ' ' . $this->groupby . ' ' . $this->order . ' ' . $this->option;
318
319        return $sqlse;
320    }
321
322    /**
323     * SELECT 文の末尾に付与する SQL を設定する.
324     *
325     * この関数で設定した値は SC_Query::getSql() で使用されます.
326     *
327     * @param string $str 付与する SQL 文
328     * @return SC_Query 自分自身のインスタンス
329     */
330    function setOption($str) {
331        $this->option = $str;
332        return $this;
333    }
334
335    /**
336     * SELECT 文に付与する LIMIT, OFFSET 句を設定する.
337     *
338     * この関数で設定した値は SC_Query::getSql() で使用されます.
339     * TODO MDB2::setLimit() を使用する
340     *
341     * @param integer $limit LIMIT 句に付与する値
342     * @param integer $offset OFFSET 句に付与する値
343     * @return SC_Query 自分自身のインスタンス
344     */
345    function setLimitOffset($limit, $offset = 0) {
346        if (is_numeric($limit) && is_numeric($offset)) {
347
348            $option = ' LIMIT ' . $limit;
349            $option.= ' OFFSET ' . $offset;
350            $this->option .= $option;
351        }
352        return $this;
353    }
354
355    /**
356     * SELECT 文に付与する GROUP BY 句を設定する.
357     *
358     * この関数で設定した値は SC_Query::getSql() で使用されます.
359     *
360     * @param string $str GROUP BY 句に付与する文字列
361     * @return SC_Query 自分自身のインスタンス
362     */
363    function setGroupBy($str) {
364        if (strlen($str) == 0) {
365            $this->groupby = '';
366        } else {
367            $this->groupby = 'GROUP BY ' . $str;
368        }
369        return $this;
370    }
371
372    /**
373     * SELECT 文の WHERE 句に付与する AND 条件を設定する.
374     *
375     * この関数で設定した値は SC_Query::getSql() で使用されます.
376     *
377     * @param string $str WHERE 句に付与する AND 条件の文字列
378     * @return SC_Query 自分自身のインスタンス
379     */
380    function andWhere($str) {
381        if ($this->where != '') {
382            $this->where .= ' AND ' . $str;
383        } else {
384            $this->where = $str;
385        }
386        return $this;
387    }
388
389    /**
390     * SELECT 文の WHERE 句に付与する OR 条件を設定する.
391     *
392     * この関数で設定した値は SC_Query::getSql() で使用されます.
393     *
394     * @param string $str WHERE 句に付与する OR 条件の文字列
395     * @return SC_Query 自分自身のインスタンス
396     */
397    function orWhere($str) {
398        if ($this->where != '') {
399            $this->where .= ' OR ' . $str;
400        } else {
401            $this->where = $str;
402        }
403        return $this;
404    }
405
406    /**
407     * SELECT 文に付与する WHERE 句を設定する.
408     *
409     * この関数で設定した値は SC_Query::getSql() で使用されます.
410     *
411     * @param string $where WHERE 句に付与する文字列
412     * @param mixed $arrWhereVal プレースホルダ
413     * @return SC_Query 自分自身のインスタンス
414     */
415    function setWhere($where = '', $arrWhereVal = array()) {
416        $this->where = $where;
417        $this->arrWhereVal = $arrWhereVal;
418        return $this;
419    }
420
421    /**
422     * SELECT 文に付与する ORDER BY 句を設定する.
423     *
424     * この関数で設定した値は SC_Query::getSql() で使用されます.
425     *
426     * @param string $str ORDER BY 句に付与する文字列
427     * @return SC_Query 自分自身のインスタンス
428     */
429    function setOrder($str) {
430        if (strlen($str) == 0) {
431            $this->order = '';
432        } else {
433            $this->order = 'ORDER BY ' . $str;
434        }
435        return $this;
436    }
437
438    /**
439     * SELECT 文に付与する LIMIT 句を設定する.
440     *
441     * この関数で設定した値は SC_Query::getSql() で使用されます.
442     *
443     * @param integer $limit LIMIT 句に設定する値
444     * @return SC_Query 自分自身のインスタンス
445     */
446    function setLimit($limit) {
447        if (is_numeric($limit)) {
448            $this->option = ' LIMIT ' .$limit;
449        }
450        return $this;
451    }
452
453    /**
454     * SELECT 文に付与する OFFSET 句を設定する.
455     *
456     * この関数で設定した値は SC_Query::getSql() で使用されます.
457     *
458     * @param integer $offset LIMIT 句に設定する値
459     * @return SC_Query 自分自身のインスタンス
460     */
461    function setOffset($offset) {
462        if (is_numeric($offset)) {
463            $this->offset = ' OFFSET ' .$offset;
464        }
465        return $this;
466    }
467
468    /**
469     * INSERT文を実行する.
470     *
471     * @param string $table テーブル名
472     * @param array $sqlval array('カラム名' => '値', ...)の連想配列
473     * @param array $arrSql array('カラム名' => 'SQL文', ...)の連想配列
474     * @param array $arrSqlVal SQL文の中で使用するプレースホルダ配列
475     * @param string $from FROM 句・WHERE 句
476     * @param string $arrFromVal FROM 句・WHERE 句で使用するプレースホルダ配列
477     * @return integer|DB_Error 挿入件数またはDB_Error
478     */
479    function insert($table, $sqlval, $arrSql = array(), $arrSqlVal = array(), $from = '', $arrFromVal = array()) {
480        $strcol = '';
481        $strval = '';
482        $find = false;
483        $arrVal = array();
484
485        if(count($sqlval) <= 0) return false;
486        foreach ($sqlval as $key => $val) {
487            $strcol .= $key . ',';
488            if (strcasecmp('Now()', $val) === 0) {
489                $strval .= 'Now(),';
490            } else if (strcasecmp('CURRENT_TIMESTAMP', $val) === 0) {
491                $strval .= 'CURRENT_TIMESTAMP,';
492            } else {
493                $strval .= '?,';
494                $arrVal[] = $val;
495            }
496            $find = true;
497        }
498
499        foreach ($arrSql as $key => $val) {
500            $strcol .= $key . ',';
501            $strval .= $val . ',';
502        }
503
504        $arrVal = array_merge($arrVal, $arrSqlVal);
505
506        if (!$find) {
507            return false;
508        }
509        // 文末の','を削除
510        $strcol = rtrim($strcol, ',');
511        $strval = rtrim($strval, ',');
512        $sqlin = "INSERT INTO $table($strcol) SELECT $strval";
513
514        if (strlen($from) >= 1) {
515            $sqlin .= ' ' . $from;
516            $arrVal = array_merge($arrVal, $arrFromVal);
517        }
518
519        // INSERT文の実行
520        $ret = $this->query($sqlin, $arrVal, false, null, MDB2_PREPARE_MANIP);
521
522        return $ret;
523    }
524
525    /**
526     * UPDATE文を実行する.
527     *
528     * @param string $table テーブル名
529     * @param array $sqlval array('カラム名' => '値', ...)の連想配列
530     * @param string $where WHERE句
531     * @param array $arrWhereVal WHERE句用のプレースホルダ配列 (従来は追加カラム用も兼ねていた)
532     * @param array $arrRawSql 追加カラム
533     * @param array $arrRawSqlVal 追加カラム用のプレースホルダ配列
534     * @return
535     */
536    function update($table, $sqlval, $where = '', $arrWhereVal = array(), $arrRawSql = array(), $arrRawSqlVal = array()) {
537        $arrCol = array();
538        $arrVal = array();
539        $find = false;
540
541        foreach ($sqlval as $key => $val) {
542            if (strcasecmp('Now()', $val) === 0) {
543                $arrCol[] = $key . '= Now()';
544            } else if (strcasecmp('CURRENT_TIMESTAMP', $val) === 0) {
545                $arrCol[] = $key . '= CURRENT_TIMESTAMP';
546            } else {
547                $arrCol[] = $key . '= ?';
548                $arrVal[] = $val;
549            }
550            $find = true;
551        }
552
553        if ($arrRawSql != '') {
554            foreach ($arrRawSql as $key => $val) {
555                $arrCol[] = "$key = $val";
556            }
557        }
558
559        $arrVal = array_merge($arrVal, $arrRawSqlVal);
560
561        if (empty($arrCol)) {
562            return false;
563        }
564
565        // 文末の','を削除
566        $strcol = implode(', ', $arrCol);
567
568        if (is_array($arrWhereVal)) { // 旧版との互換用
569            // プレースホルダー用に配列を追加
570            $arrVal = array_merge($arrVal, $arrWhereVal);
571        }
572
573        $sqlup = "UPDATE $table SET $strcol";
574        if (strlen($where) >= 1) {
575            $sqlup .= " WHERE $where";
576        }
577
578        // UPDATE文の実行
579        return $this->query($sqlup, $arrVal, false, null, MDB2_PREPARE_MANIP);
580    }
581
582    /**
583     * MAX文を実行する.
584     *
585     * @param string $table テーブル名
586     * @param string $col カラム名
587     * @param string $where 付与する WHERE 句
588     * @param array $arrWhereVal プレースホルダに挿入する値
589     * @return integer MAX文の実行結果
590     */
591    function max($col, $table, $where = '', $arrWhereVal = array()) {
592        $ret = $this->get("MAX($col)", $table, $where, $arrWhereVal);
593        return $ret;
594    }
595
596    /**
597     * MIN文を実行する.
598     *
599     * @param string $table テーブル名
600     * @param string $col カラム名
601     * @param string $where 付与する WHERE 句
602     * @param array $arrWhereVal プレースホルダに挿入する値
603     * @return integer MIN文の実行結果
604     */
605    function min($col, $table, $where = '', $arrWhereVal = array()) {
606        $ret = $this->get("MIN($col)", $table, $where, $arrWhereVal);
607        return $ret;
608    }
609
610    /**
611     * SQL を構築して, 特定のカラムの値を取得する.
612     *
613     * @param string $table テーブル名
614     * @param string $col カラム名
615     * @param string $where 付与する WHERE 句
616     * @param array $arrWhereVal プレースホルダに挿入する値
617     * @return mixed SQL の実行結果
618     */
619    function get($col, $table, $where = '', $arrWhereVal = array()) {
620        $sqlse = $this->getSql($col, $table, $where, $arrWhereVal);
621        // SQL文の実行
622        $ret = $this->getOne($sqlse, $arrWhereVal);
623        return $ret;
624    }
625
626    /**
627     * SQL を指定して, 特定のカラムの値を取得する.
628     *
629     * @param string $sql 実行する SQL
630     * @param array $arrVal プレースホルダに挿入する値
631     * @return mixed SQL の実行結果
632     */
633    function getOne($sql, $arrVal = array()) {
634
635        $sql = $this->dbFactory->sfChangeMySQL($sql);
636
637        $sth =& $this->prepare($sql);
638        if (PEAR::isError($sth) && $this->force_run) {
639            return;
640        }
641
642        $affected =& $this->execute($sth, $arrVal);
643        if (PEAR::isError($affected) && $this->force_run) {
644            return;
645        }
646
647        // MySQL での不具合対応のため、一旦変数に退避
648        $arrRet = $affected->fetchOne();
649
650        // PREPAREの解放
651        $sth->free();
652
653        return $arrRet;
654    }
655
656    /**
657     * 一行をカラム名をキーとした連想配列として取得
658     *
659     * @param string $table テーブル名
660     * @param string $col カラム名
661     * @param string $where WHERE句
662     * @param array $arrWhereVal プレースホルダ配列
663     * @param integer $fetchmode 使用するフェッチモード。デフォルトは MDB2_FETCHMODE_ASSOC。
664     * @return array array('カラム名' => '値', ...)の連想配列
665     */
666    function getRow($col, $table, $where = '', $arrWhereVal = array(), $fetchmode = MDB2_FETCHMODE_ASSOC) {
667
668        $sql = $this->getSql($col, $table, $where, $arrWhereVal);
669        $sql = $this->dbFactory->sfChangeMySQL($sql);
670
671        $sth =& $this->prepare($sql);
672        if (PEAR::isError($sth) && $this->force_run) {
673            return;
674        }
675
676        $affected =& $this->execute($sth, $arrWhereVal);
677        if (PEAR::isError($affected) && $this->force_run) {
678            return;
679        }
680
681        // MySQL での不具合対応のため、一旦変数に退避
682        $arrRet = $affected->fetchRow($fetchmode);
683
684        // PREPAREの解放
685        $sth->free();
686
687        return $arrRet;
688    }
689
690    /**
691     * SELECT 文の実行結果を 1列のみ取得する.
692     *
693     * @param string $table テーブル名
694     * @param string $col カラム名
695     * @param string $where 付与する WHERE 句
696     * @param array $arrWhereVal プレースホルダに挿入する値
697     * @return array SQL の実行結果の配列
698     */
699    function getCol($col, $table, $where = '', $arrWhereVal = array()) {
700        $sql = $this->getSql($col, $table, $where, $arrWhereVal);
701        $sql = $this->dbFactory->sfChangeMySQL($sql);
702
703        $sth =& $this->prepare($sql);
704        if (PEAR::isError($sth) && $this->force_run) {
705            return;
706        }
707
708        $affected =& $this->execute($sth, $arrWhereVal);
709        if (PEAR::isError($affected) && $this->force_run) {
710            return;
711        }
712
713        // MySQL での不具合対応のため、一旦変数に退避
714        $arrRet = $affected->fetchCol();
715
716        // PREPAREの解放
717        $sth->free();
718
719        return $arrRet;
720    }
721
722    /**
723     * レコードの削除
724     *
725     * @param string $table テーブル名
726     * @param string $where WHERE句
727     * @param array $arrWhereVal プレースホルダ
728     * @return
729     */
730    function delete($table, $where = '', $arrWhereVal = array()) {
731        if (strlen($where) <= 0) {
732            $sqlde = "DELETE FROM $table";
733        } else {
734            $sqlde = "DELETE FROM $table WHERE $where";
735        }
736        $ret = $this->query($sqlde, $arrWhereVal, false, null, MDB2_PREPARE_MANIP);
737        return $ret;
738    }
739
740    /**
741     * 次のシーケンス値を取得する.
742     *
743     * @param string $seq_name 取得するシーケンス名
744     * @param integer 次のシーケンス値
745     */
746    function nextVal($seq_name) {
747        return $this->conn->nextID($seq_name);
748    }
749
750    /**
751     * 現在のシーケンス値を取得する.
752     *
753     * @param string $seq_name 取得するシーケンス名
754     * @return integer 現在のシーケンス値
755     */
756    function currVal($seq_name) {
757        return $this->conn->currID($seq_name);
758    }
759
760    /**
761     * シーケンス値を設定する.
762     *
763     * @param string $seq_name シーケンス名
764     * @param integer $start 設定するシーケンス値
765     * @return MDB2_OK
766     */
767    function setVal($seq_name, $start) {
768        $objManager =& $this->conn->loadModule('Manager');
769        // XXX エラーハンドリングを行う
770        $objManager->dropSequence($seq_name);
771        return $objManager->createSequence($seq_name, $start);
772    }
773
774    /**
775     * SQL を実行する.
776     *
777     * FIXME $ignore_errが無視されるようになっているが互換性として問題が無いか確認が必要
778     *
779     * @param string $n 実行する SQL 文
780     * @param array $arr プレースホルダに挿入する値
781     * @param boolean $ignore_err MDB2切替で無効化されている (エラーが発生しても処理を続行する場合 true)
782     * @param mixed $types プレースホルダの型指定 デフォルトnull = string
783     * @param mixed $result_types 返値の型指定またはDML実行(MDB2_PREPARE_MANIP)
784     * @return array SQL の実行結果の配列
785     */
786    function query($n ,$arr = array(), $ignore_err = false, $types = null, $result_types = MDB2_PREPARE_RESULT) {
787
788        $n = $this->dbFactory->sfChangeMySQL($n);
789
790        $sth =& $this->prepare($n, $types, $result_types);
791        if (PEAR::isError($sth) && $this->force_run) {
792            return $sth;
793        }
794
795        $result = $this->execute($sth, $arr);
796        if (PEAR::isError($result) && $this->force_run) {
797            return $sth;
798        }
799
800        // PREPAREの解放
801        $sth->free();
802
803        return $result;
804    }
805
806    /**
807     * シーケンスの一覧を取得する.
808     *
809     * @return array シーケンス名の配列
810     */
811    function listSequences() {
812        $objManager =& $this->conn->loadModule('Manager');
813        return $objManager->listSequences();
814    }
815
816    /**
817     * テーブル一覧を取得する.
818     *
819     * @return array テーブル名の配列
820     */
821    function listTables() {
822        $objManager =& $this->conn->loadModule('Manager');
823        return $objManager->listTables();
824    }
825
826    /**
827     * テーブルのカラム一覧を取得する.
828     *
829     * @param string $table テーブル名
830     * @return array 指定のテーブルのカラム名の配列
831     */
832    function listTableFields($table) {
833        $objManager =& $this->conn->loadModule('Manager');
834        return $objManager->listTableFields($table);
835    }
836
837    /**
838     * テーブルのインデックス一覧を取得する.
839     *
840     * @param string $table テーブル名
841     * @return array 指定のテーブルのインデックス一覧
842     */
843    function listTableIndexes($table) {
844        $objManager =& $this->conn->loadModule('Manager');
845        return $objManager->listTableIndexes($table);
846    }
847
848    /**
849     * テーブルにインデックスを付与する
850     *
851     * @param string $table テーブル名
852     * @param string $name インデックス名
853     * @param array $definition フィールド名など 通常のフィールド指定時は、$definition=array('fields' => array('フィールド名' => array()));
854     *               MySQLのtext型フィールドを指定する場合は $definition['length'] = 'text_field(NNN)' が必要
855     */
856    function createIndex($table, $name, $definition) {
857        $definition = $this->dbFactory->sfGetCreateIndexDefinition($table, $name, $definition);
858        $objManager =& $this->conn->loadModule('Manager');
859        return $objManager->createIndex($table, $name, $definition);
860    }
861
862    /**
863     * テーブルにインデックスを破棄する
864     *
865     * @param string $table テーブル名
866     * @param string $name インデックス名
867     */
868    function dropIndex($table, $name) {
869        $objManager =& $this->conn->loadModule('Manager');
870        return $objManager->dropIndex($table, $name);
871    }
872
873    /**
874     * テーブルの詳細情報を取得する。
875     *
876     * @param string $table テーブル名
877     * @return array テーブル情報の配列
878     */
879    function getTableInfo($table) {
880        $objManager =& $this->conn->loadModule('Reverse');
881        return $objManager->tableInfo($table, NULL);
882    }
883
884    /**
885     * 値を適切にクォートする.
886     *
887     * TODO MDB2 に対応するための暫定的な措置.
888     *      プレースホルダが使用できない実装があるため.
889     *      本来であれば, MDB2::prepare() を適切に使用するべき
890     *
891     * @see MDB2::quote()
892     * @param string $val クォートを行う文字列
893     * @return string クォートされた文字列
894     */
895    function quote($val) {
896        return $this->conn->quote($val);
897    }
898
899    /**
900     * パラメーターの連想配列から, テーブルに存在する列のみを取得する.
901     *
902     * @param string $table テーブル名
903     * @param array プレースホルダの連想配列
904     * @return array テーブルに存在する列のみ抽出した連想配列
905     */
906    function extractOnlyColsOf($table, $arrParams) {
907        $arrCols = $this->listTableFields($table);
908        $arrResults = array();
909        foreach ($arrParams as $key => $val) {
910            if (in_array($key, $arrCols)) {
911                $arrResults[$key] = $val;
912            }
913        }
914        return $arrResults;
915    }
916
917    /**
918     * プリペアドステートメントを構築する.
919     *
920     * @access private
921     * @param string $sql プリペアドステートメントを構築する SQL
922     * @param mixed $types プレースホルダの型指定 デフォルト null
923     * @param mixed $result_types 返値の型指定またはDML実行(MDB2_PREPARE_MANIP)、nullは指定無し
924     * @return MDB2_Statement_Common プリペアドステートメントインスタンス
925     */
926    function prepare($sql, $types = null, $result_types = MDB2_PREPARE_RESULT) {
927        $sth =& $this->conn->prepare($sql, $types, $result_types);
928        if (PEAR::isError($sth)) {
929            $msg = $this->traceError($sth, $sql);
930            $this->error($msg);
931        }
932        return $sth;
933    }
934
935    /**
936     * プリペアドクエリを実行する.
937     *
938     * @access private
939     * @param MDB2_Statement_Common プリペアドステートメントインスタンス
940     * @param array $arrVal プレースホルダに挿入する配列
941     * @return MDB2_Result 結果セットのインスタンス
942     */
943    function execute(&$sth, $arrVal = array()) {
944
945        $arrStartInfo =& $this->lfStartDbTraceLog($sth, $arrVal);
946        $affected =& $sth->execute((array)$arrVal);
947        $this->lfEndDbTraceLog($arrStartInfo, $sth, $arrVal);
948
949        if (PEAR::isError($affected)) {
950            $sql = isset($sth->query) ? $sth->query : '';
951            $msg = $this->traceError($affected, $sql, $arrVal);
952            $this->error($msg);
953        }
954        $this->conn->last_query = stripslashes($sth->query);
955        return $affected;
956    }
957
958    /**
959     * エラーの内容をトレースする.
960     *
961     * XXX trigger_error で処理する場合、1024文字以内に抑える必要がある。
962     * XXX 重要な情報を先頭に置き、冗長になりすぎないように留意する。
963     * @access private
964     * @param PEAR::Error $error PEAR::Error インスタンス
965     * @param string $sql エラーの発生した SQL 文
966     * @param array $arrVal プレースホルダ
967     * @return string トレースしたエラー文字列
968     */
969    function traceError($error, $sql = '', $arrVal = false) {
970        $err = "SQL: [$sql]\n";
971        if ($arrVal !== false) {
972            $err .= 'PlaceHolder: [' . var_export($arrVal, true) . "]\n";
973        }
974        $err .= $error->getMessage() . "\n";
975        $err .= rtrim($error->getUserInfo()) . "\n";
976
977        // PEAR::MDB2 内部のスタックトレースを出力する場合、下記のコメントを外す。
978        // $err .= GC_Utils_Ex::toStringBacktrace($error->getBackTrace());
979
980        return $err;
981    }
982
983    /**
984     * エラー処理
985     */
986    function error($msg) {
987        $msg = "DB処理でエラーが発生しました。\n" . $msg;
988        if (!$this->force_run) {
989            trigger_error($msg, E_USER_ERROR);
990        } else {
991            GC_Utils_Ex::gfPrintLog($msg, ERROR_LOG_REALFILE, true);
992        }
993    }
994
995    /**
996     * SQLクエリの結果セットのカラム名だけを取得する
997     *
998     * @param string $n 実行する SQL 文
999     * @param array $arr プレースホルダに挿入する値
1000     * @param boolean エラーが発生しても処理を続行する場合 true
1001     * @param mixed $types プレースホルダの型指定 デフォルトnull = string
1002     * @param mixed $result_types 返値の型指定またはDML実行(MDB2_PREPARE_MANIP)
1003     * @return array 実行結果の配列
1004     */
1005    function getQueryDefsFields($n ,$arr = array(), $ignore_err = false, $types = null, $result_types = MDB2_PREPARE_RESULT) {
1006
1007        $n = $this->dbFactory->sfChangeMySQL($n);
1008
1009        $sth =& $this->prepare($n, $types, $result_types);
1010        if (PEAR::isError($sth) && ($this->force_run || $ignore_err)) {
1011            return;
1012        }
1013
1014        $result = $this->execute($sth, $arr);
1015        if (PEAR::isError($result) && ($this->force_run || $ignore_err)) {
1016            return;
1017        }
1018        $arrRet = $result->getColumnNames();
1019        // PREPAREの解放
1020        $sth->free();
1021
1022        return $arrRet;
1023    }
1024
1025    /**
1026     * SQL の実行ログ (トレースログ) を書き出す
1027     *
1028     * @param string 実行するSQL文
1029     * @param array $arrVal プレースホルダに挿入する配列
1030     * @return void
1031     */
1032    private function lfStartDbTraceLog(&$objSth, &$arrVal) {
1033        if (!defined('SQL_QUERY_LOG_MODE') || SQL_QUERY_LOG_MODE === 0) {
1034            return;
1035        }
1036        $arrInfo =& $GLOBALS['_SC_Query_TraceLogInfo'];
1037        if (!isset($arrInfo['http_request_id'])) {
1038            $arrInfo['http_request_id'] = uniqid();
1039        }
1040
1041        $arrStartInfo = array(
1042            'http_request_id'   => $arrInfo['http_request_id'],
1043            'time_start'        => microtime(true),
1044            'count'             => ++$arrInfo['count'],
1045        );
1046
1047        // ログモード1の場合、開始はログに出力しない
1048        if (SQL_QUERY_LOG_MODE === 1) {
1049            return $arrStartInfo;
1050        }
1051
1052        $msg = "[execute start {$arrStartInfo['http_request_id']}#{$arrStartInfo['count']}]\n"
1053             . 'SQL: ' . $objSth->query . "\n"
1054             . 'PlaceHolder: ' . var_export($arrVal, true) . "\n";
1055        GC_Utils_Ex::gfPrintLog($msg, DB_LOG_REALFILE);
1056
1057        return $arrStartInfo;
1058    }
1059
1060    /**
1061     * SQL の実行ログ (トレースログ) を書き出す
1062     *
1063     * @param string 実行するSQL文
1064     * @param array $arrVal プレースホルダに挿入する配列
1065     * @return void
1066     */
1067    private function lfEndDbTraceLog(&$arrStartInfo, &$objSth, &$arrVal) {
1068        if (!defined('SQL_QUERY_LOG_MODE') || SQL_QUERY_LOG_MODE === 0) {
1069            return;
1070        }
1071        $msg = "[execute end {$arrStartInfo['http_request_id']}#{$arrStartInfo['count']}]\n";
1072
1073        $timeEnd = microtime(true);
1074        $timeExecTime = $timeEnd - $arrStartInfo['time_start'];
1075
1076        // ログモード1の場合、
1077        if (SQL_QUERY_LOG_MODE === 1) {
1078            // 規定時間より速い場合、ログに出力しない
1079            if (!defined('SQL_QUERY_LOG_MIN_EXEC_TIME') || $timeExecTime < (float)SQL_QUERY_LOG_MIN_EXEC_TIME) {
1080                return;
1081            }
1082            // 開始時にログ出力していないため、ここで実行内容を出力する
1083            $msg .= 'SQL: ' . $objSth->query . "\n";
1084            $msg .= 'PlaceHolder: ' . var_export($arrVal, true) . "\n";
1085        }
1086
1087        $msg .= 'execution time: ' . sprintf('%.2f sec', $timeExecTime) . "\n";
1088        GC_Utils_Ex::gfPrintLog($msg, DB_LOG_REALFILE);
1089    }
1090}
Note: See TracBrowser for help on using the repository browser.