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

« back to all changes in this revision

Viewing changes to plugins/wiki/www/lib/pear/DB/oci8.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
// | Author: James L. Pine <jlp@valinux.com>                              |
 
17
// | Maintainer: Daniel Convissor <danielc@php.net>                       |
 
18
// +----------------------------------------------------------------------+
 
19
//
 
20
// $Id: oci8.php 6184 2008-08-22 10:33:41Z vargenau $
 
21
 
 
22
 
 
23
// be aware...  OCIError() only appears to return anything when given a
 
24
// statement, so functions return the generic DB_ERROR instead of more
 
25
// useful errors that have to do with feedback from the database.
 
26
 
 
27
 
 
28
require_once 'DB/common.php';
 
29
 
 
30
/**
 
31
 * Database independent query interface definition for PHP's Oracle 8
 
32
 * call-interface extension.
 
33
 *
 
34
 * Definitely works with versions 8 and 9 of Oracle.
 
35
 *
 
36
 * @package  DB
 
37
 * @version  $Id: oci8.php 6184 2008-08-22 10:33:41Z vargenau $
 
38
 * @category Database
 
39
 * @author   James L. Pine <jlp@valinux.com>
 
40
 */
 
41
class DB_oci8 extends DB_common
 
42
{
 
43
    // {{{ properties
 
44
 
 
45
    var $connection;
 
46
    var $phptype, $dbsyntax;
 
47
    var $manip_query = array();
 
48
    var $prepare_types = array();
 
49
    var $autoCommit = 1;
 
50
    var $last_stmt = false;
 
51
 
 
52
    /**
 
53
     * stores the $data passed to execute() in the oci8 driver
 
54
     *
 
55
     * Gets reset to array() when simpleQuery() is run.
 
56
     *
 
57
     * Needed in case user wants to call numRows() after prepare/execute
 
58
     * was used.
 
59
     *
 
60
     * @var array
 
61
     * @access private
 
62
     */
 
63
    var $_data = array();
 
64
 
 
65
    // }}}
 
66
    // {{{ constructor
 
67
 
 
68
    function DB_oci8()
 
69
    {
 
70
        $this->DB_common();
 
71
        $this->phptype = 'oci8';
 
72
        $this->dbsyntax = 'oci8';
 
73
        $this->features = array(
 
74
            'prepare' => false,
 
75
            'pconnect' => true,
 
76
            'transactions' => true,
 
77
            'limit' => 'alter'
 
78
        );
 
79
        $this->errorcode_map = array(
 
80
            1 => DB_ERROR_CONSTRAINT,
 
81
            900 => DB_ERROR_SYNTAX,
 
82
            904 => DB_ERROR_NOSUCHFIELD,
 
83
            921 => DB_ERROR_SYNTAX,
 
84
            923 => DB_ERROR_SYNTAX,
 
85
            942 => DB_ERROR_NOSUCHTABLE,
 
86
            955 => DB_ERROR_ALREADY_EXISTS,
 
87
            1400 => DB_ERROR_CONSTRAINT_NOT_NULL,
 
88
            1407 => DB_ERROR_CONSTRAINT_NOT_NULL,
 
89
            1476 => DB_ERROR_DIVZERO,
 
90
            1722 => DB_ERROR_INVALID_NUMBER,
 
91
            2289 => DB_ERROR_NOSUCHTABLE,
 
92
            2291 => DB_ERROR_CONSTRAINT,
 
93
            2449 => DB_ERROR_CONSTRAINT,
 
94
        );
 
95
    }
 
96
 
 
97
    // }}}
 
98
    // {{{ connect()
 
99
 
 
100
    /**
 
101
     * Connect to a database and log in as the specified user.
 
102
     *
 
103
     * @param $dsn the data source name (see DB::parseDSN for syntax)
 
104
     * @param $persistent (optional) whether the connection should
 
105
     *        be persistent
 
106
     *
 
107
     * @return int DB_OK on success, a DB error code on failure
 
108
     */
 
109
    function connect($dsninfo, $persistent = false)
 
110
    {
 
111
        if (!DB::assertExtension('oci8')) {
 
112
            return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
 
113
        }
 
114
        $this->dsn = $dsninfo;
 
115
 
 
116
        $connect_function = $persistent ? 'OCIPLogon' : 'OCILogon';
 
117
 
 
118
        if ($dsninfo['hostspec']) {
 
119
            $conn = @$connect_function($dsninfo['username'],
 
120
                                       $dsninfo['password'],
 
121
                                       $dsninfo['hostspec']);
 
122
        } elseif ($dsninfo['username'] || $dsninfo['password']) {
 
123
            $conn = @$connect_function($dsninfo['username'],
 
124
                                       $dsninfo['password']);
 
125
        } else {
 
126
            $conn = false;
 
127
        }
 
128
        if ($conn == false) {
 
129
            $error = OCIError();
 
130
            $error = (is_array($error)) ? $error['message'] : null;
 
131
            return $this->raiseError(DB_ERROR_CONNECT_FAILED, null, null,
 
132
                                     null, $error);
 
133
        }
 
134
        $this->connection = $conn;
 
135
        return DB_OK;
 
136
    }
 
137
 
 
138
    // }}}
 
139
    // {{{ disconnect()
 
140
 
 
141
    /**
 
142
     * Log out and disconnect from the database.
 
143
     *
 
144
     * @return bool true on success, false if not connected.
 
145
     */
 
146
    function disconnect()
 
147
    {
 
148
        $ret = @OCILogOff($this->connection);
 
149
        $this->connection = null;
 
150
        return $ret;
 
151
    }
 
152
 
 
153
    // }}}
 
154
    // {{{ simpleQuery()
 
155
 
 
156
    /**
 
157
     * Send a query to oracle and return the results as an oci8 resource
 
158
     * identifier.
 
159
     *
 
160
     * @param $query the SQL query
 
161
     *
 
162
     * @return int returns a valid oci8 result for successful SELECT
 
163
     * queries, DB_OK for other successful queries.  A DB error code
 
164
     * is returned on failure.
 
165
     */
 
166
    function simpleQuery($query)
 
167
    {
 
168
        $this->_data = array();
 
169
        $this->last_query = $query;
 
170
        $query = $this->modifyQuery($query);
 
171
        $result = @OCIParse($this->connection, $query);
 
172
        if (!$result) {
 
173
            return $this->oci8RaiseError();
 
174
        }
 
175
        if ($this->autoCommit) {
 
176
            $success = @OCIExecute($result,OCI_COMMIT_ON_SUCCESS);
 
177
        } else {
 
178
            $success = @OCIExecute($result,OCI_DEFAULT);
 
179
        }
 
180
        if (!$success) {
 
181
            return $this->oci8RaiseError($result);
 
182
        }
 
183
        $this->last_stmt=$result;
 
184
        // Determine which queries that should return data, and which
 
185
        // should return an error code only.
 
186
        return DB::isManip($query) ? DB_OK : $result;
 
187
    }
 
188
 
 
189
    // }}}
 
190
    // {{{ nextResult()
 
191
 
 
192
    /**
 
193
     * Move the internal oracle result pointer to the next available result
 
194
     *
 
195
     * @param a valid oci8 result resource
 
196
     *
 
197
     * @access public
 
198
     *
 
199
     * @return true if a result is available otherwise return false
 
200
     */
 
201
    function nextResult($result)
 
202
    {
 
203
        return false;
 
204
    }
 
205
 
 
206
    // }}}
 
207
    // {{{ fetchInto()
 
208
 
 
209
    /**
 
210
     * Fetch a row and insert the data into an existing array.
 
211
     *
 
212
     * Formating of the array and the data therein are configurable.
 
213
     * See DB_result::fetchInto() for more information.
 
214
     *
 
215
     * @param resource $result    query result identifier
 
216
     * @param array    $arr       (reference) array where data from the row
 
217
     *                            should be placed
 
218
     * @param int      $fetchmode how the resulting array should be indexed
 
219
     * @param int      $rownum    the row number to fetch
 
220
     *
 
221
     * @return mixed DB_OK on success, null when end of result set is
 
222
     *               reached or on failure
 
223
     *
 
224
     * @see DB_result::fetchInto()
 
225
     * @access private
 
226
     */
 
227
    function fetchInto($result, &$arr, $fetchmode, $rownum=null)
 
228
    {
 
229
        if ($rownum !== null) {
 
230
            return $this->raiseError(DB_ERROR_NOT_CAPABLE);
 
231
        }
 
232
        if ($fetchmode & DB_FETCHMODE_ASSOC) {
 
233
            $moredata = @OCIFetchInto($result,$arr,OCI_ASSOC+OCI_RETURN_NULLS+OCI_RETURN_LOBS);
 
234
            if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE &&
 
235
                $moredata)
 
236
            {
 
237
                $arr = array_change_key_case($arr, CASE_LOWER);
 
238
            }
 
239
        } else {
 
240
            $moredata = OCIFetchInto($result,$arr,OCI_RETURN_NULLS+OCI_RETURN_LOBS);
 
241
        }
 
242
        if (!$moredata) {
 
243
            return null;
 
244
        }
 
245
        if ($this->options['portability'] & DB_PORTABILITY_RTRIM) {
 
246
            $this->_rtrimArrayValues($arr);
 
247
        }
 
248
        if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) {
 
249
            $this->_convertNullArrayValuesToEmpty($arr);
 
250
        }
 
