Subversion Repositories Applications.papyrus

Rev

Rev 443 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
320 jpm 1
<?php
2
 
3
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
4
 
5
/**
6
 * The PEAR DB driver for PHP's odbc extension
7
 * for interacting with databases via ODBC connections
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     Stig Bakken <ssb@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
1173 jp_milcent 23
 * @version    CVS: $Id: odbc.php,v 1.3 2006-12-14 15:04:28 jp_milcent Exp $
320 jpm 24
 * @link       http://pear.php.net/package/DB
25
 */
26
 
27
/**
28
 * Obtain the DB_common class so it can be extended from
29
 */
30
require_once 'DB/common.php';
31
 
32
/**
33
 * The methods PEAR DB uses to interact with PHP's odbc extension
34
 * for interacting with databases via ODBC connections
35
 *
36
 * These methods overload the ones declared in DB_common.
37
 *
38
 * More info on ODBC errors could be found here:
39
 * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/trblsql/tr_err_odbc_5stz.asp
40
 *
41
 * @category   Database
42
 * @package    DB
43
 * @author     Stig Bakken <ssb@php.net>
44
 * @author     Daniel Convissor <danielc@php.net>
45
 * @copyright  1997-2005 The PHP Group
46
 * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
1173 jp_milcent 47
 * @version    Release: 1.7.6
320 jpm 48
 * @link       http://pear.php.net/package/DB
49
 */
