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-2006 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: mysqli.php,v 1.59 2007/03/29 18:18:06 quipo Exp $
46
//
47
 
48
require_once 'MDB2/Driver/Reverse/Common.php';
49
 
50
/**
51
 * MDB2 MySQLi 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_mysqli extends MDB2_Driver_Reverse_Common
59
{
60
    /**
61
     * Array for converting MYSQLI_*_FLAG constants to text values
62
     * @var    array
63
     * @access public
64
     */
65
    var $flags = array(
66
        MYSQLI_NOT_NULL_FLAG        => 'not_null',
67
        MYSQLI_PRI_KEY_FLAG         => 'primary_key',
68
        MYSQLI_UNIQUE_KEY_FLAG      => 'unique_key',
69
        MYSQLI_MULTIPLE_KEY_FLAG    => 'multiple_key',
70
        MYSQLI_BLOB_FLAG            => 'blob',
71
        MYSQLI_UNSIGNED_FLAG        => 'unsigned',
72
        MYSQLI_ZEROFILL_FLAG        => 'zerofill',
73
        MYSQLI_AUTO_INCREMENT_FLAG  => 'auto_increment',
74
        MYSQLI_TIMESTAMP_FLAG       => 'timestamp',
75
        MYSQLI_SET_FLAG             => 'set',
76
        // MYSQLI_NUM_FLAG             => 'numeric',  // unnecessary
77
        // MYSQLI_PART_KEY_FLAG        => 'multiple_key',  // duplicatvie
78
        MYSQLI_GROUP_FLAG           => 'group_by'
79
    );
80
 
81
    /**
82
     * Array for converting MYSQLI_TYPE_* constants to text values
83
     * @var    array
84
     * @access public
85
     */
86
    var $types = array(
87
        MYSQLI_TYPE_DECIMAL     => 'decimal',
88
        246                     => 'decimal',
89
        MYSQLI_TYPE_TINY        => 'tinyint',
90
        MYSQLI_TYPE_SHORT       => 'int',
91
        MYSQLI_TYPE_LONG        => 'int',
92
        MYSQLI_TYPE_FLOAT       => 'float',
93
        MYSQLI_TYPE_DOUBLE      => 'double',
94
        // MYSQLI_TYPE_NULL        => 'DEFAULT NULL',  // let flags handle it
95
        MYSQLI_TYPE_TIMESTAMP   => 'timestamp',
96
        MYSQLI_TYPE_LONGLONG    => 'bigint',
97
        MYSQLI_TYPE_INT24       => 'mediumint',
98
        MYSQLI_TYPE_DATE        => 'date',
99
        MYSQLI_TYPE_TIME        => 'time',
100
        MYSQLI_TYPE_DATETIME    => 'datetime',
101
        MYSQLI_TYPE_YEAR        => 'year',
102
        MYSQLI_TYPE_NEWDATE     => 'date',
103
        MYSQLI_TYPE_ENUM        => 'enum',
104
        MYSQLI_TYPE_SET         => 'set',
105
        MYSQLI_TYPE_TINY_BLOB   => 'tinyblob',
106
        MYSQLI_TYPE_MEDIUM_BLOB => 'mediumblob',
107
        MYSQLI_TYPE_LONG_BLOB   => 'longblob',
108
        MYSQLI_TYPE_BLOB        => 'blob',
109
        MYSQLI_TYPE_VAR_STRING  => 'varchar',
110
        MYSQLI_TYPE_STRING      => 'char',
111
        MYSQLI_TYPE_GEOMETRY    => 'geometry',
112
    );
113
 
114
    // {{{ getTableFieldDefinition()
115
 
116
    /**
117
     * Get the structure of a field into an array
118
     *
119
     * @param string    $table       name of table that should be used in method
120
     * @param string    $field_name  name of field that should be used in method
121
     * @return mixed data array on success, a MDB2 error on failure
122
     * @access public
123
     */
124
    function getTableFieldDefinition($table, $field_name)