251
        return DB_OK;
 
252
    }
 
253
 
 
254
    // }}}
 
255
    // {{{ freeResult()
 
256
 
 
257
    /**
 
258
     * Free the internal resources associated with $result.
 
259
     *
 
260
     * @param $result oci8 result identifier
 
261
     *
 
262
     * @return bool true on success, false if $result is invalid
 
263
     */
 
264
    function freeResult($result)
 
265
    {
 
266
        return @OCIFreeStatement($result);
 
267
    }
 
268
 
 
269
    /**
 
270
     * Free the internal resources associated with a prepared query.
 
271
     *
 
272
     * @param $stmt oci8 statement identifier
 
273
     *
 
274
     * @return bool true on success, false if $result is invalid
 
275
     */
 
276
    function freePrepared($stmt)
 
277
    {
 
278
        if (isset($this->prepare_types[(int)$stmt])) {
 
279
            unset($this->prepare_types[(int)$stmt]);
 
280
            unset($this->manip_query[(int)$stmt]);
 
281
        } else {
 
282
            return false;
 
283
        }
 
284
        return true;
 
285
    }
 
286
 
 
287
    // }}}
 
288
    // {{{ numRows()
 
289
 
 
290
    function numRows($result)
 
291
    {
 
292
        // emulate numRows for Oracle.  yuck.
 
293
        if ($this->options['portability'] & DB_PORTABILITY_NUMROWS &&
 
294
            $result === $this->last_stmt)
 
295
        {
 
296
            $countquery = 'SELECT COUNT(*) FROM ('.$this->last_query.')';
 
297
            $save_query = $this->last_query;
 
298
            $save_stmt = $this->last_stmt;
 
299
 
 
300
            if (count($this->_data)) {
 
301
                $smt = $this->prepare('SELECT COUNT(*) FROM ('.$this->last_query.')');
 
302
                $count = $this->execute($smt, $this->_data);
 
303
            } else {
 
304
                $count =& $this->query($countquery);
 
305
            }
 
306
 
 
307
            if (DB::isError($count) ||
 
308
                DB::isError($row = $count->fetchRow(DB_FETCHMODE_ORDERED)))
 
309
            {
 
310
                $this->last_query = $save_query;
 
311
                $this->last_stmt = $save_stmt;
 
312
                return $this->raiseError(DB_ERROR_NOT_CAPABLE);
 
313
            }
 
314
            return $row[0];
 
315
        }
 
316
        return $this->raiseError(DB_ERROR_NOT_CAPABLE);
 
317
    }
 
