~patrix-sbs/oraculum/git

« back to all changes in this revision

Viewing changes to models/doctrine/lib/Doctrine/DataDict/Mysql.php

  • Committer: Patrick Kaminski
  • Date: 2009-09-02 02:33:07 UTC
  • Revision ID: git-v1:943803254fca67bfb4c0374422b1b836b14dc518
Tags: v0.1a
Sending Oraculum Framework v0.1 alpha

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<?php
 
2
/*
 
3
 *  $Id: Mysql.php 5232 2008-12-01 22:41:30Z jwage $
 
4
 *
 
5
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 
6
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 
7
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 
8
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 
9
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 
10
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 
11
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 
12
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 
13
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
14
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 
15
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
16
 *
 
17
 * This software consists of voluntary contributions made by many individuals
 
18
 * and is licensed under the LGPL. For more information, see
 
19
 * <http://www.phpdoctrine.org>.
 
20
 */
 
21
 
 
22
/**
 
23
 * @package     Doctrine
 
24
 * @subpackage  DataDict
 
25
 * @license     http://www.opensource.org/licenses/lgpl-license.php LGPL
 
26
 * @author      Konsta Vesterinen <kvesteri@cc.hut.fi>
 
27
 * @author      Lukas Smith <smith@pooteeweet.org> (PEAR MDB2 library)
 
28
 * @version     $Revision: 5232 $
 
29
 * @link        www.phpdoctrine.org
 
30
 * @since       1.0
 
31
 */
 
32
class Doctrine_DataDict_Mysql extends Doctrine_DataDict
 
