Subversion-Projekte lars-tiefland.php_share

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 1
<?php
2
/*
3
 *  $Id: Mysql.php 7653 2010-06-08 15:54:31Z 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.doctrine-project.org>.
20
 */
21
 
22
/**
23
 * Doctrine_Export_Mysql
24
 *
25
 * @package     Doctrine
26
 * @subpackage  Export
27
 * @author      Konsta Vesterinen <kvesteri@cc.hut.fi>
28
 * @author      Lukas Smith <smith@pooteeweet.org> (PEAR MDB2 library)
29
 * @license     http://www.opensource.org/licenses/lgpl-license.php LGPL
30
 * @link        www.doctrine-project.org
31
 * @since       1.0
32
 * @version     $Revision: 7653 $
33
 */
34
class Doctrine_Export_Mysql extends Doctrine_Export
35
{
36
    /**
37
     * drop existing constraint
38
     *
39
     * @param string    $table        name of table that should be used in method
40
     * @param string    $name         name of the constraint to be dropped
41
     * @param string    $primary      hint if the constraint is primary
42
     * @return void
43
     */
44
    public function dropConstraint($table, $name, $primary = false)
45
    {
46
        $table = $this->conn->quoteIdentifier($table);
47
 
48
        if ( ! $primary) {
49
            $name = 'CONSTRAINT ' . $this->conn->quoteIdentifier($name);
50
        } else {
51
            $name = 'PRIMARY KEY';
52
        }
53
 
54
        return $this->conn->exec('ALTER TABLE ' . $table . ' DROP ' . $name);
55
    }
56
 
57
    /**
58
     * createDatabaseSql
59
     *
60
     * @param string $name
61
     * @return void
62
     */
63
    public function createDatabaseSql($name)
64
    {
65
        return 'CREATE DATABASE ' . $this->conn->quoteIdentifier($name, true);
66
    }
67
 
68
    /**
69
     * drop an existing database
70
     *
71
     * @param string $name name of the database that should be dropped
72
     * @return string
73
     */
74
    public function dropDatabaseSql($name)
75
    {
76
        return array(
77
            'SET FOREIGN_KEY_CHECKS = 0',
78
            'DROP DATABASE ' . $this->conn->quoteIdentifier($name),
79
            'SET FOREIGN_KEY_CHECKS = 1'
80
        );
81
    }
82
 
83
    /**
84
     * create a new table
85
     *
86
     * @param string $name   Name of the database that should be created
87
     * @param array $fields  Associative array that contains the definition of each field of the new table
88
     *                       The indexes of the array entries are the names of the fields of the table an
89
     *                       the array entry values are associative arrays like those that are meant to be
90
     *                       passed with the field definitions to get[Type]Declaration() functions.
91
     *                          array(
92
     *                              'id' => array(
93
     *                                  'type' => 'integer',
94
     *                                  'unsigned' => 1
95
     *                                  'notnull' => 1
96
     *                                  'default' => 0
97
     *                              ),
98
     *                              'name' => array(
99
     *                                  'type' => 'text',
100
     *                                  'length' => 12
101
     *                              ),
102
     *                              'password' => array(
103
     *                                  'type' => 'text',
104
     *                                  'length' => 12
105
     *                              )
106
     *                          );
107
     * @param array $options  An associative array of table options:
108
     *                          array(
109
     *                              'comment' => 'Foo',
110
     *                              'charset' => 'utf8',
111
     *                              'collate' => 'utf8_unicode_ci',
112
     *                              'type'    => 'innodb',
113
     *                          );
114
     *
115
     * @return void
116
     */
117
    public function createTableSql($name, array $fields, array $options = array())
118
    {
119
        if ( ! $name)
120
            throw new Doctrine_Export_Exception('no valid table name specified');
121
 
122
        if (empty($fields)) {
123
            throw new Doctrine_Export_Exception('no fields specified for table "'.$name.'"');
124
        }
125
        $queryFields = $this->getFieldDeclarationList($fields);
126
 
127
        // build indexes for all foreign key fields (needed in MySQL!!)
128
        if (isset($options['foreignKeys'])) {
129
            foreach ($options['foreignKeys'] as $fk) {
130
                $local = $fk['local'];
131
                $found = false;
132
                if (isset($options['indexes'])) {
133
                    foreach ($options['indexes'] as $definition) {
134
                        if (is_string($definition['fields'])) {
135
                            // Check if index already exists on the column
136
                            $found = $found || ($local == $definition['fields']);
137
                        } else if (in_array($local, $definition['fields']) && count($definition['fields']) === 1) {
138
                            // Index already exists on the column
139
                            $found = true;
140
                        }
141
                    }
142
                }
143
                if (isset($options['primary']) && !empty($options['primary']) &&
144
                        in_array($local, $options['primary'])) {
145
                    // field is part of the PK and therefore already indexed
146
                    $found = true;
147
                }
148
 
149
                if ( ! $found) {
150
                    if (is_array($local)) {
151
                      foreach($local as $localidx) {
152
                        $options['indexes'][$localidx] = array('fields' => array($localidx => array()));
153
                      }
154
                    } else {
155
                      $options['indexes'][$local] = array('fields' => array($local => array()));
156
                    }
157
                }
158
            }
159
        }
160
 
161
        // add all indexes
162
        if (isset($options['indexes']) && ! empty($options['indexes'])) {
163
            // Case Insensitive checking for duplicate indexes...
164
            $dupes = array();
165
            foreach ($options['indexes'] as $key => $index) {
166
                if (in_array(strtolower($key), $dupes)) {
167
                    unset($options['indexes'][$key]);
168
                } else {
169
                    $dupes[] = strtolower($key);
170
                }
171
            }
172
            unset($dupes);
173
 
174
            foreach($options['indexes'] as $index => $definition) {
175
                $queryFields .= ', ' . $this->getIndexDeclaration($index, $definition);
176
            }
177
        }
178
 
179
        // attach all primary keys
180
        if (isset($options['primary']) && ! empty($options['primary'])) {
181
            $keyColumns = array_values($options['primary']);
182
            $keyColumns = array_map(array($this->conn, 'quoteIdentifier'), $keyColumns);
183
            $queryFields .= ', PRIMARY KEY(' . implode(', ', $keyColumns) . ')';
184
        }
185
 
186
        $query = 'CREATE TABLE ' . $this->conn->quoteIdentifier($name, true) . ' (' . $queryFields . ')';
187
 
188
        $optionStrings = array();
189
 
190
        if (isset($options['comment'])) {
191
            $optionStrings['comment'] = 'COMMENT = ' . $this->conn->quote($options['comment'], 'text');
192
        }
193
        if (isset($options['charset'])) {
194
            $optionStrings['charset'] = 'DEFAULT CHARACTER SET ' . $options['charset'];
195
        }
196
        if (isset($options['collate'])) {
197
            $optionStrings['collate'] = 'COLLATE ' . $options['collate'];
198
        }
199
 
200
        $type = false;
201
 
202
        // get the type of the table
203
        if (isset($options['type'])) {
204
            $type = $options['type'];
205
        } else {
206
            $type = $this->conn->getAttribute(Doctrine_Core::ATTR_DEFAULT_TABLE_TYPE);
207
        }
208
 
209
        if ($type) {
210
            $optionStrings[] = 'ENGINE = ' . $type;
211
        }
212
 
213
        if ( ! empty($optionStrings)) {
214
            $query.= ' '.implode(' ', $optionStrings);
215
        }
216
        $sql[] = $query;
217
 
218
        if (isset($options['foreignKeys'])) {
219
 
220
            foreach ((array) $options['foreignKeys'] as $k => $definition) {
221
                if (is_array($definition)) {
222
                    $sql[] = $this->createForeignKeySql($name, $definition);
223
                }
224
            }
225
        }
226
        return $sql;
227
    }
228
 
229
    /**
230
     * Obtain DBMS specific SQL code portion needed to declare a generic type
231
     * field to be used in statements like CREATE TABLE.
232
     *
233
     * @param string $name   name the field to be declared.
234
     * @param array  $field  associative array with the name of the properties
235
     *      of the field being declared as array indexes. Currently, the types
236
     *      of supported field properties are as follows:
237
     *
238
     *      length
239
     *          Integer value that determines the maximum length of the text
240
     *          field. If this argument is missing the field should be
241
     *          declared to have the longest length allowed by the DBMS.
242
     *
243
     *      default
244
     *          Text value to be used as default for this field.
245
     *
246
     *      notnull
247
     *          Boolean flag that indicates whether this field is constrained
248
     *          to not be set to null.
249
     *      charset
250
     *          Text value with the default CHARACTER SET for this field.
251
     *      collation
252
     *          Text value with the default COLLATION for this field.
253
     *      unique
254
     *          unique constraint
255
     *      check
256
     *          column check constraint
257
     *
258
     * @return string  DBMS specific SQL code portion that should be used to
259
     *      declare the specified field.
260
     */
261
    public function getDeclaration($name, array $field)
262
    {
263
 
264
        $default   = $this->getDefaultFieldDeclaration($field);
265
 
266
        $charset   = (isset($field['charset']) && $field['charset']) ?
267
                    ' ' . $this->getCharsetFieldDeclaration($field['charset']) : '';
268
 
269
        $collation = (isset($field['collation']) && $field['collation']) ?
270
                    ' ' . $this->getCollationFieldDeclaration($field['collation']) : '';
271
 
272
        $notnull   = (isset($field['notnull']) && $field['notnull']) ? ' NOT NULL' : '';
273
 
274
        $unique    = (isset($field['unique']) && $field['unique']) ?
275
                    ' ' . $this->getUniqueFieldDeclaration() : '';
276
 
277
        $check     = (isset($field['check']) && $field['check']) ?
278
                    ' ' . $field['check'] : '';
279
 
280
        $comment   = (isset($field['comment']) && $field['comment']) ?
281
                    " COMMENT " . $this->conn->quote($field['comment'], 'text') : '';
282
 
283
        $method = 'get' . $field['type'] . 'Declaration';
284
 
285
        try {
286
            if (method_exists($this->conn->dataDict, $method)) {
287
                return $this->conn->dataDict->$method($name, $field);
288
            } else {
289
                $dec = $this->conn->dataDict->getNativeDeclaration($field);
290
            }
291
 
292
            return $this->conn->quoteIdentifier($name, true)
293
                 . ' ' . $dec . $charset . $default . $notnull . $comment . $unique . $check . $collation;
294
        } catch (Exception $e) {
295
            throw new Doctrine_Exception('Around field ' . $name . ': ' . $e->getMessage() . "\n\n" . $e->getTraceAsString() . "\n\n");
296
        }
297
    }
298
 
299
    /**
300
     * alter an existing table
301
     *
302
     * @param string $name         name of the table that is intended to be changed.
303
     * @param array $changes     associative array that contains the details of each type
304
     *                             of change that is intended to be performed. The types of
305
     *                             changes that are currently supported are defined as follows:
306
     *
307
     *                             name
308
     *
309
     *                                New name for the table.
310
     *
311
     *                            add
312
     *
313
     *                                Associative array with the names of fields to be added as
314
     *                                 indexes of the array. The value of each entry of the array
315
     *                                 should be set to another associative array with the properties
316
     *                                 of the fields to be added. The properties of the fields should
317
     *                                 be the same as defined by the Metabase parser.
318
     *
319
     *
320
     *                            remove
321
     *
322
     *                                Associative array with the names of fields to be removed as indexes
323
     *                                 of the array. Currently the values assigned to each entry are ignored.
324
     *                                 An empty array should be used for future compatibility.
325
     *
326
     *                            rename
327
     *
328
     *                                Associative array with the names of fields to be renamed as indexes
329
     *                                 of the array. The value of each entry of the array should be set to
330
     *                                 another associative array with the entry named name with the new
331
     *                                 field name and the entry named Declaration that is expected to contain
332
     *                                 the portion of the field declaration already in DBMS specific SQL code
333
     *                                 as it is used in the CREATE TABLE statement.
334
     *
335
     *                            change
336
     *
337
     *                                Associative array with the names of the fields to be changed as indexes
338
     *                                 of the array. Keep in mind that if it is intended to change either the
339
     *                                 name of a field and any other properties, the change array entries
340
     *                                 should have the new names of the fields as array indexes.
341
     *
342
     *                                The value of each entry of the array should be set to another associative
343
     *                                 array with the properties of the fields to that are meant to be changed as
344
     *                                 array entries. These entries should be assigned to the new values of the
345
     *                                 respective properties. The properties of the fields should be the same
346
     *                                 as defined by the Metabase parser.
347
     *
348
     *                            Example
349
     *                                array(
350
     *                                    'name' => 'userlist',
351
     *                                    'add' => array(
352
     *                                        'quota' => array(
353
     *                                            'type' => 'integer',
354
     *                                            'unsigned' => 1
355
     *                                        )
356
     *                                    ),
357
     *                                    'remove' => array(
358
     *                                        'file_limit' => array(),
359
     *                                        'time_limit' => array()
360
     *                                    ),
361
     *                                    'change' => array(
362
     *                                        'name' => array(
363
     *                                            'length' => '20',
364
     *                                            'definition' => array(
365
     *                                                'type' => 'text',
366
     *                                                'length' => 20,
367
     *                                            ),
368
     *                                        )
369
     *                                    ),
370
     *                                    'rename' => array(
371
     *                                        'sex' => array(
372
     *                                            'name' => 'gender',
373
     *                                            'definition' => array(
374
     *                                                'type' => 'text',
375
     *                                                'length' => 1,
376
     *                                                'default' => 'M',
377
     *                                            ),
378
     *                                        )
379
     *                                    )
380
     *                                )
381
     *
382
     * @param boolean $check     indicates whether the function should just check if the DBMS driver
383
     *                           can perform the requested table alterations if the value is true or
384
     *                           actually perform them otherwise.
385
     * @return boolean
386
     */
387
    public function alterTableSql($name, array $changes, $check = false)
388
    {
389
        if ( ! $name) {
390
            throw new Doctrine_Export_Exception('no valid table name specified');
391
        }
392
        foreach ($changes as $changeName => $change) {
393
            switch ($changeName) {
394
                case 'add':
395
                case 'remove':
396
                case 'change':
397
                case 'rename':
398
                case 'name':
399
                    break;
400
                default:
401
                    throw new Doctrine_Export_Exception('change type "' . $changeName . '" not yet supported');
402
            }
403
        }
404
 
405
        if ($check) {
406
            return true;
407
        }
408
 
409
        $query = '';
410
        if ( ! empty($changes['name'])) {
411
            $change_name = $this->conn->quoteIdentifier($changes['name']);
412
            $query .= 'RENAME TO ' . $change_name;
413
        }
414
 
415
        if ( ! empty($changes['add']) && is_array($changes['add'])) {
416
            foreach ($changes['add'] as $fieldName => $field) {
417
                if ($query) {
418
                    $query.= ', ';
419
                }
420
                $query.= 'ADD ' . $this->getDeclaration($fieldName, $field);
421
            }
422
        }
423
 
424
        if ( ! empty($changes['remove']) && is_array($changes['remove'])) {
425
            foreach ($changes['remove'] as $fieldName => $field) {
426
                if ($query) {
427
                    $query .= ', ';
428
                }
429
                $fieldName = $this->conn->quoteIdentifier($fieldName);
430
                $query .= 'DROP ' . $fieldName;
431
            }
432
        }
433
 
434
        $rename = array();
435
        if ( ! empty($changes['rename']) && is_array($changes['rename'])) {
436
            foreach ($changes['rename'] as $fieldName => $field) {
437
                $rename[$field['name']] = $fieldName;
438
            }
439
        }
440
 
441
        if ( ! empty($changes['change']) && is_array($changes['change'])) {
442
            foreach ($changes['change'] as $fieldName => $field) {
443
                if ($query) {
444
                    $query.= ', ';
445
                }
446
                if (isset($rename[$fieldName])) {
447
                    $oldFieldName = $rename[$fieldName];
448
                    unset($rename[$fieldName]);
449
                } else {
450
                    $oldFieldName = $fieldName;
451
                }
452
                $oldFieldName = $this->conn->quoteIdentifier($oldFieldName, true);
453
                $query .= 'CHANGE ' . $oldFieldName . ' '
454
                        . $this->getDeclaration($fieldName, $field['definition']);
455
            }
456
        }
457
 
458
        if ( ! empty($rename) && is_array($rename)) {
459
            foreach ($rename as $renameName => $renamedField) {
460
                if ($query) {
461
                    $query.= ', ';
462
                }
463
                $field = $changes['rename'][$renamedField];
464
                $renamedField = $this->conn->quoteIdentifier($renamedField, true);
465
                $query .= 'CHANGE ' . $renamedField . ' '
466
                        . $this->getDeclaration($field['name'], $field['definition']);
467
            }
468
        }
469
 
470
        if ( ! $query) {
471
            return false;
472
        }
473
 
474
        $name = $this->conn->quoteIdentifier($name, true);
475
 
476
        return 'ALTER TABLE ' . $name . ' ' . $query;
477
    }
478
 
479
    /**
480
     * create sequence
481
     *
482
     * @param string    $sequenceName name of the sequence to be created
483
     * @param string    $start        start value of the sequence; default is 1
484
     * @param array     $options  An associative array of table options:
485
     *                          array(
486
     *                              'comment' => 'Foo',
487
     *                              'charset' => 'utf8',
488
     *                              'collate' => 'utf8_unicode_ci',
489
     *                              'type'    => 'innodb',
490
     *                          );
491
     * @return boolean
492
     */
493
    public function createSequence($sequenceName, $start = 1, array $options = array())
494
    {
495
        $sequenceName   = $this->conn->quoteIdentifier($sequenceName, true);
496
        $seqcolName     = $this->conn->quoteIdentifier($this->conn->getAttribute(Doctrine_Core::ATTR_SEQCOL_NAME), true);
497
 
498
        $optionsStrings = array();
499
 
500
        if (isset($options['comment']) && ! empty($options['comment'])) {
501
            $optionsStrings['comment'] = 'COMMENT = ' . $this->conn->quote($options['comment'], 'string');
502
        }
503
 
504
        if (isset($options['charset']) && ! empty($options['charset'])) {
505
            $optionsStrings['charset'] = 'DEFAULT CHARACTER SET ' . $options['charset'];
506
 
507
            if (isset($options['collate'])) {
508
                $optionsStrings['charset'] .= ' COLLATE ' . $options['collate'];
509
            }
510
        }
511
 
512
        $type = false;
513
 
514
        if (isset($options['type'])) {
515
            $type = $options['type'];
516
        } else {
517
            $type = $this->conn->getAttribute(Doctrine_Core::ATTR_DEFAULT_TABLE_TYPE);
518
        }
519
        if ($type) {
520
            $optionsStrings[] = 'ENGINE = ' . $type;
521
        }
522
 
523
 
524
        try {
525
            $query  = 'CREATE TABLE ' . $sequenceName
526
                    . ' (' . $seqcolName . ' BIGINT NOT NULL AUTO_INCREMENT, PRIMARY KEY ('
527
                    . $seqcolName . ')) ' . implode($optionsStrings, ' ');
528
 
529
            $res    = $this->conn->exec($query);
530
        } catch(Doctrine_Connection_Exception $e) {
531
            throw new Doctrine_Export_Exception('could not create sequence table');
532
        }
533
 
534
        if ($start == 1 && $res == 1)
535
            return true;
536
 
537
        $query  = 'INSERT INTO ' . $sequenceName
538
                . ' (' . $seqcolName . ') VALUES (' . ($start - 1) . ')';
539
 
540
        $res    = $this->conn->exec($query);
541
 
542
        if ($res == 1)
543
            return true;
544
 
545
        // Handle error
546
        try {
547
            $result = $this->conn->exec('DROP TABLE ' . $sequenceName);
548
        } catch(Doctrine_Connection_Exception $e) {
549
            throw new Doctrine_Export_Exception('could not drop inconsistent sequence table');
550
        }
551
 
552
 
553
    }
554
 
555
    /**
556
     * Get the stucture of a field into an array
557
     *
558
     * @author Leoncx
559
     * @param string    $table         name of the table on which the index is to be created
560
     * @param string    $name          name of the index to be created
561
     * @param array     $definition    associative array that defines properties of the index to be created.
562
     *                                 Currently, only one property named FIELDS is supported. This property
563
     *                                 is also an associative with the names of the index fields as array
564
     *                                 indexes. Each entry of this array is set to another type of associative
565
     *                                 array that specifies properties of the index that are specific to
566
     *                                 each field.
567
     *
568
     *                                 Currently, only the sorting property is supported. It should be used
569
     *                                 to define the sorting direction of the index. It may be set to either
570
     *                                 ascending or descending.
571
     *
572
     *                                 Not all DBMS support index sorting direction configuration. The DBMS
573
     *                                 drivers of those that do not support it ignore this property. Use the
574
     *                                 function supports() to determine whether the DBMS driver can manage indexes.
575
     *
576
     *                                 Example
577
     *                                    array(
578
     *                                        'fields' => array(
579
     *                                            'user_name' => array(
580
     *                                                'sorting' => 'ASC'
581
     *                                                'length' => 10
582
     *                                            ),
583
     *                                            'last_login' => array()
584
     *                                        )
585
     *                                    )
586
     * @throws PDOException
587
     * @return void
588
     */
589
    public function createIndexSql($table, $name, array $definition)
590
    {
591
        $table  = $table;
592
        $table  = $this->conn->quoteIdentifier($table, true);
593
 
594
        $name   = $this->conn->formatter->getIndexName($name);
595
        $name   = $this->conn->quoteIdentifier($name);
596
        $type   = '';
597
        if (isset($definition['type'])) {
598
            switch (strtolower($definition['type'])) {
599
                case 'fulltext':
600
                case 'unique':
601
                    $type = strtoupper($definition['type']) . ' ';
602
                break;
603
                default:
604
                    throw new Doctrine_Export_Exception(
605
                        'Unknown type ' . $definition['type'] . ' for index ' . $name . ' in table ' . $table
606
                    );
607
            }
608
        }
609
        $query  = 'CREATE ' . $type . 'INDEX ' . $name . ' ON ' . $table;
610
        $query .= ' (' . $this->getIndexFieldDeclarationList($definition['fields']) . ')';
611
 
612
        return $query;
613
    }
614
 
615
    /**
616
     * getDefaultDeclaration
617
     * Obtain DBMS specific SQL code portion needed to set a default value
618
     * declaration to be used in statements like CREATE TABLE.
619
     *
620
     * @param array $field      field definition array
621
     * @return string           DBMS specific SQL code portion needed to set a default value
622
     */
623
    public function getDefaultFieldDeclaration($field)
624
    {
625
        $default = '';
626
        if (isset($field['default']) && ( ! isset($field['length']) || $field['length'] <= 255)) {
627
            if ($field['default'] === '') {
628
                $field['default'] = empty($field['notnull'])
629
                    ? null : $this->valid_default_values[$field['type']];
630
 
631
                if ($field['default'] === ''
632
                    && ($this->conn->getAttribute(Doctrine_Core::ATTR_PORTABILITY) & Doctrine_Core::PORTABILITY_EMPTY_TO_NULL)
633
                ) {
634
                    $field['default'] = ' ';
635
                }
636
            }
637
 
638
            // Proposed patch:
639
            if ($field['type'] == 'enum' && $this->conn->getAttribute(Doctrine_Core::ATTR_USE_NATIVE_ENUM)) {
640
                $fieldType = 'varchar';
641
            } else {
642
                $fieldType = $field['type'];
643
            }
644
 
645
            $default = ' DEFAULT ' . (is_null($field['default'])
646
                ? 'NULL'
647
                : $this->conn->quote($field['default'], $fieldType));
648
            //$default = ' DEFAULT ' . $this->conn->quote($field['default'], $field['type']);
649
        }
650
 
651
        return $default;
652
    }
653
 
654
    /**
655
     * Obtain DBMS specific SQL code portion needed to set an index
656
     * declaration to be used in statements like CREATE TABLE.
657
     *
658
     * @param string $charset       name of the index
659
     * @param array $definition     index definition
660
     * @return string  DBMS specific SQL code portion needed to set an index
661
     */
662
    public function getIndexDeclaration($name, array $definition)
663
    {
664
        $name   = $this->conn->formatter->getIndexName($name);
665
        $type   = '';
666
        if (isset($definition['type'])) {
667
            switch (strtolower($definition['type'])) {
668
                case 'fulltext':
669
                case 'unique':
670
                    $type = strtoupper($definition['type']) . ' ';
671
                break;
672
                default:
673
                    throw new Doctrine_Export_Exception(
674
                        'Unknown type ' . $definition['type'] . ' for index ' . $name
675
                    );
676
            }
677
        }
678
 
679
        if ( ! isset($definition['fields'])) {
680
            throw new Doctrine_Export_Exception('No columns given for index ' . $name);
681
        }
682
        if ( ! is_array($definition['fields'])) {
683
            $definition['fields'] = array($definition['fields']);
684
        }
685
 
686
        $query = $type . 'INDEX ' . $this->conn->quoteIdentifier($name);
687
 
688
        $query .= ' (' . $this->getIndexFieldDeclarationList($definition['fields']) . ')';
689
 
690
        return $query;
691
    }
692
 
693
    /**
694
     * getIndexFieldDeclarationList
695
     * Obtain DBMS specific SQL code portion needed to set an index
696
     * declaration to be used in statements like CREATE TABLE.
697
     *
698
     * @return string
699
     */
700
    public function getIndexFieldDeclarationList(array $fields)
701
    {
702
        $declFields = array();
703
 
704
        foreach ($fields as $fieldName => $field) {
705
            $fieldString = $this->conn->quoteIdentifier($fieldName);
706
 
707
            if (is_array($field)) {
708
                if (isset($field['length'])) {
709
                    $fieldString .= '(' . $field['length'] . ')';
710
                }
711
 
712
                if (isset($field['sorting'])) {
713
                    $sort = strtoupper($field['sorting']);
714
                    switch ($sort) {
715
                        case 'ASC':
716
                        case 'DESC':
717
                            $fieldString .= ' ' . $sort;
718
                            break;
719
                        default:
720
                            throw new Doctrine_Export_Exception('Unknown index sorting option given.');
721
                    }
722
                }
723
            } else {
724
                $fieldString = $this->conn->quoteIdentifier($field);
725
            }
726
            $declFields[] = $fieldString;
727
        }
728
        return implode(', ', $declFields);
729
    }
730
 
731
    /**
732
     * Returns a character set declaration.
733
     *
734
     * @param string $charset A character set
735
     *
736
     * @return string A character set declaration
737
     */
738
    public function getCharsetFieldDeclaration($charset)
739
    {
740
        return $this->conn->dataDict->getCharsetFieldDeclaration($charset);
741
    }
742
 
743
    /**
744
     * Returns a collation declaration.
745
     *
746
     * @param string $collation A collation
747
     *
748
     * @return string A collation declaration
749
     */
750
    public function getCollationFieldDeclaration($collation)
751
    {
752
        return $this->conn->dataDict->getCollationFieldDeclaration($collation);
753
    }
754
 
755
    /**
756
     * getAdvancedForeignKeyOptions
757
     * Return the FOREIGN KEY query section dealing with non-standard options
758
     * as MATCH, INITIALLY DEFERRED, ON UPDATE, ...
759
     *
760
     * @param array $definition
761
     * @return string
762
     */
763
    public function getAdvancedForeignKeyOptions(array $definition)
764
    {
765
        $query = '';
766
        if ( ! empty($definition['match'])) {
767
            $query .= ' MATCH ' . $definition['match'];
768
        }
769
        if ( ! empty($definition['onUpdate'])) {
770
            $query .= ' ON UPDATE ' . $this->getForeignKeyReferentialAction($definition['onUpdate']);
771
        }
772
        if ( ! empty($definition['onDelete'])) {
773
            $query .= ' ON DELETE ' . $this->getForeignKeyReferentialAction($definition['onDelete']);
774
        }
775
        return $query;
776
    }
777
 
778
    /**
779
     * drop existing index
780
     *
781
     * @param string    $table          name of table that should be used in method
782
     * @param string    $name           name of the index to be dropped
783
     * @return void
784
     */
785
    public function dropIndexSql($table, $name)
786
    {
787
        $table  = $this->conn->quoteIdentifier($table, true);
788
        $name   = $this->conn->quoteIdentifier($this->conn->formatter->getIndexName($name), true);
789
        return 'DROP INDEX ' . $name . ' ON ' . $table;
790
    }
791
 
792
    /**
793
     * dropTable
794
     *
795
     * @param string    $table          name of table that should be dropped from the database
796
     * @throws PDOException
797
     * @return void
798
     */
799
    public function dropTableSql($table)
800
    {
801
        $table  = $this->conn->quoteIdentifier($table, true);
802
        return 'DROP TABLE ' . $table;
803
    }
804
 
805
    /**
806
     * drop existing foreign key
807
     *
808
     * @param string    $table        name of table that should be used in method
809
     * @param string    $name         name of the foreign key to be dropped
810
     * @return void
811
     */
812
    public function dropForeignKey($table, $name)
813
    {
814
        $table = $this->conn->quoteIdentifier($table);
815
        $name  = $this->conn->quoteIdentifier($this->conn->formatter->getForeignKeyName($name));
816
 
817
        return $this->conn->exec('ALTER TABLE ' . $table . ' DROP FOREIGN KEY ' . $name);
818
    }
819
}