50
class DB_odbc extends DB_common
51
{
52
    // {{{ properties
53
 
54
    /**
55
     * The DB driver type (mysql, oci8, odbc, etc.)
56
     * @var string
57
     */
58
    var $phptype = 'odbc';
59
 
60
    /**
61
     * The database syntax variant to be used (db2, access, etc.), if any
62
     * @var string
63
     */
64
    var $dbsyntax = 'sql92';
65
 
66
    /**
67
     * The capabilities of this DB implementation
68
     *
69
     * The 'new_link' element contains the PHP version that first provided
70
     * new_link support for this DBMS.  Contains false if it's unsupported.
71
     *
72
     * Meaning of the 'limit' element:
73
     *   + 'emulate' = emulate with fetch row by number
74
     *   + 'alter'   = alter the query
75
     *   + false     = skip rows
76
     *
77
     * NOTE: The feature set of the following drivers are different than
78
     * the default:
79
     *   + solid: 'transactions' = true
80
     *   + navision: 'limit' = false
81
     *
82
     * @var array
83
     */
84
    var $features = array(
85
        'limit'         => 'emulate',
86
        'new_link'      => false,
87
        'numrows'       => true,
88
        'pconnect'      => true,
89
        'prepare'       => false,
90
        'ssl'           => false,
91
        'transactions'  => false,
92
    );
93
 
94
    /**
95
     * A mapping of native error codes to DB error codes
96
     * @var array
97
     */
98
    var $errorcode_map = array(
99
        '01004' => DB_ERROR_TRUNCATED,
100
        '07001' => DB_ERROR_MISMATCH,
101
        '21S01' => DB_ERROR_VALUE_COUNT_ON_ROW,
102
        '21S02' => DB_ERROR_MISMATCH,
103
        '22001' => DB_ERROR_INVALID,
104
        '22003' => DB_ERROR_INVALID_NUMBER,
105
        '22005' => DB_ERROR_INVALID_NUMBER,
106
        '22008' => DB_ERROR_INVALID_DATE,
107
        '22012' => DB_ERROR_DIVZERO,
108
        '23000' => DB_ERROR_CONSTRAINT,
109
        '23502' => DB_ERROR_CONSTRAINT_NOT_NULL,
110
        '23503' => DB_ERROR_CONSTRAINT,
111
        '23504' => DB_ERROR_CONSTRAINT,
112
        '23505' => DB_ERROR_CONSTRAINT,
113
        '24000' => DB_ERROR_INVALID,
114
        '34000' => DB_ERROR_INVALID,
115
        '37000' => DB_ERROR_SYNTAX,
116
        '42000' => DB_ERROR_SYNTAX,
117
        '42601' => DB_ERROR_SYNTAX,
118
        'IM001' => DB_ERROR_UNSUPPORTED,
119
        'S0000' => DB_ERROR_NOSUCHTABLE,
120
        'S0001' => DB_ERROR_ALREADY_EXISTS,
121
        'S0002' => DB_ERROR_NOSUCHTABLE,
122
        'S0011' => DB_ERROR_ALREADY_EXISTS,
123
        'S0012' => DB_ERROR_NOT_FOUND,
124
        'S0021' => DB_ERROR_ALREADY_EXISTS,
125
        'S0022' => DB_ERROR_NOSUCHFIELD,
126
        'S1009' => DB_ERROR_INVALID,
127
        'S1090' => DB_ERROR_INVALID,
128
        'S1C00' => DB_ERROR_NOT_CAPABLE,
129
    );
130
 
131
    /**
132
     * The raw database connection created by PHP
133
     * @var resource
134
     */
135
    var $connection;
136
 
137
    /**
138
     * The DSN information for connecting to a database
139
     * @var array
140
     */
141
    var $dsn = array();
142
 
143
 
144
    /**
145
     * The number of rows affected by a data manipulation query
146
     * @var integer
147
     * @access private
148
     */
149
    var $affected = 0;
150
 
151
 
152
    // }}}
153
    // {{{ constructor
154
 
155
    /**
156
     * This constructor calls <kbd>$this->DB_common()</kbd>
157
     *
158
     * @return void
159
     */
160
    function DB_odbc()
161
    {
162
        $this->DB_common();
163
    }
164
 
165
    // }}}
166
    // {{{ connect()
167
 
168
    /**
169
     * Connect to the database server, log in and open the database
170
     *
171
     * Don't call this method directly.  Use DB::connect() instead.
172
     *
173
     * PEAR DB's odbc driver supports the following extra DSN options:
174
     *   + cursor  The type of cursor to be used for this connection.
175
     *
176
     * @param array $dsn         the data source name
177
     * @param bool  $persistent  should the connection be persistent?
178
     *
179
     * @return int  DB_OK on success. A DB_Error object on failure.
180
     */
181
    function connect($dsn, $persistent = false)
182
    {
183
        if (!PEAR::loadExtension('odbc')) {
184
            return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
185
        }
186
 
187
        $this->dsn = $dsn;
188
        if ($dsn['dbsyntax']) {
189
            $this->dbsyntax = $dsn['dbsyntax'];
190
        }
191
        switch ($this->dbsyntax) {
192
            case 'access':
193
            case 'db2':
194
            case 'solid':
195
                $this->features['transactions'] = true;
196
                break;
197
            case 'navision':
198
                $this->features['limit'] = false;
199
        }
200
 
201
        /*
202
         * This is hear for backwards compatibility. Should have been using
203
         * 'database' all along, but prior to 1.6.0RC3 'hostspec' was used.
204
         */
205
        if ($dsn['database']) {
206
            $odbcdsn = $dsn['database'];
207
        } elseif ($dsn['hostspec']) {
208
            $odbcdsn = $dsn['hostspec'];
209
        } else {
210
            $odbcdsn = 'localhost';
211
        }
212
 
213
        $connect_function = $persistent ? 'odbc_pconnect' : 'odbc_connect';
214
 
215
        if (empty($dsn['cursor'])) {
216
            $this->connection = @$connect_function($odbcdsn, $dsn['username'],
217
                                                   $dsn['password']);
218
        } else {
219
            $this->connection = @$connect_function($odbcdsn, $dsn['username'],
220
                                                   $dsn['password'],
221
                                                   $dsn['cursor']);
222
        }
223
 
224
        if (!is_resource($this->connection)) {
225
            return $this->raiseError(DB_ERROR_CONNECT_FAILED,
226
                                     null, null, null,
227
                                     $this->errorNative());
228
        }
229
        return DB_OK;
230
    }
231
 
232
    // }}}
233
    // {{{ disconnect()
234
 
235
    /**
236
     * Disconnects from the database server
237
     *
238
     * @return bool  TRUE on success, FALSE on failure
239
     */
240
    function disconnect()
241
    {
242
        $err = @odbc_close($this->connection);
243
        $this->connection = null;
244
        return $err;
245
    }
246
 
247
    // }}}
248
    // {{{ simpleQuery()
249
 
250
    /**
251
     * Sends a query to the database server
252
     *
253
     * @param string  the SQL query string
254
     *
255
     * @return mixed  + a PHP result resrouce for successful SELECT queries
256
     *                + the DB_OK constant for other successful queries
257
     *                + a DB_Error object on failure
258
     */
259
    function simpleQuery($query)
260
    {
261
        $this->last_query = $query;
262
        $query = $this->modifyQuery($query);
263
        $result = @odbc_exec($this->connection, $query);
264
        if (!$result) {
265
            return $this->odbcRaiseError(); // XXX ERRORMSG
266
        }
267
        // Determine which queries that should return data, and which
268
        // should return an error code only.
269
        if (DB::isManip($query)) {
270
            $this->affected = $result; // For affectedRows()
271
            return DB_OK;
272
        }
273
        $this->affected = 0;
274
        return $result;
275
    }
276
 
277
    // }}}
278
    // {{{ nextResult()
279
 
280
    /**
281
     * Move the internal odbc result pointer to the next available result
282
     *
283
     * @param a valid fbsql result resource
284
     *
285
     * @access public
286
     *
287
     * @return true if a result is available otherwise return false
288
     */
289
    function nextResult($result)
290
    {
291
        return @odbc_next_result($result);
292
    }
293
 
294
    // }}}
295
    // {{{ fetchInto()
296
 
297
    /**
298
     * Places a row from the result set into the given array
299
     *
300
     * Formating of the array and the data therein are configurable.
301
     * See DB_result::fetchInto() for more information.
302
     *
303
     * This method is not meant to be called directly.  Use
304
     * DB_result::fetchInto() instead.  It can't be declared "protected"
305
     * because DB_result is a separate object.
306
     *
307
     * @param resource $result    the query result resource
308
     * @param array    $arr       the referenced array to put the data in
309
     * @param int      $fetchmode how the resulting array should be indexed
310
     * @param int      $rownum    the row number to fetch (0 = first row)
311
     *
312
     * @return mixed  DB_OK on success, NULL when the end of a result set is
313
     *                 reached or on failure
314
     *
315
     * @see DB_result::fetchInto()
316
     */
317
    function fetchInto($result, &$arr, $fetchmode, $rownum = null)
318
    {
319
        $arr = array();
320
        if ($rownum !== null) {
321
            $rownum++; // ODBC first row is 1
322
            if (version_compare(phpversion(), '4.2.0', 'ge')) {
323
                $cols = @odbc_fetch_into($result, $arr, $rownum);
324
            } else {
325
                $cols = @odbc_fetch_into($result, $rownum, $arr);
326
            }
327
        } else {
328
            $cols = @odbc_fetch_into($result, $arr);
329
        }
330
        if (!$cols) {
331
            return null;
332
        }
333
        if ($fetchmode !== DB_FETCHMODE_ORDERED) {
334
            for ($i = 0; $i < count($arr); $i++) {
335
                $colName = @odbc_field_name($result, $i+1);
336
                $a[$colName] = $arr[$i];
337
            }
338
            if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
339
                $a = array_change_key_case($a, CASE_LOWER);
340
            }
341
            $arr = $a;
342
        }
343
        if ($this->options['portability'] & DB_PORTABILITY_RTRIM) {
344
            $this->_rtrimArrayValues($arr);
345
        }
346
        if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) {
347
            $this->_convertNullArrayValuesToEmpty($arr);
348
        }