33
{
 
34
    protected $keywords = array(
 
35
                          'ADD', 'ALL', 'ALTER',
 
36
                          'ANALYZE', 'AND', 'AS',
 
37
                          'ASC', 'ASENSITIVE', 'BEFORE',
 
38
                          'BETWEEN', 'BIGINT', 'BINARY',
 
39
                          'BLOB', 'BOTH', 'BY', 'BIT',
 
40
                          'CALL', 'CASCADE', 'CASE',
 
41
                          'CHANGE', 'CHAR', 'CHARACTER',
 
42
                          'CHECK', 'COLLATE', 'COLUMN',
 
43
                          'CONDITION', 'CONNECTION', 'CONSTRAINT',
 
44
                          'CONTINUE', 'CONVERT', 'CREATE',
 
45
                          'CROSS', 'CURRENT_DATE', 'CURRENT_TIME',
 
46
                          'CURRENT_TIMESTAMP', 'CURRENT_USER', 'CURSOR',
 
47
                          'DATABASE', 'DATABASES', 'DAY_HOUR',
 
48
                          'DAY_MICROSECOND', 'DAY_MINUTE', 'DAY_SECOND',
 
49
                          'DEC', 'DECIMAL', 'DECLARE',
 
50
                          'DEFAULT', 'DELAYED', 'DELETE',
 
51
                          'DESC', 'DESCRIBE', 'DETERMINISTIC',
 
52
                          'DISTINCT', 'DISTINCTROW', 'DIV',
 
53
                          'DOUBLE', 'DROP', 'DUAL',
 
54
                          'EACH', 'ELSE', 'ELSEIF',
 
55
                          'ENCLOSED', 'ESCAPED', 'EXISTS',
 
56
                          'EXIT', 'EXPLAIN', 'FALSE',
 
57
                          'FETCH', 'FLOAT', 'FLOAT4',
 
58
                          'FLOAT8', 'FOR', 'FORCE',
 
59
                          'FOREIGN', 'FROM', 'FULLTEXT',
 
60
                          'GRANT', 'GROUP', 'HAVING',
 
61
                          'HIGH_PRIORITY', 'HOUR_MICROSECOND', 'HOUR_MINUTE',
 
62
                          'HOUR_SECOND', 'IF', 'IGNORE',
 
63
                          'IN', 'INDEX', 'INFILE',
 
64
                          'INNER', 'INOUT', 'INSENSITIVE',
 
65
                          'INSERT', 'INT', 'INT1',
 
66
                          'INT2', 'INT3', 'INT4',
 
67
                          'INT8', 'INTEGER', 'INTERVAL',
 
68
                          'INTO', 'IS', 'ITERATE',
 
69
                          'JOIN', 'KEY', 'KEYS',
 
70
                          'KILL', 'LEADING', 'LEAVE',
 
71
                          'LEFT', 'LIKE', 'LIMIT',
 
72
                          'LINES', 'LOAD', 'LOCALTIME',
 
73
                          'LOCALTIMESTAMP', 'LOCK', 'LONG',
 
74
                          'LONGBLOB', 'LONGTEXT', 'LOOP',
 
75
                          'LOW_PRIORITY', 'MATCH', 'MEDIUMBLOB',
 
76
                          'MEDIUMINT', 'MEDIUMTEXT', 'MIDDLEINT',
 
77
                          'MINUTE_MICROSECOND', 'MINUTE_SECOND', 'MOD',
 
78
                          'MODIFIES', 'NATURAL', 'NOT',
 
79
                          'NO_WRITE_TO_BINLOG', 'NULL', 'NUMERIC',
 
80
                          'ON', 'OPTIMIZE', 'OPTION',
 
81
                          'OPTIONALLY', 'OR', 'ORDER',
 
82
                          'OUT', 'OUTER', 'OUTFILE',
 
83
                          'PRECISION', 'PRIMARY', 'PROCEDURE',
 
84
                          'PURGE', 'RAID0', 'READ',
 
85
                          'READS', 'REAL', 'REFERENCES',
 
86
                          'REGEXP', 'RELEASE', 'RENAME',
 
87
                          'REPEAT', 'REPLACE', 'REQUIRE',
 
88
                          'RESTRICT', 'RETURN', 'REVOKE',
 
89
                          'RIGHT', 'RLIKE', 'SCHEMA',
 
90
                          'SCHEMAS', 'SECOND_MICROSECOND', 'SELECT',
 
91
                          'SENSITIVE', 'SEPARATOR', 'SET',
 
92
                          'SHOW', 'SMALLINT', 'SONAME',
 
93
                          'SPATIAL', 'SPECIFIC', 'SQL',
 
94
                          'SQLEXCEPTION', 'SQLSTATE', 'SQLWARNING',
 
95
                          'SQL_BIG_RESULT', 'SQL_CALC_FOUND_ROWS', 'SQL_SMALL_RESULT',
 
96
                          'SSL', 'STARTING', 'STRAIGHT_JOIN',
 
97
                          'TABLE', 'TERMINATED', 'THEN',
 
98
                          'TINYBLOB', 'TINYINT', 'TINYTEXT',
 
99
                          'TO', 'TRAILING', 'TRIGGER',
 
100
                          'TRUE', 'UNDO', 'UNION',
 
101
                          'UNIQUE', 'UNLOCK', 'UNSIGNED',
 
102
                          'UPDATE', 'USAGE', 'USE',
 
103
                          'USING', 'UTC_DATE', 'UTC_TIME',
 
104
                          'UTC_TIMESTAMP', 'VALUES', 'VARBINARY',
 
105
                          'VARCHAR', 'VARCHARACTER', 'VARYING',
 
106
                          'WHEN', 'WHERE', 'WHILE',
 
107
                          'WITH', 'WRITE', 'X509',
 
108
                          'XOR', 'YEAR_MONTH', 'ZEROFILL'
 
109
                          );
 
110
 
 
111
    /**
 
112
     * Obtain DBMS specific SQL code portion needed to declare an text type
 
113
     * field to be used in statements like CREATE TABLE.
 
114
     *
 
115
     * @param array $field  associative array with the name of the properties
 
116
     *      of the field being declared as array indexes. Currently, the types
 
117
     *      of supported field properties are as follows:
 
118
     *
 
119
     *      length
 
120
     *          Integer value that determines the maximum length of the text
 
121
     *          field. If this argument is missing the field should be
 
122
     *          declared to have the longest length allowed by the DBMS.
 
123
     *
 
124
     *      default
 
125
     *          Text value to be used as default for this field.
 
126
     *
 
127
     *      notnull
 
128
     *          Boolean flag that indicates whether this field is constrained
 
129
     *          to not be set to null.
 
130
     *
 
131
     * @return string  DBMS specific SQL code portion that should be used to
 
132
     *      declare the specified field.
 
133
     */
 
134
    public function getNativeDeclaration($field)
 
135
    {
 
136
        if ( ! isset($field['type'])) {
 
137
            throw new Doctrine_DataDict_Exception('Missing column type.');
 
138
        }
 
139
 
 
140
        switch ($field['type']) {
 
141
            case 'char':
 
142
                $length = ( ! empty($field['length'])) ? $field['length'] : false;
 
143
 
 
144
                return $length ? 'CHAR('.$length.')' : 'CHAR(255)';
 
145
            case 'enum':
 
146
                if ($this->conn->getAttribute(Doctrine::ATTR_USE_NATIVE_ENUM)) {
 
147
                    $values = array();
 
148
                    foreach ($field['values'] as $value) {
 
149
                      $values[] = $this->conn->quote($value, 'varchar');
 
150
                    }
 
151
                    return 'ENUM('.implode(', ', $values).')';
 
152
                } else {
 
153
                    $field['length'] = isset($field['length']) && $field['length'] ? $field['length']:255;
 
154
                }
 
155
            case 'varchar':
 
156
            case 'array':
 
157
            case 'object':
 
158
            case 'string':
 
159
            case 'gzip':
 
160
                if ( ! isset($field['length'])) {
 
161
                    if (array_key_exists('default', $field)) {
 
162
                        $field['length'] = $this->conn->varchar_max_length;
 
163
                    } else {
 
164
                        $field['length'] = false;
 
165
                    }
 
166
                }
 
167
 
 
168
                $length = ($field['length'] <= $this->conn->varchar_max_length) ? $field['length'] : false;
 
169
                $fixed  = (isset($field['fixed'])) ? $field['fixed'] : false;
 
170
 
 
171
                return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(255)')
 
172
                    : ($length ? 'VARCHAR(' . $length . ')' : 'TEXT');
 
173
            case 'clob':
 
174
                if ( ! empty($field['length'])) {
 
175
                    $length = $field['length'];
 
176
                    if ($length <= 255) {
 
177
                        return 'TINYTEXT';
 
178
                    } elseif ($length <= 65532) {
 
179
                        return 'TEXT';
 
180
                    } elseif ($length <= 16777215) {
 
181
                        return 'MEDIUMTEXT';
 
182
                    }
 
183
                }
 
184
                return 'LONGTEXT';
 
185
            case 'blob':
 
186
                if ( ! empty($field['length'])) {
 
187
                    $length = $field['length'];
 
188
                    if ($length <= 255) {
 
189
                        return 'TINYBLOB';
 
190
                    } elseif ($length <= 65532) {
 
191
                        return 'BLOB';
 
192
                    } elseif ($length <= 16777215) {
 
193
                        return 'MEDIUMBLOB';
 
194
                    }
 
195
                }
 
196
                return 'LONGBLOB';
 
197
            case 'integer':
 
198
            case 'int':
 
199
                if ( ! empty($field['length'])) {
 
200
                    $length = $field['length'];
 
201
                    if ($length <= 1) {
 
202
                        return 'TINYINT';
 
203
                    } elseif ($length == 2) {
 
204
                        return 'SMALLINT';
 
205
                    } elseif ($length == 3) {
 
206
                        return 'MEDIUMINT';
 
207
                    } elseif ($length == 4) {
 
208
                        return 'INT';
 
209
                    } elseif ($length > 4) {
 
210
                        return 'BIGINT';
 
211
                    }
 
212
                }
 
213
                return 'INT';
 
214
            case 'boolean':
 
215
                return 'TINYINT(1)';
 
216
            case 'date':
 
217
                return 'DATE';
 
218
            case 'time':
 
219
                return 'TIME';
 
220
            case 'timestamp':
 
221
                return 'DATETIME';
 
222
            case 'float':
 
223
            case 'double':
 
224
                return 'DOUBLE';
 
225
            case 'decimal':
 
226
                $length = !empty($field['length']) ? $field['length'] : 18;
 
227
                $scale = !empty($field['scale']) ? $field['scale'] : $this->conn->getAttribute(Doctrine::ATTR_DECIMAL_PLACES);
 
228
                return 'DECIMAL('.$length.','.$scale.')';
 
229
            case 'bit':
 
230
                return 'BIT';
 
231
        }
 
232
        throw new Doctrine_DataDict_Exception('Unknown field type \'' . $field['type'] .  '\'.');
 
233
    }
 
234
 
 
235
    /**
 
236
     * Maps a native array description of a field to a MDB2 datatype and length
 
237
     *
 
238
     * @param array  $field native field description
 
239
     * @return array containing the various possible types, length, sign, fixed
 
240
     */
 
241
    public function getPortableDeclaration(array $field)
 
242
    {
 
243
        $dbType = strtolower($field['type']);
 
244
        $dbType = strtok($dbType, '(), ');
 
245
        if ($dbType == 'national') {
 
246
            $dbType = strtok('(), ');
 
247
        }
 
248
        if (isset($field['length'])) {
 
249
            $length = $field['length'];
 
250
            $decimal = '';
 
251
        } else {
 
252
            $length = strtok('(), ');
 
253
            $decimal = strtok('(), ') ? strtok('(), '):null;
 
254
        }
 
255
        $type = array();
 
256
        $unsigned = $fixed = null;
 
257
 
 
258
        if ( ! isset($field['name'])) {
 
259
            $field['name'] = '';
 
260
        }
 
261
 
 
262
        $values = null;
 
263
        $scale = null;
 
264
 
 
265
        switch ($dbType) {
 
266
            case 'tinyint':
 
267
                $type[] = 'integer';
 
268
                $type[] = 'boolean';
 
269
                if (preg_match('/^(is|has)/', $field['name'])) {
 
270
                    $type = array_reverse($type);
 
271
                }
 
272
                $unsigned = preg_match('/ unsigned/i', $field['type']);
 
273
                $length = 1;
 
274
            break;
 
275
            case 'smallint':
 
276
                $type[] = 'integer';
 
277
                $unsigned = preg_match('/ unsigned/i', $field['type']);
 
278
                $length = 2;
 
279
            break;
 
280
            case 'mediumint':
 
281
                $type[] = 'integer';
 
282
                $unsigned = preg_match('/ unsigned/i', $field['type']);
 
283
                $length = 3;
 
284
            break;
 
285
            case 'int':
 
286
            case 'integer':
 
287
                $type[] = 'integer';
 
288
                $unsigned = preg_match('/ unsigned/i', $field['type']);
 
289
                $length = 4;
 
290
            break;
 
291
            case 'bigint':
 
292
                $type[] = 'integer';
 
293
                $unsigned = preg_match('/ unsigned/i', $field['type']);
 
294
                $length = 8;
 
295
            break;
 
296
            case 'tinytext':
 
297
            case 'mediumtext':
 
298
            case 'longtext':
 
299
            case 'text':
 
300
            case 'text':
 
301
            case 'varchar':
 
302
                $fixed = false;
 
303
            case 'string':
 
304
            case 'char':
 
305
                $type[] = 'string';
 
306
                if ($length == '1') {
 
307
                    $type[] = 'boolean';
 
308
                    if (preg_match('/^(is|has)/', $field['name'])) {
 
309
                        $type = array_reverse($type);
 
310
                    }
 
311
                } elseif (strstr($dbType, 'text')) {
 
312
                    $type[] = 'clob';
 
313
                    if ($decimal == 'binary') {
 
314
                        $type[] = 'blob';
 
315
                    }
 
316
                }
 
317
                if ($fixed !== false) {
 
318
                    $fixed = true;
 
319
                }
 
320
            break;
 
321
            case 'enum':
 
322
                $type[] = 'enum';
 
323
                preg_match_all('/\'((?:\'\'|[^\'])*)\'/', $field['type'], $matches);
 
324
                $length = 0;
 
325
                $fixed = false;
 
326
                if (is_array($matches)) {
 
327
                    foreach ($matches[1] as &$value) {
 
328
                        $value = str_replace('\'\'', '\'', $value);
 
329
                        $length = max($length, strlen($value));
 
330
                    }
 
331
                    if ($length == '1' && count($matches[1]) == 2) {
 
332
                        $type[] = 'boolean';
 
333
                        if (preg_match('/^(is|has)/', $field['name'])) {
 
334
                            $type = array_reverse($type);
 
335
                        }
 
336
                    }
 
337
 
 
338
                    $values = $matches[1];
 
339
                }
 
340
                $type[] = 'integer';
 
341
                break;
 
342
            case 'set':
 
343
                $fixed = false;
 
344
                $type[] = 'text';
 
345
                $type[] = 'integer';
 
346
            break;
 
347
            case 'date':
 
348
                $type[] = 'date';
 
349
                $length = null;
 
350
            break;
 
351
            case 'datetime':
 
352
            case 'timestamp':
 
353
                $type[] = 'timestamp';
 
354
                $length = null;
 
355
            break;
 
356
            case 'time':
 
357
                $type[] = 'time';
 
358
                $length = null;
 
359
            break;
 
360
            case 'float':
 
361
            case 'double':
 
362
            case 'real':
 
363
                $type[] = 'float';
 
364
                $unsigned = preg_match('/ unsigned/i', $field['type']);
 
365
            break;
 
366
            case 'unknown':
 
367
            case 'decimal':
 
368
                if ($decimal !== null) {
 
369
                    $scale = $decimal;
 
370
                }
 
371
            case 'numeric':
 
372
                $type[] = 'decimal';
 
373
                $unsigned = preg_match('/ unsigned/i', $field['type']);
 
374
            break;
 
375
            case 'tinyblob':
 
376
            case 'mediumblob':
 
377
            case 'longblob':
 
378
            case 'blob':
 
379
            case 'binary':
 
380
            case 'varbinary':
 
381
                $type[] = 'blob';
 
382
                $length = null;
 
383
            break;
 
384
            case 'year':
 
385
                $type[] = 'integer';
 
386
                $type[] = 'date';
 
387
                $length = null;
 
388
            break;
 
389
            case 'bit':
 
390
                $type[] = 'bit';
 
391
            break;
 
392
            case 'geometry':
 
393
            case 'geometrycollection':
 
394
            case 'point':
 
395
            case 'multipoint':
 
396
            case 'linestring':
 
397
            case 'multilinestring':
 
398
            case 'polygon':
 
399
            case 'multipolygon':
 
400
                $type[] = 'blob';
 
401
                $length = null;
 
402
            break;
 
403
            default:
 
404
                throw new Doctrine_DataDict_Exception('unknown database attribute type: ' . $dbType);
 
405
        }
 
406
 
 
407
        $length = ((int) $length == 0) ? null : (int) $length;
 
408
        $def =  array('type' => $type, 'length' => $length, 'unsigned' => $unsigned, 'fixed' => $fixed);
 
409
        if ($values !== null) {
 
410
            $def['values'] = $values;
 
411
        }
 
412
        if ($scale !== null) {
 
413
            $def['scale'] = $scale;
 
414
        }
 
415
        return $def;
 
416
    }
 
417
 
 
418
    /**
 
419
     * Obtain DBMS specific SQL code portion needed to set the CHARACTER SET
 
420
     * of a field declaration to be used in statements like CREATE TABLE.
 
421
     *
 
422
     * @param string $charset   name of the charset
 
423
     * @return string  DBMS specific SQL code portion needed to set the CHARACTER SET
 
424
     *                 of a field declaration.
 
425
     */
 
426
    public function getCharsetFieldDeclaration($charset)
 
427
    {
 
428
        return 'CHARACTER SET ' . $charset;
 
429
    }
 
430
 
 
431
    /**
 
432
     * Obtain DBMS specific SQL code portion needed to set the COLLATION
 
433
     * of a field declaration to be used in statements like CREATE TABLE.
 
434
     *
 
435
     * @param string $collation   name of the collation
 
436
     * @return string  DBMS specific SQL code portion needed to set the COLLATION
 
437
     *                 of a field declaration.
 
438
     */
 
439
    public function getCollationFieldDeclaration($collation)
 
440
    {
 
441
        return 'COLLATE ' . $collation;
 
442
    }
 
443
 
 
444
    /**
 
445
     * Obtain DBMS specific SQL code portion needed to declare an integer type
 
446
     * field to be used in statements like CREATE TABLE.
 
447
     *
 
448
     * @param string  $name   name the field to be declared.
 
449
     * @param string  $field  associative array with the name of the properties
 
450
     *                        of the field being declared as array indexes.
 
451
     *                        Currently, the types of supported field
 
452
     *                        properties are as follows:
 
453
     *
 
454
     *                       unsigned
 
455
     *                        Boolean flag that indicates whether the field
 
456
     *                        should be declared as unsigned integer if
 
457
     *                        possible.
 
458
     *
 
459
     *                       default
 
460
     *                        Integer value to be used as default for this
 
461
     *                        field.
 
462
     *
 
463
     *                       notnull
 
464
     *                        Boolean flag that indicates whether this field is
 
465
     *                        constrained to not be set to null.
 
466
     * @return string  DBMS specific SQL code portion that should be used to
 
467
     *                 declare the specified field.
 
468
     */
 
469
    public function getIntegerDeclaration($name, $field)
 
470
    {
 
471
        $default = $autoinc = '';
 
472
        if ( ! empty($field['autoincrement'])) {
 
473
            $autoinc = ' AUTO_INCREMENT';
 
474
        } elseif (array_key_exists('default', $field)) {
 
475
            if ($field['default'] === '') {
 
476
                $field['default'] = empty($field['notnull']) ? null : 0;
 
477
            }
 
478
 
 
479
            $default = ' DEFAULT ' . (is_null($field['default'])
 
480
                ? 'NULL'
 
481
                : $this->conn->quote($field['default']));
 
482
        }
 
483
        /**
 
484
        elseif (empty($field['notnull'])) {
 
485
            $default = ' DEFAULT NULL';
 
486
        }
 
487
        */
 
488
 
 
489
        $notnull  = (isset($field['notnull'])  && $field['notnull'])  ? ' NOT NULL' : '';
 
490
        $unsigned = (isset($field['unsigned']) && $field['unsigned']) ? ' UNSIGNED' : '';
 
491
        $comment  = (isset($field['comment']) && $field['comment']) 
 
492
            ? " COMMENT '" . $field['comment'] . "'" : '';
 
493
 
 
494
        $name = $this->conn->quoteIdentifier($name, true);
 
495
 
 
496
        return $name . ' ' . $this->getNativeDeclaration($field) . $unsigned 
 
497
            . $default . $notnull . $autoinc . $comment;
 
498
    }
 
499
}