Subversion Repositories Applications.gtt

Rev

Rev 94 | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 94 Rev 187
Line 4... Line 4...
4
 
4
 
5
/**
5
/**
6
 * The PEAR DB driver for PHP's pgsql extension
6
 * The PEAR DB driver for PHP's pgsql extension
7
 * for interacting with PostgreSQL databases
7
 * for interacting with PostgreSQL databases
8
 *
8
 *
9
 * PHP versions 4 and 5
9
 * PHP version 5
10
 *
10
 *
11
 * LICENSE: This source file is subject to version 3.0 of the PHP license
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:
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
13
 * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
Line 17... Line 17...
17
 * @category   Database
17
 * @category   Database
18
 * @package    DB
18
 * @package    DB
19
 * @author     Rui Hirokawa <hirokawa@php.net>
19
 * @author     Rui Hirokawa <hirokawa@php.net>
20
 * @author     Stig Bakken <ssb@php.net>
20
 * @author     Stig Bakken <ssb@php.net>
21
 * @author     Daniel Convissor <danielc@php.net>
21
 * @author     Daniel Convissor <danielc@php.net>
22
 * @copyright  1997-2005 The PHP Group
22
 * @copyright  1997-2007 The PHP Group
23
 * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
23
 * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
24
 * @version    CVS: $Id: pgsql.php,v 1.126 2005/03/04 23:12:36 danielc Exp $
24
 * @version    CVS: $Id$
25
 * @link       http://pear.php.net/package/DB
25
 * @link       http://pear.php.net/package/DB
26
 */
26
 */
Line 27... Line 27...
27
 
27
 
28
/**
28
/**
Line 39... Line 39...
39
 * @category   Database
39
 * @category   Database
40
 * @package    DB
40
 * @package    DB
41
 * @author     Rui Hirokawa <hirokawa@php.net>
41
 * @author     Rui Hirokawa <hirokawa@php.net>
42
 * @author     Stig Bakken <ssb@php.net>
42
 * @author     Stig Bakken <ssb@php.net>
43
 * @author     Daniel Convissor <danielc@php.net>
43
 * @author     Daniel Convissor <danielc@php.net>
44
 * @copyright  1997-2005 The PHP Group
44
 * @copyright  1997-2007 The PHP Group
45
 * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
45
 * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
46
 * @version    Release: 1.7.6
46
 * @version    Release: 1.9.2
47
 * @link       http://pear.php.net/package/DB
47
 * @link       http://pear.php.net/package/DB
48
 */
48
 */