349
        return DB_OK;
350
    }
351
 
352
    // }}}
353
    // {{{ freeResult()
354
 
355
    /**
356
     * Deletes the result set and frees the memory occupied by the result set
357
     *
358
     * This method is not meant to be called directly.  Use
359
     * DB_result::free() instead.  It can't be declared "protected"
360
     * because DB_result is a separate object.
361
     *
362
     * @param resource $result  PHP's query result resource
363
     *
364
     * @return bool  TRUE on success, FALSE if $result is invalid
365
     *
366
     * @see DB_result::free()
367
     */
368
    function freeResult($result)
369
    {
370
        return @odbc_free_result($result);
371
    }
372
 
373
    // }}}
374
    // {{{ numCols()
375
 
376
    /**
377
     * Gets the number of columns in a result set
378
     *
379
     * This method is not meant to be called directly.  Use
380
     * DB_result::numCols() instead.  It can't be declared "protected"
381
     * because DB_result is a separate object.
382
     *
383
     * @param resource $result  PHP's query result resource
384
     *
385
     * @return int  the number of columns.  A DB_Error object on failure.
386
     *
387
     * @see DB_result::numCols()
388
     */
389
    function numCols($result)
390
    {
391
        $cols = @odbc_num_fields($result);
392
        if (!$cols) {
393
            return $this->odbcRaiseError();
394
        }
395
        return $cols;
396
    }
