source: branches/version-2_11-dev/data/class/SC_Query.php @ 21270

Revision 21270, 32.5 KB checked in by Seasoft, 9 years ago (diff)

#1489 (SC_Query エラートレースでプレースホルダをダンプする)

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