~ubuntu-branches/ubuntu/trusty/fusionforge/trusty

« back to all changes in this revision

Viewing changes to plugins/wiki/www/lib/pear/DB/sybase.php

  • Committer: Bazaar Package Importer
  • Author(s): Roland Mas
  • Date: 2011-04-15 14:55:34 UTC
  • mfrom: (4.1.10 sid)
  • Revision ID: james.westby@ubuntu.com-20110415145534-mvn1nochufjmw177
Tags: 5.0.3-1
New upstream bugfix release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<?php
 
2
/* vim: set expandtab tabstop=4 shiftwidth=4 foldmethod=marker: */
 
3
// +----------------------------------------------------------------------+
 
4
// | PHP Version 4                                                        |
 
5
// +----------------------------------------------------------------------+
 
6
// | Copyright (c) 1997-2004 The PHP Group                                |
 
7
// +----------------------------------------------------------------------+
 
8
// | This source file is subject to version 2.02 of the PHP license,      |
 
9
// | that is bundled with this package in the file LICENSE, and is        |
 
10
// | available at through the world-wide-web at                           |
 
11
// | http://www.php.net/license/2_02.txt.                                 |
 
12
// | If you did not receive a copy of the PHP license and are unable to   |
 
13
// | obtain it through the world-wide-web, please send a note to          |
 
14
// | license@php.net so we can mail you a copy immediately.               |
 
15
// +----------------------------------------------------------------------+
 
16
// | Authors: Sterling Hughes <sterling@php.net>                          |
 
17
// |          Ant�nio Carlos Ven�ncio J�nior <floripa@php.net>            |
 
18
// | Maintainer: Daniel Convissor <danielc@php.net>                       |
 
19
// +----------------------------------------------------------------------+
 
20
//
 
21
// $Id: sybase.php 6184 2008-08-22 10:33:41Z vargenau $
 
22
 
 
23
 
 
24
// TODO
 
25
//    - This driver may fail with multiple connections under the same
 
26
//      user/pass/host and different databases
 
27
 
 
28
 
 
29
require_once 'DB/common.php';
 
30
 
 
31
/**
 
32
 * Database independent query interface definition for PHP's Sybase
 
33
 * extension.
 
34
 *
 
35
 * @package  DB
 
36
 * @version  $Id: sybase.php 6184 2008-08-22 10:33:41Z vargenau $
 
37
 * @category Database
 
38
 * @author   Sterling Hughes <sterling@php.net>
 
39
 * @author   Ant�nio Carlos Ven�ncio J�nior <floripa@php.net>
 
40
 */
 
41
class DB_sybase extends DB_common
 