318
 
 
319
    // }}}
 
320
    // {{{ numCols()
 
321
 
 
322
    /**
 
323
     * Get the number of columns in a result set.
 
324
     *
 
325
     * @param $result oci8 result identifier
 
326
     *
 
327
     * @return int the number of columns per row in $result
 
328
     */
 
329
    function numCols($result)
 
330
    {
 
331
        $cols = @OCINumCols($result);
 
332
        if (!$cols) {
 
333
            return $this->oci8RaiseError($result);
 
334
        }
 
335
        return $cols;
 
336
    }
 
337
 
 
338
    // }}}
 
339
    // {{{ errorNative()
 
340
 
 
341
    /**
 
342
     * Get the native error code of the last error (if any) that occured
 
343
     * on the current connection.  This does not work, as OCIError does
 
344
     * not work unless given a statement.  If OCIError does return
 
345
     * something, so will this.
 
346
     *
 
347
     * @return int native oci8 error code
 
348
     */
 
349
    function errorNative()
 
350
    {
 
351
        if (is_resource($this->last_stmt)) {
 
352
            $error = @OCIError($this->last_stmt);
 
353
        } else {
 
354
            $error = @OCIError($this->connection);
 
355
        }
 
356
        if (is_array($error)) {
 
357
            return $error['code'];
 
358
        }
 
359
        return false;
 
360
    }
 
