/[cvs]/nfo/php/libs/net.php.pear/DB/oci8.php
ViewVC logotype

Annotation of /nfo/php/libs/net.php.pear/DB/oci8.php

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.1 - (hide annotations)
Tue Oct 29 19:11:41 2002 UTC (21 years, 8 months ago) by cvsjoko
Branch: MAIN
CVS Tags: HEAD
+ new pear-libraries

1 cvsjoko 1.1 <?php
2     //
3     // +----------------------------------------------------------------------+
4     // | PHP Version 4 |
5     // +----------------------------------------------------------------------+
6     // | Copyright (c) 1997-2002 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     // +----------------------------------------------------------------------+
18     //
19     // $Id: oci8.php,v 1.47.2.1 2002/04/09 19:04:15 ssb Exp $
20     //
21     // Database independent query interface definition for PHP's Oracle 8
22     // call-interface extension.
23     //
24    
25     //
26     // be aware... OCIError() only appears to return anything when given a
27     // statement, so functions return the generic DB_ERROR instead of more
28     // useful errors that have to do with feedback from the database.
29     //
30    
31    
32     require_once 'DB/common.php';
33    
34     class DB_oci8 extends DB_common
35     {
36     // {{{ properties
37    
38     var $connection;
39     var $phptype, $dbsyntax;
40     var $manip_query = array();
41     var $prepare_types = array();
42     var $autoCommit = 1;
43     var $last_stmt = false;
44    
45     // }}}
46     // {{{ constructor
47    
48     function DB_oci8()
49     {
50     $this->DB_common();
51     $this->phptype = 'oci8';
52     $this->dbsyntax = 'oci8';
53     $this->features = array(
54     'prepare' => false,
55     'pconnect' => true,
56     'transactions' => true,
57     'limit' => 'alter'
58     );
59     $this->errorcode_map = array(
60     900 => DB_ERROR_SYNTAX,
61     904 => DB_ERROR_NOSUCHFIELD,
62     923 => DB_ERROR_SYNTAX,
63     942 => DB_ERROR_NOSUCHTABLE,
64     955 => DB_ERROR_ALREADY_EXISTS,
65     1476 => DB_ERROR_DIVZERO,
66     1722 => DB_ERROR_INVALID_NUMBER,
67     2289 => DB_ERROR_NOSUCHTABLE,
68     2291 => DB_ERROR_CONSTRAINT,
69     2449 => DB_ERROR_CONSTRAINT,
70     );
71     }
72    
73     // }}}
74     // {{{ connect()
75    
76     /**
77     * Connect to a database and log in as the specified user.
78     *
79     * @param $dsn the data source name (see DB::parseDSN for syntax)
80     * @param $persistent (optional) whether the connection should
81     * be persistent
82     *
83     * @return int DB_OK on success, a DB error code on failure
84     */
85     function connect($dsninfo, $persistent = false)
86     {
87     if (!DB::assertExtension('oci8')) {
88     return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
89     }
90     $this->dsn = $dsninfo;
91     $user = $dsninfo['username'];
92     $pw = $dsninfo['password'];
93     $hostspec = $dsninfo['hostspec'];
94    
95     $connect_function = $persistent ? 'OCIPLogon' : 'OCILogon';
96    
97     if ($hostspec) {
98     $conn = @$connect_function($user,$pw,$hostspec);
99     } elseif ($user || $pw) {
100     $conn = @$connect_function($user,$pw);
101     } else {
102     $conn = false;
103     }
104     if ($conn == false) {
105     $error = OCIError();
106     $error = (is_array($error)) ? $error['message'] : null;
107     return $this->raiseError(DB_ERROR_CONNECT_FAILED, null, null,
108     null, $error);
109     }
110     $this->connection = $conn;
111     return DB_OK;
112     }
113    
114     // }}}
115     // {{{ disconnect()
116    
117     /**
118     * Log out and disconnect from the database.
119     *
120     * @return bool TRUE on success, FALSE if not connected.
121     */
122     function disconnect()
123     {
124     $ret = @OCILogOff($this->connection);
125     $this->connection = null;
126     return $ret;
127     }
128    
129     // }}}
130     // {{{ simpleQuery()
131    
132     /**
133     * Send a query to oracle and return the results as an oci8 resource
134     * identifier.
135     *
136     * @param $query the SQL query
137     *
138     * @return int returns a valid oci8 result for successful SELECT
139     * queries, DB_OK for other successful queries. A DB error code
140     * is returned on failure.
141     */
142     function simpleQuery($query)
143     {
144     $this->last_query = $query;
145     $query = $this->modifyQuery($query);
146     $result = @OCIParse($this->connection, $query);
147     if (!$result) {
148     return $this->oci8RaiseError();
149     }
150     if ($this->autoCommit) {
151     $success = @OCIExecute($result,OCI_COMMIT_ON_SUCCESS);
152     } else {
153     $success = @OCIExecute($result,OCI_DEFAULT);
154     }
155     if (!$success) {
156     return $this->oci8RaiseError($result);
157     }
158     $this->last_stmt=$result;
159     // Determine which queries that should return data, and which
160     // should return an error code only.
161     return DB::isManip($query) ? DB_OK : $result;
162     }
163    
164     // }}}
165     // {{{ nextResult()
166    
167     /**
168     * Move the internal oracle result pointer to the next available result
169     *
170     * @param a valid oci8 result resource
171     *
172     * @access public
173     *
174     * @return true if a result is available otherwise return false
175     */
176     function nextResult($result)
177     {
178     return false;
179     }
180    
181     // }}}
182     // {{{ fetchRow()
183    
184     /**
185     * Fetch a row and return as array.
186     *
187     * @param $result oci8 result identifier
188     * @param $fetchmode how the resulting array should be indexed
189     *
190     * @return int an array on success, a DB error code on failure, NULL
191     * if there is no more data
192     */
193     function &fetchRow($result, $fetchmode = DB_FETCHMODE_DEFAULT)
194     {
195     if ($fetchmode == DB_FETCHMODE_DEFAULT) {
196     $fetchmode = $this->fetchmode;
197     }
198     if ($fetchmode & DB_FETCHMODE_ASSOC) {
199     $moredata = @OCIFetchInto($result, $row, OCI_ASSOC + OCI_RETURN_NULLS + OCI_RETURN_LOBS);
200     } else {
201     $moredata = @OCIFetchInto($result, $row, OCI_RETURN_NULLS + OCI_RETURN_LOBS);
202     }
203     if (!$moredata) {
204     return NULL;
205     }
206     return $row;
207     }
208    
209     // }}}
210     // {{{ fetchInto()
211    
212     /**
213     * Fetch a row and insert the data into an existing array.
214     *
215     * @param $result oci8 result identifier
216     * @param $arr (reference) array where data from the row is stored
217     * @param $fetchmode how the array data should be indexed
218     * @param $rownum the row number to fetch (not yet supported)
219     *
220     * @return int DB_OK on success, a DB error code on failure
221     */
222     function fetchInto($result, &$arr, $fetchmode = DB_FETCHMODE_DEFAULT, $rownum=NULL)
223     {
224     if ($rownum !== NULL) {
225     return $this->raiseError(DB_ERROR_NOT_CAPABLE);
226     }
227     if ($fetchmode & DB_FETCHMODE_ASSOC) {
228     $moredata = @OCIFetchInto($result,$arr,OCI_ASSOC+OCI_RETURN_NULLS+OCI_RETURN_LOBS);
229     if ($moredata && $this->options['optimize'] == 'portability') {
230     $arr = array_change_key_case($arr, CASE_LOWER);
231     }
232     } else {
233     $moredata = @OCIFetchInto($result,$arr,OCI_RETURN_NULLS+OCI_RETURN_LOBS);
234     }
235     if (!$moredata) {
236     return NULL;
237     }
238     return DB_OK;
239     }
240    
241     // }}}
242     // {{{ freeResult()
243    
244     /**
245     * Free the internal resources associated with $result.
246     *
247     * @param $result oci8 result identifier or DB statement identifier
248     *
249     * @return bool TRUE on success, FALSE if $result is invalid
250     */
251     function freeResult($result)
252     {
253     if (is_resource($result)) {
254     return @OCIFreeStatement($result);
255     }
256     if (!isset($this->prepare_tokens[(int)$result])) {
257     return false;
258     }
259     unset($this->prepare_tokens[(int)$result]);
260     unset($this->prepare_types[(int)$result]);
261     unset($this->manip_query[(int)$result]);
262     return true;
263     }
264    
265     // }}}
266     // {{{ numRows()
267    
268     function numRows($result)
269     {
270     // emulate numRows for Oracle. yuck.
271     if ($this->options['optimize'] == 'portability' &&
272     $result === $this->last_stmt) {
273     $countquery = preg_replace('/^\s*SELECT\s+(.*?)\s+FROM\s+/is',
274     'SELECT COUNT(*) FROM ',
275     $this->last_query);
276     $save_query = $this->last_query;
277     $save_stmt = $this->last_stmt;
278     $count = $this->query($countquery);
279     if (DB::isError($count) ||
280     DB::isError($row = $count->fetchRow(DB_FETCHMODE_ORDERED)))
281     {
282     $this->last_query = $save_query;
283     $this->last_stmt = $save_stmt;
284     return $this->raiseError(DB_ERROR_NOT_CAPABLE);
285     }
286     return $row[0];
287     }
288     return $this->raiseError(DB_ERROR_NOT_CAPABLE);
289     }
290    
291     // }}}
292     // {{{ numCols()
293    
294     /**
295     * Get the number of columns in a result set.
296     *
297     * @param $result oci8 result identifier
298     *
299     * @return int the number of columns per row in $result
300     */
301     function numCols($result)
302     {
303     $cols = @OCINumCols($result);
304     if (!$cols) {
305     return $this->oci8RaiseError($result);
306     }
307     return $cols;
308     }
309    
310     // }}}
311     // {{{ errorNative()
312    
313     /**
314     * Get the native error code of the last error (if any) that occured
315     * on the current connection. This does not work, as OCIError does
316     * not work unless given a statement. If OCIError does return
317     * something, so will this.
318     *
319     * @return int native oci8 error code
320     */
321     function errorNative()
322     {
323     if (is_resource($this->last_stmt)) {
324     $error = @OCIError($this->last_stmt);
325     } else {
326     $error = @OCIError($this->connection);
327     }
328     if (is_array($error)) {
329     return $error['code'];
330     }
331     return false;
332     }
333    
334     // }}}
335     // {{{ prepare()
336    
337     /**
338     * Prepares a query for multiple execution with execute(). With
339     * oci8, this is emulated.
340     * @param $query query to be prepared
341     *
342     * @return DB statement resource
343     */
344     function prepare($query)
345     {
346     $tokens = split('[\&\?]', $query);
347     $token = 0;
348     $types = array();
349     for ($i = 0; $i < strlen($query); $i++) {
350     switch ($query[$i]) {
351     case '?':
352     $types[$token++] = DB_PARAM_SCALAR;
353     break;
354     case '&':
355     $types[$token++] = DB_PARAM_OPAQUE;
356     break;
357     }
358     }
359     $binds = sizeof($tokens) - 1;
360     $newquery = '';
361     for ($i = 0; $i < $binds; $i++) {
362     $newquery .= $tokens[$i] . ":bind" . $i;
363     }
364     $newquery .= $tokens[$i];
365     $this->last_query = $query;
366     $newquery = $this->modifyQuery($newquery);
367     $stmt = @OCIParse($this->connection, $newquery);
368     $this->prepare_types[$stmt] = $types;
369     $this->manip_query[(int)$stmt] = DB::isManip($query);
370     return $stmt;
371     }
372    
373     // }}}
374     // {{{ execute()
375    
376     /**
377     * Executes a DB statement prepared with prepare().
378     *
379     * @param $stmt a DB statement resource (returned from prepare())
380     * @param $data data to be used in execution of the statement
381     *
382     * @return int returns an oci8 result resource for successful
383     * SELECT queries, DB_OK for other successful queries. A DB error
384     * code is returned on failure.
385     */
386     function execute($stmt, $data = false)
387     {
388     $types=&$this->prepare_types[$stmt];
389     if (($size = sizeof($types)) != sizeof($data)) {
390     return $this->raiseError(DB_ERROR_MISMATCH);
391     }
392     for ($i = 0; $i < $size; $i++) {
393     if (is_array($data)) {
394     $pdata[$i] = &$data[$i];
395     }
396     else {
397     $pdata[$i] = &$data;
398     }
399     if ($types[$i] == DB_PARAM_OPAQUE) {
400     $fp = fopen($pdata[$i], "r");
401     $pdata[$i] = '';
402     if ($fp) {
403     while (($buf = fread($fp, 4096)) != false) {
404     $pdata[$i] .= $buf;
405     }
406     }
407     }
408     if (!@OCIBindByName($stmt, ":bind" . $i, $pdata[$i], -1)) {
409     return $this->oci8RaiseError($stmt);
410     }
411     }
412     if ($this->autoCommit) {
413     $success = @OCIExecute($stmt, OCI_COMMIT_ON_SUCCESS);
414     }
415     else {
416     $success = @OCIExecute($stmt, OCI_DEFAULT);
417     }
418     if (!$success) {
419     return $this->oci8RaiseError($stmt);
420     }
421     $this->last_stmt = $stmt;
422     if ($this->manip_query[(int)$stmt]) {
423     return DB_OK;
424     } else {
425     return new DB_result($this, $stmt);
426     }
427     }
428    
429     // }}}
430     // {{{ autoCommit()
431    
432     /**
433     * Enable/disable automatic commits
434     *
435     * @param $onoff true/false whether to autocommit
436     */
437     function autoCommit($onoff = false)
438     {
439     $this->autoCommit = (bool)$onoff;;
440     return DB_OK;
441     }
442    
443     // }}}
444     // {{{ commit()
445    
446     /**
447     * Commit transactions on the current connection
448     *
449     * @return DB_ERROR or DB_OK
450     */
451     function commit()
452     {
453     $result = @OCICommit($this->connection);
454     if (!$result) {
455     return $this->oci8RaiseError();
456     }
457     return DB_OK;
458     }
459    
460     // }}}
461     // {{{ rollback()
462    
463     /**
464     * Roll back all uncommitted transactions on the current connection.
465     *
466     * @return DB_ERROR or DB_OK
467     */
468     function rollback()
469     {
470     $result = @OCIRollback($this->connection);
471     if (!$result) {
472     return $this->oci8RaiseError();
473     }
474     return DB_OK;
475     }
476    
477     // }}}
478     // {{{ affectedRows()
479    
480     /**
481     * Gets the number of rows affected by the last query.
482     * if the last query was a select, returns 0.
483     *
484     * @return number of rows affected by the last query or DB_ERROR
485     */
486     function affectedRows()
487     {
488     if ($this->last_stmt === false) {
489     return $this->oci8RaiseError();
490     }
491     $result = @OCIRowCount($this->last_stmt);
492     if ($result === false) {
493     return $this->oci8RaiseError($this->last_stmt);
494     }
495     return $result;
496     }
497    
498     // }}}
499     // {{{ modifyQuery()
500    
501     function modifyQuery($query)
502     {
503     // "SELECT 2+2" must be "SELECT 2+2 FROM dual" in Oracle
504     if (preg_match('/^\s*SELECT/i', $query) &&
505     !preg_match('/\sFROM\s/i', $query)) {
506     $query .= " FROM dual";
507     }
508     return $query;
509     }
510    
511     // }}}
512     // {{{ modifyLimitQuery()
513    
514     /**
515     * Emulate the row limit support altering the query
516     *
517     * @param string $query The query to treat
518     * @param int $from The row to start to fetch from
519     * @param int $count The offset
520     * @return string The modified query
521     *
522     * @author Tomas V.V.Cox <cox@idecnet.com>
523     */
524     function modifyLimitQuery($query, $from, $count)
525     {
526     // Let Oracle return the name of the columns instead of
527     // coding a "home" SQL parser
528     $q_fields = "SELECT * FROM ($query) WHERE NULL = NULL";
529     if (!$result = OCIParse($this->connection, $q_fields)) {
530     return $this->oci8RaiseError();
531     }
532     if (!OCIExecute($result, OCI_DEFAULT)) {
533     return $this->oci8RaiseError($result);
534     }
535     $ncols = OCINumCols($result);
536     $cols = array();
537     for ( $i = 1; $i <= $ncols; $i++ ) {
538     $cols[] = OCIColumnName($result, $i);
539     }
540     $fields = implode(', ', $cols);
541     // XXX Test that (tip by John Lim)
542     //if(preg_match('/^\s*SELECT\s+/is', $query, $match)) {
543     // // Introduce the FIRST_ROWS Oracle query optimizer
544     // $query = substr($query, strlen($match[0]), strlen($query));
545     // $query = "SELECT /* +FIRST_ROWS */ " . $query;
546     //}
547    
548     // Construct the query
549     // more at: http://marc.theaimsgroup.com/?l=php-db&m=99831958101212&w=2
550     // Perhaps this could be optimized with the use of Unions
551     $from += 1; // in Oracle rownum starts at 1
552     $query = "SELECT $fields FROM".
553     " (SELECT rownum as linenum, $fields FROM".
554     " ($query)".
555     " WHERE rownum <= ". ($from + $count) .
556     ") WHERE linenum >= $from";
557     return $query;
558     }
559    
560     // }}}
561     // {{{ nextId()
562    
563     /**
564     * Get the next value in a sequence. We emulate sequences
565     * for MySQL. Will create the sequence if it does not exist.
566     *
567     * @access public
568     *
569     * @param $seq_name the name of the sequence
570     *
571     * @param $ondemand whether to create the sequence table on demand
572     * (default is true)
573     *
574     * @return a sequence integer, or a DB error
575     */
576     function nextId($seq_name, $ondemand = true)
577     {
578     $seqname = $this->getSequenceName($seq_name);
579     $repeat = 0;
580     do {
581     $this->expectError(DB_ERROR_NOSUCHTABLE);
582     $result = $this->query("SELECT ${seqname}.nextval FROM dual");
583     $this->popExpect();
584     if ($ondemand && DB::isError($result) &&
585     $result->getCode() == DB_ERROR_NOSUCHTABLE) {
586     $repeat = 1;
587     $result = $this->createSequence($seq_name);
588     if (DB::isError($result)) {
589     return $this->raiseError($result);
590     }
591     } else {
592     $repeat = 0;
593     }
594     } while ($repeat);
595     if (DB::isError($result)) {
596     return $this->raiseError($result);
597     }
598     $arr = $result->fetchRow(DB_FETCHMODE_ORDERED);
599     return $arr[0];
600     }
601    
602     // }}}
603     // {{{ createSequence()
604    
605     function createSequence($seq_name)
606     {
607     $seqname = $this->getSequenceName($seq_name);
608     return $this->query("CREATE SEQUENCE ${seqname}");
609     }
610    
611     // }}}
612     // {{{ dropSequence()
613    
614     function dropSequence($seq_name)
615     {
616     $seqname = $this->getSequenceName($seq_name);
617     return $this->query("DROP SEQUENCE ${seqname}");
618     }
619    
620     // }}}
621     // {{{ oci8RaiseError()
622    
623     function oci8RaiseError($errno = null)
624     {
625     if ($errno === null) {
626     $error = @OCIError($this->connection);
627     return $this->raiseError($this->errorCode($error['code']),
628     null, null, null, $error['message']);
629     } elseif (is_resource($errno)) {
630     $error = @OCIError($errno);
631     return $this->raiseError($this->errorCode($error['code']),
632     null, null, null, $error['message']);
633     }
634     return $this->raiseError($this->errorCode($errno));
635     }
636    
637     // }}}
638     // {{{ getSpecialQuery()
639    
640     /**
641     * Returns the query needed to get some backend info
642     * @param string $type What kind of info you want to retrieve
643     * @return string The SQL query string
644     */
645     function getSpecialQuery($type)
646     {
647     switch ($type) {
648     case 'tables':
649     $sql = "SELECT table_name FROM user_tables";
650     break;
651     default:
652     return null;
653     }
654     return $sql;
655     }
656    
657     // }}}
658    
659     }
660     // Local variables:
661     // tab-width: 4
662     // c-basic-offset: 4
663     // End:
664     ?>

MailToCvsAdmin">MailToCvsAdmin
ViewVC Help
Powered by ViewVC 1.1.26 RSS 2.0 feed