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

Revision 21583, 35.9 KB checked in by Seasoft, 11 years ago (diff)

#1603 (プラグイン機能(エンジン部分))

  • 互換性のない旧プラグイン機能を削除

#1607 (未使用定義の削除)
#1605 (PHP4向けコードの除去、PHP5向けのコード最適化)

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