42
{
 
43
    // {{{ properties
 
44
 
 
45
    var $connection;
 
46
    var $phptype, $dbsyntax;
 
47
    var $prepare_tokens = array();
 
48
    var $prepare_types = array();
 
49
    var $transaction_opcount = 0;
 
50
    var $autocommit = true;
 
51
 
 
52
    // }}}
 
53
    // {{{ constructor
 
54
 
 
55
    /**
 
56
     * DB_sybase constructor.
 
57
     *
 
58
     * @access public
 
59
     */
 
60
    function DB_sybase()
 
61
    {
 
62
        $this->DB_common();
 
63
        $this->phptype = 'sybase';
 
64
        $this->dbsyntax = 'sybase';
 
65
        $this->features = array(
 
66
            'prepare' => false,
 
67
            'pconnect' => true,
 
68
            'transactions' => false,
 
69
            'limit' => 'emulate'
 
70
        );
 
71
        $this->errorcode_map = array(
 
72
        );
 
73
    }
 
74
 
 
75
    // }}}
 
76
    // {{{ connect()
 
77
 
 
78
    /**
 
79
     * Connect to a database and log in as the specified user.
 
80
     *
 
81
     * @param $dsn the data source name (see DB::parseDSN for syntax)
 
82
     * @param $persistent (optional) whether the connection should
 
83
     *        be persistent
 
84
     * @access public
 
85
     * @return int DB_OK on success, a DB error on failure
 
86
     */
 
87
    function connect($dsninfo, $persistent = false)
 
88
    {
 
89
        if (!DB::assertExtension('sybase') &&
 
90
            !DB::assertExtension('sybase_ct'))
 
91
        {
 
92
            return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
 
93
        }
 
94
 
 
95
        $this->dsn = $dsninfo;
 
96
 
 
97
        $interface = $dsninfo['hostspec'] ? $dsninfo['hostspec'] : 'localhost';
 
98
        $connect_function = $persistent ? 'sybase_pconnect' : 'sybase_connect';
 
99
 
 
100
        if ($interface && $dsninfo['username'] && $dsninfo['password']) {
 
101
            $conn = @$connect_function($interface, $dsninfo['username'],
 
102
                                       $dsninfo['password']);
 
103
        } elseif ($interface && $dsninfo['username']) {
 
104
            /*
 
105
             * Using false for pw as a workaround to avoid segfault.
 
106
             * See PEAR bug 631
 
107
             */
 
108
            $conn = @$connect_function($interface, $dsninfo['username'],
 
109
                                       false);
 
110
        } else {
 
111
            $conn = false;
 
112
        }
 
113
 
 
114
        if (!$conn) {
 
115
            return $this->raiseError(DB_ERROR_CONNECT_FAILED);
 
116
        }
 
117
 
 
118
        if ($dsninfo['database']) {
 
119
            if (!@sybase_select_db($dsninfo['database'], $conn)) {
 
120
                return $this->raiseError(DB_ERROR_NODBSELECTED, null,
 
121
                                         null, null, @sybase_get_last_message());
 
122
            }
 
123
            $this->_db = $dsninfo['database'];
 
124
        }
 
125
 
 
126
        $this->connection = $conn;
 
127
        return DB_OK;
 
128
    }
 
129
 
 
130
    // }}}
 
131
    // {{{ disconnect()
 
132
 
 
133
    /**
 
134
     * Log out and disconnect from the database.
 
135
     *
 
136
     * @access public
 
137
     *
 
138
     * @return bool true on success, false if not connected.
 
139
     */
 
140
    function disconnect()
 
141
    {
 
142
        $ret = @sybase_close($this->connection);
 
143
        $this->connection = null;
 
144
        return $ret;
 
145
    }
 
146
 
 
147
    // }}}
 
148
    // {{{ errorNative()
 
149
 
 
150
    /**
 
151
     * Get the last server error messge (if any)
 
152
     *
 
153
     * @return string sybase last error message
 
154
     */
 
155
    function errorNative()
 
156
    {
 
157
        return @sybase_get_last_message();
 
158
    }
 
159
 
 
160
    // }}}
 
161
    // {{{ errorCode()
 
162
 
 
163
    /**
 
164
     * Determine PEAR::DB error code from the database's text error message.
 
165
     *
 
166
     * @param  string  $errormsg  error message returned from the database
 
167
     * @return integer  an error number from a DB error constant
 
168
     */
 
169
    function errorCode($errormsg)
 
170
    {
 
171
        static $error_regexps;
 
172
        if (!isset($error_regexps)) {
 
173
            $error_regexps = array(
 
174
                '/Incorrect syntax near/'
 
175
                    => DB_ERROR_SYNTAX,
 
176
                '/^Unclosed quote before the character string [\"\'].*[\"\']\./'
 
177
                    => DB_ERROR_SYNTAX,
 
178
                '/Implicit conversion from datatype [\"\'].+[\"\'] to [\"\'].+[\"\'] is not allowed\./'
 
179
                    => DB_ERROR_INVALID_NUMBER,
 
180
                '/Cannot drop the table [\"\'].+[\"\'], because it doesn\'t exist in the system catalogs\./'
 
181
                    => DB_ERROR_NOSUCHTABLE,
 
182
                '/Only the owner of object [\"\'].+[\"\'] or a user with System Administrator \(SA\) role can run this command\./'
 
183
                    => DB_ERROR_ACCESS_VIOLATION,
 
184
                '/^.+ permission denied on object .+, database .+, owner .+/'
 
185
                    => DB_ERROR_ACCESS_VIOLATION,
 
186
                '/^.* permission denied, database .+, owner .+/'
 
187
                    => DB_ERROR_ACCESS_VIOLATION,
 
188
                '/[^.*] not found\./'
 
189
                    => DB_ERROR_NOSUCHTABLE,
 
190
                '/There is already an object named/'
 
191
                    => DB_ERROR_ALREADY_EXISTS,
 
192
                '/Invalid column name/'
 
193
                    => DB_ERROR_NOSUCHFIELD,
 
194
                '/does not allow null values/'
 
195
                    => DB_ERROR_CONSTRAINT_NOT_NULL,
 
196
                '/Command has been aborted/'
 
197
                    => DB_ERROR_CONSTRAINT,
 
198
            );
 
199
        }
 
200
 
 
201
        foreach ($error_regexps as $regexp => $code) {
 
202
            if (preg_match($regexp, $errormsg)) {
 
203
                return $code;
 
204
            }
 
205
        }
 
206
        return DB_ERROR;
 
207
    }
 
208
 
 
209
    // }}}
 
210
    // {{{ sybaseRaiseError()
 
211
 
 
212
    /**
 
213
     * Gather information about an error, then use that info to create a
 
214
     * DB error object and finally return that object.
 
215
     *
 
216
     * @param  integer  $errno  PEAR error number (usually a DB constant) if
 
217
     *                          manually raising an error
 
218
     * @return object  DB error object
 
219
     * @see errorNative()
 
220
     * @see errorCode()
 
221
     * @see DB_common::raiseError()
 
222
     */
 
223
    function sybaseRaiseError($errno = null)
 
224
    {
 
225
        $native = $this->errorNative();
 
226
        if ($errno === null) {
 
227
            $errno = $this->errorCode($native);
 
228
        }
 
229
        return $this->raiseError($errno, null, null, null, $native);
 
230
    }
 
231
 
 
232
    // }}}
 
233
    // {{{ simpleQuery()
 
234
 
 
235
    /**
 
236
     * Send a query to Sybase and return the results as a Sybase resource
 
237
     * identifier.
 
238
     *
 
239
     * @param the SQL query
 
240
     *
 
241
     * @access public
 
242
     *
 
243
     * @return mixed returns a valid Sybase result for successful SELECT
 
244
     * queries, DB_OK for other successful queries.  A DB error is
 
245
     * returned on failure.
 
246
     */
 
247
    function simpleQuery($query)
 
248
    {
 
249
        $ismanip = DB::isManip($query);
 
250
        $this->last_query = $query;
 
251
        if (!@sybase_select_db($this->_db, $this->connection)) {
 
252
            return $this->sybaseRaiseError(DB_ERROR_NODBSELECTED);
 
253
        }
 
254
        $query = $this->modifyQuery($query);
 
255
        if (!$this->autocommit && $ismanip) {
 
256
            if ($this->transaction_opcount == 0) {
 
257
                $result = @sybase_query('BEGIN TRANSACTION', $this->connection);
 
258
                if (!$result) {
 
259
                    return $this->sybaseRaiseError();
 
260
                }
 
261
            }
 
262
            $this->transaction_opcount++;
 
263
        }
 
264
        $result = @sybase_query($query, $this->connection);
 
265
        if (!$result) {
 
266
            return $this->sybaseRaiseError();
 
267
        }
 
268
        if (is_resource($result)) {
 
269
            $numrows = $this->numRows($result);
 
270
            if (is_object($numrows)) {
 
271
                return $numrows;
 
272
            }
 
273
            $this->num_rows[(int)$result] = $numrows;
 
274
            return $result;
 
275
        }
 
276
        // Determine which queries that should return data, and which
 
277
        // should return an error code only.
 
278
        return $ismanip ? DB_OK : $result;
 
279
    }
 
280
 
 
281
    // }}}
 
282
    // {{{ nextResult()
 
283
 
 
284
    /**
 
285
     * Move the internal sybase result pointer to the next available result
 
286
     *
 
287
     * @param a valid sybase result resource
 
288
     *
 
289
     * @access public
 
290
     *
 
291
     * @return true if a result is available otherwise return false
 
292
     */
 
293
    function nextResult($result)
 
294
    {
 
295
        return false;
 
296
    }
 
297
 
 
298
    // }}}
 
299
    // {{{ fetchInto()
 
300
 
 
301
    /**
 
302
     * Fetch a row and insert the data into an existing array.
 
303
     *
 
304
     * Formating of the array and the data therein are configurable.
 
305
     * See DB_result::fetchInto() for more information.
 
306
     *
 
307
     * @param resource $result    query result identifier
 
308
     * @param array    $arr       (reference) array where data from the row
 
309
     *                            should be placed
 
310
     * @param int      $fetchmode how the resulting array should be indexed
 
311
     * @param int      $rownum    the row number to fetch
 
312
     *
 
313
     * @return mixed DB_OK on success, null when end of result set is
 
314
     *               reached or on failure
 
315
     *
 
316
     * @see DB_result::fetchInto()
 
317
     * @access private
 
318
     */
 
319
    function fetchInto($result, &$arr, $fetchmode, $rownum=null)
 
320
    {
 
321
        if ($rownum !== null) {
 
322
            if (!@sybase_data_seek($result, $rownum)) {
 
323
                return null;
 
324
            }
 
325
        }
 
326
        if ($fetchmode & DB_FETCHMODE_ASSOC) {
 
327
            if (function_exists('sybase_fetch_assoc')) {
 
328
                $arr = @sybase_fetch_assoc($result);
 
329
            } else {
 
330
                if ($arr = @sybase_fetch_array($result)) {
 
331
                    foreach ($arr as $key => $value) {
 
332
                        if (is_int($key)) {
 
333
                            unset($arr[$key]);
 
334
                        }
 
335
                    }
 
336
                }
 
337
            }
 
338
            if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) {
 
339
                $arr = array_change_key_case($arr, CASE_LOWER);
 
340
            }
 
341
        } else {
 
342
            $arr = @sybase_fetch_row($result);
 
343
        }
 
344
        if (!$arr) {
 
345
            // reported not work as seems that sybase_get_last_message()
 
346
            // always return a message here
 
347
            //if ($errmsg = @sybase_get_last_message()) {
 
348
            //    return $this->sybaseRaiseError($errmsg);
 
349
            //} else {
 
350
                return null;
 
351
            //}
 
352
        }
 
353
        if ($this->options['portability'] & DB_PORTABILITY_RTRIM) {
 
354
            $this->_rtrimArrayValues($arr);
 
355
        }
 
356
        if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) {
 
357
            $this->_convertNullArrayValuesToEmpty($arr);
 
358
        }
 