361
 
 
362
    // }}}
 
363
    // {{{ prepare()
 
364
 
 
365
    /**
 
366
     * Prepares a query for multiple execution with execute().
 
367
     *
 
368
     * With oci8, this is emulated.
 
369
     *
 
370
     * prepare() requires a generic query as string like <code>
 
371
     *    INSERT INTO numbers VALUES (?, ?, ?)
 
372
     * </code>.  The <kbd>?</kbd> characters are placeholders.
 
373
     *
 
374
     * Three types of placeholders can be used:
 
375
     *   + <kbd>?</kbd>  a quoted scalar value, i.e. strings, integers
 
376
     *   + <kbd>!</kbd>  value is inserted 'as is'
 
377
     *   + <kbd>&</kbd>  requires a file name.  The file's contents get
 
378
     *                     inserted into the query (i.e. saving binary
 
379
     *                     data in a db)
 
380
     *
 
381
     * Use backslashes to escape placeholder characters if you don't want
 
382
     * them to be interpreted as placeholders.  Example: <code>
 
383
     *    "UPDATE foo SET col=? WHERE col='over \& under'"
 
384
     * </code>
 
385
     *
 
386
     * @param string $query query to be prepared
 
387
     * @return mixed DB statement resource on success. DB_Error on failure.
 
388
     */
 
389
    function prepare($query)
 
390
    {
 
391
        $tokens   = preg_split('/((?<!\\\)[&?!])/', $query, -1,
 
392
                               PREG_SPLIT_DELIM_CAPTURE);
 
393
        $binds    = count($tokens) - 1;
 
394
        $token    = 0;
 
395
        $types    = array();
 
396
        $newquery = '';
 
397
 
 
398
        foreach ($tokens as $key => $val) {
 
399
            switch ($val) {
 
400
                case '?':
 
401
                    $types[$token++] = DB_PARAM_SCALAR;
 
402
                    unset($tokens[$key]);
 
403
                    break;
 
404
                case '&':
 
405
                    $types[$token++] = DB_PARAM_OPAQUE;
 
406
                    unset($tokens[$key]);
 
407
                    break;
 
408
                case '!':
 
409
                    $types[$token++] = DB_PARAM_MISC;
 
410
                    unset($tokens[$key]);
 
411
                    break;
 
412
                default:
 
413
                    $tokens[$key] = preg_replace('/\\\([&?!])/', "\\1", $val);
 
414
                    if ($key != $binds) {
 
415
                        $newquery .= $tokens[$key] . ':bind' . $token;
 
416
                    } else {
 
417
                        $newquery .= $tokens[$key];
 
418
                    }
 
419
            }
 
420
        }
 
421
 
 
422
        $this->last_query = $query;
 
423
        $newquery = $this->modifyQuery($newquery);
 
424
        if (!$stmt = @OCIParse($this->connection, $newquery)) {
 
425
            return $this->oci8RaiseError();
 
426
        }
 
427
        $this->prepare_types[$stmt] = $types;
 
428
        $this->manip_query[(int)$stmt] = DB::isManip($query);
 
429
        return $stmt;
 
430
    }
 
431
 
 
432
    // }}}
 
433
    // {{{ execute()
 
434
 
 
435
    /**
 
436
     * Executes a DB statement prepared with prepare().
 
437
     *
 
438
     * @param resource  $stmt  a DB statement resource returned from prepare()
 
439
     * @param mixed  $data  array, string or numeric data to be used in
 
440
     *                      execution of the statement.  Quantity of items
 
441
     *                      passed must match quantity of placeholders in
 
442
     *                      query:  meaning 1 for non-array items or the
 
443
     *                      quantity of elements in the array.
 
444
     * @return int returns an oci8 result resource for successful
 
445
     * SELECT queries, DB_OK for other successful queries.  A DB error
 
446
     * code is returned on failure.
 
447
     * @see DB_oci::prepare()
 
448
     */
 
