source: branches/version-2_13-dev/data/module/MDB2/Driver/Datatype/mysql.php @ 23022

Revision 23022, 21.9 KB checked in by Seasoft, 11 years ago (diff)

#2322 (セッションのGC処理がエラーとなる)

  • Property svn:eol-style set to LF
  • Property svn:mime-type set to text/x-httpd-php; charset=UTF-8
Line 
1<?php
2// vim: set et ts=4 sw=4 fdm=marker:
3// +----------------------------------------------------------------------+
4// | PHP versions 4 and 5                                                 |
5// +----------------------------------------------------------------------+
6// | Copyright (c) 1998-2008 Manuel Lemos, Tomas V.V.Cox,                 |
7// | Stig. S. Bakken, Lukas Smith                                         |
8// | All rights reserved.                                                 |
9// +----------------------------------------------------------------------+
10// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB  |
11// | API as well as database abstraction for PHP applications.            |
12// | This LICENSE is in the BSD license style.                            |
13// |                                                                      |
14// | Redistribution and use in source and binary forms, with or without   |
15// | modification, are permitted provided that the following conditions   |
16// | are met:                                                             |
17// |                                                                      |
18// | Redistributions of source code must retain the above copyright       |
19// | notice, this list of conditions and the following disclaimer.        |
20// |                                                                      |
21// | Redistributions in binary form must reproduce the above copyright    |
22// | notice, this list of conditions and the following disclaimer in the  |
23// | documentation and/or other materials provided with the distribution. |
24// |                                                                      |
25// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken,    |
26// | Lukas Smith nor the names of his contributors may be used to endorse |
27// | or promote products derived from this software without specific prior|
28// | written permission.                                                  |
29// |                                                                      |
30// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS  |
31// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT    |
32// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS    |
33// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE      |
34// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,          |
35// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
36// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
37// |  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED  |
38// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT          |
39// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
40// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE          |
41// | POSSIBILITY OF SUCH DAMAGE.                                          |
42// +----------------------------------------------------------------------+
43// | Author: Lukas Smith <smith@pooteeweet.org>                           |
44// +----------------------------------------------------------------------+
45//
46// $Id: mysql.php 327310 2012-08-27 15:16:18Z danielc $
47//
48
49require_once 'MDB2/Driver/Datatype/Common.php';
50
51/**
52 * MDB2 MySQL driver
53 *
54 * @package MDB2
55 * @category Database
56 * @author  Lukas Smith <smith@pooteeweet.org>
57 */
58class MDB2_Driver_Datatype_mysql extends MDB2_Driver_Datatype_Common
59{
60    // {{{ _getCharsetFieldDeclaration()
61
62    /**
63     * Obtain DBMS specific SQL code portion needed to set the CHARACTER SET
64     * of a field declaration to be used in statements like CREATE TABLE.
65     *
66     * @param string $charset   name of the charset
67     * @return string  DBMS specific SQL code portion needed to set the CHARACTER SET
68     *                 of a field declaration.
69     */
70    function _getCharsetFieldDeclaration($charset)
71    {
72        return 'CHARACTER SET '.$charset;
73    }
74
75    // }}}
76    // {{{ _getCollationFieldDeclaration()
77
78    /**
79     * Obtain DBMS specific SQL code portion needed to set the COLLATION
80     * of a field declaration to be used in statements like CREATE TABLE.
81     *
82     * @param string $collation   name of the collation
83     * @return string  DBMS specific SQL code portion needed to set the COLLATION
84     *                 of a field declaration.
85     */
86    function _getCollationFieldDeclaration($collation)
87    {
88        return 'COLLATE '.$collation;
89    }
90
91    // }}}
92    // {{{ getDeclaration()
93
94    /**
95     * Obtain DBMS specific SQL code portion needed to declare
96     * of the given type
97     *
98     * @param string $type  type to which the value should be converted to
99     * @param string $name  name the field to be declared.
100     * @param string $field definition of the field
101     *
102     * @return string DBMS-specific SQL code portion that should be used to
103     *                declare the specified field.
104     * @access public
105     */
106    function getDeclaration($type, $name, $field)
107    {
108        // MySQL DDL syntax forbids combining NOT NULL with DEFAULT NULL.
109        // To get a default of NULL for NOT NULL columns, omit it.
110        if (   isset($field['notnull'])
111            && !empty($field['notnull'])
112            && array_key_exists('default', $field) // do not use isset() here!
113            && null === $field['default']
114        ) {
115            unset($field['default']);
116        }
117        return parent::getDeclaration($type, $name, $field);
118    }
119
120    // }}}
121    // {{{ getTypeDeclaration()
122
123    /**
124     * Obtain DBMS specific SQL code portion needed to declare an text type
125     * field to be used in statements like CREATE TABLE.
126     *
127     * @param array $field  associative array with the name of the properties
128     *      of the field being declared as array indexes. Currently, the types
129     *      of supported field properties are as follows:
130     *
131     *      length
132     *          Integer value that determines the maximum length of the text
133     *          field. If this argument is missing the field should be
134     *          declared to have the longest length allowed by the DBMS.
135     *
136     *      default
137     *          Text value to be used as default for this field.
138     *
139     *      notnull
140     *          Boolean flag that indicates whether this field is constrained
141     *          to not be set to null.
142     * @return string  DBMS specific SQL code portion that should be used to
143     *      declare the specified field.
144     * @access public
145     */
146    function getTypeDeclaration($field)
147    {
148        $db = $this->getDBInstance();
149        if (MDB2::isError($db)) {
150            return $db;
151        }
152
153        switch ($field['type']) {
154        case 'text':
155            if (empty($field['length']) && array_key_exists('default', $field)) {
156                $field['length'] = $db->varchar_max_length;
157            }
158            $length = !empty($field['length']) ? $field['length'] : false;
159            $fixed = !empty($field['fixed']) ? $field['fixed'] : false;
160            return $fixed ? ($length ? 'CHAR('.$length.')' : 'CHAR(255)')
161                : ($length ? 'VARCHAR('.$length.')' : 'TEXT');
162        case 'clob':
163            if (!empty($field['length'])) {
164                $length = $field['length'];
165                if ($length <= 255) {
166                    return 'TINYTEXT';
167                } elseif ($length <= 65532) {
168                    return 'TEXT';
169                } elseif ($length <= 16777215) {
170                    return 'MEDIUMTEXT';
171                }
172            }
173            return 'LONGTEXT';
174        case 'blob':
175            if (!empty($field['length'])) {
176                $length = $field['length'];
177                if ($length <= 255) {
178                    return 'TINYBLOB';
179                } elseif ($length <= 65532) {
180                    return 'BLOB';
181                } elseif ($length <= 16777215) {
182                    return 'MEDIUMBLOB';
183                }
184            }
185            return 'LONGBLOB';
186        case 'integer':
187            if (!empty($field['length'])) {
188                $length = $field['length'];
189                if ($length <= 1) {
190                    return 'TINYINT';
191                } elseif ($length == 2) {
192                    return 'SMALLINT';
193                } elseif ($length == 3) {
194                    return 'MEDIUMINT';
195                } elseif ($length == 4) {
196                    return 'INT';
197                } elseif ($length > 4) {
198                    return 'BIGINT';
199                }
200            }
201            return 'INT';
202        case 'boolean':
203            return 'TINYINT(1)';
204        case 'date':
205            return 'DATE';
206        case 'time':
207            return 'TIME';
208        case 'timestamp':
209            return 'DATETIME';
210        case 'float':
211            $l = '';
212            if (!empty($field['length'])) {
213                $l = '(' . $field['length'];
214                if (!empty($field['scale'])) {
215                    $l .= ',' . $field['scale'];
216                }
217                $l .= ')';
218            }
219            return 'DOUBLE' . $l;
220        case 'decimal':
221            $length = !empty($field['length']) ? $field['length'] : 18;
222            $scale = !empty($field['scale']) ? $field['scale'] : $db->options['decimal_places'];
223            return 'DECIMAL('.$length.','.$scale.')';
224        }
225        return '';
226    }
227
228    // }}}
229    // {{{ _getIntegerDeclaration()
230
231    /**
232     * Obtain DBMS specific SQL code portion needed to declare an integer type
233     * field to be used in statements like CREATE TABLE.
234     *
235     * @param string  $name   name the field to be declared.
236     * @param string  $field  associative array with the name of the properties
237     *                        of the field being declared as array indexes.
238     *                        Currently, the types of supported field
239     *                        properties are as follows:
240     *
241     *                       unsigned
242     *                        Boolean flag that indicates whether the field
243     *                        should be declared as unsigned integer if
244     *                        possible.
245     *
246     *                       default
247     *                        Integer value to be used as default for this
248     *                        field.
249     *
250     *                       notnull
251     *                        Boolean flag that indicates whether this field is
252     *                        constrained to not be set to null.
253     * @return string  DBMS specific SQL code portion that should be used to
254     *                 declare the specified field.
255     * @access protected
256     */
257    function _getIntegerDeclaration($name, $field)
258    {
259        $db = $this->getDBInstance();
260        if (MDB2::isError($db)) {
261            return $db;
262        }
263
264        $default = $autoinc = '';
265        if (!empty($field['autoincrement'])) {
266            $autoinc = ' AUTO_INCREMENT PRIMARY KEY';
267        } elseif (array_key_exists('default', $field)) {
268            if ($field['default'] === '') {
269                $field['default'] = empty($field['notnull']) ? null : 0;
270            }
271            $default = ' DEFAULT '.$this->quote($field['default'], 'integer');
272        }
273
274        $notnull = empty($field['notnull']) ? '' : ' NOT NULL';
275        $unsigned = empty($field['unsigned']) ? '' : ' UNSIGNED';
276        if (empty($default) && empty($notnull)) {
277            $default = ' DEFAULT NULL';
278        }
279        $name = $db->quoteIdentifier($name, true);
280        return $name.' '.$this->getTypeDeclaration($field).$unsigned.$default.$notnull.$autoinc;
281    }
282
283    // }}}
284    // {{{ _getFloatDeclaration()
285
286    /**
287     * Obtain DBMS specific SQL code portion needed to declare an float type
288     * field to be used in statements like CREATE TABLE.
289     *
290     * @param string  $name   name the field to be declared.
291     * @param string  $field  associative array with the name of the properties
292     *                        of the field being declared as array indexes.
293     *                        Currently, the types of supported field
294     *                        properties are as follows:
295     *
296     *                       unsigned
297     *                        Boolean flag that indicates whether the field
298     *                        should be declared as unsigned float if
299     *                        possible.
300     *
301     *                       default
302     *                        float value to be used as default for this
303     *                        field.
304     *
305     *                       notnull
306     *                        Boolean flag that indicates whether this field is
307     *                        constrained to not be set to null.
308     * @return string  DBMS specific SQL code portion that should be used to
309     *                 declare the specified field.
310     * @access protected
311     */
312    function _getFloatDeclaration($name, $field)
313    {
314        // Since AUTO_INCREMENT can be used for integer or floating-point types,
315        // reuse the INTEGER declaration
316        // @see http://bugs.mysql.com/bug.php?id=31032
317        return $this->_getIntegerDeclaration($name, $field);
318    }
319
320    // }}}
321    // {{{ _getDecimalDeclaration()
322
323    /**
324     * Obtain DBMS specific SQL code portion needed to declare an decimal type
325     * field to be used in statements like CREATE TABLE.
326     *
327     * @param string  $name   name the field to be declared.
328     * @param string  $field  associative array with the name of the properties
329     *                        of the field being declared as array indexes.
330     *                        Currently, the types of supported field
331     *                        properties are as follows:
332     *
333     *                       unsigned
334     *                        Boolean flag that indicates whether the field
335     *                        should be declared as unsigned integer if
336     *                        possible.
337     *
338     *                       default
339     *                        Decimal value to be used as default for this
340     *                        field.
341     *
342     *                       notnull
343     *                        Boolean flag that indicates whether this field is
344     *                        constrained to not be set to null.
345     * @return string  DBMS specific SQL code portion that should be used to
346     *                 declare the specified field.
347     * @access protected
348     */
349    function _getDecimalDeclaration($name, $field)
350    {
351        $db = $this->getDBInstance();
352        if (MDB2::isError($db)) {
353            return $db;
354        }
355
356        $default = '';
357        if (array_key_exists('default', $field)) {
358            if ($field['default'] === '') {
359                $field['default'] = empty($field['notnull']) ? null : 0;
360            }
361            $default = ' DEFAULT '.$this->quote($field['default'], 'integer');
362        } elseif (empty($field['notnull'])) {
363            $default = ' DEFAULT NULL';
364        }
365
366        $notnull = empty($field['notnull']) ? '' : ' NOT NULL';
367        $unsigned = empty($field['unsigned']) ? '' : ' UNSIGNED';
368        $name = $db->quoteIdentifier($name, true);
369        return $name.' '.$this->getTypeDeclaration($field).$unsigned.$default.$notnull;
370    }
371
372    // }}}
373    // {{{ matchPattern()
374
375    /**
376     * build a pattern matching string
377     *
378     * @access public
379     *
380     * @param array $pattern even keys are strings, odd are patterns (% and _)
381     * @param string $operator optional pattern operator (LIKE, ILIKE and maybe others in the future)
382     * @param string $field optional field name that is being matched against
383     *                  (might be required when emulating ILIKE)
384     *
385     * @return string SQL pattern
386     */
387    function matchPattern($pattern, $operator = null, $field = null)
388    {
389        $db = $this->getDBInstance();
390        if (MDB2::isError($db)) {
391            return $db;
392        }
393
394        $match = '';
395        if (null !== $operator) {
396            $field = (null === $field) ? '' : $field.' ';
397            $operator = strtoupper($operator);
398            switch ($operator) {
399            // case insensitive
400            case 'ILIKE':
401                $match = $field.'LIKE ';
402                break;
403            case 'NOT ILIKE':
404                $match = $field.'NOT LIKE ';
405                break;
406            // case sensitive
407            case 'LIKE':
408                $match = $field.'LIKE BINARY ';
409                break;
410            case 'NOT LIKE':
411                $match = $field.'NOT LIKE BINARY ';
412                break;
413            default:
414                return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
415                    'not a supported operator type:'. $operator, __FUNCTION__);
416            }
417        }
418        $match.= "'";
419        foreach ($pattern as $key => $value) {
420            if ($key % 2) {
421                $match.= $value;
422            } else {
423                $match.= $db->escapePattern($db->escape($value));
424            }
425        }
426        $match.= "'";
427        $match.= $this->patternEscapeString();
428        return $match;
429    }
430
431    // }}}
432    // {{{ _mapNativeDatatype()
433
434    /**
435     * Maps a native array description of a field to a MDB2 datatype and length
436     *
437     * @param array  $field native field description
438     * @return array containing the various possible types, length, sign, fixed
439     * @access public
440     */
441    function _mapNativeDatatype($field)
442    {
443        $db_type = strtolower($field['type']);
444        $db_type = strtok($db_type, '(), ');
445        if ($db_type == 'national') {
446            $db_type = strtok('(), ');
447        }
448        if (!empty($field['length'])) {
449            $length = strtok($field['length'], ', ');
450            $decimal = strtok(', ');
451        } else {
452            $length = strtok('(), ');
453            $decimal = strtok('(), ');
454        }
455        $type = array();
456        $unsigned = $fixed = null;
457        switch ($db_type) {
458        case 'tinyint':
459            $type[] = 'integer';
460            $type[] = 'boolean';
461            if (preg_match('/^(is|has)/', $field['name'])) {
462                $type = array_reverse($type);
463            }
464            $unsigned = preg_match('/ unsigned/i', $field['type']);
465            $length = 1;
466            break;
467        case 'smallint':
468            $type[] = 'integer';
469            $unsigned = preg_match('/ unsigned/i', $field['type']);
470            $length = 2;
471            break;
472        case 'mediumint':
473            $type[] = 'integer';
474            $unsigned = preg_match('/ unsigned/i', $field['type']);
475            $length = 3;
476            break;
477        case 'int':
478        case 'integer':
479            $type[] = 'integer';
480            $unsigned = preg_match('/ unsigned/i', $field['type']);
481            $length = 4;
482            break;
483        case 'bigint':
484            $type[] = 'integer';
485            $unsigned = preg_match('/ unsigned/i', $field['type']);
486            $length = 8;
487            break;
488        case 'tinytext':
489        case 'mediumtext':
490        case 'longtext':
491        case 'text':
492        case 'varchar':
493            $fixed = false;
494        case 'string':
495        case 'char':
496            $type[] = 'text';
497            if ($length == '1') {
498                $type[] = 'boolean';
499                if (preg_match('/^(is|has)/', $field['name'])) {
500                    $type = array_reverse($type);
501                }
502            } elseif (strstr($db_type, 'text')) {
503                $type[] = 'clob';
504                if ($decimal == 'binary') {
505                    $type[] = 'blob';
506                }
507                $type = array_reverse($type);
508            }
509            if ($fixed !== false) {
510                $fixed = true;
511            }
512            break;
513        case 'enum':
514            $type[] = 'text';
515            preg_match_all('/\'.+\'/U', $field['type'], $matches);
516            $length = 0;
517            $fixed = false;
518            if (is_array($matches)) {
519                foreach ($matches[0] as $value) {
520                    $length = max($length, strlen($value)-2);
521                }
522                if ($length == '1' && count($matches[0]) == 2) {
523                    $type[] = 'boolean';
524                    if (preg_match('/^(is|has)/', $field['name'])) {
525                        $type = array_reverse($type);
526                    }
527                }
528            }
529            $type[] = 'integer';
530        case 'set':
531            $fixed = false;
532            $type[] = 'text';
533            $type[] = 'integer';
534            break;
535        case 'date':
536            $type[] = 'date';
537            $length = null;
538            break;
539        case 'datetime':
540        case 'timestamp':
541            $type[] = 'timestamp';
542            $length = null;
543            break;
544        case 'time':
545            $type[] = 'time';
546            $length = null;
547            break;
548        case 'float':
549        case 'double':
550        case 'real':
551            $type[] = 'float';
552            $unsigned = preg_match('/ unsigned/i', $field['type']);
553            if ($decimal !== false) {
554                $length = $length.','.$decimal;
555            }
556            break;
557        case 'unknown':
558        case 'decimal':
559        case 'numeric':
560            $type[] = 'decimal';
561            $unsigned = preg_match('/ unsigned/i', $field['type']);
562            if ($decimal !== false) {
563                $length = $length.','.$decimal;
564            }
565            break;
566        case 'tinyblob':
567        case 'mediumblob':
568        case 'longblob':
569        case 'blob':
570            $type[] = 'blob';
571            $length = null;
572            break;
573        case 'binary':
574        case 'varbinary':
575            $type[] = 'blob';
576            break;
577        case 'year':
578            $type[] = 'integer';
579            $type[] = 'date';
580            $length = null;
581            break;
582        default:
583            $db = $this->getDBInstance();
584            if (MDB2::isError($db)) {
585                return $db;
586            }
587
588            return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
589                'unknown database attribute type: '.$db_type, __FUNCTION__);
590        }
591
592        if ((int)$length <= 0) {
593            $length = null;
594        }
595
596        return array($type, $length, $unsigned, $fixed);
597    }
598
599    // }}}
600}
601
602?>
Note: See TracBrowser for help on using the repository browser.