source: branches/comu-ver2/data/module/DB/fbsql.php @ 17877

Revision 17877, 22.7 KB checked in by Seasoft, 15 years ago (diff)

・PEAR::DB を Ver.1.7.14RC1(2007-11-27)ベースに更改。
・不適切な文字列比較を修正。

 http://xoops.ec-cube.net/modules/newbb/viewtopic.php?topic_id=1808&forum=9

  • Property svn:keywords set to Id
  • Property svn:mime-type set to text/x-httpd-php; charset=UTF-8
Line 
1<?php
2
3/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
4
5/**
6 * The PEAR DB driver for PHP's fbsql extension
7 * for interacting with FrontBase databases
8 *
9 * PHP versions 4 and 5
10 *
11 * LICENSE: This source file is subject to version 3.0 of the PHP license
12 * that is available through the world-wide-web at the following URI:
13 * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
14 * the PHP License and are unable to obtain it through the web, please
15 * send a note to license@php.net so we can mail you a copy immediately.
16 *
17 * @category   Database
18 * @package    DB
19 * @author     Frank M. Kromann <frank@frontbase.com>
20 * @author     Daniel Convissor <danielc@php.net>
21 * @copyright  1997-2007 The PHP Group
22 * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
23 * @version    CVS: $Id$
24 * @link       http://pear.php.net/package/DB
25 */
26
27/**
28 * Obtain the DB_common class so it can be extended from
29 */
30require_once 'DB/common.php';
31
32/**
33 * The methods PEAR DB uses to interact with PHP's fbsql extension
34 * for interacting with FrontBase databases
35 *
36 * These methods overload the ones declared in DB_common.
37 *
38 * @category   Database
39 * @package    DB
40 * @author     Frank M. Kromann <frank@frontbase.com>
41 * @author     Daniel Convissor <danielc@php.net>
42 * @copyright  1997-2007 The PHP Group
43 * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
44 * @version    Release: 1.7.14RC1
45 * @link       http://pear.php.net/package/DB
46 * @since      Class functional since Release 1.7.0
47 */
48class DB_fbsql extends DB_common
49{
50    // {{{ properties
51
52    /**
53     * The DB driver type (mysql, oci8, odbc, etc.)
54     * @var string
55     */
56    var $phptype = 'fbsql';
57
58    /**
59     * The database syntax variant to be used (db2, access, etc.), if any
60     * @var string
61     */
62    var $dbsyntax = 'fbsql';
63
64    /**
65     * The capabilities of this DB implementation
66     *
67     * The 'new_link' element contains the PHP version that first provided
68     * new_link support for this DBMS.  Contains false if it's unsupported.
69     *
70     * Meaning of the 'limit' element:
71     *   + 'emulate' = emulate with fetch row by number
72     *   + 'alter'   = alter the query
73     *   + false     = skip rows
74     *
75     * @var array
76     */
77    var $features = array(
78        'limit'         => 'alter',
79        'new_link'      => false,
80        'numrows'       => true,
81        'pconnect'      => true,
82        'prepare'       => false,
83        'ssl'           => false,
84        'transactions'  => true,
85    );
86
87    /**
88     * A mapping of native error codes to DB error codes
89     * @var array
90     */
91    var $errorcode_map = array(
92         22 => DB_ERROR_SYNTAX,
93         85 => DB_ERROR_ALREADY_EXISTS,
94        108 => DB_ERROR_SYNTAX,
95        116 => DB_ERROR_NOSUCHTABLE,
96        124 => DB_ERROR_VALUE_COUNT_ON_ROW,
97        215 => DB_ERROR_NOSUCHFIELD,
98        217 => DB_ERROR_INVALID_NUMBER,
99        226 => DB_ERROR_NOSUCHFIELD,
100        231 => DB_ERROR_INVALID,
101        239 => DB_ERROR_TRUNCATED,
102        251 => DB_ERROR_SYNTAX,
103        266 => DB_ERROR_NOT_FOUND,
104        357 => DB_ERROR_CONSTRAINT_NOT_NULL,
105        358 => DB_ERROR_CONSTRAINT,
106        360 => DB_ERROR_CONSTRAINT,
107        361 => DB_ERROR_CONSTRAINT,
108    );
109
110    /**
111     * The raw database connection created by PHP
112     * @var resource
113     */
114    var $connection;
115
116    /**
117     * The DSN information for connecting to a database
118     * @var array
119     */
120    var $dsn = array();
121
122
123    // }}}
124    // {{{ constructor
125
126    /**
127     * This constructor calls <kbd>$this->DB_common()</kbd>
128     *
129     * @return void
130     */
131    function DB_fbsql()
132    {
133        $this->DB_common();
134    }
135
136    // }}}
137    // {{{ connect()
138
139    /**
140     * Connect to the database server, log in and open the database
141     *
142     * Don't call this method directly.  Use DB::connect() instead.
143     *
144     * @param array $dsn         the data source name
145     * @param bool  $persistent  should the connection be persistent?
146     *
147     * @return int  DB_OK on success. A DB_Error object on failure.
148     */
149    function connect($dsn, $persistent = false)
150    {
151        if (!PEAR::loadExtension('fbsql')) {
152            return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
153        }
154
155        $this->dsn = $dsn;
156        if ($dsn['dbsyntax']) {
157            $this->dbsyntax = $dsn['dbsyntax'];
158        }
159
160        $params = array(
161            $dsn['hostspec'] ? $dsn['hostspec'] : 'localhost',
162            $dsn['username'] ? $dsn['username'] : null,
163            $dsn['password'] ? $dsn['password'] : null,
164        );
165
166        $connect_function = $persistent ? 'fbsql_pconnect' : 'fbsql_connect';
167
168        $ini = ini_get('track_errors');
169        $php_errormsg = '';
170        if ($ini) {
171            $this->connection = @call_user_func_array($connect_function,
172                                                      $params);
173        } else {
174            @ini_set('track_errors', 1);
175            $this->connection = @call_user_func_array($connect_function,
176                                                      $params);
177            @ini_set('track_errors', $ini);
178        }
179
180        if (!$this->connection) {
181            return $this->raiseError(DB_ERROR_CONNECT_FAILED,
182                                     null, null, null,
183                                     $php_errormsg);
184        }
185
186        if ($dsn['database']) {
187            if (!@fbsql_select_db($dsn['database'], $this->connection)) {
188                return $this->fbsqlRaiseError();
189            }
190        }
191
192        return DB_OK;
193    }
194
195    // }}}
196    // {{{ disconnect()
197
198    /**
199     * Disconnects from the database server
200     *
201     * @return bool  TRUE on success, FALSE on failure
202     */
203    function disconnect()
204    {
205        $ret = @fbsql_close($this->connection);
206        $this->connection = null;
207        return $ret;
208    }
209
210    // }}}
211    // {{{ simpleQuery()
212
213    /**
214     * Sends a query to the database server
215     *
216     * @param string  the SQL query string
217     *
218     * @return mixed  + a PHP result resrouce for successful SELECT queries
219     *                + the DB_OK constant for other successful queries
220     *                + a DB_Error object on failure
221     */
222    function simpleQuery($query)
223    {
224        $this->last_query = $query;
225        $query = $this->modifyQuery($query);
226        $result = @fbsql_query("$query;", $this->connection);
227        if (!$result) {
228            return $this->fbsqlRaiseError();
229        }
230        // Determine which queries that should return data, and which
231        // should return an error code only.
232        if ($this->_checkManip($query)) {
233            return DB_OK;
234        }
235        return $result;
236    }
237
238    // }}}
239    // {{{ nextResult()
240
241    /**
242     * Move the internal fbsql result pointer to the next available result
243     *
244     * @param a valid fbsql result resource
245     *
246     * @access public
247     *
248     * @return true if a result is available otherwise return false
249     */
250    function nextResult($result)
251    {
252        return @fbsql_next_result($result);
253    }
254
255    // }}}
256    // {{{ fetchInto()
257
258    /**
259     * Places a row from the result set into the given array
260     *
261     * Formating of the array and the data therein are configurable.
262     * See DB_result::fetchInto() for more information.
263     *
264     * This method is not meant to be called directly.  Use
265     * DB_result::fetchInto() instead.  It can't be declared "protected"
266     * because DB_result is a separate object.
267     *
268     * @param resource $result    the query result resource
269     * @param array    $arr       the referenced array to put the data in
270     * @param int      $fetchmode how the resulting array should be indexed
271     * @param int      $rownum    the row number to fetch (0 = first row)
272     *
273     * @return mixed  DB_OK on success, NULL when the end of a result set is
274     *                 reached or on failure
275     *
276     * @see DB_result::fetchInto()
277     */
278    function fetchInto($result, &$arr, $fetchmode, $rownum = null)
279    {
280        if ($rownum !== null) {
281            if (!@fbsql_data_seek($result, $rownum)) {
282                return null;
283            }
284        }
285        if ($fetchmode & DB_FETCHMODE_ASSOC) {
286            $arr = @fbsql_fetch_array($result, FBSQL_ASSOC);
287            if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) {
288                $arr = array_change_key_case($arr, CASE_LOWER);
289            }
290        } else {
291            $arr = @fbsql_fetch_row($result);
292        }
293        if (!$arr) {
294            return null;
295        }
296        if ($this->options['portability'] & DB_PORTABILITY_RTRIM) {
297            $this->_rtrimArrayValues($arr);
298        }
299        if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) {
300            $this->_convertNullArrayValuesToEmpty($arr);
301        }
302        return DB_OK;
303    }
304
305    // }}}
306    // {{{ freeResult()
307
308    /**
309     * Deletes the result set and frees the memory occupied by the result set
310     *
311     * This method is not meant to be called directly.  Use
312     * DB_result::free() instead.  It can't be declared "protected"
313     * because DB_result is a separate object.
314     *
315     * @param resource $result  PHP's query result resource
316     *
317     * @return bool  TRUE on success, FALSE if $result is invalid
318     *
319     * @see DB_result::free()
320     */
321    function freeResult($result)
322    {
323        return is_resource($result) ? fbsql_free_result($result) : false;
324    }
325
326    // }}}
327    // {{{ autoCommit()
328
329    /**
330     * Enables or disables automatic commits
331     *
332     * @param bool $onoff  true turns it on, false turns it off
333     *
334     * @return int  DB_OK on success.  A DB_Error object if the driver
335     *               doesn't support auto-committing transactions.
336     */
337    function autoCommit($onoff=false)
338    {
339        if ($onoff) {
340            $this->query("SET COMMIT TRUE");
341        } else {
342            $this->query("SET COMMIT FALSE");
343        }
344    }
345
346    // }}}
347    // {{{ commit()
348
349    /**
350     * Commits the current transaction
351     *
352     * @return int  DB_OK on success.  A DB_Error object on failure.
353     */
354    function commit()
355    {
356        @fbsql_commit($this->connection);
357    }
358
359    // }}}
360    // {{{ rollback()
361
362    /**
363     * Reverts the current transaction
364     *
365     * @return int  DB_OK on success.  A DB_Error object on failure.
366     */
367    function rollback()
368    {
369        @fbsql_rollback($this->connection);
370    }
371
372    // }}}
373    // {{{ numCols()
374
375    /**
376     * Gets the number of columns in a result set
377     *
378     * This method is not meant to be called directly.  Use
379     * DB_result::numCols() instead.  It can't be declared "protected"
380     * because DB_result is a separate object.
381     *
382     * @param resource $result  PHP's query result resource
383     *
384     * @return int  the number of columns.  A DB_Error object on failure.
385     *
386     * @see DB_result::numCols()
387     */
388    function numCols($result)
389    {
390        $cols = @fbsql_num_fields($result);
391        if (!$cols) {
392            return $this->fbsqlRaiseError();
393        }
394        return $cols;
395    }
396
397    // }}}
398    // {{{ numRows()
399
400    /**
401     * Gets the number of rows in a result set
402     *
403     * This method is not meant to be called directly.  Use
404     * DB_result::numRows() instead.  It can't be declared "protected"
405     * because DB_result is a separate object.
406     *
407     * @param resource $result  PHP's query result resource
408     *
409     * @return int  the number of rows.  A DB_Error object on failure.
410     *
411     * @see DB_result::numRows()
412     */
413    function numRows($result)
414    {
415        $rows = @fbsql_num_rows($result);
416        if ($rows === null) {
417            return $this->fbsqlRaiseError();
418        }
419        return $rows;
420    }
421
422    // }}}
423    // {{{ affectedRows()
424
425    /**
426     * Determines the number of rows affected by a data maniuplation query
427     *
428     * 0 is returned for queries that don't manipulate data.
429     *
430     * @return int  the number of rows.  A DB_Error object on failure.
431     */
432    function affectedRows()
433    {
434        if ($this->_last_query_manip) {
435            $result = @fbsql_affected_rows($this->connection);
436        } else {
437            $result = 0;
438        }
439        return $result;
440     }
441
442    // }}}
443    // {{{ nextId()
444
445    /**
446     * Returns the next free id in a sequence
447     *
448     * @param string  $seq_name  name of the sequence
449     * @param boolean $ondemand  when true, the seqence is automatically
450     *                            created if it does not exist
451     *
452     * @return int  the next id number in the sequence.
453     *               A DB_Error object on failure.
454     *
455     * @see DB_common::nextID(), DB_common::getSequenceName(),
456     *      DB_fbsql::createSequence(), DB_fbsql::dropSequence()
457     */
458    function nextId($seq_name, $ondemand = true)
459    {
460        $seqname = $this->getSequenceName($seq_name);
461        do {
462            $repeat = 0;
463            $this->pushErrorHandling(PEAR_ERROR_RETURN);
464            $result = $this->query('SELECT UNIQUE FROM ' . $seqname);
465            $this->popErrorHandling();
466            if ($ondemand && DB::isError($result) &&
467                $result->getCode() == DB_ERROR_NOSUCHTABLE) {
468                $repeat = 1;
469                $result = $this->createSequence($seq_name);
470                if (DB::isError($result)) {
471                    return $result;
472                }
473            } else {
474                $repeat = 0;
475            }
476        } while ($repeat);
477        if (DB::isError($result)) {
478            return $this->fbsqlRaiseError();
479        }
480        $result->fetchInto($tmp, DB_FETCHMODE_ORDERED);
481        return $tmp[0];
482    }
483
484    /**
485     * Creates a new sequence
486     *
487     * @param string $seq_name  name of the new sequence
488     *
489     * @return int  DB_OK on success.  A DB_Error object on failure.
490     *
491     * @see DB_common::createSequence(), DB_common::getSequenceName(),
492     *      DB_fbsql::nextID(), DB_fbsql::dropSequence()
493     */
494    function createSequence($seq_name)
495    {
496        $seqname = $this->getSequenceName($seq_name);
497        $res = $this->query('CREATE TABLE ' . $seqname
498                            . ' (id INTEGER NOT NULL,'
499                            . ' PRIMARY KEY(id))');
500        if ($res) {
501            $res = $this->query('SET UNIQUE = 0 FOR ' . $seqname);
502        }
503        return $res;
504    }
505
506    // }}}
507    // {{{ dropSequence()
508
509    /**
510     * Deletes a sequence
511     *
512     * @param string $seq_name  name of the sequence to be deleted
513     *
514     * @return int  DB_OK on success.  A DB_Error object on failure.
515     *
516     * @see DB_common::dropSequence(), DB_common::getSequenceName(),
517     *      DB_fbsql::nextID(), DB_fbsql::createSequence()
518     */
519    function dropSequence($seq_name)
520    {
521        return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name)
522                            . ' RESTRICT');
523    }
524
525    // }}}
526    // {{{ modifyLimitQuery()
527
528    /**
529     * Adds LIMIT clauses to a query string according to current DBMS standards
530     *
531     * @param string $query   the query to modify
532     * @param int    $from    the row to start to fetching (0 = the first row)
533     * @param int    $count   the numbers of rows to fetch
534     * @param mixed  $params  array, string or numeric data to be used in
535     *                         execution of the statement.  Quantity of items
536     *                         passed must match quantity of placeholders in
537     *                         query:  meaning 1 placeholder for non-array
538     *                         parameters or 1 placeholder per array element.
539     *
540     * @return string  the query string with LIMIT clauses added
541     *
542     * @access protected
543     */
544    function modifyLimitQuery($query, $from, $count, $params = array())
545    {
546        if (DB::isManip($query) || $this->_next_query_manip) {
547            return preg_replace('/^([\s(])*SELECT/i',
548                                "\\1SELECT TOP($count)", $query);
549        } else {
550            return preg_replace('/([\s(])*SELECT/i',
551                                "\\1SELECT TOP($from, $count)", $query);
552        }
553    }
554
555    // }}}
556    // {{{ quoteBoolean()
557
558    /**
559     * Formats a boolean value for use within a query in a locale-independent
560     * manner.
561     *
562     * @param boolean the boolean value to be quoted.
563     * @return string the quoted string.
564     * @see DB_common::quoteSmart()
565     * @since Method available since release 1.7.8.
566     */
567    function quoteBoolean($boolean) {
568        return $boolean ? 'TRUE' : 'FALSE';
569    }
570     
571    // }}}
572    // {{{ quoteFloat()
573
574    /**
575     * Formats a float value for use within a query in a locale-independent
576     * manner.
577     *
578     * @param float the float value to be quoted.
579     * @return string the quoted string.
580     * @see DB_common::quoteSmart()
581     * @since Method available since release 1.7.8.
582     */
583    function quoteFloat($float) {
584        return $this->escapeSimple(str_replace(',', '.', strval(floatval($float))));
585    }
586     
587    // }}}
588    // {{{ fbsqlRaiseError()
589
590    /**
591     * Produces a DB_Error object regarding the current problem
592     *
593     * @param int $errno  if the error is being manually raised pass a
594     *                     DB_ERROR* constant here.  If this isn't passed
595     *                     the error information gathered from the DBMS.
596     *
597     * @return object  the DB_Error object
598     *
599     * @see DB_common::raiseError(),
600     *      DB_fbsql::errorNative(), DB_common::errorCode()
601     */
602    function fbsqlRaiseError($errno = null)
603    {
604        if ($errno === null) {
605            $errno = $this->errorCode(fbsql_errno($this->connection));
606        }
607        return $this->raiseError($errno, null, null, null,
608                                 @fbsql_error($this->connection));
609    }
610
611    // }}}
612    // {{{ errorNative()
613
614    /**
615     * Gets the DBMS' native error code produced by the last query
616     *
617     * @return int  the DBMS' error code
618     */
619    function errorNative()
620    {
621        return @fbsql_errno($this->connection);
622    }
623
624    // }}}
625    // {{{ tableInfo()
626
627    /**
628     * Returns information about a table or a result set
629     *
630     * @param object|string  $result  DB_result object from a query or a
631     *                                 string containing the name of a table.
632     *                                 While this also accepts a query result
633     *                                 resource identifier, this behavior is
634     *                                 deprecated.
635     * @param int            $mode    a valid tableInfo mode
636     *
637     * @return array  an associative array with the information requested.
638     *                 A DB_Error object on failure.
639     *
640     * @see DB_common::tableInfo()
641     */
642    function tableInfo($result, $mode = null)
643    {
644        if (is_string($result)) {
645            /*
646             * Probably received a table name.
647             * Create a result resource identifier.
648             */
649            $id = @fbsql_list_fields($this->dsn['database'],
650                                     $result, $this->connection);
651            $got_string = true;
652        } elseif (isset($result->result)) {
653            /*
654             * Probably received a result object.
655             * Extract the result resource identifier.
656             */
657            $id = $result->result;
658            $got_string = false;
659        } else {
660            /*
661             * Probably received a result resource identifier.
662             * Copy it.
663             * Deprecated.  Here for compatibility only.
664             */
665            $id = $result;
666            $got_string = false;
667        }
668
669        if (!is_resource($id)) {
670            return $this->fbsqlRaiseError(DB_ERROR_NEED_MORE_DATA);
671        }
672
673        if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
674            $case_func = 'strtolower';
675        } else {
676            $case_func = 'strval';
677        }
678
679        $count = @fbsql_num_fields($id);
680        $res   = array();
681
682        if ($mode) {
683            $res['num_fields'] = $count;
684        }
685
686        for ($i = 0; $i < $count; $i++) {
687            $res[$i] = array(
688                'table' => $case_func(@fbsql_field_table($id, $i)),
689                'name'  => $case_func(@fbsql_field_name($id, $i)),
690                'type'  => @fbsql_field_type($id, $i),
691                'len'   => @fbsql_field_len($id, $i),
692                'flags' => @fbsql_field_flags($id, $i),
693            );
694            if ($mode & DB_TABLEINFO_ORDER) {
695                $res['order'][$res[$i]['name']] = $i;
696            }
697            if ($mode & DB_TABLEINFO_ORDERTABLE) {
698                $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
699            }
700        }
701
702        // free the result only if we were called on a table
703        if ($got_string) {
704            @fbsql_free_result($id);
705        }
706        return $res;
707    }
708
709    // }}}
710    // {{{ getSpecialQuery()
711
712    /**
713     * Obtains the query string needed for listing a given type of objects
714     *
715     * @param string $type  the kind of objects you want to retrieve
716     *
717     * @return string  the SQL query string or null if the driver doesn't
718     *                  support the object type requested
719     *
720     * @access protected
721     * @see DB_common::getListOf()
722     */
723    function getSpecialQuery($type)
724    {
725        switch ($type) {
726            case 'tables':
727                return 'SELECT "table_name" FROM information_schema.tables'
728                       . ' t0, information_schema.schemata t1'
729                       . ' WHERE t0.schema_pk=t1.schema_pk AND'
730                       . ' "table_type" = \'BASE TABLE\''
731                       . ' AND "schema_name" = current_schema';
732            case 'views':
733                return 'SELECT "table_name" FROM information_schema.tables'
734                       . ' t0, information_schema.schemata t1'
735                       . ' WHERE t0.schema_pk=t1.schema_pk AND'
736                       . ' "table_type" = \'VIEW\''
737                       . ' AND "schema_name" = current_schema';
738            case 'users':
739                return 'SELECT "user_name" from information_schema.users';
740            case 'functions':
741                return 'SELECT "routine_name" FROM'
742                       . ' information_schema.psm_routines'
743                       . ' t0, information_schema.schemata t1'
744                       . ' WHERE t0.schema_pk=t1.schema_pk'
745                       . ' AND "routine_kind"=\'FUNCTION\''
746                       . ' AND "schema_name" = current_schema';
747            case 'procedures':
748                return 'SELECT "routine_name" FROM'
749                       . ' information_schema.psm_routines'
750                       . ' t0, information_schema.schemata t1'
751                       . ' WHERE t0.schema_pk=t1.schema_pk'
752                       . ' AND "routine_kind"=\'PROCEDURE\''
753                       . ' AND "schema_name" = current_schema';
754            default:
755                return null;
756        }
757    }
758
759    // }}}
760}
761
762/*
763 * Local variables:
764 * tab-width: 4
765 * c-basic-offset: 4
766 * End:
767 */
768
769?>
Note: See TracBrowser for help on using the repository browser.