449
    function &execute($stmt, $data = array())
 
450
    {
 
451
        if (!is_array($data)) {
 
452
            $data = array($data);
 
453
        }
 
454
 
 
455
        $this->_data = $data;
 
456
 
 
457
        $types =& $this->prepare_types[$stmt];
 
458
        if (count($types) != count($data)) {
 
459
            $tmp =& $this->raiseError(DB_ERROR_MISMATCH);
 
460
            return $tmp;
 
461
        }
 
462
 
 
463
        $i = 0;
 
464
        foreach ($data as $key => $value) {
 
465
            if ($types[$i] == DB_PARAM_MISC) {
 
466
                /*
 
467
                 * Oracle doesn't seem to have the ability to pass a
 
468
                 * parameter along unchanged, so strip off quotes from start
 
469
                 * and end, plus turn two single quotes to one single quote,
 
470
                 * in order to avoid the quotes getting escaped by
 
471
                 * Oracle and ending up in the database.
 
472
                 */
 
473
                $data[$key] = preg_replace("/^'(.*)'$/", "\\1", $data[$key]);
 
474
                $data[$key] = str_replace("''", "'", $data[$key]);
 
475
            } elseif ($types[$i] == DB_PARAM_OPAQUE) {
 
476
                $fp = @fopen($data[$key], 'rb');
 
477
                if (!$fp) {
 
478
                    $tmp =& $this->raiseError(DB_ERROR_ACCESS_VIOLATION);
 
479
                    return $tmp;
 
480
                }
 
481
                $data[$key] = fread($fp, filesize($data[$key]));
 
482
                fclose($fp);
 
483
            }
 
484
            if (!@OCIBindByName($stmt, ':bind' . $i, $data[$key], -1)) {
 
485
                $tmp = $this->oci8RaiseError($stmt);
 
486
                return $tmp;
 
487
            }
 
488
            $i++;
 
489
        }
 
490
        if ($this->autoCommit) {
 
491
            $success = @OCIExecute($stmt, OCI_COMMIT_ON_SUCCESS);
 
492
        } else {
 
493
            $success = @OCIExecute($stmt, OCI_DEFAULT);
 
494
        }
 
495
        if (!$success) {
 
496
            $tmp = $this->oci8RaiseError($stmt);
 
497
            return $tmp;
 
498
        }
 
499
        $this->last_stmt = $stmt;
 
500
        if ($this->manip_query[(int)$stmt]) {
 
501
            $tmp = DB_OK;
 
502
        } else {
 
503
            $tmp =& new DB_result($this, $stmt);
 
504
        }
 
505
        return $tmp;
 
506
    }
 
507
 
 
508
    // }}}
 
509
    // {{{ autoCommit()
 
510
 
 
511
    /**
 
512
     * Enable/disable automatic commits
 
513
     *
 
514
     * @param $onoff true/false whether to autocommit
 
515
     */
 
516
    function autoCommit($onoff = false)
 
517
    {
 
518
        $this->autoCommit = (bool)$onoff;;
 
519
        return DB_OK;
 
520
    }
 
521
 
 
522
    // }}}
 
523
    // {{{ commit()
 
524
 
 
525
    /**
 
526
     * Commit transactions on the current connection
 
527
     *
 
528
     * @return DB_ERROR or DB_OK
 
529
     */
 
530
    function commit()
 
531
    {
 
532
        $result = @OCICommit($this->connection);
 
533
        if (!$result) {
 
534
            return $this->oci8RaiseError();
 
535
        }
 
536
        return DB_OK;
 
537
    }
 
538
 
 
539
    // }}}
 
540
    // {{{ rollback()
 
541
 
 
542
    /**
 
543
     * Roll back all uncommitted transactions on the current connection.
 
544
     *
 
545
     * @return DB_ERROR or DB_OK
 
546
     */
 
547
    function rollback()
 
548
    {
 
549
        $result = @OCIRollback($this->connection);
 
550
        if (!$result) {
 
551
            return $this->oci8RaiseError();
 
552
        }
 
553
        return DB_OK;
 
554
    }
 
555
 
 
556
    // }}}
 
557
    // {{{ affectedRows()
 
558
 
 
559
    /**
 
560
     * Gets the number of rows affected by the last query.
 
561
     * if the last query was a select, returns 0.
 
562
     *
 
563
     * @return number of rows affected by the last query or DB_ERROR
 
564
     */
 
