Subversion-Projekte lars-tiefland.php_share

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 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: Lukas Smith <smith@pooteeweet.org>                           |
43
// +----------------------------------------------------------------------+
44
//
45
// $Id: mysql.php,v 1.68 2007/03/29 18:18:06 quipo Exp $
46
//
47
 
48
require_once 'MDB2/Driver/Reverse/Common.php';
49
 
50
/**
51
 * MDB2 MySQL driver for the schema reverse engineering module
52
 *
53
 * @package MDB2
54
 * @category Database
55
 * @author  Lukas Smith <smith@pooteeweet.org>
56
 * @author  Lorenzo Alberton <l.alberton@quipo.it>
57
 */
58
class MDB2_Driver_Reverse_mysql extends MDB2_Driver_Reverse_Common
59
{
60
    // {{{ getTableFieldDefinition()
61
 
62
    /**
63
     * Get the structure of a field into an array
64
     *
65
     * @param string    $table       name of table that should be used in method
66
     * @param string    $field_name  name of field that should be used in method
67
     * @return mixed data array on success, a MDB2 error on failure
68
     * @access public
69
     */
70
    function getTableFieldDefinition($table, $field_name)
71
    {
72
        $db =& $this->getDBInstance();
73
        if (PEAR::isError($db)) {
74
            return $db;
75
        }
76
 
77
        $result = $db->loadModule('Datatype', null, true);
78
        if (PEAR::isError($result)) {
79
            return $result;
80
        }
81
        $table = $db->quoteIdentifier($table, true);
82
        $query = "SHOW COLUMNS FROM $table LIKE ".$db->quote($field_name);
83
        $columns = $db->queryAll($query, null, MDB2_FETCHMODE_ASSOC);
84
        if (PEAR::isError($columns)) {
85
            return $columns;
86
        }
87
        foreach ($columns as $column) {
88
            $column = array_change_key_case($column, CASE_LOWER);
89
            $column['name'] = $column['field'];
90
            unset($column['field']);
91
            if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
92
                if ($db->options['field_case'] == CASE_LOWER) {
93
                    $column['name'] = strtolower($column['name']);
94
                } else {
95
                    $column['name'] = strtoupper($column['name']);
96
                }
97
            } else {
98
                $column = array_change_key_case($column, $db->options['field_case']);
99
            }
100
            if ($field_name == $column['name']) {
101
                $mapped_datatype = $db->datatype->mapNativeDatatype($column);
102
                if (PEAR::IsError($mapped_datatype)) {
103
                    return $mapped_datatype;
104
                }
105
                list($types, $length, $unsigned, $fixed) = $mapped_datatype;
106
                $notnull = false;
107
                if (empty($column['null']) || $column['null'] !== 'YES') {
108
                    $notnull = true;
109
                }
110
                $default = false;
111
                if (array_key_exists('default', $column)) {
112
                    $default = $column['default'];
113
                    if (is_null($default) && $notnull) {
114
                        $default = '';
115
                    }
116
                }
117
                $autoincrement = false;
118
                if (!empty($column['extra']) && $column['extra'] == 'auto_increment') {
119
                    $autoincrement = true;
120
                }
121
 
122
                $definition[0] = array(
123
                    'notnull' => $notnull,
124
                    'nativetype' => preg_replace('/^([a-z]+)[^a-z].*/i', '\\1', $column['type'])
125
                );
126
                if (!is_null($length)) {
127
                    $definition[0]['length'] = $length;
128
                }
129
                if (!is_null($unsigned)) {
130
                    $definition[0]['unsigned'] = $unsigned;
131
                }
132
                if (!is_null($fixed)) {
133
                    $definition[0]['fixed'] = $fixed;
134
                }
135
                if ($default !== false) {
136
                    $definition[0]['default'] = $default;
137
                }
138
                if ($autoincrement !== false) {
139
                    $definition[0]['autoincrement'] = $autoincrement;
140
                }
141
                foreach ($types as $key => $type) {
142
                    $definition[$key] = $definition[0];
143
                    if ($type == 'clob' || $type == 'blob') {
144
                        unset($definition[$key]['default']);
145
                    }
146
                    $definition[$key]['type'] = $type;
147
                    $definition[$key]['mdb2type'] = $type;
148
                }
149
                return $definition;
150
            }
151
        }
152
 
153
        return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
154
            'it was not specified an existing table column', __FUNCTION__);
155
    }
156
 
157
    // }}}
158
    // {{{ getTableIndexDefinition()
159
 
160
    /**
161
     * Get the structure of an index into an array
162
     *
163
     * @param string    $table      name of table that should be used in method
164
     * @param string    $constraint_name name of constraint that should be used in method
165
     * @return mixed data array on success, a MDB2 error on failure
166
     * @access public
167
     */
168
    function getTableIndexDefinition($table, $constraint_name)