397
 
398
    // }}}
399
    // {{{ affectedRows()
400
 
401
    /**
402
     * Determines the number of rows affected by a data maniuplation query
403
     *
404
     * 0 is returned for queries that don't manipulate data.
405
     *
406
     * @return int  the number of rows.  A DB_Error object on failure.
407
     */
408
    function affectedRows()
409
    {
410
        if (empty($this->affected)) {  // In case of SELECT stms
411
            return 0;
412
        }
413
        $nrows = @odbc_num_rows($this->affected);
414
        if ($nrows == -1) {
415
            return $this->odbcRaiseError();
416
        }
417
        return $nrows;
418
    }
419
 
420
    // }}}
421
    // {{{ numRows()
422
 
423
    /**
424
     * Gets the number of rows in a result set
425
     *
426
     * Not all ODBC drivers support this functionality.  If they don't
427
     * a DB_Error object for DB_ERROR_UNSUPPORTED is returned.
428
     *
429
     * This method is not meant to be called directly.  Use
430
     * DB_result::numRows() instead.  It can't be declared "protected"
431
     * because DB_result is a separate object.
432
     *
433
     * @param resource $result  PHP's query result resource
434
     *
435
     * @return int  the number of rows.  A DB_Error object on failure.
436
     *
437
     * @see DB_result::numRows()
438
     */
439
    function numRows($result)
440
    {
441
        $nrows = @odbc_num_rows($result);
442
        if ($nrows == -1) {
443
            return $this->odbcRaiseError(DB_ERROR_UNSUPPORTED);
444
        }
445
        if ($nrows === false) {
446
            return $this->odbcRaiseError();
447
        }
448
        return $nrows;
449
    }
450
 
451
    // }}}
452
    // {{{ quoteIdentifier()
453
 
454
    /**
455
     * Quotes a string so it can be safely used as a table or column name
456
     *
457
     * Use 'mssql' as the dbsyntax in the DB DSN only if you've unchecked
458
     * "Use ANSI quoted identifiers" when setting up the ODBC data source.
459
     *
460
     * @param string $str  identifier name to be quoted
461
     *
462
     * @return string  quoted identifier string
463
     *
464
     * @see DB_common::quoteIdentifier()
465
     * @since Method available since Release 1.6.0
466
     */
467
    function quoteIdentifier($str)
468
    {
469
        switch ($this->dsn['dbsyntax']) {
470
            case 'access':
471
                return '[' . $str . ']';
472
            case 'mssql':
473
            case 'sybase':
474
                return '[' . str_replace(']', ']]', $str) . ']';
475
            case 'mysql':
476
            case 'mysqli':
477
                return '`' . $str . '`';
478
            default:
479
                return '"' . str_replace('"', '""', $str) . '"';
480
        }
481
    }
482
 
483
    // }}}
484
    // {{{ quote()
485
 
486
    /**
487
     * @deprecated  Deprecated in release 1.6.0
488
     * @internal
489
     */
490
    function quote($str)
491
    {
492
        return $this->quoteSmart($str);
493
    }
494
 
495
    // }}}
496
    // {{{ nextId()
497
 