565
    function affectedRows()
 
566
    {
 
567
        if ($this->last_stmt === false) {
 
568
            return $this->oci8RaiseError();
 
569
        }
 
570
        $result = @OCIRowCount($this->last_stmt);
 
571
        if ($result === false) {
 
572
            return $this->oci8RaiseError($this->last_stmt);
 
573
        }
 
574
        return $result;
 
575
    }
 
576
 
 
577
    // }}}
 
578
    // {{{ modifyQuery()
 
579
 
 
580
    function modifyQuery($query)
 
581
    {
 
582
        // "SELECT 2+2" must be "SELECT 2+2 FROM dual" in Oracle
 
583
        if (preg_match('/^\s*SELECT/i', $query) &&
 
584
            !preg_match('/\sFROM\s/i', $query)) {
 
585
            $query .= ' FROM dual';
 
586
        }
 
587
        return $query;
 
588
    }
 
589
 
 
590
    // }}}
 
591
    // {{{ modifyLimitQuery()
 
592
 
 
593
    /**
 
594
     * Emulate the row limit support altering the query
 
595
     *
 
596
     * @param string $query The query to treat
 
597
     * @param int    $from  The row to start to fetch from
 
598
     * @param int    $count The offset
 
599
     * @return string The modified query
 
600
     *
 
601
     * @author Tomas V.V.Cox <cox@idecnet.com>
 
602
     */
 
603
    function modifyLimitQuery($query, $from, $count)
 
604
    {
 
605
        // Let Oracle return the name of the columns instead of
 
606
        // coding a "home" SQL parser
 
607
        $q_fields = "SELECT * FROM ($query) WHERE NULL = NULL";
 
608
        if (!$result = @OCIParse($this->connection, $q_fields)) {
 
609
            $this->last_query = $q_fields;
 
610
            return $this->oci8RaiseError();
 
611
        }
 
612
        if (!@OCIExecute($result, OCI_DEFAULT)) {
 
613
            $this->last_query = $q_fields;
 
614
            return $this->oci8RaiseError($result);
 
615
        }
 
616
        $ncols = OCINumCols($result);
 
617
        $cols  = array();
 
618
        for ( $i = 1; $i <= $ncols; $i++ ) {
 
619
            $cols[] = '"' . OCIColumnName($result, $i) . '"';
 
620
        }
 
621
        $fields = implode(', ', $cols);
 
622
        // XXX Test that (tip by John Lim)
 
623
        //if (preg_match('/^\s*SELECT\s+/is', $query, $match)) {
 
624
        //    // Introduce the FIRST_ROWS Oracle query optimizer
 
625
        //    $query = substr($query, strlen($match[0]), strlen($query));
 
626
        //    $query = "SELECT /* +FIRST_ROWS */ " . $query;
 
627
        //}
 
628
 
 
629
        // Construct the query
 
630
        // more at: http://marc.theaimsgroup.com/?l=php-db&m=99831958101212&w=2
 
631
        // Perhaps this could be optimized with the use of Unions
 
632
        $query = "SELECT $fields FROM".
 
633
                 "  (SELECT rownum as linenum, $fields FROM".
 
634
                 "      ($query)".
 
635
                 '  WHERE rownum <= '. ($from + $count) .
 
636
                 ') WHERE linenum >= ' . ++$from;
 
637
        return $query;
 
638
    }
 
639
 
 
640
    // }}}
 
641
    // {{{ nextId()
 
642
 
 
643
    /**
 
644
     * Returns the next free id in a sequence
 
645
     *
 
646
     * @param string  $seq_name  name of the sequence
 
647
     * @param boolean $ondemand  when true, the seqence is automatically
 
648
     *                           created if it does not exist
 
649
     *
 
650
     * @return int  the next id number in the sequence.  DB_Error if problem.
 
651
     *
 
652
     * @internal
 
653
     * @see DB_common::nextID()
 
654
     * @access public
 
655
     */
 
656
    function nextId($seq_name, $ondemand = true)
 