169
    {
170
        $db =& $this->getDBInstance();
171
        if (PEAR::isError($db)) {
172
            return $db;
173
        }
174
 
175
        $table = $db->quoteIdentifier($table, true);
176
        $query = "SHOW INDEX FROM $table /*!50002 WHERE Key_name = %s */";
177
        $constraint_name_mdb2 = $db->getIndexName($constraint_name);
178
        $result = $db->queryRow(sprintf($query, $db->quote($constraint_name_mdb2)));
179
        if (!PEAR::isError($result) && !is_null($result)) {
180
            // apply 'idxname_format' only if the query succeeded, otherwise
181
            // fallback to the given $index_name, without transformation
182
            $constraint_name = $constraint_name_mdb2;
183
        }
184
        $result = $db->query(sprintf($query, $db->quote($constraint_name)));
185
        if (PEAR::isError($result)) {
186
            return $result;
187
        }
188
        $colpos = 1;
189
        $definition = array();
190
        while (is_array($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC))) {
191
            $row = array_change_key_case($row, CASE_LOWER);
192
            $key_name = $row['key_name'];
193
            if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
194
                if ($db->options['field_case'] == CASE_LOWER) {
195
                    $key_name = strtolower($key_name);
196
                } else {
197
                    $key_name = strtoupper($key_name);
198
                }
199
            }
200
            if ($constraint_name == $key_name) {
201
                if (!$row['non_unique']) {
202
                    return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
203
                        $constraint_name . ' is not an existing table constraint', __FUNCTION__);
204
                }
205
                $column_name = $row['column_name'];
206
                if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
207
                    if ($db->options['field_case'] == CASE_LOWER) {
208
                        $column_name = strtolower($column_name);
209
                    } else {
210
                        $column_name = strtoupper($column_name);
211
                    }
212
                }
213
                $definition['fields'][$column_name] = array(
214
                    'position' => $colpos++
215
                );
216
                if (!empty($row['collation'])) {
217
                    $definition['fields'][$column_name]['sorting'] = ($row['collation'] == 'A'
218
                        ? 'ascending' : 'descending');
219
                }
220
            }
221
        }
222
        $result->free();
223
        if (empty($definition['fields'])) {
224
            return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
225
                $constraint_name . ' is not an existing table constraint', __FUNCTION__);
226
        }
227
        return $definition;
228
    }
229
 
230
    // }}}
231
    // {{{ getTableConstraintDefinition()
232
 
233
    /**
234
     * Get the structure of a constraint into an array
235
     *
236
     * @param string    $table      name of table that should be used in method
237
     * @param string    $index_name name of index that should be used in method
238
     * @return mixed data array on success, a MDB2 error on failure
239
     * @access public
240
     */
241
    function getTableConstraintDefinition($table, $index_name)
242
    {
243
        $db =& $this->getDBInstance();
244
        if (PEAR::isError($db)) {
245
            return $db;
246
        }
247
 
248
        $table = $db->quoteIdentifier($table, true);
249
        $query = "SHOW INDEX FROM $table /*!50002 WHERE Key_name = %s */";
250
        if (strtolower($index_name) != 'primary') {
251
            $index_name_mdb2 = $db->getIndexName($index_name);
252
            $result = $db->queryRow(sprintf($query, $db->quote($index_name_mdb2)));
253
            if (!PEAR::isError($result) && !is_null($result)) {
254
                // apply 'idxname_format' only if the query succeeded, otherwise
255
                // fallback to the given $index_name, without transformation
256
                $index_name = $index_name_mdb2;
257
            }
258
        }
259
        $result = $db->query(sprintf($query, $db->quote($index_name)));
260
        if (PEAR::isError($result)) {
261
            return $result;
262
        }
263
        $colpos = 1;
264
        $definition = array();
265
        while (is_array($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC))) {
266
            $row = array_change_key_case($row, CASE_LOWER);
267
            $key_name = $row['key_name'];
268
            if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
269
                if ($db->options['field_case'] == CASE_LOWER) {
270
                    $key_name = strtolower($key_name);
271
                } else {
272
                    $key_name = strtoupper($key_name);
273
                }
274
            }
275
            if ($index_name == $key_name) {
276
                if ($row['non_unique']) {
277
                    return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
278
                        'it was not specified an existing table constraint', __FUNCTION__);
279
                }
280
                if ($row['key_name'] == 'PRIMARY') {
281
                    $definition['primary'] = true;
282
                } else {
283
                    $definition['unique'] = true;
284
                }
285
                $column_name = $row['column_name'];
286
                if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
287
                    if ($db->options['field_case'] == CASE_LOWER) {
288
                        $column_name = strtolower($column_name);
289
                    } else {
290
                        $column_name = strtoupper($column_name);
291
                    }
292
                }
293
                $definition['fields'][$column_name] = array(
294
                    'position' => $colpos++
295
                );