125
    {
126
        $db =& $this->getDBInstance();
127
        if (PEAR::isError($db)) {
128
            return $db;
129
        }
130
 
131
        $result = $db->loadModule('Datatype', null, true);
132
        if (PEAR::isError($result)) {
133
            return $result;
134
        }
135
        $table = $db->quoteIdentifier($table, true);
136
        $query = "SHOW COLUMNS FROM $table LIKE ".$db->quote($field_name);
137
        $columns = $db->queryAll($query, null, MDB2_FETCHMODE_ASSOC);
138
        if (PEAR::isError($columns)) {
139
            return $columns;
140
        }
141
        foreach ($columns as $column) {
142
            $column = array_change_key_case($column, CASE_LOWER);
143
            $column['name'] = $column['field'];
144
            unset($column['field']);
145
            if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
146
                if ($db->options['field_case'] == CASE_LOWER) {
147
                    $column['name'] = strtolower($column['name']);
148
                } else {
149
                    $column['name'] = strtoupper($column['name']);
150
                }
151
            } else {
152
                $column = array_change_key_case($column, $db->options['field_case']);
153
            }
154
            if ($field_name == $column['name']) {
155
                $mapped_datatype = $db->datatype->mapNativeDatatype($column);
156
                if (PEAR::IsError($mapped_datatype)) {
157
                    return $mapped_datatype;
158
                }
159
                list($types, $length, $unsigned, $fixed) = $mapped_datatype;
160
                $notnull = false;
161
                if (empty($column['null']) || $column['null'] !== 'YES') {
162
                    $notnull = true;
163
                }
164
                $default = false;
165
                if (array_key_exists('default', $column)) {
166
                    $default = $column['default'];
167
                    if (is_null($default) && $notnull) {
168
                        $default = '';
169
                    }
170
                }
171
                $autoincrement = false;
172
                if (!empty($column['extra']) && $column['extra'] == 'auto_increment') {
173
                    $autoincrement = true;
174
                }
175
 
176
                $definition[0] = array(
177
                    'notnull' => $notnull,
178
                    'nativetype' => preg_replace('/^([a-z]+)[^a-z].*/i', '\\1', $column['type'])
179
                );
180
                if (!is_null($length)) {
181
                    $definition[0]['length'] = $length;
182
                }
183
                if (!is_null($unsigned)) {
184
                    $definition[0]['unsigned'] = $unsigned;
185
                }
186
                if (!is_null($fixed)) {
187
                    $definition[0]['fixed'] = $fixed;
188
                }
189
                if ($default !== false) {
190
                    $definition[0]['default'] = $default;
191
                }
192
                if ($autoincrement !== false) {
193
                    $definition[0]['autoincrement'] = $autoincrement;
194
                }
195
                foreach ($types as $key => $type) {
196
                    $definition[$key] = $definition[0];
197
                    if ($type == 'clob' || $type == 'blob') {
198
                        unset($definition[$key]['default']);
199
                    }
200
                    $definition[$key]['type'] = $type;
201
                    $definition[$key]['mdb2type'] = $type;
202
                }
203
                return $definition;
204
            }
205
        }
206
 
207
        return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
208
            'it was not specified an existing table column', __FUNCTION__);
209
    }
210
 
211
    // }}}
212
    // {{{ getTableIndexDefinition()
213
 
214
    /**
215
     * Get the structure of an index into an array
216
     *
217
     * @param string    $table      name of table that should be used in method
218
     * @param string    $index_name name of index that should be used in method
219
     * @return mixed data array on success, a MDB2 error on failure
220
     * @access public
221
     */
222
    function getTableIndexDefinition($table, $index_name)
223
    {
224
        $db =& $this->getDBInstance();
225
        if (PEAR::isError($db)) {
226
            return $db;
227
        }
228
 
229
        $table = $db->quoteIdentifier($table, true);
230
        $query = "SHOW INDEX FROM $table /*!50002 WHERE Key_name = %s */";
231
        $index_name_mdb2 = $db->getIndexName($index_name);
232
        $result = $db->queryRow(sprintf($query, $db->quote($index_name_mdb2)));
233
        if (!PEAR::isError($result) && !is_null($result)) {
234
            // apply 'idxname_format' only if the query succeeded, otherwise
235
            // fallback to the given $index_name, without transformation
236
            $index_name = $index_name_mdb2;
237
        }
238
        $result = $db->query(sprintf($query, $db->quote($index_name)));
239
        if (PEAR::isError($result)) {
240
            return $result;
241
        }
242
        $colpos = 1;
243
        $definition = array();
244
        while (is_array($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC))) {
245
            $row = array_change_key_case($row, CASE_LOWER);
246
            $key_name = $row['key_name'];
247
            if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
248
                if ($db->options['field_case'] == CASE_LOWER) {
249
                    $key_name = strtolower($key_name);
250
                } else {
251
                    $key_name = strtoupper($key_name);
252
                }
253
            }
