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