498
    /**
499
     * Returns the next free id in a sequence
500
     *
501
     * @param string  $seq_name  name of the sequence
502
     * @param boolean $ondemand  when true, the seqence is automatically
503
     *                            created if it does not exist
504
     *
505
     * @return int  the next id number in the sequence.
506
     *               A DB_Error object on failure.
507
     *
508
     * @see DB_common::nextID(), DB_common::getSequenceName(),
509
     *      DB_odbc::createSequence(), DB_odbc::dropSequence()
510
     */
511
    function nextId($seq_name, $ondemand = true)
512
    {
513
        $seqname = $this->getSequenceName($seq_name);
514
        $repeat = 0;
515
        do {
516
            $this->pushErrorHandling(PEAR_ERROR_RETURN);
517
            $result = $this->query("update ${seqname} set id = id + 1");
518
            $this->popErrorHandling();
519
            if ($ondemand && DB::isError($result) &&
520
                $result->getCode() == DB_ERROR_NOSUCHTABLE) {
521
                $repeat = 1;
522
                $this->pushErrorHandling(PEAR_ERROR_RETURN);
523
                $result = $this->createSequence($seq_name);
524
                $this->popErrorHandling();
525
                if (DB::isError($result)) {
526
                    return $this->raiseError($result);
527
                }
528
                $result = $this->query("insert into ${seqname} (id) values(0)");
529
            } else {
530
                $repeat = 0;
531
            }
532
        } while ($repeat);
533
 
534
        if (DB::isError($result)) {
535
            return $this->raiseError($result);
536
        }
537
 
538
        $result = $this->query("select id from ${seqname}");
539
        if (DB::isError($result)) {
540
            return $result;
541
        }
542
 
543
        $row = $result->fetchRow(DB_FETCHMODE_ORDERED);
544
        if (DB::isError($row || !$row)) {
545
            return $row;
546
        }
547
 
548
        return $row[0];
549
    }
550
 
551
    /**
552
     * Creates a new sequence
553
     *
554
     * @param string $seq_name  name of the new sequence
555
     *
556
     * @return int  DB_OK on success.  A DB_Error object on failure.
557
     *
558
     * @see DB_common::createSequence(), DB_common::getSequenceName(),
559
     *      DB_odbc::nextID(), DB_odbc::dropSequence()
560
     */
561
    function createSequence($seq_name)
562
    {
563
        return $this->query('CREATE TABLE '
564
                            . $this->getSequenceName($seq_name)
565
                            . ' (id integer NOT NULL,'
566
                            . ' PRIMARY KEY(id))');
567
    }
568
 
569
    // }}}
570
    // {{{ dropSequence()
571
 
572
    /**
573
     * Deletes a sequence
574
     *
575
     * @param string $seq_name  name of the sequence to be deleted
576
     *
577
     * @return int  DB_OK on success.  A DB_Error object on failure.
578
     *
579
     * @see DB_common::dropSequence(), DB_common::getSequenceName(),
580
     *      DB_odbc::nextID(), DB_odbc::createSequence()
581
     */
582
    function dropSequence($seq_name)
583
    {
584
        return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name));
585
    }
586
 
587
    // }}}
588
    // {{{ autoCommit()
589
 
590
    /**
591
     * Enables or disables automatic commits
592
     *
593
     * @param bool $onoff  true turns it on, false turns it off
594
     *
595
     * @return int  DB_OK on success.  A DB_Error object if the driver
596
     *               doesn't support auto-committing transactions.
597
     */
598
    function autoCommit($onoff = false)
599
    {
600
        if (!@odbc_autocommit($this->connection, $onoff)) {
601
            return $this->odbcRaiseError();
602
        }
603
        return DB_OK;
604
    }
605
 
606
    // }}}
607
    // {{{ commit()
608
 
609
    /**
610
     * Commits the current transaction
611
     *
612
     * @return int  DB_OK on success.  A DB_Error object on failure.
613
     */
614
    function commit()
615
    {
616
        if (!@odbc_commit($this->connection)) {
617
            return $this->odbcRaiseError();
618
        }
619
        return DB_OK;
620
    }
621
 
622
    // }}}
623
    // {{{ rollback()
624
 
625
    /**
626
     * Reverts the current transaction
627
     *
628
     * @return int  DB_OK on success.  A DB_Error object on failure.
629
     */
