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

Revision 21544, 34.0 KB checked in by Seasoft, 10 years ago (diff)

#1656 (カテゴリ登録のロジックを高速化)
#1661 (共通ロジックを利用する)

  • SC_Query#getCol

#1660 (SC_Helper_DB#sfCountCategory メモリ消費が激しい)
#1659 (SC_Helper_DB#sfCountCategory メモリリークが発生する)

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