359
        return DB_OK;
 
360
    }
 
361
 
 
362
    // }}}
 
363
    // {{{ freeResult()
 
364
 
 
365
    /**
 
366
     * Free the internal resources associated with $result.
 
367
     *
 
368
     * @param $result Sybase result identifier
 
369
     *
 
370
     * @access public
 
371
     *
 
372
     * @return bool true on success, false if $result is invalid
 
373
     */
 
374
    function freeResult($result)
 
375
    {
 
376
        unset($this->num_rows[(int)$result]);
 
377
        return @sybase_free_result($result);
 
378
    }
 
379
 
 
380
    // }}}
 
381
    // {{{ numCols()
 
382
 
 
383
    /**
 
384
     * Get the number of columns in a result set.
 
385
     *
 
386
     * @param $result Sybase result identifier
 
387
     *
 
388
     * @access public
 
389
     *
 
390
     * @return int the number of columns per row in $result
 
391
     */
 
392
    function numCols($result)
 
393
    {
 
394
        $cols = @sybase_num_fields($result);
 
395
        if (!$cols) {
 
396
            return $this->sybaseRaiseError();
 
397
        }
 
398
        return $cols;
 
399
    }
 
400
 
 
401
    // }}}
 
402
    // {{{ numRows()
 
403
 
 
404
    /**
 
405
     * Get the number of rows in a result set.
 
406
     *
 
407
     * @param $result Sybase result identifier
 
408
     *
 
409
     * @access public
 
410
     *
 
411
     * @return int the number of rows in $result
 
412
     */
 
