source: branches/feature-module-update/data/module/DB/mssql.php @ 15532

Revision 15532, 26.9 KB checked in by nanasess, 17 years ago (diff)

svn:mime-type 修正

  • Property svn:keywords set to Id
  • Property svn:mime-type set to text/x-httpd-php; charset=UTF-8
Line 
1<?php
2
3/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
4
5/**
6 * The PEAR DB driver for PHP's mssql extension
7 * for interacting with Microsoft SQL Server databases
8 *
9 * PHP versions 4 and 5
10 *
11 * LICENSE: This source file is subject to version 3.0 of the PHP license
12 * that is available through the world-wide-web at the following URI:
13 * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
14 * the PHP License and are unable to obtain it through the web, please
15 * send a note to license@php.net so we can mail you a copy immediately.
16 *
17 * @category   Database
18 * @package    DB
19 * @author     Sterling Hughes <sterling@php.net>
20 * @author     Daniel Convissor <danielc@php.net>
21 * @copyright  1997-2005 The PHP Group
22 * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
23 * @version    CVS: $Id$
24 * @link       http://pear.php.net/package/DB
25 */
26
27/**
28 * Obtain the DB_common class so it can be extended from
29 */
30require_once 'DB/common.php';
31
32/**
33 * The methods PEAR DB uses to interact with PHP's mssql extension
34 * for interacting with Microsoft SQL Server databases
35 *
36 * These methods overload the ones declared in DB_common.
37 *
38 * @category   Database
39 * @package    DB
40 * @author     Sterling Hughes <sterling@php.net>
41 * @author     Daniel Convissor <danielc@php.net>
42 * @copyright  1997-2005 The PHP Group
43 * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
44 * @version    Release: @package_version@
45 * @link       http://pear.php.net/package/DB
46 */
47class DB_mssql extends DB_common
48{
49    // {{{ properties
50
51    /**
52     * The DB driver type (mysql, oci8, odbc, etc.)
53     * @var string
54     */
55    var $phptype = 'mssql';
56
57    /**
58     * The database syntax variant to be used (db2, access, etc.), if any
59     * @var string
60     */
61    var $dbsyntax = 'mssql';
62
63    /**
64     * The capabilities of this DB implementation
65     *
66     * The 'new_link' element contains the PHP version that first provided
67     * new_link support for this DBMS.  Contains false if it's unsupported.
68     *
69     * Meaning of the 'limit' element:
70     *   + 'emulate' = emulate with fetch row by number
71     *   + 'alter'   = alter the query
72     *   + false     = skip rows
73     *
74     * @var array
75     */
76    var $features = array(
77        'limit'         => 'emulate',
78        'new_link'      => false,
79        'numrows'       => true,
80        'pconnect'      => true,
81        'prepare'       => false,
82        'ssl'           => false,
83        'transactions'  => true,
84    );
85
86    /**
87     * A mapping of native error codes to DB error codes
88     * @var array
89     */
90    // XXX Add here error codes ie: 'S100E' => DB_ERROR_SYNTAX
91    var $errorcode_map = array(
92        110   => DB_ERROR_VALUE_COUNT_ON_ROW,
93        155   => DB_ERROR_NOSUCHFIELD,
94        170   => DB_ERROR_SYNTAX,
95        207   => DB_ERROR_NOSUCHFIELD,
96        208   => DB_ERROR_NOSUCHTABLE,
97        245   => DB_ERROR_INVALID_NUMBER,
98        515   => DB_ERROR_CONSTRAINT_NOT_NULL,
99        547   => DB_ERROR_CONSTRAINT,
100        1913  => DB_ERROR_ALREADY_EXISTS,
101        2627  => DB_ERROR_CONSTRAINT,
102        2714  => DB_ERROR_ALREADY_EXISTS,
103        3701  => DB_ERROR_NOSUCHTABLE,
104        8134  => DB_ERROR_DIVZERO,
105    );
106
107    /**
108     * The raw database connection created by PHP
109     * @var resource
110     */
111    var $connection;
112
113    /**
114     * The DSN information for connecting to a database
115     * @var array
116     */
117    var $dsn = array();
118
119
120    /**
121     * Should data manipulation queries be committed automatically?
122     * @var bool
123     * @access private
124     */
125    var $autocommit = true;
126
127    /**
128     * The quantity of transactions begun
129     *
130     * {@internal  While this is private, it can't actually be designated
131     * private in PHP 5 because it is directly accessed in the test suite.}}
132     *
133     * @var integer
134     * @access private
135     */
136    var $transaction_opcount = 0;
137
138    /**
139     * The database specified in the DSN
140     *
141     * It's a fix to allow calls to different databases in the same script.
142     *
143     * @var string
144     * @access private
145     */
146    var $_db = null;
147
148
149    // }}}
150    // {{{ constructor
151
152    /**
153     * This constructor calls <kbd>$this->DB_common()</kbd>
154     *
155     * @return void
156     */
157    function DB_mssql()
158    {
159        $this->DB_common();
160    }
161
162    // }}}
163    // {{{ connect()
164
165    /**
166     * Connect to the database server, log in and open the database
167     *
168     * Don't call this method directly.  Use DB::connect() instead.
169     *
170     * @param array $dsn         the data source name
171     * @param bool  $persistent  should the connection be persistent?
172     *
173     * @return int  DB_OK on success. A DB_Error object on failure.
174     */
175    function connect($dsn, $persistent = false)
176    {
177        if (!PEAR::loadExtension('mssql') && !PEAR::loadExtension('sybase')
178            && !PEAR::loadExtension('sybase_ct'))
179        {
180            return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
181        }
182
183        $this->dsn = $dsn;
184        if ($dsn['dbsyntax']) {
185            $this->dbsyntax = $dsn['dbsyntax'];
186        }
187
188        $params = array(
189            $dsn['hostspec'] ? $dsn['hostspec'] : 'localhost',
190            $dsn['username'] ? $dsn['username'] : null,
191            $dsn['password'] ? $dsn['password'] : null,
192        );
193        if ($dsn['port']) {
194            $params[0] .= ((substr(PHP_OS, 0, 3) == 'WIN') ? ',' : ':')
195                        . $dsn['port'];
196        }
197
198        $connect_function = $persistent ? 'mssql_pconnect' : 'mssql_connect';
199
200        $this->connection = @call_user_func_array($connect_function, $params);
201
202        if (!$this->connection) {
203            return $this->raiseError(DB_ERROR_CONNECT_FAILED,
204                                     null, null, null,
205                                     @mssql_get_last_message());
206        }
207        if ($dsn['database']) {
208            if (!@mssql_select_db($dsn['database'], $this->connection)) {
209                return $this->raiseError(DB_ERROR_NODBSELECTED,
210                                         null, null, null,
211                                         @mssql_get_last_message());
212            }
213            $this->_db = $dsn['database'];
214        }
215        return DB_OK;
216    }
217
218    // }}}
219    // {{{ disconnect()
220
221    /**
222     * Disconnects from the database server
223     *
224     * @return bool  TRUE on success, FALSE on failure
225     */
226    function disconnect()
227    {
228        $ret = @mssql_close($this->connection);
229        $this->connection = null;
230        return $ret;
231    }
232
233    // }}}
234    // {{{ simpleQuery()
235
236    /**
237     * Sends a query to the database server
238     *
239     * @param string  the SQL query string
240     *
241     * @return mixed  + a PHP result resrouce for successful SELECT queries
242     *                + the DB_OK constant for other successful queries
243     *                + a DB_Error object on failure
244     */
245    function simpleQuery($query)
246    {
247        $ismanip = DB::isManip($query);
248        $this->last_query = $query;
249        if (!@mssql_select_db($this->_db, $this->connection)) {
250            return $this->mssqlRaiseError(DB_ERROR_NODBSELECTED);
251        }
252        $query = $this->modifyQuery($query);
253        if (!$this->autocommit && $ismanip) {
254            if ($this->transaction_opcount == 0) {
255                $result = @mssql_query('BEGIN TRAN', $this->connection);
256                if (!$result) {
257                    return $this->mssqlRaiseError();
258                }
259            }
260            $this->transaction_opcount++;
261        }
262        $result = @mssql_query($query, $this->connection);
263        if (!$result) {
264            return $this->mssqlRaiseError();
265        }
266        // Determine which queries that should return data, and which
267        // should return an error code only.
268        return $ismanip ? DB_OK : $result;
269    }
270
271    // }}}
272    // {{{ nextResult()
273
274    /**
275     * Move the internal mssql result pointer to the next available result
276     *
277     * @param a valid fbsql result resource
278     *
279     * @access public
280     *
281     * @return true if a result is available otherwise return false
282     */
283    function nextResult($result)
284    {
285        return @mssql_next_result($result);
286    }
287
288    // }}}
289    // {{{ fetchInto()
290
291    /**
292     * Places a row from the result set into the given array
293     *
294     * Formating of the array and the data therein are configurable.
295     * See DB_result::fetchInto() for more information.
296     *
297     * This method is not meant to be called directly.  Use
298     * DB_result::fetchInto() instead.  It can't be declared "protected"
299     * because DB_result is a separate object.
300     *
301     * @param resource $result    the query result resource
302     * @param array    $arr       the referenced array to put the data in
303     * @param int      $fetchmode how the resulting array should be indexed
304     * @param int      $rownum    the row number to fetch (0 = first row)
305     *
306     * @return mixed  DB_OK on success, NULL when the end of a result set is
307     *                 reached or on failure
308     *
309     * @see DB_result::fetchInto()
310     */
311    function fetchInto($result, &$arr, $fetchmode, $rownum = null)
312    {
313        if ($rownum !== null) {
314            if (!@mssql_data_seek($result, $rownum)) {
315                return null;
316            }
317        }
318        if ($fetchmode & DB_FETCHMODE_ASSOC) {
319            $arr = @mssql_fetch_array($result, MSSQL_ASSOC);
320            if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) {
321                $arr = array_change_key_case($arr, CASE_LOWER);
322            }
323        } else {
324            $arr = @mssql_fetch_row($result);
325        }
326        if (!$arr) {
327            return null;
328        }
329        if ($this->options['portability'] & DB_PORTABILITY_RTRIM) {
330            $this->_rtrimArrayValues($arr);
331        }
332        if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) {
333            $this->_convertNullArrayValuesToEmpty($arr);
334        }
335        return DB_OK;
336    }
337
338    // }}}
339    // {{{ freeResult()
340
341    /**
342     * Deletes the result set and frees the memory occupied by the result set
343     *
344     * This method is not meant to be called directly.  Use
345     * DB_result::free() instead.  It can't be declared "protected"
346     * because DB_result is a separate object.
347     *
348     * @param resource $result  PHP's query result resource
349     *
350     * @return bool  TRUE on success, FALSE if $result is invalid
351     *
352     * @see DB_result::free()
353     */
354    function freeResult($result)
355    {
356        return @mssql_free_result($result);
357    }
358
359    // }}}
360    // {{{ numCols()
361
362    /**
363     * Gets the number of columns in a result set
364     *
365     * This method is not meant to be called directly.  Use
366     * DB_result::numCols() instead.  It can't be declared "protected"
367     * because DB_result is a separate object.
368     *
369     * @param resource $result  PHP's query result resource
370     *
371     * @return int  the number of columns.  A DB_Error object on failure.
372     *
373     * @see DB_result::numCols()
374     */
375    function numCols($result)
376    {
377        $cols = @mssql_num_fields($result);
378        if (!$cols) {
379            return $this->mssqlRaiseError();
380        }
381        return $cols;
382    }
383
384    // }}}
385    // {{{ numRows()
386
387    /**
388     * Gets the number of rows in a result set
389     *
390     * This method is not meant to be called directly.  Use
391     * DB_result::numRows() instead.  It can't be declared "protected"
392     * because DB_result is a separate object.
393     *
394     * @param resource $result  PHP's query result resource
395     *
396     * @return int  the number of rows.  A DB_Error object on failure.
397     *
398     * @see DB_result::numRows()
399     */
400    function numRows($result)
401    {
402        $rows = @mssql_num_rows($result);
403        if ($rows === false) {
404            return $this->mssqlRaiseError();
405        }
406        return $rows;
407    }
408
409    // }}}
410    // {{{ autoCommit()
411
412    /**
413     * Enables or disables automatic commits
414     *
415     * @param bool $onoff  true turns it on, false turns it off
416     *
417     * @return int  DB_OK on success.  A DB_Error object if the driver
418     *               doesn't support auto-committing transactions.
419     */
420    function autoCommit($onoff = false)
421    {
422        // XXX if $this->transaction_opcount > 0, we should probably
423        // issue a warning here.
424        $this->autocommit = $onoff ? true : false;
425        return DB_OK;
426    }
427
428    // }}}
429    // {{{ commit()
430
431    /**
432     * Commits the current transaction
433     *
434     * @return int  DB_OK on success.  A DB_Error object on failure.
435     */
436    function commit()
437    {
438        if ($this->transaction_opcount > 0) {
439            if (!@mssql_select_db($this->_db, $this->connection)) {
440                return $this->mssqlRaiseError(DB_ERROR_NODBSELECTED);
441            }
442            $result = @mssql_query('COMMIT TRAN', $this->connection);
443            $this->transaction_opcount = 0;
444            if (!$result) {
445                return $this->mssqlRaiseError();
446            }
447        }
448        return DB_OK;
449    }
450
451    // }}}
452    // {{{ rollback()
453
454    /**
455     * Reverts the current transaction
456     *
457     * @return int  DB_OK on success.  A DB_Error object on failure.
458     */
459    function rollback()
460    {
461        if ($this->transaction_opcount > 0) {
462            if (!@mssql_select_db($this->_db, $this->connection)) {
463                return $this->mssqlRaiseError(DB_ERROR_NODBSELECTED);
464            }
465            $result = @mssql_query('ROLLBACK TRAN', $this->connection);
466            $this->transaction_opcount = 0;
467            if (!$result) {
468                return $this->mssqlRaiseError();
469            }
470        }
471        return DB_OK;
472    }
473
474    // }}}
475    // {{{ affectedRows()
476
477    /**
478     * Determines the number of rows affected by a data maniuplation query
479     *
480     * 0 is returned for queries that don't manipulate data.
481     *
482     * @return int  the number of rows.  A DB_Error object on failure.
483     */
484    function affectedRows()
485    {
486        if (DB::isManip($this->last_query)) {
487            $res = @mssql_query('select @@rowcount', $this->connection);
488            if (!$res) {
489                return $this->mssqlRaiseError();
490            }
491            $ar = @mssql_fetch_row($res);
492            if (!$ar) {
493                $result = 0;
494            } else {
495                @mssql_free_result($res);
496                $result = $ar[0];
497            }
498        } else {
499            $result = 0;
500        }
501        return $result;
502    }
503
504    // }}}
505    // {{{ nextId()
506
507    /**
508     * Returns the next free id in a sequence
509     *
510     * @param string  $seq_name  name of the sequence
511     * @param boolean $ondemand  when true, the seqence is automatically
512     *                            created if it does not exist
513     *
514     * @return int  the next id number in the sequence.
515     *               A DB_Error object on failure.
516     *
517     * @see DB_common::nextID(), DB_common::getSequenceName(),
518     *      DB_mssql::createSequence(), DB_mssql::dropSequence()
519     */
520    function nextId($seq_name, $ondemand = true)
521    {
522        $seqname = $this->getSequenceName($seq_name);
523        if (!@mssql_select_db($this->_db, $this->connection)) {
524            return $this->mssqlRaiseError(DB_ERROR_NODBSELECTED);
525        }
526        $repeat = 0;
527        do {
528            $this->pushErrorHandling(PEAR_ERROR_RETURN);
529            $result = $this->query("INSERT INTO $seqname (vapor) VALUES (0)");
530            $this->popErrorHandling();
531            if ($ondemand && DB::isError($result) &&
532                ($result->getCode() == DB_ERROR || $result->getCode() == DB_ERROR_NOSUCHTABLE))
533            {
534                $repeat = 1;
535                $result = $this->createSequence($seq_name);
536                if (DB::isError($result)) {
537                    return $this->raiseError($result);
538                }
539            } elseif (!DB::isError($result)) {
540                $result =& $this->query("SELECT @@IDENTITY FROM $seqname");
541                $repeat = 0;
542            } else {
543                $repeat = false;
544            }
545        } while ($repeat);
546        if (DB::isError($result)) {
547            return $this->raiseError($result);
548        }
549        $result = $result->fetchRow(DB_FETCHMODE_ORDERED);
550        return $result[0];
551    }
552
553    /**
554     * Creates a new sequence
555     *
556     * @param string $seq_name  name of the new sequence
557     *
558     * @return int  DB_OK on success.  A DB_Error object on failure.
559     *
560     * @see DB_common::createSequence(), DB_common::getSequenceName(),
561     *      DB_mssql::nextID(), DB_mssql::dropSequence()
562     */
563    function createSequence($seq_name)
564    {
565        return $this->query('CREATE TABLE '
566                            . $this->getSequenceName($seq_name)
567                            . ' ([id] [int] IDENTITY (1, 1) NOT NULL,'
568                            . ' [vapor] [int] NULL)');
569    }
570
571    // }}}
572    // {{{ dropSequence()
573
574    /**
575     * Deletes a sequence
576     *
577     * @param string $seq_name  name of the sequence to be deleted
578     *
579     * @return int  DB_OK on success.  A DB_Error object on failure.
580     *
581     * @see DB_common::dropSequence(), DB_common::getSequenceName(),
582     *      DB_mssql::nextID(), DB_mssql::createSequence()
583     */
584    function dropSequence($seq_name)
585    {
586        return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name));
587    }
588
589    // }}}
590    // {{{ quoteIdentifier()
591
592    /**
593     * Quotes a string so it can be safely used as a table or column name
594     *
595     * @param string $str  identifier name to be quoted
596     *
597     * @return string  quoted identifier string
598     *
599     * @see DB_common::quoteIdentifier()
600     * @since Method available since Release 1.6.0
601     */
602    function quoteIdentifier($str)
603    {
604        return '[' . str_replace(']', ']]', $str) . ']';
605    }
606
607    // }}}
608    // {{{ mssqlRaiseError()
609
610    /**
611     * Produces a DB_Error object regarding the current problem
612     *
613     * @param int $errno  if the error is being manually raised pass a
614     *                     DB_ERROR* constant here.  If this isn't passed
615     *                     the error information gathered from the DBMS.
616     *
617     * @return object  the DB_Error object
618     *
619     * @see DB_common::raiseError(),
620     *      DB_mssql::errorNative(), DB_mssql::errorCode()
621     */
622    function mssqlRaiseError($code = null)
623    {
624        $message = @mssql_get_last_message();
625        if (!$code) {
626            $code = $this->errorNative();
627        }
628        return $this->raiseError($this->errorCode($code, $message),
629                                 null, null, null, "$code - $message");
630    }
631
632    // }}}
633    // {{{ errorNative()
634
635    /**
636     * Gets the DBMS' native error code produced by the last query
637     *
638     * @return int  the DBMS' error code
639     */
640    function errorNative()
641    {
642        $res = @mssql_query('select @@ERROR as ErrorCode', $this->connection);
643        if (!$res) {
644            return DB_ERROR;
645        }
646        $row = @mssql_fetch_row($res);
647        return $row[0];
648    }
649
650    // }}}
651    // {{{ errorCode()
652
653    /**
654     * Determines PEAR::DB error code from mssql's native codes.
655     *
656     * If <var>$nativecode</var> isn't known yet, it will be looked up.
657     *
658     * @param  mixed  $nativecode  mssql error code, if known
659     * @return integer  an error number from a DB error constant
660     * @see errorNative()
661     */
662    function errorCode($nativecode = null, $msg = '')
663    {
664        if (!$nativecode) {
665            $nativecode = $this->errorNative();
666        }
667        if (isset($this->errorcode_map[$nativecode])) {
668            if ($nativecode == 3701
669                && preg_match('/Cannot drop the index/i', $msg))
670            {
671                return DB_ERROR_NOT_FOUND;
672            }
673            return $this->errorcode_map[$nativecode];
674        } else {
675            return DB_ERROR;
676        }
677    }
678
679    // }}}
680    // {{{ tableInfo()
681
682    /**
683     * Returns information about a table or a result set
684     *
685     * NOTE: only supports 'table' and 'flags' if <var>$result</var>
686     * is a table name.
687     *
688     * @param object|string  $result  DB_result object from a query or a
689     *                                 string containing the name of a table.
690     *                                 While this also accepts a query result
691     *                                 resource identifier, this behavior is
692     *                                 deprecated.
693     * @param int            $mode    a valid tableInfo mode
694     *
695     * @return array  an associative array with the information requested.
696     *                 A DB_Error object on failure.
697     *
698     * @see DB_common::tableInfo()
699     */
700    function tableInfo($result, $mode = null)
701    {
702        if (is_string($result)) {
703            /*
704             * Probably received a table name.
705             * Create a result resource identifier.
706             */
707            if (!@mssql_select_db($this->_db, $this->connection)) {
708                return $this->mssqlRaiseError(DB_ERROR_NODBSELECTED);
709            }
710            $id = @mssql_query("SELECT * FROM $result WHERE 1=0",
711                               $this->connection);
712            $got_string = true;
713        } elseif (isset($result->result)) {
714            /*
715             * Probably received a result object.
716             * Extract the result resource identifier.
717             */
718            $id = $result->result;
719            $got_string = false;
720        } else {
721            /*
722             * Probably received a result resource identifier.
723             * Copy it.
724             * Deprecated.  Here for compatibility only.
725             */
726            $id = $result;
727            $got_string = false;
728        }
729
730        if (!is_resource($id)) {
731            return $this->mssqlRaiseError(DB_ERROR_NEED_MORE_DATA);
732        }
733
734        if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
735            $case_func = 'strtolower';
736        } else {
737            $case_func = 'strval';
738        }
739
740        $count = @mssql_num_fields($id);
741        $res   = array();
742
743        if ($mode) {
744            $res['num_fields'] = $count;
745        }
746
747        for ($i = 0; $i < $count; $i++) {
748            $res[$i] = array(
749                'table' => $got_string ? $case_func($result) : '',
750                'name'  => $case_func(@mssql_field_name($id, $i)),
751                'type'  => @mssql_field_type($id, $i),
752                'len'   => @mssql_field_length($id, $i),
753                // We only support flags for table
754                'flags' => $got_string
755                           ? $this->_mssql_field_flags($result,
756                                                       @mssql_field_name($id, $i))
757                           : '',
758            );
759            if ($mode & DB_TABLEINFO_ORDER) {
760                $res['order'][$res[$i]['name']] = $i;
761            }
762            if ($mode & DB_TABLEINFO_ORDERTABLE) {
763                $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
764            }
765        }
766
767        // free the result only if we were called on a table
768        if ($got_string) {
769            @mssql_free_result($id);
770        }
771        return $res;
772    }
773
774    // }}}
775    // {{{ _mssql_field_flags()
776
777    /**
778     * Get a column's flags
779     *
780     * Supports "not_null", "primary_key",
781     * "auto_increment" (mssql identity), "timestamp" (mssql timestamp),
782     * "unique_key" (mssql unique index, unique check or primary_key) and
783     * "multiple_key" (multikey index)
784     *
785     * mssql timestamp is NOT similar to the mysql timestamp so this is maybe
786     * not useful at all - is the behaviour of mysql_field_flags that primary
787     * keys are alway unique? is the interpretation of multiple_key correct?
788     *
789     * @param string $table   the table name
790     * @param string $column  the field name
791     *
792     * @return string  the flags
793     *
794     * @access private
795     * @author Joern Barthel <j_barthel@web.de>
796     */
797    function _mssql_field_flags($table, $column)
798    {
799        static $tableName = null;
800        static $flags = array();
801
802        if ($table != $tableName) {
803
804            $flags = array();
805            $tableName = $table;
806
807            // get unique and primary keys
808            $res = $this->getAll("EXEC SP_HELPINDEX[$table]", DB_FETCHMODE_ASSOC);
809
810            foreach ($res as $val) {
811                $keys = explode(', ', $val['index_keys']);
812
813                if (sizeof($keys) > 1) {
814                    foreach ($keys as $key) {
815                        $this->_add_flag($flags[$key], 'multiple_key');
816                    }
817                }
818
819                if (strpos($val['index_description'], 'primary key')) {
820                    foreach ($keys as $key) {
821                        $this->_add_flag($flags[$key], 'primary_key');
822                    }
823                } elseif (strpos($val['index_description'], 'unique')) {
824                    foreach ($keys as $key) {
825                        $this->_add_flag($flags[$key], 'unique_key');
826                    }
827                }
828            }
829
830            // get auto_increment, not_null and timestamp
831            $res = $this->getAll("EXEC SP_COLUMNS[$table]", DB_FETCHMODE_ASSOC);
832
833            foreach ($res as $val) {
834                $val = array_change_key_case($val, CASE_LOWER);
835                if ($val['nullable'] == '0') {
836                    $this->_add_flag($flags[$val['column_name']], 'not_null');
837                }
838                if (strpos($val['type_name'], 'identity')) {
839                    $this->_add_flag($flags[$val['column_name']], 'auto_increment');
840                }
841                if (strpos($val['type_name'], 'timestamp')) {
842                    $this->_add_flag($flags[$val['column_name']], 'timestamp');
843                }
844            }
845        }
846
847        if (array_key_exists($column, $flags)) {
848            return(implode(' ', $flags[$column]));
849        }
850        return '';
851    }
852
853    // }}}
854    // {{{ _add_flag()
855
856    /**
857     * Adds a string to the flags array if the flag is not yet in there
858     * - if there is no flag present the array is created
859     *
860     * @param array  &$array  the reference to the flag-array
861     * @param string $value   the flag value
862     *
863     * @return void
864     *
865     * @access private
866     * @author Joern Barthel <j_barthel@web.de>
867     */
868    function _add_flag(&$array, $value)
869    {
870        if (!is_array($array)) {
871            $array = array($value);
872        } elseif (!in_array($value, $array)) {
873            array_push($array, $value);
874        }
875    }
876
877    // }}}
878    // {{{ getSpecialQuery()
879
880    /**
881     * Obtains the query string needed for listing a given type of objects
882     *
883     * @param string $type  the kind of objects you want to retrieve
884     *
885     * @return string  the SQL query string or null if the driver doesn't
886     *                  support the object type requested
887     *
888     * @access protected
889     * @see DB_common::getListOf()
890     */
891    function getSpecialQuery($type)
892    {
893        switch ($type) {
894            case 'tables':
895                return "SELECT name FROM sysobjects WHERE type = 'U'"
896                       . ' ORDER BY name';
897            case 'views':
898                return "SELECT name FROM sysobjects WHERE type = 'V'";
899            default:
900                return null;
901        }
902    }
903
904    // }}}
905}
906
907/*
908 * Local variables:
909 * tab-width: 4
910 * c-basic-offset: 4
911 * End:
912 */
913
914?>
Note: See TracBrowser for help on using the repository browser.