254
            if ($index_name == $key_name) {
255
                if (!$row['non_unique']) {
256
                    return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
257
                        'it was not specified an existing table index', __FUNCTION__);
258
                }
259
                $column_name = $row['column_name'];
260
                if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
261
                    if ($db->options['field_case'] == CASE_LOWER) {
262
                        $column_name = strtolower($column_name);
263
                    } else {
264
                        $column_name = strtoupper($column_name);
265
                    }
266
                }
267
                $definition['fields'][$column_name] = array(
268
                    'position' => $colpos++
269
                );
270
                if (!empty($row['collation'])) {
271
                    $definition['fields'][$column_name]['sorting'] = ($row['collation'] == 'A'
272
                        ? 'ascending' : 'descending');
273
                }
274
            }
275
        }
276
        $result->free();
277
        if (empty($definition['fields'])) {
278
            return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
279
                'it was not specified an existing table index', __FUNCTION__);
280
        }
281
        return $definition;
282
    }
283
 
284
    // }}}
285
    // {{{ getTableConstraintDefinition()
286
 
287
    /**
288
     * Get the structure of a constraint into an array
289
     *
290
     * @param string    $table      name of table that should be used in method
291
     * @param string    $constraint_name name of constraint that should be used in method
292
     * @return mixed data array on success, a MDB2 error on failure
293
     * @access public
294
     */
295
    function getTableConstraintDefinition($table, $constraint_name)
296
    {
297
        $db =& $this->getDBInstance();
298
        if (PEAR::isError($db)) {
299
            return $db;
300
        }
301
 
302
        $table = $db->quoteIdentifier($table, true);
303
        $query = "SHOW INDEX FROM $table /*!50002 WHERE Key_name = %s */";
304
        if (strtolower($constraint_name) != 'primary') {
305
            $constraint_name_mdb2 = $db->getIndexName($constraint_name);
306
            $result = $db->queryRow(sprintf($query, $db->quote($constraint_name_mdb2)));
307
            if (!PEAR::isError($result) && !is_null($result)) {
308
                // apply 'idxname_format' only if the query succeeded, otherwise
309
                // fallback to the given $index_name, without transformation
310
                $constraint_name = $constraint_name_mdb2;
311
            }
312
        }
313
        $result = $db->query(sprintf($query, $db->quote($constraint_name)));
314
        if (PEAR::isError($result)) {
315
            return $result;
316
        }
317
        $colpos = 1;
318
        $definition = array();
319
        while (is_array($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC))) {
320
            $row = array_change_key_case($row, CASE_LOWER);
321
            $key_name = $row['key_name'];
322
            if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
323
                if ($db->options['field_case'] == CASE_LOWER) {
324
                    $key_name = strtolower($key_name);
325
                } else {
326
                    $key_name = strtoupper($key_name);
327
                }
328
            }
329
            if ($constraint_name == $key_name) {
330
                if ($row['non_unique']) {
331
                    return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
332
                        $constraint_name . ' is not an existing table constraint', __FUNCTION__);
333
                }
334
                if ($row['key_name'] == 'PRIMARY') {
335
                    $definition['primary'] = true;
336
                } else {
337
                    $definition['unique'] = true;
338
                }
339
                $column_name = $row['column_name'];
340
                if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
341
                    if ($db->options['field_case'] == CASE_LOWER) {
342
                        $column_name = strtolower($column_name);
343
                    } else {
344
                        $column_name = strtoupper($column_name);
345
                    }
346
                }
347
                $definition['fields'][$column_name] = array(
348
                    'position' => $colpos++
349
                );
350
                if (!empty($row['collation'])) {
351
                    $definition['fields'][$column_name]['sorting'] = ($row['collation'] == 'A'
352
                        ? 'ascending' : 'descending');
353
                }
354
            }
355
        }
356
        $result->free();
357
        if (empty($definition['fields'])) {
358
            return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
359
                $constraint_name . ' is not an existing table constraint', __FUNCTION__);
360
        }
361
        return $definition;
362
    }
363
 
364
    // }}}
365
    // {{{ getTriggerDefinition()
366
 
367
    /**
368
     * Get the structure of a trigger into an array
369
     *
370
     * EXPERIMENTAL
371
     *
372
     * WARNING: this function is experimental and may change the returned value
373
     * at any time until labelled as non-experimental
374
     *
375
     * @param string    $trigger    name of trigger that should be used in method
376
     * @return mixed data array on success, a MDB2 error on failure
377
     * @access public
378
     */