413
    function numRows($result)
 
414
    {
 
415
        $rows = @sybase_num_rows($result);
 
416
        if ($rows === false) {
 
417
            return $this->sybaseRaiseError();
 
418
        }
 
419
        return $rows;
 
420
    }
 
421
 
 
422
    // }}}
 
423
    // {{{ affectedRows()
 
424
 
 
425
    /**
 
426
     * Gets the number of rows affected by the data manipulation
 
427
     * query.  For other queries, this function returns 0.
 
428
     *
 
429
     * @return number of rows affected by the last query
 
430
     */
 
431
    function affectedRows()
 
432
    {
 
433
        if (DB::isManip($this->last_query)) {
 
434
            $result = @sybase_affected_rows($this->connection);
 
435
        } else {
 
436
            $result = 0;
 
437
        }
 
438
        return $result;
 
439
     }
 
440
 
 
441
    // }}}
 
442
    // {{{ nextId()
 
443
 
 
444
    /**
 
445
     * Returns the next free id in a sequence
 
446
     *
 
447
     * @param string  $seq_name  name of the sequence
 
448
     * @param boolean $ondemand  when true, the seqence is automatically
 
449
     *                           created if it does not exist
 
450
     *
 
451
     * @return int  the next id number in the sequence.  DB_Error if problem.
 
452
     *
 
453
     * @internal
 
454
     * @see DB_common::nextID()
 
455
     * @access public
 
456
     */
 
