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

Revision 21830, 36.9 KB checked in by nanasess, 8 years ago (diff)

#1654 (MDB2 への接続設定を連想配列に)

  • 下位互換のため DEFAULT_DSN は残しておく

#1607 (未使用定義の削除)

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