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: Frank M. Kromann <frank@kromann.info>                        |
43 // +----------------------------------------------------------------------+
44 //
45 // $Id$
46 //
47
48 require_once 'MDB2/Driver/Manager/Common.php';
49 // {{{ class MDB2_Driver_Manager_mssql
50 /**
51  * MDB2 MSSQL 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_mssql 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         $query = "CREATE DATABASE $name";
76         if($db->options['database_device']) {
77             $query.= ' ON '.$db->options['database_device'];
78             $query.= $db->options['database_size'] ? '='.$db->options['database_size'] : '';
79         }
80         return $db->standaloneQuery($query);
81     }
82
83     // }}}
84     // {{{ dropDatabase()
85
86     /**
87      * drop an existing database
88      *
89      * @param string $name name of the database that should be dropped
90      * @return mixed MDB2_OK on success, a MDB2 error on failure
91      * @access public
92      */
93     function dropDatabase($name)
94     {
95         $db =& $this->getDBInstance();
96         if (PEAR::isError($db)) {
97             return $db;
98         }
99
100         return $db->standaloneQuery("DROP DATABASE $name");
101     }
102
103     // }}}
104     // {{{ alterTable()
105
106     /**
107      * alter an existing table
108      *
109      * @param string $name         name of the table that is intended to be changed.
110      * @param array $changes     associative array that contains the details of each type
111      *                             of change that is intended to be performed. The types of
112      *                             changes that are currently supported are defined as follows:
113      *
114      *                             name
115      *
116      *                                New name for the table.
117      *
118      *                            add
119      *
120      *                                Associative array with the names of fields to be added as
121      *                                 indexes of the array. The value of each entry of the array
122      *                                 should be set to another associative array with the properties
123      *                                 of the fields to be added. The properties of the fields should
124      *                                 be the same as defined by the Metabase parser.
125      *
126      *
127      *                            remove
128      *
129      *                                Associative array with the names of fields to be removed as indexes
130      *                                 of the array. Currently the values assigned to each entry are ignored.
131      *                                 An empty array should be used for future compatibility.
132      *
133      *                            rename
134      *
135      *                                Associative array with the names of fields to be renamed as indexes
136      *                                 of the array. The value of each entry of the array should be set to
137      *                                 another associative array with the entry named name with the new
138      *                                 field name and the entry named Declaration that is expected to contain
139      *                                 the portion of the field declaration already in DBMS specific SQL code
140      *                                 as it is used in the CREATE TABLE statement.
141      *
142      *                            change
143      *
144      *                                Associative array with the names of the fields to be changed as indexes
145      *                                 of the array. Keep in mind that if it is intended to change either the
146      *                                 name of a field and any other properties, the change array entries
147      *                                 should have the new names of the fields as array indexes.
148      *
149      *                                The value of each entry of the array should be set to another associative
150      *                                 array with the properties of the fields to that are meant to be changed as
151      *                                 array entries. These entries should be assigned to the new values of the
152      *                                 respective properties. The properties of the fields should be the same
153      *                                 as defined by the Metabase parser.
154      *
155      *                            Example
156      *                                array(
157      *                                    'name' => 'userlist',
158      *                                    'add' => array(
159      *                                        'quota' => array(
160      *                                            'type' => 'integer',
161      *                                            'unsigned' => 1
162      *                                        )
163      *                                    ),
164      *                                    'remove' => array(
165      *                                        'file_limit' => array(),
166      *                                        'time_limit' => array()
167      *                                        ),
168      *                                    'change' => array(
169      *                                        'gender' => array(
170      *                                            'default' => 'M',
171      *                                        )
172      *                                    ),
173      *                                    'rename' => array(
174      *                                        'sex' => array(
175      *                                            'name' => 'gender',
176      *                                        )
177      *                                    ),
178      *                                )
179      *
180      * @param boolean $check     indicates whether the function should just check if the DBMS driver
181      *                             can perform the requested table alterations if the value is true or
182      *                             actually perform them otherwise.
183      * @access public
184      *
185      * @return mixed MDB2_OK on success, a MDB2 error on failure
186      */
187     function alterTable($name, $changes, $check)
188     {
189         $db =& $this->getDBInstance();
190         if (PEAR::isError($db)) {
191             return $db;
192         }
193
194         foreach ($changes as $change_name => $change) {
195             switch ($change_name) {
196             case 'add':
197                 break;
198             case 'remove':
199                 break;
200             case 'name':
201             case 'rename':
202             case 'change':
203             default:
204                 return $db->raiseError(MDB2_ERROR_CANNOT_ALTER, null, null,
205                     'alterTable: change type "'.$change_name.'" not yet supported');
206             }
207         }
208
209         if ($check) {
210             return MDB2_OK;
211         }
212
213         $query = '';
214         if (array_key_exists('add', $changes)) {
215             if ($query) {
216                 $query.= ', ';
217             }
218             $query.= 'ADD ';
219             foreach ($changes['add'] as $field_name => $field) {
220                 if ($query) {
221                     $query.= ', ';
222                 }
223                 $query.= $db->getDeclaration($field['type'], $field_name, $field);
224             }
225         }
226         if(array_key_exists('remove', $changes)) {
227             if ($query) {
228             $query.= ', ';
229             }
230             $query.= 'DROP COLUMN';
231             foreach ($changes['remove'] as $field_name => $field) {
232                 if ($query) {
233                     $query.= ', ';
234                 }
235                 $query.= $db->getDeclaration($field['type'], $field_name, $field);
236             }
237         }
238             
239
240         if (!$query) {
241             return MDB2_OK;
242         }
243
244         return $db->query("ALTER TABLE $name $query");
245     }
246
247     // }}}
248     // {{{ listTables()
249
250     /**
251      * list all tables in the current database
252      *
253      * @return mixed data array on success, a MDB error on failure
254      * @access public
255      */
256     function listTables()
257     {
258         $db =& $this->getDBInstance();
259
260         if (PEAR::isError($db)) {
261             return $db;
262         }
263
264         $query = 'EXEC sp_tables @table_type = "\'TABLE\'"';
265         $table_names = $db->queryCol($query, null, 2);
266         if (PEAR::isError($table_names)) {
267             return $table_names;
268         }
269
270         $tables = array();
271         for ($i = 0, $j = count($table_names); $i <$j; ++$i) {
272             if (!$this->_isSequenceName($db, $table_names[$i])) {
273                 $tables[] = $table_names[$i];
274             }
275         }
276         return $tables;
277     }
278
279     // }}}
280     // {{{ listTableFields()
281
282     /**
283      * list all fields in a tables in the current database
284      *
285      * @param string $table name of table that should be used in method
286      * @return mixed data array on success, a MDB error on failure
287      * @access public
288      */
289     function listTableFields($table)
290     {
291         $db =& $this->getDBInstance();
292         if (PEAR::isError($db)) {
293             return $db;
294         }
295
296         $result = $db->query("SELECT * FROM [$table]");
297         if (PEAR::isError($result)) {
298             return $result;
299         }
300         $columns = $result->getColumnNames();
301         $result->free();
302         if (PEAR::isError($columns)) {
303             return $columns;
304         }
305         return array_flip($columns);
306     }
307
308     // }}}
309     // {{{ listTableIndexes()
310
311     /**
312      * list all indexes in a table
313      *
314      * @param string    $table     name of table that should be used in method
315      * @return mixed data array on success, a MDB error on failure
316      * @access public
317      */
318     function listTableIndexes($table)
319     {
320         $db =& $this->getDBInstance();
321         if (PEAR::isError($db)) {
322             return $db;
323         }
324
325         $key_name = 'INDEX_NAME';
326         $pk_name = 'PK_NAME';
327         if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
328             if ($db->options['field_case'] == CASE_LOWER) {
329                 $key_name = strtolower($key_name);
330                 $pk_name  = strtolower($pk_name);
331             } else {
332                 $key_name = strtoupper($key_name);
333                 $pk_name  = strtoupper($pk_name);
334             }
335         }
336         $query = "EXEC sp_statistics @table_name='$table'";
337         $indexes_all = $db->queryCol($query, 'text', $key_name);
338         if (PEAR::isError($indexes_all)) {
339             return $indexes_all;
340         }
341         $query = "EXEC sp_pkeys @table_name='$table'";
342         $pk_all = $db->queryCol($query, 'text', $pk_name);
343         $found = $indexes = array();
344         for ($index = 0, $j = count($indexes_all); $index < $j; ++$index) {
345             if (!in_array($indexes_all[$index], $pk_all)
346                 && $indexes_all[$index] != null
347                 && !isset($found[$indexes_all[$index]])
348             ) {
349                 $indexes[] = $indexes_all[$index];
350                 $found[$indexes_all[$index]] = 1;
351             }
352         }
353         return $indexes;
354     }
355
356     // }}}
357     // {{{ createSequence()
358
359     /**
360      * create sequence
361      *
362      * @param string    $seq_name     name of the sequence to be created
363      * @param string    $start         start value of the sequence; default is 1
364      * @return mixed MDB2_OK on success, a MDB2 error on failure
365      * @access public
366      */
367     function createSequence($seq_name, $start = 1)
368     {
369
370         $db =& $this->getDBInstance();
371         if (PEAR::isError($db)) {
372             return $db;
373         }
374
375         $sequence_name = $db->getSequenceName($seq_name);
376         $seqcol_name   = $db->options['seqcol_name'];
377         $query = "CREATE TABLE $sequence_name ($seqcol_name " .
378                  "INT PRIMARY KEY CLUSTERED IDENTITY($start,1) NOT NULL)";
379
380         $res = $db->query($query);
381         if(PEAR::isError($res)) {
382             return $res;
383         }
384         
385         if ($start == 1) {
386             return MDB2_OK;
387         }
388
389         $query = "SET IDENTITY_INSERT $sequence_name ON ".
390                  "INSERT INTO $sequence_name ($seqcol_name) VALUES ($start)";
391         $res = $db->query($query);
392
393         if(!PEAR::isError($res)) {
394             return MDB2_OK;
395         }
396
397         $result = $db->query("DROP TABLE $sequence_name");
398         if(PEAR::isError($result)) {
399             return $db->raiseError(MDB2_ERROR, null, null,
400                    'createSequence: could not drop inconsistent sequence table ('.
401                    $result->getMessage().' ('.$result->getUserInfo(). '))');
402         }
403
404         return $db->raiseError(MDB2_ERROR, null, null,
405                'createSequence: could not create sequence table ('.
406                $res->getMessage(). ' ('.$res->getUserInfo(). '))');
407     }
408
409     // }}}
410     // {{{ createIndex()
411     /**
412      * Adds an index to a table.
413      *
414      * @param string $table      The name of the table
415      * @param string $name       The name of the field
416      * @param array  $definition The definition of the new field.
417      */
418     function createIndex($table, $name, $definition)
419     {
420     }
421
422     // }}}
423     // {{{ dropSequence()
424
425     /**
426      * drop existing sequence
427      *
428      * @param string    $seq_name     name of the sequence to be dropped
429      * @return mixed MDB2_OK on success, a MDB2 error on failure
430      * @access public
431      */
432     function dropSequence($seq_name)
433     {
434         $db =& $this->getDBInstance();
435         if (PEAR::isError($db)) {
436             return $db;
437         }
438
439         $sequence_name = $db->getSequenceName($seq_name);
440         return $db->query("DROP TABLE $sequence_name");
441     }
442
443     // }}}
444     // {{{ listSequences()
445
446     /**
447      * list all sequences in the current database
448      *
449      * @return mixed data array on success, a MDB2 error on failure
450      * @access public
451      */
452     function listSequences()
453     {
454         $db =& $this->getDBInstance();
455         if (PEAR::isError($db)) {
456             return $db;
457         }
458
459         $query = "SELECT name FROM sysobjects WHERE xtype = 'U'";
460         $table_names = $db->queryCol($query);
461         if (PEAR::isError($table_names)) {
462             return $table_names;
463         }
464         $sequences = array();
465         for ($i = 0, $j = count($table_names); $i <$j; ++$i) {
466             if ($this->_isSequenceName($db, $table_names[$i])) {
467                 $sequences[] = $table_names[$i];
468             }
469         }
470         return $sequences;
471     }
472     // }}}
473 }
474 // }}}
475 ?>