457
    function nextId($seq_name, $ondemand = true)
 
458
    {
 
459
        $seqname = $this->getSequenceName($seq_name);
 
460
        if (!@sybase_select_db($this->_db, $this->connection)) {
 
461
            return $this->sybaseRaiseError(DB_ERROR_NODBSELECTED);
 
462
        }
 
463
        $repeat = 0;
 
464
        do {
 
465
            $this->pushErrorHandling(PEAR_ERROR_RETURN);
 
466
            $result = $this->query("INSERT INTO $seqname (vapor) VALUES (0)");
 
467
            $this->popErrorHandling();
 
468
            if ($ondemand && DB::isError($result) &&
 
469
                ($result->getCode() == DB_ERROR || $result->getCode() == DB_ERROR_NOSUCHTABLE))
 
470
            {
 
471
                $repeat = 1;
 
472
                $result = $this->createSequence($seq_name);
 
473
                if (DB::isError($result)) {
 
474
                    return $this->raiseError($result);
 
475
                }
 
476
            } elseif (!DB::isError($result)) {
 
477
                $result =& $this->query("SELECT @@IDENTITY FROM $seqname");
 
478
                $repeat = 0;
 
479
            } else {
 
480
                $repeat = false;
 
481
            }
 
482
        } while ($repeat);
 
483
        if (DB::isError($result)) {
 
484
            return $this->raiseError($result);
 
485
        }
 
486
        $result = $result->fetchRow(DB_FETCHMODE_ORDERED);
 
487
        return $result[0];
 
488
    }
 
489
 
 
490
    /**
 
491
     * Creates a new sequence
 
492
     *
 
493
     * @param string $seq_name  name of the new sequence
 
494
     *
 
495
     * @return int  DB_OK on success.  A DB_Error object is returned if
 
496
     *              problems arise.
 
497
     *
 
498
     * @internal
 
499
     * @see DB_common::createSequence()
 
500
     * @access public
 
501
     */
 
502
    function createSequence($seq_name)
 
