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                                         |
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@backendmedia.com>                         |
43 // +----------------------------------------------------------------------+
44 //
45 // $Id$
46 //
47
48 require_once 'MDB2/Driver/Reverse/Common.php';
49
50 /**
51  * MDB2 SQlite driver for the schema reverse engineering module
52  *
53  * @package MDB2
54  * @category Database
55  * @author  Lukas Smith <smith@backendmedia.com>
56  */
57 class MDB2_Driver_Reverse_sqlite extends MDB2_Driver_Reverse_Common
58 {
59
60     function _getTableColumns($query)
61     {
62         $start_pos = strpos($query, '(');
63         $end_pos = strrpos($query, ')');
64         $column_def = substr($query, $start_pos+1, $end_pos-$start_pos-1);
65         $column_sql = split(',', $column_def);
66         $columns = array();
67         $count = count($column_sql);
68         if ($count == 0) {
69             return $db->raiseError('unexpected empty table column definition list');
70         }
71         $regexp = '/^([^ ]+) (CHAR|VARCHAR|VARCHAR2|TEXT|INT|INTEGER|BIGINT|DOUBLE|FLOAT|DATETIME|DATE|TIME|LONGTEXT|LONGBLOB)( PRIMARY)?( \(([1-9][0-9]*)(,([1-9][0-9]*))?\))?( DEFAULT (\'[^\']*\'|[^ ]+))?( NOT NULL)?$/i';
72         for ($i=0, $j=0; $i<$count; ++$i) {
73             if (!preg_match($regexp, $column_sql[$i], $matches)) {
74                 return $db->raiseError('unexpected table column SQL definition');
75             }
76             $columns[$j]['name'] = $matches[1];
77             $columns[$j]['type'] = strtolower($matches[2]);
78             if (isset($matches[5]) && strlen($matches[5])) {
79                 $columns[$j]['length'] = $matches[5];
80             }
81             if (isset($matches[7]) && strlen($matches[7])) {
82                 $columns[$j]['decimal'] = $matches[7];
83             }
84             if (isset($matches[9]) && strlen($matches[9])) {
85                 $default = $matches[9];
86                 if (strlen($default) && $default[0]=="'") {
87                     $default = str_replace("''", "'", substr($default, 1, strlen($default)-2));
88                 }
89                 $columns[$j]['default'] = $default;
90             }
91             if (isset($matches[10]) && strlen($matches[10])) {
92                 $columns[$j]['notnull'] = true;
93             }
94             ++$j;
95         }
96         return $columns;
97     }
98
99     // {{{ getTableFieldDefinition()
100
101     /**
102      * get the stucture of a field into an array
103      *
104      * @param string    $table         name of table that should be used in method
105      * @param string    $field_name     name of field that should be used in method
106      * @return mixed data array on success, a MDB2 error on failure
107      * @access public
108      */
109     function getTableFieldDefinition($table, $field_name)
110     {
111         $db =& $GLOBALS['_MDB2_databases'][$this->db_index];
112         $result = $db->loadModule('Datatype');
113         if (PEAR::isError($result)) {
114             return $result;
115         }
116         $query = "SELECT sql FROM sqlite_master WHERE type='table' AND name='$table'";
117         $query = $db->queryOne($query);
118         if (PEAR::isError($query)) {
119             return $query;
120         }
121         if (PEAR::isError($columns = $this->_getTableColumns($query))) {
122             return $columns;
123         }
124         foreach ($columns as $column) {
125             if ($db->options['portability'] & MDB2_PORTABILITY_LOWERCASE) {
126                 $column['name'] = strtolower($column['name']);
127             } else {
128                 $column = array_change_key_case($column, CASE_LOWER);
129             }
130             if ($field_name == $column['name']) {
131                 list($types, $length) = $db->datatype->mapNativeDatatype($column);
132                 unset($notnull);
133                 if (isset($column['null']) && $column['null'] != 'YES') {
134                     $notnull = true;
135                 }
136                 unset($default);
137                 if (isset($column['default'])) {
138                     $default = $column['default'];
139                 }
140                 $definition = array();
141                 foreach ($types as $key => $type) {
142                     $definition[0][$key] = array('type' => $type);
143                     if (isset($notnull)) {
144                         $definition[0][$key]['notnull'] = true;
145                     }
146                     if (isset($default)) {
147                         $definition[0][$key]['default'] = $default;
148                     }
149                     if (isset($length)) {
150                         $definition[0][$key]['length'] = $length;
151                     }
152                 }
153                 // todo .. handle auto_inrement and primary keys
154                 return $definition;
155             }
156         }
157
158         return $db->raiseError(MDB2_ERROR, null, null,
159             'getTableFieldDefinition: it was not specified an existing table column');
160     }
161
162     // }}}
163     // {{{ getTableIndexDefinition()
164
165     /**
166      * get the stucture of an index into an array
167      *
168      * @param string    $table      name of table that should be used in method
169      * @param string    $index_name name of index that should be used in method
170      * @return mixed data array on success, a MDB2 error on failure
171      * @access public
172      */
173     function getTableIndexDefinition($table, $index_name)
174     {
175         $db =& $GLOBALS['_MDB2_databases'][$this->db_index];
176         if ($index_name == 'PRIMARY') {
177             return $db->raiseError(MDB2_ERROR, null, null,
178                 'getTableIndexDefinition: PRIMARY is an hidden index');
179         }
180         $query = "SELECT sql FROM sqlite_master WHERE type='index' AND name='$index_name' AND tbl_name='$table' AND sql NOT NULL ORDER BY name";
181         $result = $db->query($query);
182         if (PEAR::isError($result)) {
183             return $result;
184         }
185         $columns = $result->getColumnNames();
186         $column = 'sql';
187         if (!isset($columns[$column])) {
188             $result->free();
189             return $db->raiseError('getTableIndexDefinition: show index does not return the table creation sql');
190         }
191
192         $query = strtolower($result->fetchOne());
193         $unique = strstr($query, ' unique ');
194         $key_name = $index_name;
195         $start_pos = strpos($query, '(');
196         $end_pos = strrpos($query, ')');
197         $column_names = substr($query, $start_pos+1, $end_pos-$start_pos-1);
198         $column_names = split(',', $column_names);
199
200         $definition = array();
201         if ($unique) {
202             $definition['unique'] = true;
203         }
204         $count = count($column_names);
205         for ($i=0; $i<$count; ++$i) {
206             $column_name = strtok($column_names[$i]," ");
207             $collation = strtok(" ");
208             $definition['fields'][$column_name] = array();
209             if (!empty($collation)) {
210                 $definition['fields'][$column_name]['sorting'] = ($collation=='ASC' ? 'ascending' : 'descending');
211             }
212         }
213
214         $result->free();
215         if (!isset($definition['fields'])) {
216             return $db->raiseError(MDB2_ERROR, null, null,
217                 'getTableIndexDefinition: it was not specified an existing table index');
218         }
219         return $definition;
220     }
221
222     // }}}
223     // {{{ tableInfo()
224
225     /**
226      * Returns information about a table
227      *
228      * @param string         $result  a string containing the name of a table
229      * @param int            $mode    a valid tableInfo mode
230      *
231      * @return array  an associative array with the information requested.
232      *                 A MDB2_Error object on failure.
233      *
234      * @see MDB2_common::tableInfo()
235      * @since Method available since Release 1.7.0
236      */
237     function tableInfo($result, $mode = null)
238     {
239         $db =& $GLOBALS['_MDB2_databases'][$this->db_index];
240         if (is_string($result)) {
241             /*
242              * Probably received a table name.
243              * Create a result resource identifier.
244              */
245             $id = $db->queryAll("PRAGMA table_info('$result');", null, MDB2_FETCHMODE_ASSOC);
246             $got_string = true;
247         } else {
248             return $db->raiseError(MDB2_ERROR_NOT_CAPABLE, null, null,
249                                      'This DBMS can not obtain tableInfo' .
250                                      ' from result sets');
251         }
252
253         if ($db->options['portability'] & MDB2_PORTABILITY_LOWERCASE) {
254             $case_func = 'strtolower';
255         } else {
256             $case_func = 'strval';
257         }
258
259         $count = count($id);
260         $res   = array();
261
262         if ($mode) {
263             $res['num_fields'] = $count;
264         }
265
266         for ($i = 0; $i < $count; $i++) {
267             if (strpos($id[$i]['type'], '(') !== false) {
268                 $bits = explode('(', $id[$i]['type']);
269                 $type = $bits[0];
270                 $len  = rtrim($bits[1],')');
271             } else {
272                 $type = $id[$i]['type'];
273                 $len  = 0;
274             }
275
276             $flags = '';
277             if ($id[$i]['pk']) {
278                 $flags .= 'primary_key ';
279             }
280             if ($id[$i]['notnull']) {
281                 $flags .= 'not_null ';
282             }
283             if ($id[$i]['dflt_value'] !== null) {
284                 $flags .= 'default_' . rawurlencode($id[$i]['dflt_value']);
285             }
286             $flags = trim($flags);
287
288             $res[$i] = array(
289                 'table' => $case_func($result),
290                 'name'  => $case_func($id[$i]['name']),
291                 'type'  => $type,
292                 'len'   => $len,
293                 'flags' => $flags,
294             );
295
296             if ($mode & MDB2_TABLEINFO_ORDER) {
297                 $res['order'][$res[$i]['name']] = $i;
298             }
299             if ($mode & MDB2_TABLEINFO_ORDERTABLE) {
300                 $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
301             }
302         }
303
304         return $res;
305     }
306 }
307
308 ?>