379
    function getTriggerDefinition($trigger)
380
    {
381
        $db =& $this->getDBInstance();
382
        if (PEAR::isError($db)) {
383
            return $db;
384
        }
385
 
386
        $query = 'SELECT trigger_name,
387
                         event_object_table AS table_name,
388
                         action_statement AS trigger_body,
389
                         action_timing AS trigger_type,
390
                         event_manipulation AS trigger_event
391
                    FROM information_schema.triggers
392
                   WHERE trigger_name = '. $db->quote($trigger, 'text');
393
        $types = array(
394
            'trigger_name'    => 'text',
395
            'table_name'      => 'text',
396
            'trigger_body'    => 'text',
397
            'trigger_type'    => 'text',
398
            'trigger_event'   => 'text',
399
        );
400
        $def = $db->queryRow($query, $types, MDB2_FETCHMODE_ASSOC);
401
        if (PEAR::isError($def)) {
402
            return $def;
403
        }
404
        $def['trigger_comment'] = '';
405
        $def['trigger_enabled'] = true;
406
        return $def;
407
    }
408
 
409
    // }}}
410
    // {{{ tableInfo()
411
 
412
    /**
413
     * Returns information about a table or a result set
414
     *
415
     * @param object|string  $result  MDB2_result object from a query or a
416
     *                                 string containing the name of a table.
417
     *                                 While this also accepts a query result
418
     *                                 resource identifier, this behavior is
419
     *                                 deprecated.
420
     * @param int            $mode    a valid tableInfo mode
421
     *
422
     * @return array  an associative array with the information requested.
423
     *                 A MDB2_Error object on failure.
424
     *
425
     * @see MDB2_Driver_Common::setOption()
426
     */
427
    function tableInfo($result, $mode = null)
428
    {
429
        if (is_string($result)) {
430
           return parent::tableInfo($result, $mode);
431
        }
432
 
433
        $db =& $this->getDBInstance();
434
        if (PEAR::isError($db)) {
435
            return $db;
436
        }
437
 
438
        $resource = MDB2::isResultCommon($result) ? $result->getResource() : $result;
439
        if (!is_object($resource)) {
440
            return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null,
441
                'Could not generate result resource', __FUNCTION__);
442
        }
443
 
444
        if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
445
            if ($db->options['field_case'] == CASE_LOWER) {
446
                $case_func = 'strtolower';
447
            } else {
448
                $case_func = 'strtoupper';
449
            }
450
        } else {
451
            $case_func = 'strval';
452
        }
453
 
454
        $count = @mysqli_num_fields($resource);
455
        $res = array();
456
        if ($mode) {
457
            $res['num_fields'] = $count;
458
        }
459
 
460
        $db->loadModule('Datatype', null, true);
461
        for ($i = 0; $i < $count; $i++) {
462
            $tmp = @mysqli_fetch_field($resource);
463
 
464
            $flags = '';
465
            foreach ($this->flags as $const => $means) {
466
                if ($tmp->flags & $const) {
467
                    $flags.= $means . ' ';
468
                }
469
            }
470
            if ($tmp->def) {
471
                $flags.= 'default_' . rawurlencode($tmp->def);
472
            }
473
            $flags = trim($flags);
474
 
475
            $res[$i] = array(
476
                'table'  => $case_func($tmp->table),
477
                'name'   => $case_func($tmp->name),
478
                'type'   => isset($this->types[$tmp->type])
479
                    ? $this->types[$tmp->type] : 'unknown',
480
                // http://bugs.php.net/?id=36579
481
                'length' => $tmp->length,
482
                'flags'  => $flags,
483
            );
484
            $mdb2type_info = $db->datatype->mapNativeDatatype($res[$i]);
485
            if (PEAR::isError($mdb2type_info)) {
486
               return $mdb2type_info;
487
            }
488
            $res[$i]['mdb2type'] = $mdb2type_info[0][0];
489
            if ($mode & MDB2_TABLEINFO_ORDER) {
490
                $res['order'][$res[$i]['name']] = $i;
491
            }
492
            if ($mode & MDB2_TABLEINFO_ORDERTABLE) {
493
                $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
494
            }
495
        }
496
 
497
        return $res;
498
    }
499
}
500
?>