296
                if (!empty($row['collation'])) {
297
                    $definition['fields'][$column_name]['sorting'] = ($row['collation'] == 'A'
298
                        ? 'ascending' : 'descending');
299
                }
300
            }
301
        }
302
        $result->free();
303
        if (empty($definition['fields'])) {
304
            return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
305
                'it was not specified an existing table constraint', __FUNCTION__);
306
        }
307
        return $definition;
308
    }
309
 
310
    // }}}
311
    // {{{ getTriggerDefinition()
312
 
313
    /**
314
     * Get the structure of a trigger into an array
315
     *
316
     * EXPERIMENTAL
317
     *
318
     * WARNING: this function is experimental and may change the returned value
319
     * at any time until labelled as non-experimental
320
     *
321
     * @param string    $trigger    name of trigger that should be used in method
322
     * @return mixed data array on success, a MDB2 error on failure
323
     * @access public
324
     */
325
    function getTriggerDefinition($trigger)
326
    {
327
        $db =& $this->getDBInstance();
328
        if (PEAR::isError($db)) {
329
            return $db;
330
        }
331
 
332
        $query = 'SELECT trigger_name,
333
                         event_object_table AS table_name,
334
                         action_statement AS trigger_body,
335
                         action_timing AS trigger_type,
336
                         event_manipulation AS trigger_event
337
                    FROM information_schema.triggers
338
                   WHERE trigger_name = '. $db->quote($trigger, 'text');
339
        $types = array(
340
            'trigger_name'    => 'text',
341
            'table_name'      => 'text',
342
            'trigger_body'    => 'text',
343
            'trigger_type'    => 'text',
344
            'trigger_event'   => 'text',
345
        );
346
        $def = $db->queryRow($query, $types, MDB2_FETCHMODE_ASSOC);
347
        if (PEAR::isError($def)) {
348
            return $def;
349
        }
350
        $def['trigger_comment'] = '';
351
        $def['trigger_enabled'] = true;
352
        return $def;
353
    }
354
 
355
    // }}}
356
    // {{{ tableInfo()
357
 
358
    /**
359
     * Returns information about a table or a result set
360
     *
361
     * @param object|string  $result  MDB2_result object from a query or a
362
     *                                 string containing the name of a table.
363
     *                                 While this also accepts a query result
364
     *                                 resource identifier, this behavior is
365
     *                                 deprecated.
366
     * @param int            $mode    a valid tableInfo mode
367
     *
368
     * @return array  an associative array with the information requested.
369
     *                 A MDB2_Error object on failure.
370
     *
371
     * @see MDB2_Driver_Common::setOption()
372
     */
373
    function tableInfo($result, $mode = null)
374
    {
375
        if (is_string($result)) {
376
           return parent::tableInfo($result, $mode);
377
        }
378
 
379
        $db =& $this->getDBInstance();
380
        if (PEAR::isError($db)) {
381
            return $db;
382
        }
383
 
384
        $resource = MDB2::isResultCommon($result) ? $result->getResource() : $result;
385
        if (!is_resource($resource)) {
386
            return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null,
387
                'Could not generate result resource', __FUNCTION__);
388
        }
389
 
390
        if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
391
            if ($db->options['field_case'] == CASE_LOWER) {
392
                $case_func = 'strtolower';
393
            } else {
394
                $case_func = 'strtoupper';
395
            }
396
        } else {
397
            $case_func = 'strval';
398
        }
399
 
400
        $count = @mysql_num_fields($resource);
401
        $res   = array();
402
 
403
        if ($mode) {
404
            $res['num_fields'] = $count;
405
        }
406
 
407
        $db->loadModule('Datatype', null, true);
408
        for ($i = 0; $i < $count; $i++) {
409
            $res[$i] = array(
410
                'table' => $case_func(@mysql_field_table($resource, $i)),
411
                'name'  => $case_func(@mysql_field_name($resource, $i)),
412
                'type'  => @mysql_field_type($resource, $i),
413
                'length'   => @mysql_field_len($resource, $i),
414
                'flags' => @mysql_field_flags($resource, $i),
415
            );
416
            if ($res[$i]['type'] == 'string') {
417
                $res[$i]['type'] = 'char';
418
            } elseif ($res[$i]['type'] == 'unknown') {
419
                $res[$i]['type'] = 'decimal';
420
            }
421
            $mdb2type_info = $db->datatype->mapNativeDatatype($res[$i]);
422
            if (PEAR::isError($mdb2type_info)) {
423
               return $mdb2type_info;
424
            }
425
            $res[$i]['mdb2type'] = $mdb2type_info[0][0];
426
            if ($mode & MDB2_TABLEINFO_ORDER) {
427
                $res['order'][$res[$i]['name']] = $i;
428
            }
429
            if ($mode & MDB2_TABLEINFO_ORDERTABLE) {
430
                $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
431
            }
432
        }
433
 
434
        return $res;
435
    }
436
}
437
?>