657
    {
 
658
        $seqname = $this->getSequenceName($seq_name);
 
659
        $repeat = 0;
 
660
        do {
 
661
            $this->expectError(DB_ERROR_NOSUCHTABLE);
 
662
            $result =& $this->query("SELECT ${seqname}.nextval FROM dual");
 
663
            $this->popExpect();
 
664
            if ($ondemand && DB::isError($result) &&
 
665
                $result->getCode() == DB_ERROR_NOSUCHTABLE) {
 
666
                $repeat = 1;
 
667
                $result = $this->createSequence($seq_name);
 
668
                if (DB::isError($result)) {
 
669
                    return $this->raiseError($result);
 
670
                }
 
671
            } else {
 
672
                $repeat = 0;
 
673
            }
 
674
        } while ($repeat);
 
675
        if (DB::isError($result)) {
 
676
            return $this->raiseError($result);
 
677
        }
 
678
        $arr = $result->fetchRow(DB_FETCHMODE_ORDERED);
 
679
        return $arr[0];
 
680
    }
 
681
 
 
682
    /**
 
683
     * Creates a new sequence
 
684
     *
 
685
     * @param string $seq_name  name of the new sequence
 
686
     *
 
687
     * @return int  DB_OK on success.  A DB_Error object is returned if
 
688
     *              problems arise.
 
689
     *
 
690
     * @internal
 
691
     * @see DB_common::createSequence()
 
692
     * @access public
 
693
     */
 
694
    function createSequence($seq_name)
 
695
    {
 
696
        $seqname = $this->getSequenceName($seq_name);
 
697
        return $this->query("CREATE SEQUENCE ${seqname}");
 
698
    }
 
699
 
 
700
    // }}}
 
701
    // {{{ dropSequence()
 
702
 
 
703
    /**
 
704
     * Deletes a sequence
 
705
     *
 
706
     * @param string $seq_name  name of the sequence to be deleted
 
707
     *
 
708
     * @return int  DB_OK on success.  DB_Error if problems.
 
709
     *
 
710
     * @internal
 
711
     * @see DB_common::dropSequence()
 
712
     * @access public
 
713
     */
 
714
    function dropSequence($seq_name)
 
715
    {
 
716
        $seqname = $this->getSequenceName($seq_name);
 
717
        return $this->query("DROP SEQUENCE ${seqname}");
 
718
    }
 
719
 
 
720
    // }}}
 
721
    // {{{ oci8RaiseError()
 
722
 
 
723
    /**
 
724
     * Gather information about an error, then use that info to create a
 
725
     * DB error object and finally return that object.
 
726
     *
 
727
     * @param  integer  $errno  PEAR error number (usually a DB constant) if
 
728
     *                          manually raising an error
 
729
     * @return object  DB error object
 
730
     * @see DB_common::errorCode()
 
731
     * @see DB_common::raiseError()
 
732
     */
 
733
    function oci8RaiseError($errno = null)
 
734
    {
 
735
        if ($errno === null) {
 
736
            $error = @OCIError($this->connection);
 
737
            return $this->raiseError($this->errorCode($error['code']),
 
738
                                     null, null, null, $error['message']);
 
739
        } elseif (is_resource($errno)) {
 
740
            $error = @OCIError($errno);
 
741
            return $this->raiseError($this->errorCode($error['code']),
 
742
                                     null, null, null, $error['message']);
 
743
        }
 
744
        return $this->raiseError($this->errorCode($errno));
 
745
    }
 
746
 
 
747
    // }}}
 
748
    // {{{ getSpecialQuery()
 
749
 
 
750
    /**
 
751
     * Returns the query needed to get some backend info
 
752
     * @param string $type What kind of info you want to retrieve
 
753
     * @return string The SQL query string
 
754
     */
 
755
    function getSpecialQuery($type)
 
756
    {
 
757
        switch ($type) {
 
758
            case 'tables':
 
759
                return 'SELECT table_name FROM user_tables';
 
760
            default:
 
761
                return null;
 
762
        }
 
763
    }
 
764
 
 
765
    // }}}
 
766
    // {{{ tableInfo()
 
767
 
 
768
    /**
 
769
     * Returns information about a table or a result set.
 
770
     *
 
771
     * NOTE: only supports 'table' and 'flags' if <var>$result</var>
 
772
     * is a table name.
 
773
     *
 
774
     * NOTE: flags won't contain index information.
 
775
     *
 
776
     * @param object|string  $result  DB_result object from a query or a
 
777
     *                                string containing the name of a table
 
778
     * @param int            $mode    a valid tableInfo mode
 
779
     * @return array  an associative array with the information requested
 
780
     *                or an error object if something is wrong
 
781
     * @access public
 
782
     * @internal
 
783
     * @see DB_common::tableInfo()
 
784
     */
 