630
    function rollback()
631
    {
632
        if (!@odbc_rollback($this->connection)) {
633
            return $this->odbcRaiseError();
634
        }
635
        return DB_OK;
636
    }
637
 
638
    // }}}
639
    // {{{ odbcRaiseError()
640
 
641
    /**
642
     * Produces a DB_Error object regarding the current problem
643
     *
644
     * @param int $errno  if the error is being manually raised pass a
645
     *                     DB_ERROR* constant here.  If this isn't passed
646
     *                     the error information gathered from the DBMS.
647
     *
648
     * @return object  the DB_Error object
649
     *
650
     * @see DB_common::raiseError(),
651
     *      DB_odbc::errorNative(), DB_common::errorCode()
652
     */
653
    function odbcRaiseError($errno = null)
654
    {
655
        if ($errno === null) {
656
            switch ($this->dbsyntax) {
657
                case 'access':
658
                    if ($this->options['portability'] & DB_PORTABILITY_ERRORS) {
659
                        $this->errorcode_map['07001'] = DB_ERROR_NOSUCHFIELD;
660
                    } else {
661
                        // Doing this in case mode changes during runtime.
662
                        $this->errorcode_map['07001'] = DB_ERROR_MISMATCH;
663
                    }
664
 
665
                    $native_code = odbc_error($this->connection);
666
 
667
                    // S1000 is for "General Error."  Let's be more specific.
668
                    if ($native_code == 'S1000') {
669
                        $errormsg = odbc_errormsg($this->connection);
670
                        static $error_regexps;
671
                        if (!isset($error_regexps)) {
672
                            $error_regexps = array(
673
                                '/includes related records.$/i'  => DB_ERROR_CONSTRAINT,
674
                                '/cannot contain a Null value/i' => DB_ERROR_CONSTRAINT_NOT_NULL,
675
                            );
676
                        }
677
                        foreach ($error_regexps as $regexp => $code) {
678
                            if (preg_match($regexp, $errormsg)) {
679
                                return $this->raiseError($code,
680
                                        null, null, null,
681
                                        $native_code . ' ' . $errormsg);
682
                            }
683
                        }
684
                        $errno = DB_ERROR;
685
                    } else {
686
                        $errno = $this->errorCode($native_code);
687
                    }
688
                    break;
689
                default:
690
                    $errno = $this->errorCode(odbc_error($this->connection));
691
            }
692
        }
693
        return $this->raiseError($errno, null, null, null,
694
                                 $this->errorNative());
695
    }
696
 
697
    // }}}
698
    // {{{ errorNative()
699
 
700
    /**
701
     * Gets the DBMS' native error code and message produced by the last query
702
     *
703
     * @return string  the DBMS' error code and message
704
     */
705
    function errorNative()
706
    {
707
        if (!is_resource($this->connection)) {
708
            return @odbc_error() . ' ' . @odbc_errormsg();
709
        }
710
        return @odbc_error($this->connection) . ' ' . @odbc_errormsg($this->connection);
711
    }
712
 
713
    // }}}
714
    // {{{ tableInfo()
715
 
716
    /**
717
     * Returns information about a table or a result set
718
     *
719
     * @param object|string  $result  DB_result object from a query or a
720
     *                                 string containing the name of a table.
721
     *                                 While this also accepts a query result
722
     *                                 resource identifier, this behavior is
723
     *                                 deprecated.
724
     * @param int            $mode    a valid tableInfo mode
725
     *
726
     * @return array  an associative array with the information requested.
727
     *                 A DB_Error object on failure.
728
     *
729
     * @see DB_common::tableInfo()
730
     * @since Method available since Release 1.7.0
731
     */
732
    function tableInfo($result, $mode = null)