503
    {
 
504
        $seqname = $this->getSequenceName($seq_name);
 
505
        return $this->query("CREATE TABLE $seqname ".
 
506
                            '(id numeric(10,0) IDENTITY NOT NULL ,' .
 
507
                            'vapor int NULL)');
 
508
    }
 
509
 
 
510
    // }}}
 
511
    // {{{ dropSequence()
 
512
 
 
513
    /**
 
514
     * Deletes a sequence
 
515
     *
 
516
     * @param string $seq_name  name of the sequence to be deleted
 
517
     *
 
518
     * @return int  DB_OK on success.  DB_Error if problems.
 
519
     *
 
520
     * @internal
 
521
     * @see DB_common::dropSequence()
 
522
     * @access public
 
523
     */
 
524
    function dropSequence($seq_name)
 
525
    {
 
526
        $seqname = $this->getSequenceName($seq_name);
 
527
        return $this->query("DROP TABLE $seqname");
 
528
    }
 
529
 
 
530
    // }}}
 
531
    // {{{ getSpecialQuery()
 
532
 
 
533
    /**
 
534
     * Returns the query needed to get some backend info
 
535
     * @param string $type What kind of info you want to retrieve
 
536
     * @return string The SQL query string
 
537
     */
 
538
    function getSpecialQuery($type)
 
539
    {
 
540
        switch ($type) {
 
541
            case 'tables':
 
542
                return "select name from sysobjects where type = 'U' order by name";
 
543
            case 'views':
 
544
                return "select name from sysobjects where type = 'V'";
 
545
            default:
 
546
                return null;
 
547
        }
 
548
    }
 
549
 
 
550
    // }}}
 
551
    // {{{ autoCommit()
 
552
 
 
553
    /**
 
554
     * Enable/disable automatic commits
 
555
     */
 
556
    function autoCommit($onoff = false)
 
557
    {
 
558
        // XXX if $this->transaction_opcount > 0, we should probably
 
559
        // issue a warning here.
 
560
        $this->autocommit = $onoff ? true : false;
 
561
        return DB_OK;
 
562
    }
 
563
 
 
564
    // }}}
 
565
    // {{{ commit()
 
566
 
 
567
    /**
 
568
     * Commit the current transaction.
 
569
     */
 
570
    function commit()
 
571
    {
 
572
        if ($this->transaction_opcount > 0) {
 
573
            if (!@sybase_select_db($this->_db, $this->connection)) {
 
574
                return $this->sybaseRaiseError(DB_ERROR_NODBSELECTED);
 
575
            }
 
576
            $result = @sybase_query('COMMIT', $this->connection);
 
577
            $this->transaction_opcount = 0;
 
578
            if (!$result) {
 
579
                return $this->sybaseRaiseError();
 
580
            }
 
581
        }
 
582
        return DB_OK;
 
583
    }
 
584
 
 
585
    // }}}
 
586
    // {{{ rollback()
 
587
 
 
588
    /**
 
589
     * Roll back (undo) the current transaction.
 
590
     */
 
591
    function rollback()
 
592
    {
 
593
        if ($this->transaction_opcount > 0) {
 
594
            if (!@sybase_select_db($this->_db, $this->connection)) {
 
595
                return $this->sybaseRaiseError(DB_ERROR_NODBSELECTED);
 
596
            }
 
597
            $result = @sybase_query('ROLLBACK', $this->connection);
 
598
            $this->transaction_opcount = 0;
 
599
            if (!$result) {
 
600
                return $this->sybaseRaiseError();
 
601
            }
 
602
        }
 
603
        return DB_OK;
 
604
    }
 
605
 
 
606
    // }}}
 
607
    // {{{ tableInfo()
 
