source: branches/version-2_5-dev/data/module/MDB2/Driver/Datatype/pgsql.php @ 20116

Revision 20116, 18.6 KB checked in by nanasess, 13 years ago (diff)
  • svn properties を再設定
  • 再設定用のスクリプト追加
  • 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// | PHP versions 4 and 5                                                 |
4// +----------------------------------------------------------------------+
5// | Copyright (c) 1998-2007 Manuel Lemos, Tomas V.V.Cox,                 |
6// | Stig. S. Bakken, Lukas Smith                                         |
7// | All rights reserved.                                                 |
8// +----------------------------------------------------------------------+
9// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB  |
10// | API as well as database abstraction for PHP applications.            |
11// | This LICENSE is in the BSD license style.                            |
12// |                                                                      |
13// | Redistribution and use in source and binary forms, with or without   |
14// | modification, are permitted provided that the following conditions   |
15// | are met:                                                             |
16// |                                                                      |
17// | Redistributions of source code must retain the above copyright       |
18// | notice, this list of conditions and the following disclaimer.        |
19// |                                                                      |
20// | Redistributions in binary form must reproduce the above copyright    |
21// | notice, this list of conditions and the following disclaimer in the  |
22// | documentation and/or other materials provided with the distribution. |
23// |                                                                      |
24// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken,    |
25// | Lukas Smith nor the names of his contributors may be used to endorse |
26// | or promote products derived from this software without specific prior|
27// | written permission.                                                  |
28// |                                                                      |
29// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS  |
30// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT    |
31// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS    |
32// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE      |
33// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,          |
34// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
35// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
36// |  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED  |
37// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT          |
38// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
39// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE          |
40// | POSSIBILITY OF SUCH DAMAGE.                                          |
41// +----------------------------------------------------------------------+
42// | Author: Paul Cooper <pgc@ucecom.com>                                 |
43// +----------------------------------------------------------------------+
44//
45// $Id$
46
47require_once 'MDB2/Driver/Datatype/Common.php';
48
49/**
50 * MDB2 PostGreSQL driver
51 *
52 * @package MDB2
53 * @category Database
54 * @author  Paul Cooper <pgc@ucecom.com>
55 */
56class MDB2_Driver_Datatype_pgsql extends MDB2_Driver_Datatype_Common
57{
58    // {{{ _baseConvertResult()
59
60    /**
61     * General type conversion method
62     *
63     * @param mixed   $value refernce to a value to be converted
64     * @param string  $type  specifies which type to convert to
65     * @param boolean $rtrim [optional] when TRUE [default], apply rtrim() to text
66     * @return object a MDB2 error on failure
67     * @access protected
68     */
69    function _baseConvertResult($value, $type, $rtrim = true)
70    {
71        if (is_null($value)) {
72            return null;
73        }
74        switch ($type) {
75        case 'boolean':
76            return $value == 't';
77        case 'float':
78            return doubleval($value);
79        case 'date':
80            return $value;
81        case 'time':
82            return substr($value, 0, strlen('HH:MM:SS'));
83        case 'timestamp':
84            return substr($value, 0, strlen('YYYY-MM-DD HH:MM:SS'));
85        case 'blob':
86            $value = pg_unescape_bytea($value);
87            return parent::_baseConvertResult($value, $type, $rtrim);
88        }
89        return parent::_baseConvertResult($value, $type, $rtrim);
90    }
91
92    // }}}
93    // {{{ getTypeDeclaration()
94
95    /**
96     * Obtain DBMS specific SQL code portion needed to declare an text type
97     * field to be used in statements like CREATE TABLE.
98     *
99     * @param array $field  associative array with the name of the properties
100     *      of the field being declared as array indexes. Currently, the types
101     *      of supported field properties are as follows:
102     *
103     *      length
104     *          Integer value that determines the maximum length of the text
105     *          field. If this argument is missing the field should be
106     *          declared to have the longest length allowed by the DBMS.
107     *
108     *      default
109     *          Text value to be used as default for this field.
110     *
111     *      notnull
112     *          Boolean flag that indicates whether this field is constrained
113     *          to not be set to null.
114     * @return string  DBMS specific SQL code portion that should be used to
115     *      declare the specified field.
116     * @access public
117     */
118    function getTypeDeclaration($field)
119    {
120        $db =& $this->getDBInstance();
121        if (PEAR::isError($db)) {
122            return $db;
123        }
124
125        switch ($field['type']) {
126        case 'text':
127            $length = !empty($field['length']) ? $field['length'] : false;
128            $fixed = !empty($field['fixed']) ? $field['fixed'] : false;
129            return $fixed ? ($length ? 'CHAR('.$length.')' : 'CHAR('.$db->options['default_text_field_length'].')')
130                : ($length ? 'VARCHAR('.$length.')' : 'TEXT');
131        case 'clob':
132            return 'TEXT';
133        case 'blob':
134            return 'BYTEA';
135        case 'integer':
136            if (!empty($field['autoincrement'])) {
137                if (!empty($field['length'])) {
138                    $length = $field['length'];
139                    if ($length > 4) {
140                        return 'BIGSERIAL PRIMARY KEY';
141                    }
142                }
143                return 'SERIAL PRIMARY KEY';
144            }
145            if (!empty($field['length'])) {
146                $length = $field['length'];
147                if ($length <= 2) {
148                    return 'SMALLINT';
149                } elseif ($length == 3 || $length == 4) {
150                    return 'INT';
151                } elseif ($length > 4) {
152                    return 'BIGINT';
153                }
154            }
155            return 'INT';
156        case 'boolean':
157            return 'BOOLEAN';
158        case 'date':
159            return 'DATE';
160        case 'time':
161            return 'TIME without time zone';
162        case 'timestamp':
163            return 'TIMESTAMP without time zone';
164        case 'float':
165            return 'FLOAT8';
166        case 'decimal':
167            $length = !empty($field['length']) ? $field['length'] : 18;
168            $scale = !empty($field['scale']) ? $field['scale'] : $db->options['decimal_places'];
169            return 'NUMERIC('.$length.','.$scale.')';
170        }
171    }
172
173    // }}}
174    // {{{ _getIntegerDeclaration()
175
176    /**
177     * Obtain DBMS specific SQL code portion needed to declare an integer type
178     * field to be used in statements like CREATE TABLE.
179     *
180     * @param string $name name the field to be declared.
181     * @param array $field associative array with the name of the properties
182     *       of the field being declared as array indexes. Currently, the types
183     *       of supported field properties are as follows:
184     *
185     *       unsigned
186     *           Boolean flag that indicates whether the field should be
187     *           declared as unsigned integer if possible.
188     *
189     *       default
190     *           Integer value to be used as default for this field.
191     *
192     *       notnull
193     *           Boolean flag that indicates whether this field is constrained
194     *           to not be set to null.
195     * @return string DBMS specific SQL code portion that should be used to
196     *       declare the specified field.
197     * @access protected
198     */
199    function _getIntegerDeclaration($name, $field)
200    {
201        $db =& $this->getDBInstance();
202        if (PEAR::isError($db)) {
203            return $db;
204        }
205
206        if (!empty($field['unsigned'])) {
207            $db->warnings[] = "unsigned integer field \"$name\" is being declared as signed integer";
208        }
209        if (!empty($field['autoincrement'])) {
210            $name = $db->quoteIdentifier($name, true);
211            return $name.' '.$this->getTypeDeclaration($field);
212        }
213        $default = '';
214        if (array_key_exists('default', $field)) {
215            if ($field['default'] === '') {
216                $field['default'] = empty($field['notnull']) ? null : 0;
217            }
218            $default = ' DEFAULT '.$this->quote($field['default'], 'integer');
219        }
220
221        $notnull = empty($field['notnull']) ? '' : ' NOT NULL';
222        $name = $db->quoteIdentifier($name, true);
223        return $name.' '.$this->getTypeDeclaration($field).$default.$notnull;
224    }
225
226    // }}}
227    // {{{ _quoteCLOB()
228
229    /**
230     * Convert a text value into a DBMS specific format that is suitable to
231     * compose query statements.
232     *
233     * @param string $value text string value that is intended to be converted.
234     * @param bool $quote determines if the value should be quoted and escaped
235     * @param bool $escape_wildcards if to escape escape wildcards
236     * @return string text string that represents the given argument value in
237     *      a DBMS specific format.
238     * @access protected
239     */
240    function _quoteCLOB($value, $quote, $escape_wildcards)
241    {
242        return $this->_quoteText($value, $quote, $escape_wildcards);
243    }
244
245    // }}}
246    // {{{ _quoteBLOB()
247
248    /**
249     * Convert a text value into a DBMS specific format that is suitable to
250     * compose query statements.
251     *
252     * @param string $value text string value that is intended to be converted.
253     * @param bool $quote determines if the value should be quoted and escaped
254     * @param bool $escape_wildcards if to escape escape wildcards
255     * @return string text string that represents the given argument value in
256     *      a DBMS specific format.
257     * @access protected
258     */
259    function _quoteBLOB($value, $quote, $escape_wildcards)
260    {
261        if (!$quote) {
262            return $value;
263        }
264        if (version_compare(PHP_VERSION, '5.2.0RC6', '>=')) {
265            $db =& $this->getDBInstance();
266            if (PEAR::isError($db)) {
267                return $db;
268            }
269            $connection = $db->getConnection();
270            if (PEAR::isError($connection)) {
271                return $connection;
272            }
273            $value = @pg_escape_bytea($connection, $value);
274        } else {
275            $value = @pg_escape_bytea($value);
276        }
277        return "'".$value."'";
278    }
279
280    // }}}
281    // {{{ _quoteBoolean()
282
283    /**
284     * Convert a text value into a DBMS specific format that is suitable to
285     * compose query statements.
286     *
287     * @param string $value text string value that is intended to be converted.
288     * @param bool $quote determines if the value should be quoted and escaped
289     * @param bool $escape_wildcards if to escape escape wildcards
290     * @return string text string that represents the given argument value in
291     *       a DBMS specific format.
292     * @access protected
293     */
294    function _quoteBoolean($value, $quote, $escape_wildcards)
295    {
296        $value = $value ? 't' : 'f';
297        if (!$quote) {
298            return $value;
299        }
300        return "'".$value."'";
301    }
302
303    // }}}
304    // {{{ matchPattern()
305
306    /**
307     * build a pattern matching string
308     *
309     * @access public
310     *
311     * @param array $pattern even keys are strings, odd are patterns (% and _)
312     * @param string $operator optional pattern operator (LIKE, ILIKE and maybe others in the future)
313     * @param string $field optional field name that is being matched against
314     *                  (might be required when emulating ILIKE)
315     *
316     * @return string SQL pattern
317     */
318    function matchPattern($pattern, $operator = null, $field = null)
319    {
320        $db =& $this->getDBInstance();
321        if (PEAR::isError($db)) {
322            return $db;
323        }
324
325        $match = '';
326        if (!is_null($operator)) {
327            $field = is_null($field) ? '' : $field.' ';
328            $operator = strtoupper($operator);
329            switch ($operator) {
330            // case insensitive
331            case 'ILIKE':
332                $match = $field.'ILIKE ';
333                break;
334            // case sensitive
335            case 'LIKE':
336                $match = $field.'LIKE ';
337                break;
338            default:
339                return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
340                    'not a supported operator type:'. $operator, __FUNCTION__);
341            }
342        }
343        $match.= "'";
344        foreach ($pattern as $key => $value) {
345            if ($key % 2) {
346                $match.= $value;
347            } else {
348                $match.= $db->escapePattern($db->escape($value));
349            }
350        }
351        $match.= "'";
352        $match.= $this->patternEscapeString();
353        return $match;
354    }
355
356    // }}}
357    // {{{ patternEscapeString()
358
359    /**
360     * build string to define escape pattern string
361     *
362     * @access public
363     *
364     *
365     * @return string define escape pattern
366     */
367    function patternEscapeString()
368    {
369        $db =& $this->getDBInstance();
370        if (PEAR::isError($db)) {
371            return $db;
372        }
373        return ' ESCAPE '.$this->quote($db->string_quoting['escape_pattern']);
374    }
375
376    // }}}
377    // {{{ _mapNativeDatatype()
378
379    /**
380     * Maps a native array description of a field to a MDB2 datatype and length
381     *
382     * @param array  $field native field description
383     * @return array containing the various possible types, length, sign, fixed
384     * @access public
385     */
386    function _mapNativeDatatype($field)
387    {
388        $db_type = strtolower($field['type']);
389        $length = $field['length'];
390        $type = array();
391        $unsigned = $fixed = null;
392        switch ($db_type) {
393        case 'smallint':
394        case 'int2':
395            $type[] = 'integer';
396            $unsigned = false;
397            $length = 2;
398            if ($length == '2') {
399                $type[] = 'boolean';
400                if (preg_match('/^(is|has)/', $field['name'])) {
401                    $type = array_reverse($type);
402                }
403            }
404            break;
405        case 'int':
406        case 'int4':
407        case 'integer':
408        case 'serial':
409        case 'serial4':
410            $type[] = 'integer';
411            $unsigned = false;
412            $length = 4;
413            break;
414        case 'bigint':
415        case 'int8':
416        case 'bigserial':
417        case 'serial8':
418            $type[] = 'integer';
419            $unsigned = false;
420            $length = 8;
421            break;
422        case 'bool':
423        case 'boolean':
424            $type[] = 'boolean';
425            $length = null;
426            break;
427        case 'text':
428        case 'varchar':
429            $fixed = false;
430        case 'unknown':
431        case 'char':
432        case 'bpchar':
433            $type[] = 'text';
434            if ($length == '1') {
435                $type[] = 'boolean';
436                if (preg_match('/^(is|has)/', $field['name'])) {
437                    $type = array_reverse($type);
438                }
439            } elseif (strstr($db_type, 'text')) {
440                $type[] = 'clob';
441                $type = array_reverse($type);
442            }
443            if ($fixed !== false) {
444                $fixed = true;
445            }
446            break;
447        case 'date':
448            $type[] = 'date';
449            $length = null;
450            break;
451        case 'datetime':
452        case 'timestamp':
453        case 'timestamptz':
454            $type[] = 'timestamp';
455            $length = null;
456            break;
457        case 'time':
458            $type[] = 'time';
459            $length = null;
460            break;
461        case 'float':
462        case 'float4':
463        case 'float8':
464        case 'double':
465        case 'real':
466            $type[] = 'float';
467            break;
468        case 'decimal':
469        case 'money':
470        case 'numeric':
471            $type[] = 'decimal';
472            if (isset($field['scale'])) {
473                $length = $length.','.$field['scale'];
474            }
475            break;
476        case 'tinyblob':
477        case 'mediumblob':
478        case 'longblob':
479        case 'blob':
480        case 'bytea':
481            $type[] = 'blob';
482            $length = null;
483            break;
484        case 'oid':
485            $type[] = 'blob';
486            $type[] = 'clob';
487            $length = null;
488            break;
489        case 'year':
490            $type[] = 'integer';
491            $type[] = 'date';
492            $length = null;
493            break;
494        default:
495            $db =& $this->getDBInstance();
496            if (PEAR::isError($db)) {
497                return $db;
498            }
499            return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
500                'unknown database attribute type: '.$db_type, __FUNCTION__);
501        }
502
503        if ((int)$length <= 0) {
504            $length = null;
505        }
506
507        return array($type, $length, $unsigned, $fixed);
508    }
509
510    // }}}
511    // {{{ mapPrepareDatatype()
512
513    /**
514     * Maps an mdb2 datatype to native prepare type
515     *
516     * @param string $type
517     * @return string
518     * @access public
519     */
520    function mapPrepareDatatype($type)
521    {
522        $db =& $this->getDBInstance();
523        if (PEAR::isError($db)) {
524            return $db;
525        }
526
527        if (!empty($db->options['datatype_map'][$type])) {
528            $type = $db->options['datatype_map'][$type];
529            if (!empty($db->options['datatype_map_callback'][$type])) {
530                $parameter = array('type' => $type);
531                return call_user_func_array($db->options['datatype_map_callback'][$type], array(&$db, __FUNCTION__, $parameter));
532            }
533        }
534
535        switch ($type) {
536            case 'integer':
537                return 'int';
538            case 'boolean':
539                return 'bool';
540            case 'decimal':
541            case 'float':
542                return 'numeric';
543            case 'clob':
544                return 'text';
545            case 'blob':
546                return 'bytea';
547            default:
548                break;
549        }
550        return $type;
551    }
552    // }}}
553}
554?>
Note: See TracBrowser for help on using the repository browser.