785
    function tableInfo($result, $mode = null)
 
786
    {
 
787
        if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
 
788
            $case_func = 'strtolower';
 
789
        } else {
 
790
            $case_func = 'strval';
 
791
        }
 
792
 
 
793
        if (is_string($result)) {
 
794
            /*
 
795
             * Probably received a table name.
 
796
             * Create a result resource identifier.
 
797
             */
 
798
            $result = strtoupper($result);
 
799
            $q_fields = 'SELECT column_name, data_type, data_length, '
 
800
                        . 'nullable '
 
801
                        . 'FROM user_tab_columns '
 
802
                        . "WHERE table_name='$result' ORDER BY column_id";
 
803
 
 
804
            $this->last_query = $q_fields;
 
805
 
 
806
            if (!$stmt = @OCIParse($this->connection, $q_fields)) {
 
807
                return $this->oci8RaiseError(DB_ERROR_NEED_MORE_DATA);
 
808
            }
 
809
            if (!@OCIExecute($stmt, OCI_DEFAULT)) {
 
810
                return $this->oci8RaiseError($stmt);
 
811
            }
 
812
 
 
813
            $i = 0;
 
814
            while (@OCIFetch($stmt)) {
 
815
                $res[$i]['table'] = $case_func($result);
 
816
                $res[$i]['name']  = $case_func(@OCIResult($stmt, 1));
 
817
                $res[$i]['type']  = @OCIResult($stmt, 2);
 
818
                $res[$i]['len']   = @OCIResult($stmt, 3);
 
819
                $res[$i]['flags'] = (@OCIResult($stmt, 4) == 'N') ? 'not_null' : '';
 
820
 
 
821
                if ($mode & DB_TABLEINFO_ORDER) {
 
822
                    $res['order'][$res[$i]['name']] = $i;
 
823
                }
 
824
                if ($mode & DB_TABLEINFO_ORDERTABLE) {
 
825
                    $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
 
826
                }
 
827
                $i++;
 
828
            }
 
829
 
 
830
            if ($mode) {
 
831
                $res['num_fields'] = $i;
 
832
            }
 
833
            @OCIFreeStatement($stmt);
 
834
 
 
835
        } else {
 
836
            if (isset($result->result)) {
 
837
                /*
 
838
                 * Probably received a result object.
 
839
                 * Extract the result resource identifier.
 
840
                 */
 
841
                $result = $result->result;
 
842
            } else {
 
843
                /*
 
844
                 * ELSE, probably received a result resource identifier.
 
845
                 * Depricated.  Here for compatibility only.
 
846
                 */
 
847
            }
 
848
 
 
849
            if ($result === $this->last_stmt) {
 
850
                $count = @OCINumCols($result);
 
851
 
 
852
                for ($i=0; $i<$count; $i++) {
 
853
                    $res[$i]['table'] = '';
 
854
                    $res[$i]['name']  = $case_func(@OCIColumnName($result, $i+1));
 
855
                    $res[$i]['type']  = @OCIColumnType($result, $i+1);
 
856
                    $res[$i]['len']   = @OCIColumnSize($result, $i+1);
 
857
                    $res[$i]['flags'] = '';
 
858
 
 
859
                    if ($mode & DB_TABLEINFO_ORDER) {
 
860
                        $res['order'][$res[$i]['name']] = $i;
 
861
                    }
 
862
                    if ($mode & DB_TABLEINFO_ORDERTABLE) {
 
863
                        $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
 
864
                    }
 
865
                }
 
866
 
 
867
                if ($mode) {
 
868
                    $res['num_fields'] = $count;
 
869
                }
 
870
 
 
871
            } else {
 
872
                return $this->raiseError(DB_ERROR_NOT_CAPABLE);
 
873
            }
 
874
        }
 
875
        return $res;
 
876
    }
 
877
 
 
878
    // }}}
 
879
 
 
880
}
 
881
 
 
882
/*
 
883
 * Local variables:
 
884
 * tab-width: 4
 
885
 * c-basic-offset: 4
 
886
 * End:
 
887
 */
 
888
 
 
889
?>