608
 
 
609
    /**
 
610
     * Returns information about a table or a result set.
 
611
     *
 
612
     * NOTE: only supports 'table' and 'flags' if <var>$result</var>
 
613
     * is a table name.
 
614
     *
 
615
     * @param object|string  $result  DB_result object from a query or a
 
616
     *                                string containing the name of a table
 
617
     * @param int            $mode    a valid tableInfo mode
 
618
     * @return array  an associative array with the information requested
 
619
     *                or an error object if something is wrong
 
620
     * @access public
 
621
     * @internal
 
622
     * @since 1.6.0
 
623
     * @see DB_common::tableInfo()
 
624
     */
 
625
    function tableInfo($result, $mode = null)
 
626
    {
 
627
        if (isset($result->result)) {
 
628
            /*
 
629
             * Probably received a result object.
 
630
             * Extract the result resource identifier.
 
631
             */
 
632
            $id = $result->result;
 
633
            $got_string = false;
 
634
        } elseif (is_string($result)) {
 
635
            /*
 
636
             * Probably received a table name.
 
637
             * Create a result resource identifier.
 
638
             */
 
639
            if (!@sybase_select_db($this->_db, $this->connection)) {
 
640
                return $this->sybaseRaiseError(DB_ERROR_NODBSELECTED);
 
641
            }
 
642
            $id = @sybase_query("SELECT * FROM $result WHERE 1=0",
 
643
                                $this->connection);
 
644
            $got_string = true;
 
645
        } else {
 
646
            /*
 
647
             * Probably received a result resource identifier.
 
648
             * Copy it.
 
649
             * Depricated.  Here for compatibility only.
 
650
             */
 
651
            $id = $result;
 
652
            $got_string = false;
 
653
        }
 
654
 
 
655
        if (!is_resource($id)) {
 
656
            return $this->sybaseRaiseError(DB_ERROR_NEED_MORE_DATA);
 
657
        }
 
658
 
 
659
        if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
 
660
            $case_func = 'strtolower';
 
661
        } else {
 
662
            $case_func = 'strval';
 
663
        }
 
664
 
 
665
        $count = @sybase_num_fields($id);
 
666
 
 
667
        // made this IF due to performance (one if is faster than $count if's)
 
668
        if (!$mode) {
 
669
 
 
670
            for ($i=0; $i<$count; $i++) {
 
671
                $f = @sybase_fetch_field($id, $i);
 
672
 
 
673
                // column_source is often blank
 
674
                if ($got_string) {
 
675
                    $res[$i]['table'] = $case_func($result);
 
676
                } else {
 
677
                    $res[$i]['table'] = $case_func($f->column_source);
 
678
                }
 
679
                $res[$i]['name']  = $case_func($f->name);
 
680
                $res[$i]['type']  = $f->type;
 
681
                $res[$i]['len']   = $f->max_length;
 
682
                if ($res[$i]['table']) {
 
683
                    $res[$i]['flags'] = $this->_sybase_field_flags(
 
684
                            $res[$i]['table'], $res[$i]['name']);
 
685
                } else {
 
686
                    $res[$i]['flags'] = '';
 
687
                }
 
688
            }
 
689
 
 
690
        } else {
 
691
            // get full info
 
692
 
 
693
            $res['num_fields'] = $count;
 
694
 
 
695
            for ($i=0; $i<$count; $i++) {
 
696
                $f = @sybase_fetch_field($id, $i);
 
697
 
 
698
                // column_source is often blank
 
699
                if ($got_string) {
 
700
                    $res[$i]['table'] = $case_func($result);
 
701
                } else {
 
702
                    $res[$i]['table'] = $case_func($f->column_source);
 
703
                }
 
704
                $res[$i]['name']  = $case_func($f->name);
 
705
                $res[$i]['type']  = $f->type;
 
706
                $res[$i]['len']   = $f->max_length;
 
707
                if ($res[$i]['table']) {
 
708
                    $res[$i]['flags'] = $this->_sybase_field_flags(
 
709
                            $res[$i]['table'], $res[$i]['name']);
 
710
                } else {
 
711
                    $res[$i]['flags'] = '';
 
712
                }
 
713
 
 
714
                if ($mode & DB_TABLEINFO_ORDER) {
 
715
                    $res['order'][$res[$i]['name']] = $i;
 
716
                }
 
717
                if ($mode & DB_TABLEINFO_ORDERTABLE) {
 
718
                    $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
 
719
                }
 
720
            }
 
721
        }
 
