thomascube
2006-03-04 f5121b5639992fc9e51fd551bac2254429b638fa
commit | author | age
c9462d 1 <?php
S 2 // +----------------------------------------------------------------------+
3 // | PHP versions 4 and 5                                                 |
4 // +----------------------------------------------------------------------+
5 // | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox,                 |
6 // | Stig. S. Bakken, Lukas Smith, Frank M. Kromann                       |
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$
46 //
47
48 require_once 'MDB2/Driver/Manager/Common.php';
49
50 /**
51  * MDB2 FrontBase driver for the management modules
52  *
53  * @package MDB2
54  * @category Database
55  * @author  Frank M. Kromann <frank@kromann.info>
56  */
57 class MDB2_Driver_Manager_fbsql extends MDB2_Driver_Manager_Common
58 {
59     // {{{ createDatabase()
60
61     /**
62      * create a new database
63      *
64      * @param string $name name of the database that should be created
65      * @return mixed MDB2_OK on success, a MDB2 error on failure
66      * @access public
67      */
68     function createDatabase($name)
69     {
70         $db =& $this->getDBInstance();
71         if (PEAR::isError($db)) {
72             return $db;
73         }
74
75         if (PEAR::isError($result = $db->connect())) {
76             return $result;
77         }
78         $query = "CREATE DATABASE $name";
79         if (PEAR::isError($result = $db->query($query))) {
80             return $result;
81         }
82
83         return MDB2_OK;
84     }
85
86     // }}}
87     // {{{ dropDatabase()
88
89     /**
90      * drop an existing database
91      *
92      * @param string $name name of the database that should be dropped
93      * @return mixed MDB2_OK on success, a MDB2 error on failure
94      * @access public
95      */
96     function dropDatabase($name)
97     {
98         $db =& $this->getDBInstance();
99         if (PEAR::isError($db)) {
100             return $db;
101         }
102
103         if (PEAR::isError($result = $db->connect())) {
104             return $result;
105         }
106         $query = "DELETE DATABASE $name";
107         if (PEAR::isError($result = $db->query($query))) {
108             return $result;
109         }
110
111         return MDB2_OK;
112     }
113
114     // }}}
115     // {{{ dropTable()
116
117     /**
118      * drop an existing table
119      *
120      * @param object    $dbs        database object that is extended by this class
121      * @param string $name name of the table that should be dropped
122      * @return mixed MDB2_OK on success, a MDB2 error on failure
123      * @access public
124      */
125     function dropTable($name)
126     {
127         $db =& $this->getDBInstance();
128         if (PEAR::isError($db)) {
129             return $db;
130         }
131
132         return $db->query("DROP TABLE $name CASCADE");
133     }
134
135     // }}}
136     // {{{ alterTable()
137
138     /**
139      * alter an existing table
140      *
141      * @param string $name         name of the table that is intended to be changed.
142      * @param array $changes     associative array that contains the details of each type
143      *                             of change that is intended to be performed. The types of
144      *                             changes that are currently supported are defined as follows:
145      *
146      *                             name
147      *
148      *                                New name for the table.
149      *
150      *                            add
151      *
152      *                                Associative array with the names of fields to be added as
153      *                                 indexes of the array. The value of each entry of the array
154      *                                 should be set to another associative array with the properties
155      *                                 of the fields to be added. The properties of the fields should
156      *                                 be the same as defined by the Metabase parser.
157      *
158      *
159      *                            remove
160      *
161      *                                Associative array with the names of fields to be removed as indexes
162      *                                 of the array. Currently the values assigned to each entry are ignored.
163      *                                 An empty array should be used for future compatibility.
164      *
165      *                            rename
166      *
167      *                                Associative array with the names of fields to be renamed as indexes
168      *                                 of the array. The value of each entry of the array should be set to
169      *                                 another associative array with the entry named name with the new
170      *                                 field name and the entry named Declaration that is expected to contain
171      *                                 the portion of the field declaration already in DBMS specific SQL code
172      *                                 as it is used in the CREATE TABLE statement.
173      *
174      *                            change
175      *
176      *                                Associative array with the names of the fields to be changed as indexes
177      *                                 of the array. Keep in mind that if it is intended to change either the
178      *                                 name of a field and any other properties, the change array entries
179      *                                 should have the new names of the fields as array indexes.
180      *
181      *                                The value of each entry of the array should be set to another associative
182      *                                 array with the properties of the fields to that are meant to be changed as
183      *                                 array entries. These entries should be assigned to the new values of the
184      *                                 respective properties. The properties of the fields should be the same
185      *                                 as defined by the Metabase parser.
186      *
187      *                            Example
188      *                                array(
189      *                                    'name' => 'userlist',
190      *                                    'add' => array(
191      *                                        'quota' => array(
192      *                                            'type' => 'integer',
193      *                                            'unsigned' => 1
194      *                                        )
195      *                                    ),
196      *                                    'remove' => array(
197      *                                        'file_limit' => array(),
198      *                                        'time_limit' => array()
199      *                                        ),
200      *                                    'change' => array(
201      *                                        'gender' => array(
202      *                                            'default' => 'M',
203      *                                        )
204      *                                    ),
205      *                                    'rename' => array(
206      *                                        'sex' => array(
207      *                                            'name' => 'gender',
208      *                                        )
209      *                                    )
210      *                                )
211      *
212      * @param boolean $check     indicates whether the function should just check if the DBMS driver
213      *                             can perform the requested table alterations if the value is true or
214      *                             actually perform them otherwise.
215      * @access public
216      *
217       * @return mixed MDB2_OK on success, a MDB2 error on failure
218      */
219     function alterTable($name, $changes, $check)
220     {
221         $db =& $this->getDBInstance();
222         if (PEAR::isError($db)) {
223             return $db;
224         }
225
226         foreach ($changes as $change_name => $change){
227             switch ($change_name) {
228             case 'add':
229             case 'remove':
230             case 'change':
231             case 'rename':
232             case 'name':
233                 break;
234             default:
235                 return $db->raiseError(MDB2_ERROR_CANNOT_ALTER, null, null,
236                     'alterTable: change type "'.$change_name.'" not yet supported');
237             }
238         }
239
240         if ($check) {
241             return MDB2_OK;
242         }
243
244         $query = (array_key_exists('name', $changes) ? 'RENAME AS '.$changes['name'] : '');
245
246         if (array_key_exists('add', $changes)) {
247             foreach ($changes['add'] as $field_name => $field) {
248                 $type_declaration = $db->getDeclaration($field['type'], $field_name, $field);
249                 if (PEAR::isError($type_declaration)) {
250                     return $err;
251                 }
252                 if ($query) {
253                     $query.= ', ';
254                 }
255                 $query.= 'ADD ' . $type_declaration;
256             }
257         }
258
259         if (array_key_exists('remove', $changes)) {
260             foreach ($changes['remove'] as $field_name => $field) {
261                 if ($query) {
262                     $query.= ', ';
263                 }
264                 $query.= 'DROP ' . $field_name;
265             }
266         }
267
268         $rename = array();
269         if (array_key_exists('rename', $changes)) {
270             foreach ($changes['rename'] as $field_name => $field) {
271                 $rename[$field['name']] = $field_name;
272             }
273         }
274
275         if (array_key_exists('change', $changes)) {
276             foreach ($changes['change'] as $field_name => $field) {
277                 if ($query) {
278                     $query.= ', ';
279                 }
280                 if (isset($rename[$field_name])) {
281                     $old_field_name = $rename[$field_name];
282                     unset($rename[$field_name]);
283                 } else {
284                     $old_field_name = $field_name;
285                 }
286                 $query.= "CHANGE $old_field_name " . $db->getDeclaration($field['type'], $old_field_name, $field);
287             }
288         }
289
290         if (!empty($rename)) {
291             foreach ($rename as $renamed_field_name => $renamed_field) {
292                 if ($query) {
293                     $query.= ', ';
294                 }
295                 $old_field_name = $rename[$renamed_field_name];
296                 $field = $changes['rename'][$old_field_name];
297                 $query.= 'CHANGE ' . $db->getDeclaration($field['type'], $old_field_name, $field);
298             }
299         }
300
301         if (!$query) {
302             return MDB2_OK;
303         }
304
305         return $db->query("ALTER TABLE $name $query");
306     }
307
308     // }}}
309     // {{{ listDatabases()
310
311     /**
312      * list all databases
313      *
314      * @return mixed data array on success, a MDB2 error on failure
315      * @access public
316      */
317     function listDatabases()
318     {
319         $db =& $this->getDBInstance();
320         if (PEAR::isError($db)) {
321             return $db;
322         }
323
324         return $db->raiseError(MDB2_ERROR_NOT_CAPABLE);
325     }
326
327     // }}}
328     // {{{ listUsers()
329
330     /**
331      * list all users
332      *
333      * @return mixed data array on success, a MDB2 error on failure
334      * @access public
335      */
336     function listUsers()
337     {
338         $db =& $this->getDBInstance();
339         if (PEAR::isError($db)) {
340             return $db;
341         }
342
343         return $db->queryCol('SELECT "user_name" FROM information_schema.users');
344     }
345
346     // }}}
347     // {{{ listTables()
348
349     /**
350      * list all tables in the current database
351      *
352      * @return mixed data array on success, a MDB2 error on failure
353      * @access public
354      */
355     function listTables()
356     {
357         $db =& $this->getDBInstance();
358         if (PEAR::isError($db)) {
359             return $db;
360         }
361
362         $table_names = $db->queryCol('SELECT "table_name"'
363                 . ' FROM information_schema.tables'
364                 . ' t0, information_schema.schemata t1'
365                 . ' WHERE t0.schema_pk=t1.schema_pk AND'
366                 . ' "table_type" = \'BASE TABLE\''
367                 . ' AND "schema_name" = current_schema');
368         if (PEAR::isError($table_names)) {
369             return $table_names;
370         }
371         for ($i = 0, $j = count($table_names), $tables = array(); $i < $j; ++$i) {
372             if (!$this->_isSequenceName($table_names[$i]))
373                 $tables[] = $table_names[$i];
374         }
375         return $tables;
376     }
377
378     // }}}
379     // {{{ listTableFields()
380
381     /**
382      * list all fields in a tables in the current database
383      *
384      * @param string $table name of table that should be used in method
385      * @return mixed data array on success, a MDB2 error on failure
386      * @access public
387      */
388     function listTableFields($table)
389     {
390         $db =& $this->getDBInstance();
391         if (PEAR::isError($db)) {
392             return $db;
393         }
394
395         $fields = $db->queryCol("SHOW COLUMNS FROM $table");
396         if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
397             $fields = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $fields);
398         }
399         return $fields;
400     }
401
402     // }}}
403     // {{{ createIndex()
404
405     /**
406      * get the stucture of a field into an array
407      *
408      * @param string    $table         name of the table on which the index is to be created
409      * @param string    $name         name of the index to be created
410      * @param array     $definition        associative array that defines properties of the index to be created.
411      *                                 Currently, only one property named FIELDS is supported. This property
412      *                                 is also an associative with the names of the index fields as array
413      *                                 indexes. Each entry of this array is set to another type of associative
414      *                                 array that specifies properties of the index that are specific to
415      *                                 each field.
416      *
417      *                                Currently, only the sorting property is supported. It should be used
418      *                                 to define the sorting direction of the index. It may be set to either
419      *                                 ascending or descending.
420      *
421      *                                Not all DBMS support index sorting direction configuration. The DBMS
422      *                                 drivers of those that do not support it ignore this property. Use the
423      *                                 function support() to determine whether the DBMS driver can manage indexes.
424
425      *                                 Example
426      *                                    array(
427      *                                        'fields' => array(
428      *                                            'user_name' => array(
429      *                                                'sorting' => 'ascending'
430      *                                            ),
431      *                                            'last_login' => array()
432      *                                        )
433      *                                    )
434      * @return mixed MDB2_OK on success, a MDB2 error on failure
435      * @access public
436      */
437     function createIndex($table, $name, $definition)
438     {
439         $db =& $this->getDBInstance();
440         if (PEAR::isError($db)) {
441             return $db;
442         }
443
444         $query = "CREATE ".(array_key_exists('unique', $definition) ? 'UNIQUE INDEX' : 'INDEX')." $name on $table (";
445         $query.= implode(', ', array_keys($definition['fields']));
446         $query.= ')';
447         return $db->query($query);
448     }
449
450     // }}}
451     // {{{ dropIndex()
452
453     /**
454      * drop existing index
455      *
456      * @param string    $table         name of table that should be used in method
457      * @param string    $name         name of the index to be dropped
458      * @return mixed MDB2_OK on success, a MDB2 error on failure
459      * @access public
460      */
461     function dropIndex($table, $name)
462     {
463         $db =& $this->getDBInstance();
464         if (PEAR::isError($db)) {
465             return $db;
466         }
467
468         return $db->query("ALTER TABLE $table DROP INDEX $name");
469     }
470
471     // }}}
472     // {{{ listTableIndexes()
473
474     /**
475      * list all indexes in a table
476      *
477      * @param string    $table      name of table that should be used in method
478      * @return mixed data array on success, a MDB2 error on failure
479      * @access public
480      */
481     function listTableIndexes($table)
482     {
483         $db =& $this->getDBInstance();
484         if (PEAR::isError($db)) {
485             return $db;
486         }
487
488         $key_name = 'Key_name';
489         if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
490             if ($db->options['field_case'] == CASE_LOWER) {
491                 $key_name = strtolower($key_name);
492             } else {
493                 $key_name = strtoupper($key_name);
494             }
495         }
496
497         $query = "SHOW INDEX FROM $table";
498         $indexes_all = $db->queryCol($query, 'text', $key_name);
499         if (PEAR::isError($indexes_all)) {
500             return $indexes_all;
501         }
502
503         $indexes = array_unique($indexes_all);
504
505         if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
506             $indexes = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $indexes);
507         }
508
509         return $indexes;
510     }
511
512     // }}}
513     // {{{ createSequence()
514
515     /**
516      * create sequence
517      *
518      * @param string    $seq_name     name of the sequence to be created
519      * @param string    $start         start value of the sequence; default is 1
520      * @return mixed MDB2_OK on success, a MDB2 error on failure
521      * @access public
522      */
523     function createSequence($seq_name, $start = 1)
524     {
525         $db =& $this->getDBInstance();
526         if (PEAR::isError($db)) {
527             return $db;
528         }
529
530         $sequence_name = $db->getSequenceName($seq_name);
531         $seqcol_name = $db->options['seqcol_name'];
532         $query = "CREATE TABLE $sequence_name ($seqcol_name INTEGER DEFAULT UNIQUE, PRIMARY KEY($seqcol_name))";
533         $res = $db->query($query);
534         $res = $db->query("SET UNIQUE = 1 FOR $sequence_name");
535         if (PEAR::isError($res)) {
536             return $res;
537         }
538         if ($start == 1) {
539             return MDB2_OK;
540         }
541         $res = $db->query("INSERT INTO $sequence_name ($seqcol_name) VALUES (".($start-1).')');
542         if (!PEAR::isError($res)) {
543             return MDB2_OK;
544         }
545         // Handle error
546         $result = $db->query("DROP TABLE $sequence_name");
547         if (PEAR::isError($result)) {
548             return $db->raiseError(MDB2_ERROR, null, null,
549                 'createSequence: could not drop inconsistent sequence table ('.
550                 $result->getMessage().' ('.$result->getUserinfo().'))');
551         }
552         return $db->raiseError(MDB2_ERROR, null, null,
553             'createSequence: could not create sequence table ('.
554             $res->getMessage().' ('.$res->getUserinfo().'))');
555     }
556
557     // }}}
558     // {{{ dropSequence()
559
560     /**
561      * drop existing sequence
562      *
563      * @param string    $seq_name     name of the sequence to be dropped
564      * @return mixed MDB2_OK on success, a MDB2 error on failure
565      * @access public
566      */
567     function dropSequence($seq_name)
568     {
569         $db =& $this->getDBInstance();
570         if (PEAR::isError($db)) {
571             return $db;
572         }
573
574         $sequence_name = $db->getSequenceName($seq_name);
575         return $db->query("DROP TABLE $sequence_name CASCADE");
576     }
577
578     // }}}
579     // {{{ listSequences()
580
581     /**
582      * list all sequences in the current database
583      *
584      * @return mixed data array on success, a MDB2 error on failure
585      * @access public
586      */
587     function listSequences()
588     {
589         $db =& $this->getDBInstance();
590         if (PEAR::isError($db)) {
591             return $db;
592         }
593
594         $table_names = $db->queryCol('SHOW TABLES', 'text');
595         if (PEAR::isError($table_names)) {
596             return $table_names;
597         }
598         $sequences = array();
599         for ($i = 0, $j = count($table_names); $i < $j; ++$i) {
600             if ($sqn = $this->_isSequenceName($table_names[$i]))
601                 $sequences[] = $sqn;
602         }
603         return $sequences;
604     }
605     // }}}
606 }
607
608 ?>