49
class DB_pgsql extends DB_common
49
class DB_pgsql extends DB_common
50
{
50
{
51
    // {{{ properties
51
    // {{{ properties
Line 146... Line 146...
146
 
146
 
147
    // }}}
147
    // }}}
Line 148... Line 148...
148
    // {{{ constructor
148
    // {{{ constructor
149
 
149
 
150
    /**
150
    /**
151
     * This constructor calls <kbd>$this->DB_common()</kbd>
151
     * This constructor calls <kbd>parent::__construct()</kbd>
152
     *
152
     *
153
     * @return void
153
     * @return void
154
     */
154
     */
155
    function DB_pgsql()
155
    function __construct()
156
    {
156
    {
Line 157... Line 157...
157
        $this->DB_common();
157
        parent::__construct();
158
    }
158
    }
Line 191... Line 191...
191
     * $dsn = 'pgsql://user:pass@unix(/tmp)/dbname?new_link=true';
191
     * $dsn = 'pgsql://user:pass@unix(/tmp)/dbname?new_link=true';
192
     * $options = array(
192
     * $options = array(
193
     *     'portability' => DB_PORTABILITY_ALL,
193
     *     'portability' => DB_PORTABILITY_ALL,
194
     * );
194
     * );
195
     * 
195
     * 
196
     * $db =& DB::connect($dsn, $options);
196
     * $db = DB::connect($dsn, $options);
197
     * if (PEAR::isError($db)) {
197
     * if (PEAR::isError($db)) {
198
     *     die($db->getMessage());
198
     *     die($db->getMessage());
199
     * }
199
     * }
200
     * </code>
200
     * </code>
201
     *
201
     *
Line 275... Line 275...
275
        $php_errormsg = '';
275
        $php_errormsg = '';
276
        if ($ini) {
276
        if ($ini) {
277
            $this->connection = @call_user_func_array($connect_function,
277
            $this->connection = @call_user_func_array($connect_function,
278
                                                      $params);
278
                                                      $params);
279
        } else {
279
        } else {
280
            ini_set('track_errors', 1);
280
            @ini_set('track_errors', 1);
281
            $this->connection = @call_user_func_array($connect_function,
281
            $this->connection = @call_user_func_array($connect_function,
282
                                                      $params);
282
                                                      $params);
283
            ini_set('track_errors', $ini);
283
            @ini_set('track_errors', $ini);
284
        }
284
        }
Line 285... Line 285...
285
 
285
 
286
        if (!$this->connection) {
286
        if (!$this->connection) {
287
            return $this->raiseError(DB_ERROR_CONNECT_FAILED,
287
            return $this->raiseError(DB_ERROR_CONNECT_FAILED,
Line 318... Line 318...
318
     *                + the DB_OK constant for other successful queries
318
     *                + the DB_OK constant for other successful queries
319
     *                + a DB_Error object on failure
319
     *                + a DB_Error object on failure
320
     */
320
     */
321
    function simpleQuery($query)
321
    function simpleQuery($query)
322
    {
322
    {
323
        $ismanip = DB::isManip($query);
323
        $ismanip = $this->_checkManip($query);
324
        $this->last_query = $query;
324
        $this->last_query = $query;
325
        $query = $this->modifyQuery($query);
325
        $query = $this->modifyQuery($query);
326
        if (!$this->autocommit && $ismanip) {
326
        if (!$this->autocommit && $ismanip) {
327
            if ($this->transaction_opcount == 0) {
327
            if ($this->transaction_opcount == 0) {
328
                $result = @pg_exec($this->connection, 'begin;');
328
                $result = @pg_exec($this->connection, 'begin;');
Line 334... Line 334...
334
        }
334
        }
335
        $result = @pg_exec($this->connection, $query);
335
        $result = @pg_exec($this->connection, $query);
336
        if (!$result) {
336
        if (!$result) {
337
            return $this->pgsqlRaiseError();
337
            return $this->pgsqlRaiseError();
338
        }
338
        }
-
 
339
 
-
 
340
        /*
339
        // Determine which queries that should return data, and which
341
         * Determine whether queries produce affected rows, result or nothing.
-
 
342
         *
-
 
343
         * This logic was introduced in version 1.1 of the file by ssb,
-
 
344
         * though the regex has been modified slightly since then.
-
 
345
         *
340
        // should return an error code only.
346
         * PostgreSQL commands:
-
 
347
         * ABORT, ALTER, BEGIN, CLOSE, CLUSTER, COMMIT, COPY,
-
 
348
         * CREATE, DECLARE, DELETE, DROP TABLE, EXPLAIN, FETCH,
-
 
349
         * GRANT, INSERT, LISTEN, LOAD, LOCK, MOVE, NOTIFY, RESET,
-
 
350
         * REVOKE, ROLLBACK, SELECT, SELECT INTO, SET, SHOW,
-
 
351
         * UNLISTEN, UPDATE, VACUUM, WITH
-
 
352
         */
341
        if ($ismanip) {
353
        if ($ismanip) {
342
            $this->affected = @pg_affected_rows($result);
354
            $this->affected = @pg_affected_rows($result);
343
            return DB_OK;
355
            return DB_OK;
344
        } elseif (preg_match('/^\s*\(*\s*(SELECT|EXPLAIN|SHOW)\s/si', $query)) {
356
        } elseif (preg_match('/^\s*\(*\s*(SELECT|EXPLAIN|FETCH|SHOW|WITH)\s/si',
345
            /* PostgreSQL commands:
-
 
346
               ABORT, ALTER, BEGIN, CLOSE, CLUSTER, COMMIT, COPY,
-
 
347
               CREATE, DECLARE, DELETE, DROP TABLE, EXPLAIN, FETCH,
-
 
348
               GRANT, INSERT, LISTEN, LOAD, LOCK, MOVE, NOTIFY, RESET,
-
 
349
               REVOKE, ROLLBACK, SELECT, SELECT INTO, SET, SHOW,
-
 
350
               UNLISTEN, UPDATE, VACUUM
357
                             $query))
351
            */
358
        {
352
            $this->row[(int)$result] = 0; // reset the row counter.
359
            $this->row[(int)$result] = 0; // reset the row counter.
353
            $numrows = $this->numRows($result);
360
            $numrows = $this->numRows($result);
354
            if (is_object($numrows)) {
361
            if (is_object($numrows)) {
355
                return $numrows;
362
                return $numrows;
356
            }
363
            }
Line 457... Line 464...
457
        }
464
        }
458
        return false;
465
        return false;
459
    }
466
    }
Line 460... Line 467...
460
 
467
 
461
    // }}}
-
 
462
    // {{{ quote()
-
 
463
 
-
 
464
    /**
-
 
465
     * @deprecated  Deprecated in release 1.6.0
-
 
466
     * @internal
-
 
467
     */
-
 
468
    function quote($str)
-
 
469
    {
-
 
470
        return $this->quoteSmart($str);
-
 
471
    }
-
 
472
 
-
 
473
    // }}}
468
    // }}}
Line 474... Line 469...
474
    // {{{ quoteSmart()
469
    // {{{ quoteBoolean()
475
 
470
 
476
    /**
471
    /**
477
     * Formats input so it can be safely used in a query
-
 
478
     *
-
 
479
     * @param mixed $in  the data to be formatted
-
 
480
     *
-
 
481
     * @return mixed  the formatted data.  The format depends on the input's
-
 
482
     *                 PHP type:
-
 
483
     *                 + null = the string <samp>NULL</samp>
-
 
484
     *                 + boolean = string <samp>TRUE</samp> or <samp>FALSE</samp>
-
 
485
     *                 + integer or double = the unquoted number
-
 
486
     *                 + other (including strings and numeric strings) =
-
 
487
     *                   the data escaped according to MySQL's settings
472
     * Formats a boolean value for use within a query in a locale-independent
-
 
473
     * manner.
-
 
474
     *
488
     *                   then encapsulated between single quotes
475
     * @param boolean the boolean value to be quoted.
489
     *
476
     * @return string the quoted string.
490
     * @see DB_common::quoteSmart()
477
     * @see DB_common::quoteSmart()
491
     * @since Method available since Release 1.6.0
478
     * @since Method available since release 1.7.8.
492
     */
-
 
493
    function quoteSmart($in)
-
 
494
    {
-
 
495
        if (is_int($in) || is_double($in)) {
-
 
496
            return $in;
479
     */
497
        } elseif (is_bool($in)) {
-
 
498
            return $in ? 'TRUE' : 'FALSE';
-
 
499
        } elseif (is_null($in)) {
-
 
500
            return 'NULL';
-
 
501
        } else {
-
 
502
            return "'" . $this->escapeSimple($in) . "'";
480
    function quoteBoolean($boolean) {
503
        }
481
        return $boolean ? 'TRUE' : 'FALSE';
504
    }
482
    }
505
 
483
     
Line 506... Line 484...
506
    // }}}
484
    // }}}
507
    // {{{ escapeSimple()
485
    // {{{ escapeSimple()
508
 
486
 
509
    /**
487
    /**
510
     * Escapes a string according to the current DBMS's standards
488
     * Escapes a string according to the current DBMS's standards
511
     *
489
     *
512
     * {@internal PostgreSQL treats a backslash as an escape character,
-
 
513
     * so they are escaped as well.
-
 
514
     *
-
 
515
     * Not using pg_escape_string() yet because it requires PostgreSQL
490
     * {@internal PostgreSQL treats a backslash as an escape character,
516
     * to be at version 7.2 or greater.}}
491
     * so they are escaped as well.
517
     *
492
     *
518
     * @param string $str  the string to be escaped
493
     * @param string $str  the string to be escaped
519
     *
494
     *
520
     * @return string  the escaped string
495
     * @return string  the escaped string
521
     *
496
     *
522
     * @see DB_common::quoteSmart()
497
     * @see DB_common::quoteSmart()
523
     * @since Method available since Release 1.6.0
498
     * @since Method available since Release 1.6.0
-
 
499
     */
-
 
500
    function escapeSimple($str)
-
 
501
    {
-
 
502
        if (function_exists('pg_escape_string')) {
-
 
503
            /* This fixes an undocumented BC break in PHP 5.2.0 which changed
-
 
504
             * the prototype of pg_escape_string. I'm not thrilled about having
-
 
505
             * to sniff the PHP version, quite frankly, but it's the only way
-
 
506
             * to deal with the problem. Revision 1.331.2.13.2.10 on
-
 
507
             * php-src/ext/pgsql/pgsql.c (PHP_5_2 branch) is to blame, for the
-
 
508
             * record. */
-
 
509
            if (version_compare(PHP_VERSION, '5.2.0', '>=')) {
-
 
510
                return pg_escape_string($this->connection, $str);
-
 
511
            } else {
524
     */
512
                return pg_escape_string($str);
-
 
513
            }
525
    function escapeSimple($str)
514
        } else {
Line 526... Line 515...
526
    {
515
            return str_replace("'", "''", str_replace('\\', '\\\\', $str));
527
        return str_replace("'", "''", str_replace('\\', '\\\\', $str));
516
        }
Line 673... Line 662...
673
    {
662
    {
674
        $seqname = $this->getSequenceName($seq_name);
663
        $seqname = $this->getSequenceName($seq_name);
675
        $repeat = false;
664
        $repeat = false;
676
        do {
665
        do {
677
            $this->pushErrorHandling(PEAR_ERROR_RETURN);
666
            $this->pushErrorHandling(PEAR_ERROR_RETURN);
678
            $result =& $this->query("SELECT NEXTVAL('${seqname}')");
667
            $result = $this->query("SELECT NEXTVAL('${seqname}')");
679
            $this->popErrorHandling();
668
            $this->popErrorHandling();
680
            if ($ondemand && DB::isError($result) &&
669
            if ($ondemand && DB::isError($result) &&
681
                $result->getCode() == DB_ERROR_NOSUCHTABLE) {
670
                $result->getCode() == DB_ERROR_NOSUCHTABLE) {
682
                $repeat = true;
671
                $repeat = true;
683
                $this->pushErrorHandling(PEAR_ERROR_RETURN);
672
                $this->pushErrorHandling(PEAR_ERROR_RETURN);
Line 777... Line 766...
777
     *      DB_pgsql::errorNative(), DB_pgsql::errorCode()
766
     *      DB_pgsql::errorNative(), DB_pgsql::errorCode()
778
     */
767
     */
779
    function pgsqlRaiseError($errno = null)
768
    function pgsqlRaiseError($errno = null)
780
    {
769
    {
781
        $native = $this->errorNative();
770
        $native = $this->errorNative();
-
 
771
        if (!$native) {
-
 
772
            $native = 'Database connection has been lost.';
-
 
773
            $errno = DB_ERROR_CONNECT_FAILED;
-
 
774
        }
782
        if ($errno === null) {
775
        if ($errno === null) {
783
            $errno = $this->errorCode($native);
776
            $errno = $this->errorCode($native);
784
        }
777
        }
785
        return $this->raiseError($errno, null, null, null, $native);
778
        return $this->raiseError($errno, null, null, null, $native);
786
    }
779
    }
Line 813... Line 806...
813
    function errorCode($errormsg)
806
    function errorCode($errormsg)
814
    {
807
    {
815
        static $error_regexps;
808
        static $error_regexps;
816
        if (!isset($error_regexps)) {
809
        if (!isset($error_regexps)) {
817
            $error_regexps = array(
810
            $error_regexps = array(
-
 
811
                '/column .* (of relation .*)?does not exist/i'
-
 
812
                    => DB_ERROR_NOSUCHFIELD,
818
                '/(relation|sequence|table).*does not exist|class .* not found/i'
813
                '/(relation|sequence|table).*does not exist|class .* not found/i'
819
                    => DB_ERROR_NOSUCHTABLE,
814
                    => DB_ERROR_NOSUCHTABLE,
820
                '/index .* does not exist/'
815
                '/index .* does not exist/'
821
                    => DB_ERROR_NOT_FOUND,
816
                    => DB_ERROR_NOT_FOUND,
822
                '/column .* does not exist/i'
-
 
823
                    => DB_ERROR_NOSUCHFIELD,
-
 
824
                '/relation .* already exists/i'
817
                '/relation .* already exists/i'
825
                    => DB_ERROR_ALREADY_EXISTS,
818
                    => DB_ERROR_ALREADY_EXISTS,
826
                '/(divide|division) by zero$/i'
819
                '/(divide|division) by zero$/i'
827
                    => DB_ERROR_DIVZERO,
820
                    => DB_ERROR_DIVZERO,
828
                '/pg_atoi: error in .*: can\'t parse /i'
821
                '/pg_atoi: error in .*: can\'t parse /i'
Line 974... Line 967...
974
     */
967
     */
975
    function _pgFieldFlags($resource, $num_field, $table_name)
968
    function _pgFieldFlags($resource, $num_field, $table_name)
976
    {
969
    {
977
        $field_name = @pg_fieldname($resource, $num_field);
970
        $field_name = @pg_fieldname($resource, $num_field);
Line -... Line 971...
-
 
971
 
-
 
972
        // Check if there's a schema in $table_name and update things
-
 
973
        // accordingly.
-
 
974
        $from = 'pg_attribute f, pg_class tab, pg_type typ';
-
 
975
        if (strpos($table_name, '.') !== false) {
-
 
976
            $from .= ', pg_namespace nsp';
-
 
977
            list($schema, $table) = explode('.', $table_name);
-
 
978
            $tableWhere = "tab.relname = '$table' AND tab.relnamespace = nsp.oid AND nsp.nspname = '$schema'";
-
 
979
        } else {
-
 
980
            $tableWhere = "tab.relname = '$table_name'";
-
 
981
        }
978
 
982
 
979
        $result = @pg_exec($this->connection, "SELECT f.attnotnull, f.atthasdef
983
        $result = @pg_exec($this->connection, "SELECT f.attnotnull, f.atthasdef
980
                                FROM pg_attribute f, pg_class tab, pg_type typ
984
                                FROM $from
981
                                WHERE tab.relname = typ.typname
985
                                WHERE tab.relname = typ.typname
982
                                AND typ.typrelid = f.attrelid
986
                                AND typ.typrelid = f.attrelid
983
                                AND f.attname = '$field_name'
987
                                AND f.attname = '$field_name'
984
                                AND tab.relname = '$table_name'");
988
                                AND $tableWhere");
985
        if (@pg_numrows($result) > 0) {
989
        if (@pg_numrows($result) > 0) {
986
            $row = @pg_fetch_row($result, 0);
990
            $row = @pg_fetch_row($result, 0);
Line 987... Line 991...
987
            $flags  = ($row[0] == 't') ? 'not_null ' : '';
991
            $flags  = ($row[0] == 't') ? 'not_null ' : '';
988
 
992
 
989
            if ($row[1] == 't') {
993
            if ($row[1] == 't') {
990
                $result = @pg_exec($this->connection, "SELECT a.adsrc
994
                $result = @pg_exec($this->connection, "SELECT a.adsrc
991
                                    FROM pg_attribute f, pg_class tab, pg_type typ, pg_attrdef a
995
                                    FROM $from, pg_attrdef a
992
                                    WHERE tab.relname = typ.typname AND typ.typrelid = f.attrelid
996
                                    WHERE tab.relname = typ.typname AND typ.typrelid = f.attrelid
993
                                    AND f.attrelid = a.adrelid AND f.attname = '$field_name'
997
                                    AND f.attrelid = a.adrelid AND f.attname = '$field_name'
994
                                    AND tab.relname = '$table_name' AND f.attnum = a.adnum");
998
                                    AND $tableWhere AND f.attnum = a.adnum");
995
                $row = @pg_fetch_row($result, 0);
999
                $row = @pg_fetch_row($result, 0);
996
                $num = preg_replace("/'(.*)'::\w+/", "\\1", $row[0]);
1000
                $num = preg_replace("/'(.*)'::\w+/", "\\1", $row[0]);
997
                $flags .= 'default_' . rawurlencode($num) . ' ';
1001
                $flags .= 'default_' . rawurlencode($num) . ' ';
998
            }
1002
            }
999
        } else {
1003
        } else {
1000
            $flags = '';
1004
            $flags = '';
1001
        }
1005
        }
1002
        $result = @pg_exec($this->connection, "SELECT i.indisunique, i.indisprimary, i.indkey
1006
        $result = @pg_exec($this->connection, "SELECT i.indisunique, i.indisprimary, i.indkey
1003
                                FROM pg_attribute f, pg_class tab, pg_type typ, pg_index i
1007
                                FROM $from, pg_index i
1004
                                WHERE tab.relname = typ.typname
1008
                                WHERE tab.relname = typ.typname
1005
                                AND typ.typrelid = f.attrelid
1009
                                AND typ.typrelid = f.attrelid
1006
                                AND f.attrelid = i.indrelid
1010
                                AND f.attrelid = i.indrelid
1007
                                AND f.attname = '$field_name'
1011
                                AND f.attname = '$field_name'
Line 1008... Line 1012...
1008
                                AND tab.relname = '$table_name'");
1012
                                AND $tableWhere");
1009
        $count = @pg_numrows($result);
1013
        $count = @pg_numrows($result);
1010
 
1014
 
Line 1064... Line 1068...
1064
                return "SELECT schemaname || '.' || tablename"
1068
                return "SELECT schemaname || '.' || tablename"
1065
                        . ' AS "Name"'
1069
                        . ' AS "Name"'
1066
                        . ' FROM pg_catalog.pg_tables'
1070
                        . ' FROM pg_catalog.pg_tables'
1067
                        . ' WHERE schemaname NOT IN'
1071
                        . ' WHERE schemaname NOT IN'
1068
                        . " ('pg_catalog', 'information_schema', 'pg_toast')";
1072
                        . " ('pg_catalog', 'information_schema', 'pg_toast')";
-
 
1073
            case 'schema.views':
-
 
1074
                return "SELECT schemaname || '.' || viewname from pg_views WHERE schemaname"
-
 
1075
                        . " NOT IN ('information_schema', 'pg_catalog')";
1069
            case 'views':
1076
            case 'views':
1070
                // Table cols: viewname | viewowner | definition
1077
                // Table cols: viewname | viewowner | definition
1071
                return 'SELECT viewname from pg_views WHERE schemaname'
1078
                return 'SELECT viewname from pg_views WHERE schemaname'
1072
                        . " NOT IN ('information_schema', 'pg_catalog')";
1079
                        . " NOT IN ('information_schema', 'pg_catalog')";
1073
            case 'users':
1080
            case 'users':
Line 1082... Line 1089...
1082
                return null;
1089
                return null;
1083
        }
1090
        }
1084
    }
1091
    }
Line 1085... Line 1092...
1085
 
1092
 
-
 
1093
    // }}}
-
 
1094
    // {{{ _checkManip()
-
 
1095
 
-
 
1096
    /**
-
 
1097
     * Checks if the given query is a manipulation query. This also takes into
-
 
1098
     * account the _next_query_manip flag and sets the _last_query_manip flag
-
 
1099
     * (and resets _next_query_manip) according to the result.
-
 
1100
     *
-
 
1101
     * @param string The query to check.
-
 
1102
     *
-
 
1103
     * @return boolean true if the query is a manipulation query, false
-
 
1104
     * otherwise
-
 
1105
     *
-
 
1106
     * @access protected
-
 
1107
     */
-
 
1108
    function _checkManip($query)
-
 
1109
    {
-
 
1110
        return (preg_match('/^\s*(SAVEPOINT|RELEASE)\s+/i', $query)
-
 
1111
                || parent::_checkManip($query));
Line 1086... Line 1112...
1086
    // }}}
1112
    }
Line 1087... Line 1113...
1087
 
1113
 
1088
}
1114
}