722
 
 
723
        // free the result only if we were called on a table
 
724
        if ($got_string) {
 
725
            @sybase_free_result($id);
 
726
        }
 
727
        return $res;
 
728
    }
 
729
 
 
730
    // }}}
 
731
    // {{{ _sybase_field_flags()
 
732
 
 
733
    /**
 
734
     * Get the flags for a field.
 
735
     *
 
736
     * Currently supports:
 
737
     *  + <samp>unique_key</samp>    (unique index, unique check or primary_key)
 
738
     *  + <samp>multiple_key</samp>  (multi-key index)
 
739
     *
 
740
     * @param string  $table   table name
 
741
     * @param string  $column  field name
 
742
     * @return string  space delimited string of flags.  Empty string if none.
 
743
     * @access private
 
744
     */
 
745
    function _sybase_field_flags($table, $column)
 
746
    {
 
747
        static $tableName = null;
 
748
        static $flags = array();
 
749
 
 
750
        if ($table != $tableName) {
 
751
            $flags = array();
 
752
            $tableName = $table;
 
753
 
 
754
            // get unique/primary keys
 
755
            $res = $this->getAll("sp_helpindex $table", DB_FETCHMODE_ASSOC);
 
756
 
 
757
            if (!isset($res[0]['index_description'])) {
 
758
                return '';
 
759
            }
 
760
 
 
761
            foreach ($res as $val) {
 
762
                $keys = explode(', ', trim($val['index_keys']));
 
763
 
 
764
                if (sizeof($keys) > 1) {
 
765
                    foreach ($keys as $key) {
 
766
                        $this->_add_flag($flags[$key], 'multiple_key');
 
767
                    }
 
768
                }
 
769
 
 
770
                if (strpos($val['index_description'], 'unique')) {
 
771
                    foreach ($keys as $key) {
 
772
                        $this->_add_flag($flags[$key], 'unique_key');
 
773
                    }
 
774
                }
 
775
            }
 
776
 
 
777
        }
 
778
 
 
779
        if (array_key_exists($column, $flags)) {
 
780
            return(implode(' ', $flags[$column]));
 
781
        }
 
782
 
 
783
        return '';
 
784
    }
 
785
 
 
786
    // }}}
 
787
    // {{{ _add_flag()
 
788
 
 
789
    /**
 
790
     * Adds a string to the flags array if the flag is not yet in there
 
791
     * - if there is no flag present the array is created.
 
792
     *
 
793
     * @param array  $array  reference of flags array to add a value to
 
794
     * @param mixed  $value  value to add to the flag array
 
795
     * @access private
 
796
     */
 
797
    function _add_flag(&$array, $value)
 
798
    {
 
799
        if (!is_array($array)) {
 
800
            $array = array($value);
 
801
        } elseif (!in_array($value, $array)) {
 
802
            array_push($array, $value);
 
803
        }
 
804
    }
 
805
 
 
806
    // }}}
 
807
    // {{{ quoteIdentifier()
 
808
 
 
809
    /**
 
810
     * Quote a string so it can be safely used as a table / column name
 
811
     *
 
812
     * Quoting style depends on which database driver is being used.
 
813
     *
 
814
     * @param string $str  identifier name to be quoted
 
815
     *
 
816
     * @return string  quoted identifier string
 
817
     *
 
818
     * @since 1.6.0
 
819
     * @access public
 
820
     */
 
821
    function quoteIdentifier($str)
 
822
    {
 
823
        return '[' . str_replace(']', ']]', $str) . ']';
 
824
    }
 
825
 
 
826
    // }}}
 
827
 
 
828
}
 
829
 
 
830
/*
 
831
 * Local variables:
 
832
 * tab-width: 4
 
833
 * c-basic-offset: 4
 
834
 * End:
 
835
 */
 
836
 
 
837
?>