733
    {
734
        if (is_string($result)) {
735
            /*
736
             * Probably received a table name.
737
             * Create a result resource identifier.
738
             */
739
            $id = @odbc_exec($this->connection, "SELECT * FROM $result");
740
            if (!$id) {
741
                return $this->odbcRaiseError();
742
            }
743
            $got_string = true;
744
        } elseif (isset($result->result)) {
745
            /*
746
             * Probably received a result object.
747
             * Extract the result resource identifier.
748
             */
749
            $id = $result->result;
750
            $got_string = false;
751
        } else {
752
            /*
753
             * Probably received a result resource identifier.
754
             * Copy it.
755
             * Deprecated.  Here for compatibility only.
756
             */
757
            $id = $result;
758
            $got_string = false;
759
        }
760
 
761
        if (!is_resource($id)) {
762
            return $this->odbcRaiseError(DB_ERROR_NEED_MORE_DATA);
763
        }
764
 
765
        if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
766
            $case_func = 'strtolower';
767
        } else {
768
            $case_func = 'strval';
769
        }
770
 
771
        $count = @odbc_num_fields($id);
772
        $res   = array();
773
 
774
        if ($mode) {
775
            $res['num_fields'] = $count;
776
        }
777
 
778
        for ($i = 0; $i < $count; $i++) {
779
            $col = $i + 1;
780
            $res[$i] = array(
781
                'table' => $got_string ? $case_func($result) : '',
782
                'name'  => $case_func(@odbc_field_name($id, $col)),
783
                'type'  => @odbc_field_type($id, $col),
784
                'len'   => @odbc_field_len($id, $col),
785
                'flags' => '',
786
            );
787
            if ($mode & DB_TABLEINFO_ORDER) {
788
                $res['order'][$res[$i]['name']] = $i;
789
            }
790
            if ($mode & DB_TABLEINFO_ORDERTABLE) {
791
                $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
792
            }
793
        }
794
 
795
        // free the result only if we were called on a table
796
        if ($got_string) {
797
            @odbc_free_result($id);
798
        }
799
        return $res;
800
    }
801
 
802
    // }}}
803
    // {{{ getSpecialQuery()
804
 
805
    /**
806
     * Obtains the query string needed for listing a given type of objects
807
     *
808
     * Thanks to symbol1@gmail.com and Philippe.Jausions@11abacus.com.
809
     *
810
     * @param string $type  the kind of objects you want to retrieve
811
     *
812
     * @return string  the list of objects requested
813
     *
814
     * @access protected
815
     * @see DB_common::getListOf()
816
     * @since Method available since Release 1.7.0
817
     */
818
    function getSpecialQuery($type)
819
    {
820
        switch ($type) {
821
            case 'databases':
822
                if (!function_exists('odbc_data_source')) {
823
                    return null;
824
                }
825
                $res = @odbc_data_source($this->connection, SQL_FETCH_FIRST);
826
                if (is_array($res)) {
827
                    $out = array($res['server']);
828
                    while($res = @odbc_data_source($this->connection,
829
                                                   SQL_FETCH_NEXT))
830
                    {
831
                        $out[] = $res['server'];
832
                    }
833
                    return $out;
834
                } else {
835
                    return $this->odbcRaiseError();
836
                }
837
                break;
838
            case 'tables':
839
            case 'schema.tables':
840
                $keep = 'TABLE';
841
                break;
842
            case 'views':
843
                $keep = 'VIEW';
844
                break;
845
            default:
846
                return null;
847
        }
848
 
849
        /*
850
         * Removing non-conforming items in the while loop rather than
851
         * in the odbc_tables() call because some backends choke on this:
852
         *     odbc_tables($this->connection, '', '', '', 'TABLE')
853
         */
854
        $res  = @odbc_tables($this->connection);
855
        if (!$res) {
856
            return $this->odbcRaiseError();
857
        }
858
        $out = array();
859
        while ($row = odbc_fetch_array($res)) {
860
            if ($row['TABLE_TYPE'] != $keep) {
861
                continue;
862
            }
863
            if ($type == 'schema.tables') {
864
                $out[] = $row['TABLE_SCHEM'] . '.' . $row['TABLE_NAME'];
865
            } else {
866
                $out[] = $row['TABLE_NAME'];
867
            }
868
        }
869
        return $out;
870
    }
871
 
872
    // }}}
873
 
874
}
875
 
876
/*
877
 * Local variables:
878
 * tab-width: 4
879
 * c-basic-offset: 4
880
 * End:
881
 */
882
 
883
?>