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

Revision 21767, 36.6 KB checked in by shutta, 9 years ago (diff)

#1296 SC_* のコンストラクタの拡張が無視される
コンストラクタ名を、PHP4の記法(クラス名と同名の関数名)から、PHP5以降で標準的なconstructに変更。

  • 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 __construct($dsn = '', $force_run = false, $new = false) {
50
51        if ($dsn == '') {
52            $dsn = DEFAULT_DSN;
53        }
54
55        // オプション
56        $options = array(
57            // 持続的接続
58            'persistent' => PEAR_DB_PERSISTENT,
59            // Debugモード
60            'debug' => PEAR_DB_DEBUG,
61        );
62
63        // バッファリング trueにするとメモリが解放されない。
64        // 連続クエリ実行時に問題が生じる。
65        $options['result_buffering'] = false;
66
67        if ($new) {
68            $this->conn = MDB2::connect($dsn, $options);
69        } else {
70            $this->conn = MDB2::singleton($dsn, $options);
71        }
72        if (!PEAR::isError($this->conn)) {
73            $this->conn->setCharset('utf8');
74            $this->conn->setFetchMode(MDB2_FETCHMODE_ASSOC);
75        }
76
77        // XXX 上書きインストール時にDBを変更するケースを想定し第1引数を与えている。
78        $this->dbFactory = SC_DB_DBFactory_Ex::getInstance($this->conn->dsn['phptype']);
79        $this->dbFactory->initObjQuery($this);
80
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 $cols カラム名. 複数カラムの場合はカンマ区切りで書く
149     * @param string $from テーブル名
150     * @param string $where WHERE句
151     * @param array $arrWhereVal プレースホルダ
152     * @param integer $fetchmode 使用するフェッチモード。デフォルトは MDB2_FETCHMODE_ASSOC。
153     * @return array|null
154     */
155    function select($cols, $from = '', $where = '', $arrWhereVal = array(), $fetchmode = MDB2_FETCHMODE_ASSOC) {
156        $sqlse = $this->getSql($cols, $from, $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 $cols SELECT 文に含めるカラム名
293     * @param string $from SELECT 文に含めるテーブル名
294     * @param string $where SELECT 文に含める WHERE 句
295     * @param mixed $arrWhereVal プレースホルダ(参照)
296     * @return string 構築済みの SELECT 文
297     */
298    function getSql($cols, $from = '', $where = '', &$arrWhereVal = null) {
299        $dbFactory = SC_DB_DBFactory_Ex::getInstance();
300
301        $sqlse = "SELECT $cols";
302
303        if (strlen($from) === 0) {
304            $sqlse .= ' ' . $dbFactory->getDummyFromClauseSql();
305        } else {
306            $sqlse .= " FROM $from";
307        }
308
309        // 引数の$whereを優先する。
310        if (strlen($where) >= 1) {
311            $sqlse .= " WHERE $where";
312        } elseif (strlen($this->where) >= 1) {
313            $sqlse .= ' WHERE ' . $this->where;
314            // 実行時と同じくキャストしてから評価する (空文字を要素1の配列と評価させる意図)
315            $arrWhereValForEval = (array)$arrWhereVal;
316            if (empty($arrWhereValForEval)) {
317                $arrWhereVal = $this->arrWhereVal;
318            }
319        }
320
321        $sqlse .= ' ' . $this->groupby . ' ' . $this->order . ' ' . $this->option;
322
323        return $sqlse;
324    }
325
326    /**
327     * SELECT 文の末尾に付与する SQL を設定する.
328     *
329     * この関数で設定した値は SC_Query::getSql() で使用されます.
330     *
331     * @param string $str 付与する SQL 文
332     * @return SC_Query 自分自身のインスタンス
333     */
334    function setOption($str) {
335        $this->option = $str;
336        return $this;
337    }
338
339    /**
340     * SELECT 文に付与する LIMIT, OFFSET 句を設定する.
341     *
342     * この関数で設定した値は SC_Query::getSql() で使用されます.
343     * TODO MDB2::setLimit() を使用する
344     *
345     * @param integer $limit LIMIT 句に付与する値
346     * @param integer $offset OFFSET 句に付与する値
347     * @return SC_Query 自分自身のインスタンス
348     */
349    function setLimitOffset($limit, $offset = 0) {
350        if (is_numeric($limit) && is_numeric($offset)) {
351
352            $option = ' LIMIT ' . $limit;
353            $option.= ' OFFSET ' . $offset;
354            $this->option .= $option;
355        }
356        return $this;
357    }
358
359    /**
360     * SELECT 文に付与する GROUP BY 句を設定する.
361     *
362     * この関数で設定した値は SC_Query::getSql() で使用されます.
363     *
364     * @param string $str GROUP BY 句に付与する文字列
365     * @return SC_Query 自分自身のインスタンス
366     */
367    function setGroupBy($str) {
368        if (strlen($str) == 0) {
369            $this->groupby = '';
370        } else {
371            $this->groupby = 'GROUP BY ' . $str;
372        }
373        return $this;
374    }
375
376    /**
377     * SELECT 文の WHERE 句に付与する AND 条件を設定する.
378     *
379     * この関数で設定した値は SC_Query::getSql() で使用されます.
380     *
381     * @param string $str WHERE 句に付与する AND 条件の文字列
382     * @return SC_Query 自分自身のインスタンス
383     */
384    function andWhere($str) {
385        if ($this->where != '') {
386            $this->where .= ' AND ' . $str;
387        } else {
388            $this->where = $str;
389        }
390        return $this;
391    }
392
393    /**
394     * SELECT 文の WHERE 句に付与する OR 条件を設定する.
395     *
396     * この関数で設定した値は SC_Query::getSql() で使用されます.
397     *
398     * @param string $str WHERE 句に付与する OR 条件の文字列
399     * @return SC_Query 自分自身のインスタンス
400     */
401    function orWhere($str) {
402        if ($this->where != '') {
403            $this->where .= ' OR ' . $str;
404        } else {
405            $this->where = $str;
406        }
407        return $this;
408    }
409
410    /**
411     * SELECT 文に付与する WHERE 句を設定する.
412     *
413     * この関数で設定した値は SC_Query::getSql() で使用されます.
414     *
415     * @param string $where WHERE 句に付与する文字列
416     * @param mixed $arrWhereVal プレースホルダ
417     * @return SC_Query 自分自身のインスタンス
418     */
419    function setWhere($where = '', $arrWhereVal = array()) {
420        $this->where = $where;
421        $this->arrWhereVal = $arrWhereVal;
422        return $this;
423    }
424
425    /**
426     * SELECT 文に付与する ORDER BY 句を設定する.
427     *
428     * この関数で設定した値は SC_Query::getSql() で使用されます.
429     *
430     * @param string $str ORDER BY 句に付与する文字列
431     * @return SC_Query 自分自身のインスタンス
432     */
433    function setOrder($str) {
434        if (strlen($str) == 0) {
435            $this->order = '';
436        } else {
437            $this->order = 'ORDER BY ' . $str;
438        }
439        return $this;
440    }
441
442    /**
443     * SELECT 文に付与する LIMIT 句を設定する.
444     *
445     * この関数で設定した値は SC_Query::getSql() で使用されます.
446     *
447     * @param integer $limit LIMIT 句に設定する値
448     * @return SC_Query 自分自身のインスタンス
449     */
450    function setLimit($limit) {
451        if (is_numeric($limit)) {
452            $this->option = ' LIMIT ' .$limit;
453        }
454        return $this;
455    }
456
457    /**
458     * SELECT 文に付与する OFFSET 句を設定する.
459     *
460     * この関数で設定した値は SC_Query::getSql() で使用されます.
461     *
462     * @param integer $offset LIMIT 句に設定する値
463     * @return SC_Query 自分自身のインスタンス
464     */
465    function setOffset($offset) {
466        if (is_numeric($offset)) {
467            $this->offset = ' OFFSET ' .$offset;
468        }
469        return $this;
470    }
471
472    /**
473     * INSERT文を実行する.
474     *
475     * @param string $table テーブル名
476     * @param array $arrVal array('カラム名' => '値', ...)の連想配列
477     * @param array $arrSql array('カラム名' => 'SQL文', ...)の連想配列
478     * @param array $arrSqlVal SQL文の中で使用するプレースホルダ配列
479     * @param string $from FROM 句・WHERE 句
480     * @param string $arrFromVal FROM 句・WHERE 句で使用するプレースホルダ配列
481     * @return integer|DB_Error|boolean 挿入件数またはエラー(DB_Error, false)
482     */
483    function insert($table, $arrVal, $arrSql = array(), $arrSqlVal = array(), $from = '', $arrFromVal = array()) {
484        $strcol = '';
485        $strval = '';
486        $find = false;
487        $arrValForQuery = array();
488
489        foreach ($arrVal as $key => $val) {
490            $strcol .= $key . ',';
491            if (strcasecmp('Now()', $val) === 0) {
492                $strval .= 'Now(),';
493            } else if (strcasecmp('CURRENT_TIMESTAMP', $val) === 0) {
494                $strval .= 'CURRENT_TIMESTAMP,';
495            } else {
496                $strval .= '?,';
497                $arrValForQuery[] = $val;
498            }
499            $find = true;
500        }
501
502        foreach ($arrSql as $key => $val) {
503            $strcol .= $key . ',';
504            $strval .= $val . ',';
505            $find = true;
506        }
507
508        $arrValForQuery = array_merge($arrValForQuery, $arrSqlVal);
509
510        if (!$find) {
511            return false;
512        }
513        // 文末の','を削除
514        $strcol = rtrim($strcol, ',');
515        $strval = rtrim($strval, ',');
516        $sqlin = "INSERT INTO $table($strcol) SELECT $strval";
517
518        if (strlen($from) >= 1) {
519            $sqlin .= ' ' . $from;
520            $arrValForQuery = array_merge($arrValForQuery, $arrFromVal);
521        }
522
523        // INSERT文の実行
524        $ret = $this->query($sqlin, $arrValForQuery, false, null, MDB2_PREPARE_MANIP);
525
526        return $ret;
527    }
528
529    /**
530     * UPDATE文を実行する.
531     *
532     * @param string $table テーブル名
533     * @param array $arrVal array('カラム名' => '値', ...)の連想配列
534     * @param string $where WHERE句
535     * @param array $arrWhereVal WHERE句用のプレースホルダ配列 (従来は追加カラム用も兼ねていた)
536     * @param array $arrRawSql 追加カラム
537     * @param array $arrRawSqlVal 追加カラム用のプレースホルダ配列
538     * @return
539     */
540    function update($table, $arrVal, $where = '', $arrWhereVal = array(), $arrRawSql = array(), $arrRawSqlVal = array()) {
541        $arrCol = array();
542        $arrValForQuery = array();
543        $find = false;
544
545        foreach ($arrVal as $key => $val) {
546            if (strcasecmp('Now()', $val) === 0) {
547                $arrCol[] = $key . '= Now()';
548            } else if (strcasecmp('CURRENT_TIMESTAMP', $val) === 0) {
549                $arrCol[] = $key . '= CURRENT_TIMESTAMP';
550            } else {
551                $arrCol[] = $key . '= ?';
552                $arrValForQuery[] = $val;
553            }
554            $find = true;
555        }
556
557        if ($arrRawSql != '') {
558            foreach ($arrRawSql as $key => $val) {
559                $arrCol[] = "$key = $val";
560            }
561        }
562
563        $arrValForQuery = array_merge($arrValForQuery, $arrRawSqlVal);
564
565        if (empty($arrCol)) {
566            return false;
567        }
568
569        // 文末の','を削除
570        $strcol = implode(', ', $arrCol);
571
572        if (is_array($arrWhereVal)) { // 旧版との互換用
573            // プレースホルダー用に配列を追加
574            $arrValForQuery = array_merge($arrValForQuery, $arrWhereVal);
575        }
576
577        $sqlup = "UPDATE $table SET $strcol";
578        if (strlen($where) >= 1) {
579            $sqlup .= " WHERE $where";
580        }
581
582        // UPDATE文の実行
583        return $this->query($sqlup, $arrValForQuery, false, null, MDB2_PREPARE_MANIP);
584    }
585
586    /**
587     * MAX文を実行する.
588     *
589     * @param string $table テーブル名
590     * @param string $col カラム名
591     * @param string $where 付与する WHERE 句
592     * @param array $arrWhereVal プレースホルダに挿入する値
593     * @return integer MAX文の実行結果
594     */
595    function max($col, $table, $where = '', $arrWhereVal = array()) {
596        $ret = $this->get("MAX($col)", $table, $where, $arrWhereVal);
597        return $ret;
598    }
599
600    /**
601     * MIN文を実行する.
602     *
603     * @param string $table テーブル名
604     * @param string $col カラム名
605     * @param string $where 付与する WHERE 句
606     * @param array $arrWhereVal プレースホルダに挿入する値
607     * @return integer MIN文の実行結果
608     */
609    function min($col, $table, $where = '', $arrWhereVal = array()) {
610        $ret = $this->get("MIN($col)", $table, $where, $arrWhereVal);
611        return $ret;
612    }
613
614    /**
615     * SQL を構築して, 特定のカラムの値を取得する.
616     *
617     * @param string $table テーブル名
618     * @param string $col カラム名
619     * @param string $where 付与する WHERE 句
620     * @param array $arrWhereVal プレースホルダに挿入する値
621     * @return mixed SQL の実行結果
622     */
623    function get($col, $table = '', $where = '', $arrWhereVal = array()) {
624        $sqlse = $this->getSql($col, $table, $where, $arrWhereVal);
625        // SQL文の実行
626        $ret = $this->getOne($sqlse, $arrWhereVal);
627        return $ret;
628    }
629
630    /**
631     * SQL を指定して, 特定のカラムの値を取得する.
632     *
633     * @param string $sql 実行する SQL
634     * @param array $arrVal プレースホルダに挿入する値
635     * @return mixed SQL の実行結果
636     */
637    function getOne($sql, $arrVal = array()) {
638
639        $sql = $this->dbFactory->sfChangeMySQL($sql);
640
641        $sth =& $this->prepare($sql);
642        if (PEAR::isError($sth) && $this->force_run) {
643            return;
644        }
645
646        $affected =& $this->execute($sth, $arrVal);
647        if (PEAR::isError($affected) && $this->force_run) {
648            return;
649        }
650
651        // MySQL での不具合対応のため、一旦変数に退避
652        $arrRet = $affected->fetchOne();
653
654        // PREPAREの解放
655        $sth->free();
656
657        return $arrRet;
658    }
659
660    /**
661     * 一行をカラム名をキーとした連想配列として取得
662     *
663     * @param string $table テーブル名
664     * @param string $col カラム名
665     * @param string $where WHERE句
666     * @param array $arrWhereVal プレースホルダ配列
667     * @param integer $fetchmode 使用するフェッチモード。デフォルトは MDB2_FETCHMODE_ASSOC。
668     * @return array array('カラム名' => '値', ...)の連想配列
669     */
670    function getRow($col, $table = '', $where = '', $arrWhereVal = array(), $fetchmode = MDB2_FETCHMODE_ASSOC) {
671
672        $sql = $this->getSql($col, $table, $where, $arrWhereVal);
673        $sql = $this->dbFactory->sfChangeMySQL($sql);
674
675        $sth =& $this->prepare($sql);
676        if (PEAR::isError($sth) && $this->force_run) {
677            return;
678        }
679
680        $affected =& $this->execute($sth, $arrWhereVal);
681        if (PEAR::isError($affected) && $this->force_run) {
682            return;
683        }
684
685        // MySQL での不具合対応のため、一旦変数に退避
686        $arrRet = $affected->fetchRow($fetchmode);
687
688        // PREPAREの解放
689        $sth->free();
690
691        return $arrRet;
692    }
693
694    /**
695     * SELECT 文の実行結果を 1列のみ取得する.
696     *
697     * @param string $table テーブル名
698     * @param string $col カラム名
699     * @param string $where 付与する WHERE 句
700     * @param array $arrWhereVal プレースホルダに挿入する値
701     * @return array SQL の実行結果の配列
702     */
703    function getCol($col, $table = '', $where = '', $arrWhereVal = array()) {
704        $sql = $this->getSql($col, $table, $where, $arrWhereVal);
705        $sql = $this->dbFactory->sfChangeMySQL($sql);
706
707        $sth =& $this->prepare($sql);
708        if (PEAR::isError($sth) && $this->force_run) {
709            return;
710        }
711
712        $affected =& $this->execute($sth, $arrWhereVal);
713        if (PEAR::isError($affected) && $this->force_run) {
714            return;
715        }
716
717        // MySQL での不具合対応のため、一旦変数に退避
718        $arrRet = $affected->fetchCol();
719
720        // PREPAREの解放
721        $sth->free();
722
723        return $arrRet;
724    }
725
726    /**
727     * レコードの削除
728     *
729     * @param string $table テーブル名
730     * @param string $where WHERE句
731     * @param array $arrWhereVal プレースホルダ
732     * @return
733     */
734    function delete($table, $where = '', $arrWhereVal = array()) {
735        if (strlen($where) <= 0) {
736            $sqlde = "DELETE FROM $table";
737        } else {
738            $sqlde = "DELETE FROM $table WHERE $where";
739        }
740        $ret = $this->query($sqlde, $arrWhereVal, false, null, MDB2_PREPARE_MANIP);
741        return $ret;
742    }
743
744    /**
745     * 次のシーケンス値を取得する.
746     *
747     * @param string $seq_name 取得するシーケンス名
748     * @param integer 次のシーケンス値
749     */
750    function nextVal($seq_name) {
751        return $this->conn->nextID($seq_name);
752    }
753
754    /**
755     * 現在のシーケンス値を取得する.
756     *
757     * @param string $seq_name 取得するシーケンス名
758     * @return integer 現在のシーケンス値
759     */
760    function currVal($seq_name) {
761        return $this->conn->currID($seq_name);
762    }
763
764    /**
765     * シーケンス値を設定する.
766     *
767     * @param string $seq_name シーケンス名
768     * @param integer $start 設定するシーケンス値
769     * @return MDB2_OK
770     */
771    function setVal($seq_name, $start) {
772        $objManager =& $this->conn->loadModule('Manager');
773
774        // XXX 値変更の役割のため、存在チェックは行なわない。存在しない場合、ここでエラーとなる。
775        $ret = $objManager->dropSequence($seq_name);
776        if (PEAR::isError($ret)) {
777            $this->error("setVal -> dropSequence [$seq_name]");
778        }
779
780        $ret = $objManager->createSequence($seq_name, $start);
781        if (PEAR::isError($ret)) {
782            $this->error("setVal -> createSequence [$seq_name] [$start]");
783        }
784        return $ret;
785    }
786
787    /**
788     * SQL を実行する.
789     *
790     * FIXME $ignore_errが無視されるようになっているが互換性として問題が無いか確認が必要
791     *
792     * @param string $n 実行する SQL 文
793     * @param array $arr プレースホルダに挿入する値
794     * @param boolean $ignore_err MDB2切替で無効化されている (エラーが発生しても処理を続行する場合 true)
795     * @param mixed $types プレースホルダの型指定 デフォルトnull = string
796     * @param mixed $result_types 返値の型指定またはDML実行(MDB2_PREPARE_MANIP)
797     * @return array SQL の実行結果の配列
798     */
799    function query($n ,$arr = array(), $ignore_err = false, $types = null, $result_types = MDB2_PREPARE_RESULT) {
800
801        $n = $this->dbFactory->sfChangeMySQL($n);
802
803        $sth =& $this->prepare($n, $types, $result_types);
804        if (PEAR::isError($sth) && $this->force_run) {
805            return $sth;
806        }
807
808        $result = $this->execute($sth, $arr);
809        if (PEAR::isError($result) && $this->force_run) {
810            return $sth;
811        }
812
813        // PREPAREの解放
814        $sth->free();
815
816        return $result;
817    }
818
819    /**
820     * シーケンスの一覧を取得する.
821     *
822     * @return array シーケンス名の配列
823     */
824    function listSequences() {
825        $objManager =& $this->conn->loadModule('Manager');
826        return $objManager->listSequences();
827    }
828
829    /**
830     * テーブル一覧を取得する.
831     *
832     * @return array テーブル名の配列
833     */
834    function listTables() {
835        $objManager =& $this->conn->loadModule('Manager');
836        return $objManager->listTables();
837    }
838
839    /**
840     * テーブルのカラム一覧を取得する.
841     *
842     * @param string $table テーブル名
843     * @return array 指定のテーブルのカラム名の配列
844     */
845    function listTableFields($table) {
846        $objManager =& $this->conn->loadModule('Manager');
847        return $objManager->listTableFields($table);
848    }
849
850    /**
851     * テーブルのインデックス一覧を取得する.
852     *
853     * @param string $table テーブル名
854     * @return array 指定のテーブルのインデックス一覧
855     */
856    function listTableIndexes($table) {
857        $objManager =& $this->conn->loadModule('Manager');
858        return $objManager->listTableIndexes($table);
859    }
860
861    /**
862     * テーブルにインデックスを付与する
863     *
864     * @param string $table テーブル名
865     * @param string $name インデックス名
866     * @param array $definition フィールド名など 通常のフィールド指定時は、$definition=array('fields' => array('フィールド名' => array()));
867     *               MySQLのtext型フィールドを指定する場合は $definition['length'] = 'text_field(NNN)' が必要
868     */
869    function createIndex($table, $name, $definition) {
870        $definition = $this->dbFactory->sfGetCreateIndexDefinition($table, $name, $definition);
871        $objManager =& $this->conn->loadModule('Manager');
872        return $objManager->createIndex($table, $name, $definition);
873    }
874
875    /**
876     * テーブルにインデックスを破棄する
877     *
878     * @param string $table テーブル名
879     * @param string $name インデックス名
880     */
881    function dropIndex($table, $name) {
882        $objManager =& $this->conn->loadModule('Manager');
883        return $objManager->dropIndex($table, $name);
884    }
885
886    /**
887     * テーブルの詳細情報を取得する。
888     *
889     * @param string $table テーブル名
890     * @return array テーブル情報の配列
891     */
892    function getTableInfo($table) {
893        $objManager =& $this->conn->loadModule('Reverse');
894        return $objManager->tableInfo($table, NULL);
895    }
896
897    /**
898     * 値を適切にクォートする.
899     *
900     * TODO MDB2 に対応するための暫定的な措置.
901     *      プレースホルダが使用できない実装があるため.
902     *      本来であれば, MDB2::prepare() を適切に使用するべき
903     *
904     * @see MDB2::quote()
905     * @param string $val クォートを行う文字列
906     * @return string クォートされた文字列
907     */
908    function quote($val) {
909        return $this->conn->quote($val);
910    }
911
912    /**
913     * パラメーターの連想配列から, テーブルに存在する列のみを取得する.
914     *
915     * @param string $table テーブル名
916     * @param array プレースホルダの連想配列
917     * @return array テーブルに存在する列のみ抽出した連想配列
918     */
919    function extractOnlyColsOf($table, $arrParams) {
920        $arrCols = $this->listTableFields($table);
921        $arrResults = array();
922        foreach ($arrParams as $key => $val) {
923            if (in_array($key, $arrCols)) {
924                $arrResults[$key] = $val;
925            }
926        }
927        return $arrResults;
928    }
929
930    /**
931     * プリペアドステートメントを構築する.
932     *
933     * @access private
934     * @param string $sql プリペアドステートメントを構築する SQL
935     * @param mixed $types プレースホルダの型指定 デフォルト null
936     * @param mixed $result_types 返値の型指定またはDML実行(MDB2_PREPARE_MANIP)、nullは指定無し
937     * @return MDB2_Statement_Common プリペアドステートメントインスタンス
938     */
939    function prepare($sql, $types = null, $result_types = MDB2_PREPARE_RESULT) {
940        $sth =& $this->conn->prepare($sql, $types, $result_types);
941        if (PEAR::isError($sth)) {
942            $msg = $this->traceError($sth, $sql);
943            $this->error($msg);
944        }
945        return $sth;
946    }
947
948    /**
949     * プリペアドクエリを実行する.
950     *
951     * @access private
952     * @param MDB2_Statement_Common プリペアドステートメントインスタンス
953     * @param array $arrVal プレースホルダに挿入する配列
954     * @return MDB2_Result 結果セットのインスタンス
955     */
956    function execute(&$sth, $arrVal = array()) {
957
958        $arrStartInfo =& $this->lfStartDbTraceLog($sth, $arrVal);
959        $affected =& $sth->execute((array)$arrVal);
960        $this->lfEndDbTraceLog($arrStartInfo, $sth, $arrVal);
961
962        if (PEAR::isError($affected)) {
963            $sql = isset($sth->query) ? $sth->query : '';
964            $msg = $this->traceError($affected, $sql, $arrVal);
965            $this->error($msg);
966        }
967        $this->conn->last_query = stripslashes($sth->query);
968        return $affected;
969    }
970
971    /**
972     * エラーの内容をトレースする.
973     *
974     * XXX trigger_error で処理する場合、1024文字以内に抑える必要がある。
975     * XXX 重要な情報を先頭に置き、冗長になりすぎないように留意する。
976     * @access private
977     * @param PEAR::Error $error PEAR::Error インスタンス
978     * @param string $sql エラーの発生した SQL 文
979     * @param array $arrVal プレースホルダ
980     * @return string トレースしたエラー文字列
981     */
982    function traceError($error, $sql = '', $arrVal = false) {
983        $err = "SQL: [$sql]\n";
984        if ($arrVal !== false) {
985            $err .= 'PlaceHolder: [' . var_export($arrVal, true) . "]\n";
986        }
987        $err .= $error->getMessage() . "\n";
988        $err .= rtrim($error->getUserInfo()) . "\n";
989
990        // PEAR::MDB2 内部のスタックトレースを出力する場合、下記のコメントを外す。
991        // $err .= GC_Utils_Ex::toStringBacktrace($error->getBackTrace());
992
993        return $err;
994    }
995
996    /**
997     * エラー処理
998     */
999    function error($msg) {
1000        $msg = "DB処理でエラーが発生しました。\n" . $msg;
1001        if (!$this->force_run) {
1002            trigger_error($msg, E_USER_ERROR);
1003        } else {
1004            GC_Utils_Ex::gfPrintLog($msg, ERROR_LOG_REALFILE, true);
1005        }
1006    }
1007
1008    /**
1009     * SQLクエリの結果セットのカラム名だけを取得する
1010     *
1011     * @param string $n 実行する SQL 文
1012     * @param array $arr プレースホルダに挿入する値
1013     * @param boolean エラーが発生しても処理を続行する場合 true
1014     * @param mixed $types プレースホルダの型指定 デフォルトnull = string
1015     * @param mixed $result_types 返値の型指定またはDML実行(MDB2_PREPARE_MANIP)
1016     * @return array 実行結果の配列
1017     */
1018    function getQueryDefsFields($n ,$arr = array(), $ignore_err = false, $types = null, $result_types = MDB2_PREPARE_RESULT) {
1019
1020        $n = $this->dbFactory->sfChangeMySQL($n);
1021
1022        $sth =& $this->prepare($n, $types, $result_types);
1023        if (PEAR::isError($sth) && ($this->force_run || $ignore_err)) {
1024            return;
1025        }
1026
1027        $result = $this->execute($sth, $arr);
1028        if (PEAR::isError($result) && ($this->force_run || $ignore_err)) {
1029            return;
1030        }
1031        $arrRet = $result->getColumnNames();
1032        // PREPAREの解放
1033        $sth->free();
1034
1035        return $arrRet;
1036    }
1037
1038    /**
1039     * SQL の実行ログ (トレースログ) を書き出す
1040     *
1041     * @param string 実行するSQL文
1042     * @param array $arrVal プレースホルダに挿入する配列
1043     * @return void
1044     */
1045    private function lfStartDbTraceLog(&$objSth, &$arrVal) {
1046        if (!defined('SQL_QUERY_LOG_MODE') || SQL_QUERY_LOG_MODE === 0) {
1047            return;
1048        }
1049        $arrInfo =& $GLOBALS['_SC_Query_TraceLogInfo'];
1050        if (!isset($arrInfo['http_request_id'])) {
1051            $arrInfo['http_request_id'] = uniqid();
1052        }
1053
1054        $arrStartInfo = array(
1055            'http_request_id'   => $arrInfo['http_request_id'],
1056            'time_start'        => microtime(true),
1057            'count'             => ++$arrInfo['count'],
1058        );
1059
1060        // ログモード1の場合、開始はログに出力しない
1061        if (SQL_QUERY_LOG_MODE === 1) {
1062            return $arrStartInfo;
1063        }
1064
1065        $msg = "[execute start {$arrStartInfo['http_request_id']}#{$arrStartInfo['count']}]\n"
1066             . 'SQL: ' . $objSth->query . "\n"
1067             . 'PlaceHolder: ' . var_export($arrVal, true) . "\n";
1068        GC_Utils_Ex::gfPrintLog($msg, DB_LOG_REALFILE);
1069
1070        return $arrStartInfo;
1071    }
1072
1073    /**
1074     * SQL の実行ログ (トレースログ) を書き出す
1075     *
1076     * @param string 実行するSQL文
1077     * @param array $arrVal プレースホルダに挿入する配列
1078     * @return void
1079     */
1080    private function lfEndDbTraceLog(&$arrStartInfo, &$objSth, &$arrVal) {
1081        if (!defined('SQL_QUERY_LOG_MODE') || SQL_QUERY_LOG_MODE === 0) {
1082            return;
1083        }
1084        $msg = "[execute end {$arrStartInfo['http_request_id']}#{$arrStartInfo['count']}]\n";
1085
1086        $timeEnd = microtime(true);
1087        $timeExecTime = $timeEnd - $arrStartInfo['time_start'];
1088
1089        // ログモード1の場合、
1090        if (SQL_QUERY_LOG_MODE === 1) {
1091            // 規定時間より速い場合、ログに出力しない
1092            if (!defined('SQL_QUERY_LOG_MIN_EXEC_TIME') || $timeExecTime < (float)SQL_QUERY_LOG_MIN_EXEC_TIME) {
1093                return;
1094            }
1095            // 開始時にログ出力していないため、ここで実行内容を出力する
1096            $msg .= 'SQL: ' . $objSth->query . "\n";
1097            $msg .= 'PlaceHolder: ' . var_export($arrVal, true) . "\n";
1098        }
1099
1100        $msg .= 'execution time: ' . sprintf('%.2f sec', $timeExecTime) . "\n";
1101        GC_Utils_Ex::gfPrintLog($msg, DB_LOG_REALFILE);
1102    }
1103}
Note: See TracBrowser for help on using the repository browser.