source: branches/dev/data/module/MDB2/Driver/Reverse/Common.php @ 15918

Revision 15918, 17.4 KB checked in by kakinaka, 19 years ago (diff)
Line 
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 <[email protected]>                           |
43// +----------------------------------------------------------------------+
44//
45// $Id: Common.php,v 1.35 2007/02/25 11:14:34 quipo Exp $
46//
47
48/**
49 * @package MDB2
50 * @category Database
51 */
52
53/**
54 * These are constants for the tableInfo-function
55 * they are bitwised or'ed. so if there are more constants to be defined
56 * in the future, adjust MDB2_TABLEINFO_FULL accordingly
57 */
58
59define('MDB2_TABLEINFO_ORDER',      1);
60define('MDB2_TABLEINFO_ORDERTABLE', 2);
61define('MDB2_TABLEINFO_FULL',       3);
62
63/**
64 * Base class for the schema reverse engineering module that is extended by each MDB2 driver
65 *
66 * @package MDB2
67 * @category Database
68 * @author  Lukas Smith <[email protected]>
69 */
70class MDB2_Driver_Reverse_Common extends MDB2_Module_Common
71{
72    // }}}
73    // {{{ getTableFieldDefinition()
74
75    /**
76     * Get the structure of a field into an array
77     *
78     * @param string    $table     name of table that should be used in method
79     * @param string    $field     name of field that should be used in method
80     * @return mixed data array on success, a MDB2 error on failure.
81     *          The returned array contains an array for each field definition,
82     *          with all or some of these indices, depending on the field data type:
83     *          [notnull] [nativetype] [length] [fixed] [default] [type] [mdb2type]
84     * @access public
85     */
86    function getTableFieldDefinition($table, $field)
87    {
88        $db =& $this->getDBInstance();
89        if (PEAR::isError($db)) {
90            return $db;
91        }
92
93        return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
94            'method not implemented', __FUNCTION__);
95    }
96
97    // }}}
98    // {{{ getTableIndexDefinition()
99
100    /**
101     * Get the structure of an index into an array
102     *
103     * @param string    $table      name of table that should be used in method
104     * @param string    $index      name of index that should be used in method
105     * @return mixed data array on success, a MDB2 error on failure
106     *          The returned array has this structure:
107     *          </pre>
108     *          array (
109     *              [fields] => array (
110     *                  [field1name] => array() // one entry per each field covered
111     *                  [field2name] => array() // by the index
112     *                  [field3name] => array(
113     *                      [sorting] => ascending
114     *                  )
115     *              )
116     *          );
117     *          </pre>
118     * @access public
119     */
120    function getTableIndexDefinition($table, $index)
121    {
122        $db =& $this->getDBInstance();
123        if (PEAR::isError($db)) {
124            return $db;
125        }
126
127        return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
128            'method not implemented', __FUNCTION__);
129    }
130
131    // }}}
132    // {{{ getTableConstraintDefinition()
133
134    /**
135     * Get the structure of an constraints into an array
136     *
137     * @param string    $table      name of table that should be used in method
138     * @param string    $index      name of index that should be used in method
139     * @return mixed data array on success, a MDB2 error on failure
140     *          The returned array has this structure:
141     *          <pre>
142     *          array (
143     *              [primary] => 1
144     *              [fields] => array (
145     *                  [field1name] => array() // one entry per each field covered
146     *                  [field2name] => array() // by the index
147     *                  [field3name] => array(
148     *                      [sorting] => ascending
149     *                  )
150     *              )
151     *          );
152     *          </pre>
153     * @access public
154     */
155    function getTableConstraintDefinition($table, $index)
156    {
157        $db =& $this->getDBInstance();
158        if (PEAR::isError($db)) {
159            return $db;
160        }
161
162        return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
163            'method not implemented', __FUNCTION__);
164    }
165
166    // }}}
167    // {{{ getSequenceDefinition()
168
169    /**
170     * Get the structure of a sequence into an array
171     *
172     * @param string    $sequence   name of sequence that should be used in method
173     * @return mixed data array on success, a MDB2 error on failure
174     *          The returned array has this structure:
175     *          <pre>
176     *          array (
177     *              [start] => n
178     *          );
179     *          </pre>
180     * @access public
181     */
182    function getSequenceDefinition($sequence)
183    {
184        $db =& $this->getDBInstance();
185        if (PEAR::isError($db)) {
186            return $db;
187        }
188
189        $start = $db->currId($sequence);
190        if (PEAR::isError($start)) {
191            return $start;
192        }
193        if ($db->supports('current_id')) {
194            $start++;
195        } else {
196            $db->warnings[] = 'database does not support getting current
197                sequence value, the sequence value was incremented';
198        }
199        $definition = array();
200        if ($start != 1) {
201            $definition = array('start' => $start);
202        }
203        return $definition;
204    }
205
206    // }}}
207    // {{{ getTriggerDefinition()
208
209    /**
210     * Get the structure of a trigger into an array
211     *
212     * EXPERIMENTAL
213     *
214     * WARNING: this function is experimental and may change the returned value
215     * at any time until labelled as non-experimental
216     *
217     * @param string    $trigger    name of trigger that should be used in method
218     * @return mixed data array on success, a MDB2 error on failure
219     *          The returned array has this structure:
220     *          <pre>
221     *          array (
222     *              [trigger_name]    => 'trigger name',
223     *              [table_name]      => 'table name',
224     *              [trigger_body]    => 'trigger body definition',
225     *              [trigger_type]    => 'BEFORE' | 'AFTER',
226     *              [trigger_event]   => 'INSERT' | 'UPDATE' | 'DELETE'
227     *                  //or comma separated list of multiple events, when supported
228     *              [trigger_enabled] => true|false
229     *              [trigger_comment] => 'trigger comment',
230     *          );
231     *          </pre>
232     *          The oci8 driver also returns a [when_clause] index.
233     * @access public
234     */
235    function getTriggerDefinition($trigger)
236    {
237        $db =& $this->getDBInstance();
238        if (PEAR::isError($db)) {
239            return $db;
240        }
241
242        return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
243            'method not implemented', __FUNCTION__);
244    }
245
246    // }}}
247    // {{{ tableInfo()
248
249    /**
250     * Returns information about a table or a result set
251     *
252     * The format of the resulting array depends on which <var>$mode</var>
253     * you select.  The sample output below is based on this query:
254     * <pre>
255     *    SELECT tblFoo.fldID, tblFoo.fldPhone, tblBar.fldId
256     *    FROM tblFoo
257     *    JOIN tblBar ON tblFoo.fldId = tblBar.fldId
258     * </pre>
259     *
260     * <ul>
261     * <li>
262     *
263     * <kbd>null</kbd> (default)
264     *   <pre>
265     *   [0] => Array (
266     *       [table] => tblFoo
267     *       [name] => fldId
268     *       [type] => int
269     *       [len] => 11
270     *       [flags] => primary_key not_null
271     *   )
272     *   [1] => Array (
273     *       [table] => tblFoo
274     *       [name] => fldPhone
275     *       [type] => string
276     *       [len] => 20
277     *       [flags] =>
278     *   )
279     *   [2] => Array (
280     *       [table] => tblBar
281     *       [name] => fldId
282     *       [type] => int
283     *       [len] => 11
284     *       [flags] => primary_key not_null
285     *   )
286     *   </pre>
287     *
288     * </li><li>
289     *
290     * <kbd>MDB2_TABLEINFO_ORDER</kbd>
291     *
292     *   <p>In addition to the information found in the default output,
293     *   a notation of the number of columns is provided by the
294     *   <samp>num_fields</samp> element while the <samp>order</samp>
295     *   element provides an array with the column names as the keys and
296     *   their location index number (corresponding to the keys in the
297     *   the default output) as the values.</p>
298     *
299     *   <p>If a result set has identical field names, the last one is
300     *   used.</p>
301     *
302     *   <pre>
303     *   [num_fields] => 3
304     *   [order] => Array (
305     *       [fldId] => 2
306     *       [fldTrans] => 1
307     *   )
308     *   </pre>
309     *
310     * </li><li>
311     *
312     * <kbd>MDB2_TABLEINFO_ORDERTABLE</kbd>
313     *
314     *   <p>Similar to <kbd>MDB2_TABLEINFO_ORDER</kbd> but adds more
315     *   dimensions to the array in which the table names are keys and
316     *   the field names are sub-keys.  This is helpful for queries that
317     *   join tables which have identical field names.</p>
318     *
319     *   <pre>
320     *   [num_fields] => 3
321     *   [ordertable] => Array (
322     *       [tblFoo] => Array (
323     *           [fldId] => 0
324     *           [fldPhone] => 1
325     *       )
326     *       [tblBar] => Array (
327     *           [fldId] => 2
328     *       )
329     *   )
330     *   </pre>
331     *
332     * </li>
333     * </ul>
334     *
335     * The <samp>flags</samp> element contains a space separated list
336     * of extra information about the field.  This data is inconsistent
337     * between DBMS's due to the way each DBMS works.
338     *   + <samp>primary_key</samp>
339     *   + <samp>unique_key</samp>
340     *   + <samp>multiple_key</samp>
341     *   + <samp>not_null</samp>
342     *
343     * Most DBMS's only provide the <samp>table</samp> and <samp>flags</samp>
344     * elements if <var>$result</var> is a table name.  The following DBMS's
345     * provide full information from queries:
346     *   + fbsql
347     *   + mysql
348     *
349     * If the 'portability' option has <samp>MDB2_PORTABILITY_FIX_CASE</samp>
350     * turned on, the names of tables and fields will be lower or upper cased.
351     *
352     * @param object|string  $result  MDB2_result object from a query or a
353     *                                string containing the name of a table.
354     *                                While this also accepts a query result
355     *                                resource identifier, this behavior is
356     *                                deprecated.
357     * @param int  $mode   either unused or one of the tableInfo modes:
358     *                     <kbd>MDB2_TABLEINFO_ORDERTABLE</kbd>,
359     *                     <kbd>MDB2_TABLEINFO_ORDER</kbd> or
360     *                     <kbd>MDB2_TABLEINFO_FULL</kbd> (which does both).
361     *                     These are bitwise, so the first two can be
362     *                     combined using <kbd>|</kbd>.
363     *
364     * @return array  an associative array with the information requested.
365     *                 A MDB2_Error object on failure.
366     *
367     * @see MDB2_Driver_Common::setOption()
368     */
369    function tableInfo($result, $mode = null)
370    {
371        $db =& $this->getDBInstance();
372        if (PEAR::isError($db)) {
373            return $db;
374        }
375
376        if (!is_string($result)) {
377            return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
378                'method not implemented', __FUNCTION__);
379        }
380
381        $db->loadModule('Manager', null, true);
382        $fields = $db->manager->listTableFields($result);
383        if (PEAR::isError($fields)) {
384            return $fields;
385        }
386
387        $flags = array();
388
389        $idxname_format = $db->getOption('idxname_format');
390        $db->setOption('idxname_format', '%s');
391
392        $indexes = $db->manager->listTableIndexes($result);
393        if (PEAR::isError($indexes)) {
394            $db->setOption('idxname_format', $idxname_format);
395            return $indexes;
396        }
397
398        foreach ($indexes as $index) {
399            $definition = $this->getTableIndexDefinition($result, $index);
400            if (PEAR::isError($definition)) {
401                $db->setOption('idxname_format', $idxname_format);
402                return $definition;
403            }
404            if (count($definition['fields']) > 1) {
405                foreach ($definition['fields'] as $field => $sort) {
406                    $flags[$field] = 'multiple_key';
407                }
408            }
409        }
410
411        $constraints = $db->manager->listTableConstraints($result);
412        if (PEAR::isError($constraints)) {
413            return $constraints;
414        }
415
416        foreach ($constraints as $constraint) {
417            $definition = $this->getTableConstraintDefinition($result, $constraint);
418            if (PEAR::isError($definition)) {
419                $db->setOption('idxname_format', $idxname_format);
420                return $definition;
421            }
422            $flag = !empty($definition['primary'])
423                ? 'primary_key' : (!empty($definition['unique'])
424                    ? 'unique_key' : false);
425            if ($flag) {
426                foreach ($definition['fields'] as $field => $sort) {
427                    if (empty($flags[$field]) || $flags[$field] != 'primary_key') {
428                        $flags[$field] = $flag;
429                    }
430                }
431            }
432        }
433
434        if ($mode) {
435            $res['num_fields'] = count($fields);
436        }
437
438        foreach ($fields as $i => $field) {
439            $definition = $this->getTableFieldDefinition($result, $field);
440            if (PEAR::isError($definition)) {
441                $db->setOption('idxname_format', $idxname_format);
442                return $definition;
443            }
444            $res[$i] = $definition[0];
445            $res[$i]['name'] = $field;
446            $res[$i]['table'] = $result;
447            $res[$i]['type'] = preg_replace('/^([a-z]+).*$/i', '\\1', trim($definition[0]['nativetype']));
448            // 'primary_key', 'unique_key', 'multiple_key'
449            $res[$i]['flags'] = empty($flags[$field]) ? '' : $flags[$field];
450            // not_null', 'unsigned', 'auto_increment', 'default_[rawencodedvalue]'
451            if (!empty($res[$i]['notnull'])) {
452                $res[$i]['flags'].= ' not_null';
453            }
454            if (!empty($res[$i]['unsigned'])) {
455                $res[$i]['flags'].= ' unsigned';
456            }
457            if (!empty($res[$i]['auto_increment'])) {
458                $res[$i]['flags'].= ' autoincrement';
459            }
460            if (!empty($res[$i]['default'])) {
461                $res[$i]['flags'].= ' default_'.rawurlencode($res[$i]['default']);
462            }
463
464            if ($mode & MDB2_TABLEINFO_ORDER) {
465                $res['order'][$res[$i]['name']] = $i;
466            }
467            if ($mode & MDB2_TABLEINFO_ORDERTABLE) {
468                $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
469            }
470        }
471
472        $db->setOption('idxname_format', $idxname_format);
473        return $res;
474    }
475}
476?>
Note: See TracBrowser for help on using the repository browser.